Two lasers between two mirrors

What if we have a corridor comprised of two parallel mirrors?

|          |
|          |
|          |
|          |
|          |
|          |
|          |
|          |
|          |
|          |

Now, we shine a laser down it...

|  \       |
|   \      |
|    \     |
|     \    |
|      \   |
|       \  |
|        \ |
|         \|
|         /|
|        / |

Oh, look. It bounced, towards the end, there.

What if we draw two lasers BUT going in the opposite direction?

|  \    /  |
|   \  /   |
|    \/    |
|    /\    |
|   /  \   |
|  /    \  |
| /      \ |
|/        \|
|\        /|
| \      / |

Hmm, they didn't seem to meet, there. That's convenient. What happens if both lasers take up the same space?

|  \     / |
|   \   /  |
|    \ /   |
|     X    |
|    / \   |
|   /   \  |
|  /     \ |
| /       \|
|/        /|
|\       / |

I guess that was pretty obvious, huh?

Drawing these diagrams by hand is pretty laborious (trust me on this). Perhaps some code could do it for us?

• Write some code to output two parallel mirrors, with two bouncing, intersecting lasers.
• Input (all integers):
• The width of the corridor
• The length of the corridor
• Starting position of the right-going laser (zero-indexed, must be less than width)
• Starting position of the left-going laser (zero-indexed, must be less than width)
• Process
• If a laser is right going, it will be drawn one space to the right on the following line.
• If a laser is left going, it will be drawn one space to the left on the following line.
• If a laser can not take it's sideways step, it will change it's direction, but not it's position.
• If both laser are at the same index, print an upper-case X at that index.
• Output
• A string with multiple lines
• Each line starts and ends with a pipe character (|)
• Right-going laser are denoted by a back slash (\)
• Left-going laser are denoted by a forward slash (/)
• The intersection of two lasers is denoted by an upper-case X.
• Any language
• I'd like to see TIO links
• Attempt to fix it in the smallest number of bytes

Test cases

width: 6 length: 10 right-going: 1 left-going: 4

| \  / |
|  \/  |
|  /\  |
| /  \ |
|/    \|
|\    /|
| \  / |
|  \/  |
|  /\  |
| /  \ |

width: 6 length: 10 right-going: 0 left-going: 1

|\/    |
|/\    |
|\ \   |
| \ \  |
|  \ \ |
|   \ \|
|    \/|
|    /\|
|   / /|
|  / / |

width: 4 length: 10 right-going: 2 left-going: 0

|/ \ |
|\  \|
| \ /|
|  X |
| / \|
|/  /|
|\ / |
| X  |
|/ \ |
|\  \|

width: 20 length: 5 right-going: 5 left-going: 15

|     \         /    |
|      \       /     |
|       \     /      |
|        \   /       |
|         \ /        |

width: 5 length: 6 right-going: 2 left-going: 2

|  X  |
| / \ |
|/   \|
|\   /|
| \ / |
|  X  |

width: 1 length: 2 right-going: 0 left-going: 0

|X|
|X|
• Suggested edge case: width: 1, length: whatever, right: 0, left: 0 – Arnauld Apr 9 '18 at 14:58
• @Arnauld |X| ;) – AJFaraday Apr 9 '18 at 14:59

Stax, 40 bytes

