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

17 Answers 17

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
    \$\begingroup\$ Might want to note the input format as width [right-going left-going] length \$\endgroup\$ – Engineer Toast Apr 10 '18 at 17:56
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\$
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\$
  • \$\begingroup\$ Can you not golf \\/ to \/? Even though the backslash is interpreted twice, it will still not escape the slash. \$\endgroup\$ – Jonathan Frech Apr 10 '18 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 '18 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 '18 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\$
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\$
  • \$\begingroup\$ I am once again amazed by the speed of first answers on code golf challenges. Nice one! :) \$\endgroup\$ – AJFaraday Apr 9 '18 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\$
  • 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\$ – Kevin Cruijssen Apr 10 '18 at 7:48
  • \$\begingroup\$ Looks like you are taking two extra inputs, that is not allowed afaik. \$\endgroup\$ – O.O.Balance Apr 10 '18 at 8:25
  • 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\$ – O.O.Balance Apr 10 '18 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 '18 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 '18 at 22:35
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\$
  • \$\begingroup\$ This goes out of bounds when the input is "10 2 4 2" \$\endgroup\$ – Martijn Vissers Apr 12 '18 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 '18 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\$
  • \$\begingroup\$ It's unfortunate that onlinephpfunctions.com does not save the correct PHP version in the sharing link... \$\endgroup\$ – Arnauld Apr 10 '18 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\$
  • \$\begingroup\$ I like the formatting in your test suite, reliably showing the inputs against the output... Nice one ;) \$\endgroup\$ – AJFaraday Apr 11 '18 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\$
  • \$\begingroup\$ You kind of made my day by making it an expandable array, not just 2 starting points. \$\endgroup\$ – AJFaraday Apr 11 '18 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
    \$\begingroup\$ \\/ is equivalent to \/. \$\endgroup\$ – Jonathan Frech Apr 10 '18 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\$

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, privacy policy and cookie policy

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