72
\$\begingroup\$

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|
\$\endgroup\$
2
  • 6
    \$\begingroup\$ Suggested edge case: width: 1, length: whatever, right: 0, left: 0 \$\endgroup\$
    – Arnauld
    Apr 9, 2018 at 14:58
  • 2
    \$\begingroup\$ @Arnauld |X| ;) \$\endgroup\$
    – AJFaraday
    Apr 9, 2018 at 14:59

17 Answers 17

18
\$\begingroup\$

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[0] != p[1]:
              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
\$\endgroup\$
12
\$\begingroup\$

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
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Might want to note the input format as width [right-going left-going] length \$\endgroup\$ Apr 10, 2018 at 17:56
11
\$\begingroup\$

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!

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

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!

\$\endgroup\$
1
9
\$\begingroup\$

Python 2, 187 181 179 177 174 172 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!

\$\endgroup\$
1
  • \$\begingroup\$ I am once again amazed by the speed of first answers on code golf challenges. Nice one! :) \$\endgroup\$
    – AJFaraday
    Apr 9, 2018 at 13:45
8
\$\begingroup\$

C (clang), 240 236 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

\$\endgroup\$
9
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Apr 10, 2018 at 7:48
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Apr 10, 2018 at 9:08
  • 1
    \$\begingroup\$ In your g macro, you can golf 2 bytes by changing a==-1 to a<0. \$\endgroup\$
    – JohnWells
    Jul 8, 2018 at 21:55
  • 1
    \$\begingroup\$ Actually got more in the macro, a++,a and a--,a can golf 2 bytes each to ++a and --a \$\endgroup\$
    – JohnWells
    Jul 8, 2018 at 22:35
  • 1
    \$\begingroup\$ 187 bytes \$\endgroup\$
    – ceilingcat
    Oct 12, 2019 at 3:05
7
\$\begingroup\$

Canvas, 66 40 bytes

{²Xø⁶╵[⁷/²2%[↔}∔};x╷?⁷∔⁷+╷}[j}}n⁶[|PJp|p

Try it here!

\$\endgroup\$
5
\$\begingroup\$

Charcoal, 56 50 bytes

↷PIθM⊕η→IθF²«J⊕⎇ιεζ⁰FIθ«✳§⟦↘↙⟧ι∨⁼KKψX¿⁼KK|«¿ι→←≦¬ι

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

↷PIθM⊕η→Iθ

Print the sides.

F²«

Loop over the two lasers.

J⊕⎇ιεζ⁰

Move to the start of the laser.

FIθ«

Loop over the height.

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

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

¿⁼KK|«

Have we hit a side?

¿ι→←≦¬ι

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

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

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!

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

PHP, 177 169 166 bytes

[,$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.

\$\endgroup\$
1
  • \$\begingroup\$ It's unfortunate that onlinephpfunctions.com does not save the correct PHP version in the sharing link... \$\endgroup\$
    – Arnauld
    Apr 10, 2018 at 12:03
3
\$\begingroup\$

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!

\$\endgroup\$
1
  • \$\begingroup\$ I like the formatting in your test suite, reliably showing the inputs against the output... Nice one ;) \$\endgroup\$
    – AJFaraday
    Apr 11, 2018 at 8:55
3
\$\begingroup\$

Ruby, 117 bytes

->w,h,a{a[1]-=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.

\$\endgroup\$
1
  • \$\begingroup\$ You kind of made my day by making it an expandable array, not just 2 starting points. \$\endgroup\$
    – AJFaraday
    Apr 11, 2018 at 12:57
2
\$\begingroup\$

PowerShell, 243 233 222 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.

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ \\/ is equivalent to \/. \$\endgroup\$ Apr 10, 2018 at 0:07
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
1
\$\begingroup\$

Kotlin, 322 311 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!

\$\endgroup\$

Your Answer

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

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