àù@○⌡┼PY¼îαφu^·A☺°É⌠■╟¡Åt^◘v(µ╩Ñ♣t{╓○xß╦

Run and debug it

Try it online!

Pretty sure this can be further golfed.

Input is given in the form of width [right-going left-going] length(per comment by @EngineerToast).

ASCII equivalent:

xHXdmzx);hi+x%Y92&;Hi-x%cy=41*47+&2ME:R\{|+m'||S
• Might want to note the input format as width [right-going left-going] length – Engineer Toast Apr 10 '18 at 17:56

JavaScript (ES6), 149 bytes

Takes input in currying syntax (w)(h)([a,b]).

w=>h=>g=(p,d=[1,-1],s=Array(w).fill )=>h--?|${p=p.map((x,i)=>~(k=d[i],s[x]='/X\\'[x-p[i^1]?k+1:1],x+=k)&&x<w?x:x+(d[i]=-k)),s.join}| +g(p,d):'' Try it online! Commented w => h => // w = width, h = height g = ( // g = recursive function taking: p, // p[] = array holding the point coordinates d = [1, -1], // d[] = directions s = Array(w).fill  // s = array of w spaces (we can't use a string because it's ) => // immutable in JS) h-- ? // if we haven't reached the last row yet: |${                 //   append the left pipe
p = p.map((x, i) =>  //   for each x at position i in p[]:
~(k = d[i],        //     k = direction for this point
s[x] = '/X\\'[   //     insert either '/', 'X' or '\' at position x in s
x - p[i ^ 1] ? //     if p != p:
k + 1        //       use the direction
:              //     else:
1            //       force 'X'
], x += k        //     add k to x
) &&               //     if the result is not equal to -1
x < w ?            //     and is less than w:
x                //       use the current value of x
:                  //     else:
x + (d[i] = -k)  //       change the direction and restore the initial value of x
),                   //   end of map()
s.join}|\n +      //   join and append s; append the right bar and a linefeed
g(p, d)              //   followed by the result of a recursive call
:                      // else:
''                   //   stop recursion

Python 2, 119 bytes

w,l,a,b=input()
exec"print'|%s|'%''.join(' \/X'[sum(i==k%(2*w)for k in[a,~b]+[~a,b]*2)]for i in range(w));a+=1;b-=1;"*l

Try it online!

• Can you not golf \\/ to \/? Even though the backslash is interpreted twice, it will still not escape the slash. – Jonathan Frech Apr 10 '18 at 0:10
• @JonathanFrech You're right, I thought being in a string-in-string would fail, but it indeed doesn't escape either time. – xnor Apr 10 '18 at 1:15
• Oh jeez, my solution got painfully close to this idea -- working modulo 2w makes a lot of sense in retrospect. Very clever! – Lynn Apr 10 '18 at 15:02

Python 2, 168 bytes

w,n,r,l=input()
R=L=1
exec"""
d=[~r*R,-~l*L].count
print'|%s|'%''.join(' /\X'[2*d(~x)|d(x+1)]for x in range(w))
if-1<r+R<w:r+=R
else:R=-R
if-1<l-L<w:l-=L
else:L=-L"""*n

Try it online!

Python 2, 187181179177174172 171 bytes

def f(w,l,a,b,A=1,B=-1):
while l:l-=1;print'|%s|'%''.join(' \X/'[[0,A,B,2][(i==a)+2*(i==b)]]for i in range(w));a,A=[a,a+A,-A,A][-1<a+A<w::2];b,B=[b,b+B,-B,B][-1<b+B<w::2]

Try it online!

Recursive:

Python 2, 172 bytes

def f(w,l,a,b,A=1,B=-1):
if not-1<a<w:A=-A;a+=A
if not-1<b<w:B=-B;b+=B
if l:print'|%s|'%''.join(' \X/'[[0,A,B,2][(i==a)+2*(i==b)]]for i in range(w));f(w,l-1,a+A,b+B,A,B)

Try it online!

Recursive, alternative print:

Python 2, 172 bytes

def f(w,l,a,b,A=1,B=-1):
if not-1<a<w:A=-A;a+=A
if not-1<b<w:B=-B;b+=B
if l:L=[' ']*w;L[a]=' \/'[A];L[b]=[' \/'[B],'X'][a==b];print'|%s|'%''.join(L);f(w,l-1,a+A,b+B,A,B)

Try it online!

• I am once again amazed by the speed of first answers on code golf challenges. Nice one! :) – AJFaraday Apr 9 '18 at 13:45

C (clang), 240236 208 bytes

