X Marks the Spot

18

1

X Marks the spot

Your goal is to add a cross-hair around the capital X:

Example Input / Output

Input:

                mdhyyyyyyyhhhddmmm                
            mdyyssoo  oooosyyyhhhdmm              
          hsso     oossoooooyyhhdhhdmmm           
        yoooooo     oo ssysssyhhdyyyhmmmm         
      myso oso  o  oyo    hhhdhhyhyhhm mm m       
     mhsyhhys  oss      yyyhhhsosyhhmmmmdmmm
    mhyhhhy y         ssyhoho o shhdmmmmdmmmm        
    hhyyyh   s   oo syysyyhhdysso oyhdhhhmmmmm     
   dhysyys      sdysoXoyyyyhhso     syshm  mmm    
   hhyhyo       o      osss y   shhyyhd mmmmmm    
   yyhyyyss           o  oyyyydmmdmmmmmmmmm mm    
   ysyhyhhho   s     osy  sdm m  mddmmddhydmmm   
   h  oshhhyyyddhoo  ooyysshdmdohdmmdmddsshmmm    
    y   oyhhhdhhsyhsssshdddsss    hdddyyyhddm     
    dyyshyyhssyyhyyyyddhhmmdmmmdy syssoosyhdm     
     hsyyhhhhsoo sooyyhhdoohdhhyhyysoo  osdm      
      doyhhhyyyyhhhysyyy oossyyssso   osydm       
        soyhyyhhhhhhyhyyyooos       ohdddm        
         msoyyyyyyyhyyyyo ooo       syyd          
            ho oyyysooo    osso   osyd            
               dhyyysssyyyyyysoosdm               
                    mmdddddmmm                    

Output:

                mdhyyyyyyyhhhddmmm                
            mdyyssoo  oooosyyyhhhdmm              
          hsso     oossoooooyyhhdhhdmmm           
        yoooooo     oo ssysssyhhdyyyhmmmm         
      myso oso  o  oyo    hhhdhhyhyhhm mm m       
     mhsyhhys  oss   |  yyyhhhsosyhhmmmmdmmm
    mhyhhhy y        |ssyhoho o shhdmmmmdmmmm        
    hhyyyh   s   oo s|ysyyhhdysso oyhdhhhmmmmm     
   dhysyys      -----X-----hhso     syshm  mmm    
   hhyhyo       o    | osss y   shhyyhd mmmmmm    
   yyhyyyss          |o  oyyyydmmdmmmmmmmmm mm    
   ysyhyhhho   s     |sy  sdm m  mddmmddhydmmm   
   h  oshhhyyyddhoo  ooyysshdmdohdmmdmddsshmmm    
    y   oyhhhdhhsyhsssshdddsss    hdddyyyhddm     
    dyyshyyhssyyhyyyyddhhmmdmmmdy syssoosyhdm     
     hsyyhhhhsoo sooyyhhdoohdhhyhyysoo  osdm      
      doyhhhyyyyhhhysyyy oossyyssso   osydm       
        soyhyyhhhhhhyhyyyooos       ohdddm        
         msoyyyyyyyhyyyyo ooo       syyd          
            ho oyyysooo    osso   osyd            
               dhyyysssyyyyyysoosdm               
                    mmdddddmmm               

Input:

000000000000
000000000000
0000X0000000
0000000X0000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000

Output:

     |
 0000|00|0000
 0000|00|0000
-----X--+--00
 00--+--X-----
 0000|00|0000
 0000|00|0000
 0000000|0000
 000000000000
 000000000000
 000000000000
 000000000000
 000000000000

Input:

00000000000000000
00000000000000000
00000000000000000
00000X000X0000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000   

Output:

00000|000|0000000
00000|000|0000000
00000|000|0000000
----+#+++#+----00
00000|000|0000000
00000|000|0000000
00000|000|0000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000
00000000000000000    

Crosshair

