# ASCII Doodling: Laser in a Box

Sometimes when I'm doodling, I draw a rectangle, start with a diagonal from one of the corners, and then just trace out a line by "reflecting" it whenever I hit a side of the rectangle. I continue with this until I hit another corner of the rectangle (and hope that the aspect ratio of my rectangle was not irrational ;)). This is like tracing out the path of a laser shone into a box. You're to produce the result of that with ASCII art.

As an example, consider a box of width 5 and height 3. We'll always start in the top left corner. The # marks the boundary of the box. Note that the width and height refer to the inner dimensions.

#######    #######    #######    #######    #######    #######    #######
#\    #    #\    #    #\   \#    #\  /\#    #\  /\#    #\/ /\#    #\/\/\#
# \   #    # \  /#    # \  /#    # \/ /#    # \/ /#    #/\/ /#    #/\/\/#
#  \  #    #  \/ #    #  \/ #    # /\/ #    #\/\/ #    #\/\/ #    #\/\/\#
#######    #######    #######    #######    #######    #######    #######

## The Challenge

Given the (positive) width and height of the box, you should produce the final result of tracing out the laser. You may write a program or function, taking input via STDIN (or closest alternative), command-line argument, function argument and output the result via STDOUT (or closest alternative), or via function return values or arguments.

You may use any convenient list, string or number format for input. The output must be a single string (unless you print it to STDOUT, which you may of course do gradually). This also means you can take the height first and the width second - just specify the exact input format in your answer.

There must be neither leading nor trailing whitespace on any line of the output. You may optionally output a single trailing newline.

You must use space, /, \ and # and reproduce the test cases exactly as shown.

## Test Cases

2 2
####
#\ #
# \#
####

3 2
#####
#\/\#
#/\/#
#####

6 3
########
#\    /#
# \  / #
#  \/  #
########

7 1
#########
#\/\/\/\#
#########

1 3
###
#\#
#/#
#\#
###

7 5
#########
#\/\/\/\#
#/\/\/\/#
#\/\/\/\#
#/\/\/\/#
#\/\/\/\#
#########

22 6
########################
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
# /\  /\  /\  /\  /\  /#
#/  \/  \/  \/  \/  \/ #
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
########################
• Perhaps a nice follow-up question, once this one has run its course, is to do this challenge with arbitrarily shaped boxes and starting points. – Sanchises Apr 7 '15 at 11:45
• @sanchises I had actually considered that (and might still post it), but I decided to go with the rectangle in hopes that someone might come up with an explicit formula. I was also considering multiple starting points such that X would be necessary for crossings. Maybe next time. ;) – Martin Ender Apr 7 '15 at 11:47
• Relevant: i.imgur.com/6tXrIfw.webm – orlp Apr 8 '15 at 13:01
• This would be perfect for an animation point. "Animate 1 burst (one slash) 1 cycle/ endless)" – Martijn Apr 8 '15 at 13:18

# Pyth, 4341 39 bytes

K*\#+2QKVvzp<*QXX*dyivzQN\\_hN\/Q\#\#)K

Try it online: Pyth Compiler/Executor. Input the numbers in the following order: height first line, width second line.

Thanks to isaacg, who helped saving two bytes.

## Explanation:

My solution doesn't trace the laser, it uses a simple pattern that includes the gcd. If m, n are the dimensions of the box, let d = gcd(m, n). The size of the pattern is exactly 2*d x 2*d.

E.g. the repeating pattern for 7 5

#########
#\/\/\/\#
#/\/\/\/#
#\/\/\/\#
#/\/\/\/#
#\/\/\/\#
#########

is

\/
/\

(gcd(7, 5) = 1, size of pattern is 2 x 2)

And the repeating pattern for 22 6

########################
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
# /\  /\  /\  /\  /\  /#
#/  \/  \/  \/  \/  \/ #
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
########################

is

\  /
\/
/\
/  \

(gcd(22, 6) = 2, size of pattern is 4 x 4)

My solution does the following thing for each of the lines: it simply generates one line of the pattern, repeats it a few times and cut's it at the end so that it fit's into the box.

K*\#+2QK   implicit: Q is the second input number (=width)
K          K =
*\#+2Q        "#" * (2 + Q)
K   print K (first line)