#define g(a,b) b?a++,a==x&&(a=x-1,b=0):a--,a==-1&&(a=0,b=1)
i,m,n,o,p,t[]={47,92};f(x,y,r,l){for(m=1,n=0;y--;puts("|"),g(r,m),g(l,n))for(printf("|"),i=0;i<x;o=i==r,p=i++==l,putchar(o*p?88:o?t[m]:p?t[n]:32));}

Try it online!

f() takes parameters as follows:

x = width,
y = length,
r = Initially right-going line starting position
l = Initially left-going-line starting position

-4 Bytes. credits Kevin Cruijssen. Thanks

• You can golf 3 bytes by changing the while to a for to remove the {} and one of the semi-colons. And 1 more byte by changing c&&d to c&d. Try it online 236 bytes. – Kevin Cruijssen Apr 10 '18 at 7:48
• Looks like you are taking two extra inputs, that is not allowed afaik. – O.O.Balance Apr 10 '18 at 8:25
• You're not supposed to solve a generalisation of the challenge, but the challenge as specified. Regarding extra inputs, I dug around meta a bit and found this: codegolf.meta.stackexchange.com/a/12696/79343 I'm thinking it must be written up somewhere else, too, but i can't find it atm. It is however the norm. – O.O.Balance Apr 10 '18 at 9:08
• In your g macro, you can golf 2 bytes by changing a==-1 to a<0. – JohnWells Jul 8 '18 at 21:55
• Actually got more in the macro, a++,a and a--,a can golf 2 bytes each to ++a and --a – JohnWells Jul 8 '18 at 22:35

Canvas, 66 40 bytes

｛²Ｘø⁶╵［⁷／²２％［↔｝∔｝；ｘ╷？⁷∔⁷＋╷｝［ｊ｝｝ｎ⁶［|ＰＪｐ|ｐ

Try it here!

Charcoal, 56 50 bytes

↷ＰＩθＭ⊕η→ＩθＦ²«Ｊ⊕⎇ιεζ⁰ＦＩθ«✳§⟦↘↙⟧ι∨⁼ＫＫψX¿⁼ＫＫ|«¿ι→←≦¬ι

Try it online! Link is to verbose version of code. Edit: Saved 6 bytes by reducing reliance on pivoting. Explanation:

↷ＰＩθＭ⊕η→Ｉθ

Print the sides.

Ｆ²«

Loop over the two lasers.

Ｊ⊕⎇ιεζ⁰

Move to the start of the laser.

ＦＩθ«

Loop over the height.

✳§⟦↘↙⟧ι∨⁼ＫＫψX

Draw a \ or / in the appropriate direction, unless the square is not empty, in which case draw an X.

¿⁼ＫＫ|«

Have we hit a side?

¿ι→←≦¬ι

If so then take one step sideways and invert the direction of travel.

• This goes out of bounds when the input is "10 2 4 2" – Martijn Vissers Apr 12 '18 at 14:56
• @MartijnVissers Well yes, if your width is 2, then your positions can only be 0 or 1... – Neil Apr 12 '18 at 15:54

Java (JDK 10), 186 bytes

(w,h,r,l)->{var x="";for(int i=0,j,R=1,L=-1;i++<h;l+=L,l+=l<0|l>=w?L=-L:0,r+=R,r+=r<0|r>=w?R=-R:0,x+="|\n")for(j=0,x+="|";j<w;j++)x+="/X\\ ".charAt(j==r?j==l?1:R+1:j==l?L+1:3);return x;}

Try it online!