Your cross-hair should be a 3-tall and 5-wide:

     |
     |
     |
-----X-----
     |
     |
     |

Input

Input will be at least 12x12 characters in size and will consist of only ASCII characters. It can be taken in through STDIN or function argument. The input will not always contain an X. Input will be in any shape and have an arbitrary amount of whitespace. The input will not contain any of: +, -, #, and |

Output

Output can be through STDOUT or a function's return value. Output should be the input image with the cross-hair drawn. If there is not enough space to draw the crosshair, you must add lines / spaces to draw it. Overlapping spots should be replaced with a +. If the | or - of the crosshairs overlaps an X, instead of a +, an # should appear.

Trailing whitespace is not allowed except for a single newline at the very end.


This is code-golf so shortest code in bytes wins!

Downgoat

Posted 2015-08-04T03:48:36.483

Reputation: 27 116

1>

  • if the input is an argument, does it have to be a string with lines separated by newlines, or can it be an array of strings? 2. is it acceptable to add whitespace around the design even if not necessary (i.e always add 3 rows above / below and 5 columns to the left / right)? 3. The input is missing for the 3rd test case.
  • < – Level River St – 2015-08-04T04:42:39.727

    @steveverrill 1. It will be a newline separated string, not an array of strings 2. No, that is not allowed. You can use that in your code but it shouldn't appear in the output – Downgoat – 2015-08-04T04:44:29.067

    3Does the + for overlapping - and | apply only when those characters are part of crosshairs, or does it affect literal - and | found in the input as well? – DLosc – 2015-08-04T05:47:34.350

    Can we assume a rectangular input i.e. all lines (including whitespace) will be the same length? – Level River St – 2015-08-04T09:27:00.933

    @steveverrill I think not: The input will not always contain an X. Input will be in any shape and have an arbitrary amount of whitespace., but I agree that it would make things a lot easier. – flawr – 2015-08-04T10:20:42.167

    1@DLosc those will not be in the input. I've updated the question – Downgoat – 2015-08-04T15:53:36.013

    1What if a literal # in the input is encountered by a crosshair? Will it be overwritten? – Kodos Johnson – 2015-08-05T23:08:10.423

    @Andrew no, # won't be in the inout – Downgoat – 2015-08-05T23:12:34.803

    Will all lines of the input always be equal length? – George Reith – 2015-08-06T17:14:59.320

    @GeorgeReith no the input's lines may be different lengths – Downgoat – 2015-08-06T17:16:24.820

    Damn... I'll need to make another change to my answer then! – Dom Hastings – 2015-08-06T18:46:38.697

    Are ASCII nonprintable characters (such as '\t' or '\r') allowed in input? – edc65 – 2015-08-07T20:09:29.207

    @edc65 nope, they aren't – Downgoat – 2015-08-07T20:10:17.013

    Answers

    3

    CoffeeScript, 345 336  327 bytes

    Z=(s,c)->s in'X#'&&'#'||s in'-|+'&&'+'||c
    X=(s)->l=u=0;o=(r.split ''for r in s.split '\n');c in'X#'&&(i-x&&(o[y][i]=Z o[y][i],'-';i<l&&l=i)for i in[x-5..x+5];i-y&&((o[i]?=[])[x]=Z o[i][x],'|';i<u&&u=i)for i in[y-3..y+3])for c,x in r for r,y in o;((o[y][x]||' 'for x in[l...o[y].length]).join ''for y in[u...o.length]).join '\n'
    

    X is the function to call.

    Explained:

    # get new char. s - old char. c - '|' or '-'
    Z=(s,c)->s in'X#'&&'#'||s in'-|+'&&'+'||c
    
    X=(s)->
    
      # leftmost and upmost positions
      l=u=0
    
      # split input into 2D array
      o=(r.split ''for r in s.split '\n')
    
      # for every 'X' or '#'
      c in'X#'&&(
    
        # for positions to left and right
        i-x&&(
    
            # draw horisontal line
          o[y][i]=Z o[y][i],'-'
    
          # update leftmost position
          i<l&&l=i
    
        )for i in[x-5..x+5]
    
        # for positions above and below
        i-y&&(
    
          # add row if necessary and draw vertical line
          (o[i]?=[])[x]=Z o[i][x],'|'
    
          # update upmost position
          i<u&&u=i
    
        )for i in[y-3..y+3]
    
      )for c,x in r for r,y in o
    
      # concatenate into string, replacing empty chars with spaces
      ((o[y][x]||' 'for x in[l...o[y].length]).join ''for y in[u...o.length]).join '\n'
    

    Executable:

    <script src="http://coffeescript.org/extras/coffee-script.js"></script>
    <script type="text/coffeescript">
    
    Z=(s,c)->s in'X#'&&'#'||s in'-|+'&&'+'||c
    X=(s)->l=u=0;o=(r.split ''for r in s.split '\n');c in'X#'&&(i-x&&(o[y][i]=Z o[y][i],'-';i<l&&l=i)for i in[x-5..x+5];i-y&&((o[i]?=[])[x]=Z o[i][x],'|';i<u&&u=i)for i in[y-3..y+3])for c,x in r for r,y in o;((o[y][x]||' 'for x in[l...o[y].length]).join ''for y in[u...o.length]).join '\n'
    
    ################################################################################
    # tests follow
    s = ['''
                    mdhyyyyyyyhhhddmmm                
                mdyyssoo  oooosyyyhhhdmm              
              hsso     oossoooooyyhhdhhdmmm           
            yoooooo     oo ssysssyhhdyyyhmmmm         
          myso oso  o  oyo    hhhdhhyhyhhm mm m       
         mhsyhhys  oss      yyyhhhsosyhhmmmmdmmm
        mhyhhhy y         ssyhoho o shhdmmmmdmmmm        
        hhyyyh   s   oo syysyyhhdysso oyhdhhhmmmmm     
       dhysyys      sdysoXoyyyyhhso     syshm  mmm    
       hhyhyo       o      osss y   shhyyhd mmmmmm    
       yyhyyyss           o  oyyyydmmdmmmmmmmmm mm    
       ysyhyhhho   s     osy  sdm m  mddmmddhydmmm   
       h  oshhhyyyddhoo  ooyysshdmdohdmmdmddsshmmm    
        y   oyhhhdhhsyhsssshdddsss    hdddyyyhddm     
        dyyshyyhssyyhyyyyddhhmmdmmmdy syssoosyhdm     
         hsyyhhhhsoo sooyyhhdoohdhhyhyysoo  osdm      
          doyhhhyyyyhhhysyyy oossyyssso   osydm       
            soyhyyhhhhhhyhyyyooos       ohdddm        
             msoyyyyyyyhyyyyo ooo       syyd          
                ho oyyysooo    osso   osyd            
                   dhyyysssyyyyyysoosdm               
                        mmdddddmmm                    
    '''
    '''
    000000000000
    000000000000
    0000X0000000
    0000000X0000
    000000000000
    000000000000
    000000000000
    000000000000
    000000000000
    000000000000
    000000000000
    000000000000
    '''
    '''
    00000000000000000
    00000000000000000
    00000000000000000
    00000X000X0000000
    00000000000000000
    00000000000000000
    00000000000000000
    00000000000000000
    00000000000000000
    00000000000000000
    00000000000000000
    00000000000000000   
    '''
    'X'
    'XX\nXX'
    ]
    document.write '<pre>'
    document.write '\n\n',X x for x in s
    </script>

    metalim

    Posted 2015-08-04T03:48:36.483

    Reputation: 523

    1345 is too good! I'm trying to get close, but you're way ahead so far! I don't know if I can do much more without changing my approach entirely... Hmm :) – Dom Hastings – 2015-08-08T20:08:29.657

    Until somebody comes with CJam/Pyth/GolfScript and makes sub-100. But thank you. – metalim – 2015-08-08T21:13:14.563

    Hah.. Too true... I'm wondering if this should be the encouragement I need to learn Pyth... – Dom Hastings – 2015-08-08T21:16:40.920

    4

    Python 3, 577 519 515 490 475 467 454 bytes

    def c(g,d):
     R,L,V,e,b=range,list,len,'-|+','#';t,g=(lambda g,d:sum([[(i,j)for j in R(V(L(g.split('\n')[i])))if g.split('\n')[i][j]==d]for i in R(V(g.split('\n')))],[]))(g,d),[L(i)for i in g.split('\n')]
     for a,r in t:
      for j in R(a-3,a+4):
       if V(g)>j>-1:n=g[j][r];g[j][r]='+'if n in e else'#'if n in(d,b)else'|'
      for j in R(r-5,r+6):
       if V(g[a])>j>-1:n=g[a][j];g[a][j]='+'if n in e else'#'if n in(d,b)else'-'
     return'\n'.join(''.join(l)for l in g)
    

    I'm not sure how much farther I can golf this.

    Usage:

    c(g, d)
    

    Where g is the input grid and d is the crosshair-marking character.

    Zach Gates

    Posted 2015-08-04T03:48:36.483

    Reputation: 6 152

    3

    Perl, 370 bytes

    sub r{$h=pop;($=[$n=pop].=$"x(1+"@_"-length$=[$n]))=~s!(.{@_})(.)!"$1".($2=~/[-|+]/?'+':$2=~/[X#]/?'#':$h)!e}map{chop;push@c,[$-,pos]while/X/g;$-++}@==<>;($x,$y)=@$_,3-$x>$a?$a=3-$x:0,$x+5-@=>$b?$b=$x+5-@=:0,6-$y>$c?$c=6-$y:0 for@c;@==($",@=)for 1..$a;$_=$"x$c.$_ for@=;map{($x,$y)=@$_;$_&&r$y+$c+$_-1,$x+$a,'-'for-5..5;$_&&r$y+$c-1,$x+$_+$a,'|'for-3..3}@c;print@=,$,=$/
    

    Usage, save above as xmarks.pl:

    perl xmarks.pl <<< 'X'

    I'm not sure how much smaller I can make this, but I'm sure I'll come back to it later! I might post an explanation if anyone is interested too.

    Handles input of X and non-square inputs as well now.

    Dom Hastings

    Posted 2015-08-04T03:48:36.483

    Reputation: 16 415

    2

    Python 2, 755 706 699 694 678 626 Bytes

    Expects input on stdin, with a trailing newline. The end of input is triggered with cmd+d.

    import sys;a=sys.stdin.readlines();b=max;c=len;d=enumerate;e=c(b(a,key=lambda x:c(x)))-1;a=[list(line.replace('\n','').ljust(e))for line in a];R=range;f=lambda:[[i for i,x in d(h)if x=='X']for h in a+[[]]*4];q=lambda y,z:'#'if z=='X'else'+'if z in'|-+'else y;g=f();h=j=k=l=0
    for m,n in d(g):
     if n:h=b(3-m,h);l=b(abs(n[0]-5),l);j=b(m-c(a)+4,j);k=b(n[-1]-e+6,k)
    o=[' ']*(l+k+e);a=[o for _ in R(h)]+[[' ']*l+p+[' ']*k for p in a]+[o for _ in R(j)];g=f()
    for m,x in d(a):
     for i in[3,2,1,-1,-2,-3]:
        for r in g[m+i]:x[r]=q('|',x[r])
     for r in g[m]:
        for i in R(5,0,-1)+R(-1,-6,-1):x[r+i]=q('-',x[r+i])
    for s in a:print''.join(s)
    

    Full program:

    import sys
    
    lines = sys.stdin.readlines()
    
    # pad all lines with spaces on the right
    maxLength = len(max(lines, key=lambda x:len(x))) - 1 # Subtract the newline
    lines = [list(line.replace('\n', '').ljust(maxLength)) for line in lines]
    
    
    def findX():
        global xs
        xs = [[i for i, ltr in enumerate(line) if ltr == 'X'] for line in lines+[[]]*4]
    
    # add sufficient padding to the edges to prevent wrap
    findX()
    top,bottom,right,left=0,0,0,0
    for ind, item in enumerate(xs):
        if item:
            top = max(3-ind, top)
            left = max(abs(item[0]-5), left)
            bottom = max(ind-len(lines)+4, bottom)
            right = max(item[-1]-maxLength+6, right)
    clear = [' '] * (left+right+maxLength)
    lines = [clear for _ in range(top)] + [[' ']*left + line + [' ']*right for line in lines] + [clear for _ in range(bottom)]
    
    
    
    findX()
    def chooseChar(expected, curr):
        return '#' if curr == 'X' else ('+' if curr in '|-+' else expected)
    
    for ind, x in enumerate(lines):
        # try:
            for i in [3, 2, 1, -1, -2, -3]:
                for elem in xs[ind+i]:
                    x[elem] = chooseChar('|', x[elem])
            for elem in xs[ind]:
                for i in [5, 4, 3, 2, 1, -1, -2, -3, -4, -5]:
                    x[elem+i] = chooseChar('-', x[elem+i])
        # except:f
    
    
    
    for line in lines: print(''.join(line))
    

    I'm sure that a lot more golfing could be done on this (since I'm still learning python), so any help is appreciated.

    Edits

    1. Shaved about 50 bytes from findX by using for comprehensions
    2. Saved 7 bytes thanks to @mbomb007's suggestion about using range instead of a literal array
    3. Removed 5 bytes by changing findX to a lambda
    4. Saved 15 bytes by extending xs by 4 and eliminating the try-except block
    5. Shaved 2 more by using tabs instead of spaces
    6. Removed 5 bytes by using h=i=j=k=l=0 instead of h,j,k,l=0,0,0,0
    7. Thanks to @mbomb007, I removed about 40 more bytes from chooseChar

    J Atkin

    Posted 2015-08-04T03:48:36.483

    Reputation: 4 846

    1You should define R=range to shorten ranges. Then you can also change for i in[5,4,3,2,1,-1,-2,-3,-4,-5]: to for i in R(5,0,-1)+R(-1,-6,-1): – mbomb007 – 2015-08-06T16:31:03.370

    Thanks! I had thought about doing that but it seemed that it would be longer. – J Atkin – 2015-08-06T18:26:14.820

    Good work on trimming down! I'm not sure if you've seen the tip threads, but there might be a few shorteners you can get from here: http://codegolf.stackexchange.com/questions/54/tips-for-golfing-in-python

    – Dom Hastings – 2015-08-06T19:33:10.603

    I did a few days ago, but I forgot about some things. – J Atkin – 2015-08-06T19:55:34.497

    Also, your q lambda seems very inefficient to me. Can that be shortened at all? At the very least, I don't think the parentheses are necessary, but I think the boolean logic and string comparisons can be shortened, too. – mbomb007 – 2015-08-06T20:34:27.810

    Big thanks, after looking at it for a while I discovered that if I flipped it around it could be much shorter and clearer. – J Atkin – 2015-08-06T21:10:18.597

    @JAtkin, apologies, I didn't mean to come off as rude, I specifically noticed the input() section for STDIN and didn't know if that would work here too? Unsure because the examples there were focussed on numbers! – Dom Hastings – 2015-08-07T05:29:48.133

    You didn't come off as rude at all. In fact your reminder was useful because I had forgotten a couple of tricks, although in this case I couldn't use them (http://codegolf.stackexchange.com/a/18983/42736).

    – J Atkin – 2015-08-07T13:09:28.023