71
\$\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\$ Commented Apr 9, 2018 at 14:58
  • 2
    \$\begingroup\$ @Arnauld |X| ;) \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented Jul 8, 2018 at 22:35
  • 1
    \$\begingroup\$ 187 bytes \$\endgroup\$ Commented Oct 12, 2019 at 3:05
7
\$\begingroup\$

Canvas, 66 40 bytes

{²Xø⁶╵[⁷/²2%[↔}∔};x╷?⁷∔⁷+╷}[���}}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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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
  • \$\begingroup\$ 163 bytes \$\endgroup\$ Commented Nov 27, 2018 at 1:35
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\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.