20
\$\begingroup\$

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!

\$\endgroup\$
13
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Aug 4, 2015 at 4:42
  • \$\begingroup\$ @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 \$\endgroup\$
    – Downgoat
    Commented Aug 4, 2015 at 4:44
  • 3
    \$\begingroup\$ Does 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? \$\endgroup\$
    – DLosc
    Commented Aug 4, 2015 at 5:47
  • 1
    \$\begingroup\$ @DLosc those will not be in the input. I've updated the question \$\endgroup\$
    – Downgoat
    Commented Aug 4, 2015 at 15:53
  • 1
    \$\begingroup\$ What if a literal # in the input is encountered by a crosshair? Will it be overwritten? \$\endgroup\$ Commented Aug 5, 2015 at 23:08

4 Answers 4

4
\$\begingroup\$

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>

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 345 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 :) \$\endgroup\$ Commented Aug 8, 2015 at 20:08
  • \$\begingroup\$ Until somebody comes with CJam/Pyth/GolfScript and makes sub-100. But thank you. \$\endgroup\$
    – metalim
    Commented Aug 8, 2015 at 21:13
  • \$\begingroup\$ Hah.. Too true... I'm wondering if this should be the encouragement I need to learn Pyth... \$\endgroup\$ Commented Aug 8, 2015 at 21:16
4
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
8
  • 1
    \$\begingroup\$ You 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): \$\endgroup\$
    – mbomb007
    Commented Aug 6, 2015 at 16:31
  • \$\begingroup\$ Thanks! I had thought about doing that but it seemed that it would be longer. \$\endgroup\$
    – J Atkin
    Commented Aug 6, 2015 at 18:26
  • \$\begingroup\$ 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: codegolf.stackexchange.com/questions/54/… \$\endgroup\$ Commented Aug 6, 2015 at 19:33
  • \$\begingroup\$ I did a few days ago, but I forgot about some things. \$\endgroup\$
    – J Atkin
    Commented Aug 6, 2015 at 19:55
  • \$\begingroup\$ 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. \$\endgroup\$
    – mbomb007
    Commented Aug 6, 2015 at 20:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.