Vvzp<*QXX*dyivzQN\\_hN\/Q\#\#)K  implicit: vz is the first input number (=height)
VQ                               for N in [0, 1, ..., vz-1]:
ivzQ                             gcd(vz,Q)
y                               2*gcd(vz,Q)
*d                           string with 2*gcd(vz,Q) space chars
X       N\\                   replace the Nth char with \
X           _hN\/              replace the -(N+1)th char with /
*Q                               repeat Q times
<                   Q           only use the first Q chars
p                     \#\#       print "#" + ... + "#"
)    end for
K   print K
• Since X supports "assigning" to strings, you can change m\ to *d and remove s. – isaacg Apr 7 '15 at 18:29
• @isaacg Good call. I thought about using *\ instead of m\ shortly, but discard it because it has the same size. Didn't think of the variable d and the unnecessary s. – Jakube Apr 7 '15 at 18:35

# C, 256 bytes

f(w,h){int i,j,x=1,y=1,v=1,u=1;char b[h+2][w+3];for(i=0;i<w+3;i++)for(j=0;j<h+2;j++)b[j][i]=!i||!j||i>w||j>h?i>w+1?0:35:32;while((x||y)&&(x<=w||y<=h))v=x&&w+1-x?v:(x-=v,-v),u=y&&h+1-y?u:(y-=u,-u),b[y][x]=v/u<0?47:92,x+=v,y+=u;for(i=0;i<h+2;i++)puts(b[i]);}

I can probably get this under 200, and I'll add an explanation later, but I might have a paper due in a few hours I should be doing instead.

• Fake internet points are worth more than an educational degree, I'm sure of it. – Adam Davis Apr 7 '15 at 13:46

# J, 85 bytes

Let g = gcd(w,h). The function fills the elements of a w/g by h/g matrix with g by g tiles, having /'s and \'s in their diagonal and anti-diagonal. The resulting 4D array is raveled into a 2D one (the inside of the box) then surrounded with #'s. (The numbers 0 1 2 3 are used instead of [space] / \ # and the numbers are changed to characters at the end.)

A direct position based computation of inside coordinate could maybe yield a bit shorter solution.

' \/#'echo@:{~3,.~3,.3,~3,,$[:,[:,"%.0 2 1 3|:((,:2*|.)@=@i.@+.){~[:(2&|@+/&:i.)/,%+. Usage: 6 (' \/#'echo@:{~3,.~3,.3,~3,,$[:,[:,"%.0 2 1 3|:((,:2*|.)@=@i.@+.){~[:(2&|@+/&:i.)/,%+.) 22
########################
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
# /\  /\  /\  /\  /\  /#
#/  \/  \/  \/  \/  \/ #
#\  /\  /\  /\  /\  /\ #
# \/  \/  \/  \/  \/  \#
########################

Try it online here.

# Desmos Calculator - Non Competing to Help Further Knowledge

Try it online!

Inputs:

h as height of box, with 0-indexing
w as width of box, with 0-indexing

Intermediates:

Let b = gcd(h,w),
Let c = |b-h%2b| Or |b-mod(h,2b)|

Formula, abbreviated:

(|b-(x+y)%2b|-c)(|b-(x-y)%2b|-c)=0

Outputs:

x as x position, 0-indexed, where the ball will land when released
y as y position, 0-indexed, where the ball will land when released

How it Works:

(|b-(x+y)%2b|-c)*(|b-(x-y)%2b|-c)=0
^ OR operation - |b-(x+y)%2b|-c=0 or |b-(x-y)%2b|-c=0
|b-(x+/-y)%2b|-c = 0
|b-(x+/-y)%2b| = c
|b-(x+/-y)%2b| = c means (b-(x+/-y))%2b = + or -c
b-(x+/-y)%2b = +/- c -> b +/- c = (x+/-y)%2b -> (x+/-y) = n*2*b + b +/- c
Where n is integer.  This will force patterns to repeat every 2b steps in x and y.
Initial pattern n=0: (x +/- y) = b +/- c -> y = +/- x + b +/- c
In the x positive and y positive plane only, these correspond to lines of positive and
negative slope, set at intercept b, offset by c on either side.

Program fails to meet final criterion - generating ASCII art of box and lines, so I'm submitting as non-competitive for information to help others complete the challenge. Note that to get Desmos to work when c = 0 or c=b, a small offset factor of 0.01 was introduced, as Desmos seems to have bounds of Mod(A,B) of (0,B) instead of [0,B)