[,$w,$h,$a,$b]=$argv;for($e=-$d=1;$h--;$s[$a+=$d]^L?:$a+=$d=-$d,$s[$b+=$e]^L?:$b+=$e=-$e){$s=str_pad("",$w)."|";$s[$b]="X\/"[$e];$s[$a]="X\/"[$a-$b?$d:0];echo"|$s ";} requires PHP 7.1 for negative string indexes, PHP 5.5 or later for indexing string literals. for PHP <7.1, remove ^L, replace "X\/" with "/X\\", :0 with +1:1, [$e] with [$e+1], remove ."|" and insert | before the newline. (+3 bytes) for PHP < 5.5, replace "/X\\" with$p and insert $p="/X\\"; at the beginning. (+2 bytes) takes input from command line arguments. Run with -nr or try them online. • It's unfortunate that onlinephpfunctions.com does not save the correct PHP version in the sharing link... – Arnauld Apr 10 '18 at 12:03 Python 3, 162 bytes from numpy import* def f(w,h,u,v): v=w+w-v-1;T=eye(w);M=vstack([T,2*T[::-1]]*2*h) for r in M[u:u+h,:]+M[v:v+h,:]:print('|%s|'%''.join(' \/X'[int(i)]for i in r)) Try it online! • I like the formatting in your test suite, reliably showing the inputs against the output... Nice one ;) – AJFaraday Apr 11 '18 at 8:55 Ruby, 117 bytes ->w,h,a{a-=w;(1..h).map{s=' '*w;a.map!{|x|d=x<0?-1:1;s[x]='X\\/'[s[x][/ /]?d:0];x+=d;x==w ?-1:x<-w ?0:x};?|+s+?|}} Try it online! Anonymous lambda taking input as width w, height h and an array of starting points a. • You kind of made my day by making it an expandable array, not just 2 starting points. – AJFaraday Apr 11 '18 at 12:57 PowerShell, 243233222 205 bytes param($w,$h,$a,$b)$l,$r,$s=1,-1,' \/'
1..$h|%{$p,$p[$b],$p[$a]=[char[]](' '*$w),$s[$r],($s[$l],"x")[!($a-$b)] if($a+$l-in($z=0..($w-1))){$a+=$l}else{$l*=-1}if($b+$r-in$z){$b+=$r}else{$r*=-1}"|$(-join$p)|"}

Try it online!

Oooof. those logic blocks are big and dirty and mostly duplicated. The next step would be rewriting them so they don't need the else statement.

Python 2, 165 164 bytes

w,h,x,y=input()
a,b,s=1,-1,' \/'
exec"""l=[' ']*w
l[x],l[y]=s[a],s[b]if x-y else'X'
if-1<x+a<w:x+=a
else:a=-a
if-1<y+b<w:y+=b
else:b=-b
print'|%s|'%''.join(l)
"""*h

Saved a byte thanks to Jonathan Frech.
Try it online!

• \\/ is equivalent to \/. – Jonathan Frech Apr 10 '18 at 0:07

K (ngn/k), 58 bytes

{" \\/X|"4,'(+/3!1 2*(x#'e+2*|e:=2*x)(2*x)!z+(!y;-!y)),'4}

Try it online!

anonymous function that accepts three arguments: x the width, y the length, z a pair of starting positions for the lasers

C (gcc), 169 bytes

A,B,c;f(w,l,a,b){for(A=1,B=-1;l--;a+=A,a<0|a==w?A=-A,a+=A:0,b+=B,b<0|b==w?B=-B,b+=B:0,puts("|"))for(c=-1;c<w;c++)putchar(c<0?'|':a^c?b^c?32:B>0?92:47:b^c?A>0?92:47:88);}

Try it online!

Kotlin, 322311 302 bytes

Changed how I put laser direction in string for 11 bytes. Moved assignment out of when for 9 bytes.

{w:Int,h:Int,r:Int,l:Int->{var a=""
var f=r
var d=1>0
var s=l
var t=!d
for(o in 1..h){a+="|"
for(c in 0..w-1)a+=when{c==f&&c==s->"X"
c==f&&d||c==s&&t->"\\"
c==f||c==s->"/"
else->" "}
a+="|\n"
if(d){if(++f==w){--f
d=!d}}else if(--f<0){f=0
d=!d}
if(t){if(++s==w){--s
t=!t}}else if(--s<0){s=0
t=!t}}
a}()}

Try it online!