8
\$\begingroup\$

ASCII reflections in a box

You probably all know the Law of Reflection, in this challenge you'll visualize the trajectory of a ball in a box.

Related: ASCII Ball in Box Animation and ASCII Doodling: Laser in a Box

Task

You're given three integer pairs W,H, x,y and dx,dy - the first represents the size of the box, the second the starting position and the third pair is the direction in which the ball starts moving.

The task is to visualize the movement of the ball until it stops rolling, this happens as soon as the ball is at a position that it was before or it hits a corner.

The character * shall visualize the trajectory of the ball and + marks its final position, the rest of the box must consist of (whitespace).

Examples

To lay it out a bit clearer, in these examples _ will represent a whitespace. Also the intermediate stages are only here for clarification, you'll only need to output the last stage, these examples are 1-indexed.


Given W = 3, H = 5, x = 3, y = 2 and dx = -1, dy = 1:

___    ___    ___    ___
__*    __*    __*    __*
___ -> _*_ -> _*_ -> _+_
___    *__    *__    *_*
___    ___    _*_    _*_
  • Ball starts at point (3,2) and
  • moves in direction (-1,1), hits the wall at (1,4) and
  • gets reflected, new direction is (1,1). It hits the wall again at (2,5)
  • where it gets gets reflected. The new direction is (1,-1) and it hits the wall immediately at (3,4),
  • again it gets reflected into the direction (-1,-1). It would now travel through points (2,3),(1,2), reflected etc. but since it already visited the position (2,3) it stops there.

This example demonstrates, what happens if a ball hits a corner. For this let W = 7, H = 3, x = 1, y = 3 and dx = 1, dy = -1:

_______    __*____    __*____    __*___+
_______ -> _*_____ -> _*_*___ -> _*_*_*_
*______    *______    *___*__    *___*__
  • Start position is (1,3),
  • the ball now travels in direction (1,-1) until it hits the wall at (3,1)
  • where it gets reflected into the new direction (1,1).
  • At (5,3) it gets reflected and travels into the new direction (1,-1). It comes to an abrupt stop at (7,1) because that's a corner.

Given W = 10, H = 6, x = 6, y = 6 and dx = 1, dy = 1:

__________    __________    ________*_    ________*_    ________*_    __*_____*_    __*_____*_
__________    _________*    _________*    _______*_*    _______*_*    _*_____*_*    _*_*___*_*
__________ -> ________*_ -> ________*_ -> ______*_*_ -> *_____*_*_ -> *_____*_*_ -> *___*_*_*_
__________    _______*__    _______*__    _____*_*__    _*___*_*__    _*___*_*__    _*___+_*__
__________    ______*___    ______*___    ____*_*___    __*_*_*___    __*_*_*___    __*_*_*___
_____*____    _____*____    _____*____    ___*_*____    ___*_*____    ___*_*____    ___*_*____

Input specification

The input consists of the three integer pairs W,H, x,y and dx,dy, you may take input in any format that makes most sense for your programming language and the order doesn't matter. However the accepted input must not encode more information than these pairs contain (see this answer for an example).

  • W,H >= 1
  • x,y are either 1-indexed (1 <= x <= W and 1 <= y <= H) or 0-indexed (0 <= x < W and 0 <= y < H), please specify what indexing you chose
  • dx,dy are always either -1 or 1

Invalid input can be ignored.

Output specification

  1. No leading whitespaces are allowed
  2. Trailing whitespaces may be omitted
  3. Trailing whitespaces are not allowed if they don't fit the box
  4. Trailing newlines (after all output related lines) are allowed

Let's take the first example:

       (good by 2)
__*
_+     (good by 2)
*_*_   (bad by 3)
       (bad by 4)
_*_
       (good by 4)

Test cases

Assuming the input has the format (W,H,x,y,dx,dy) and 1-indexing was chosen, here are some test cases (again _ is here to represent whitespaces!):

Input: 1,1,1,1,1,1

Output:

+

Input: 3,3,3,3,1,1

Output:

___
___
__+

Input: 3,3,3,3,-1,-1

Output:

+__
_*_
__*

Input: 7,3,1,3,1,-1

Output:

__*___+
_*_*_*_
*___*__

Input: 10,6,6,6,1,1

Output:

__*_____*_
_*_*___*_*
*___*_*_*_
_*___+_*__
__*_*_*___
___*_*____

Input: 21,7,6,4,-1,-1

Output:

__*_______*_______*__
_*_*_____*_*_____*_*_
*___*___*___*___*___*
_*___*_*_____*_*___*_
__*___*_______+___*__
___*_*_________*_*___
____*___________*____

This is , so the shortest program/function wins, but any effort is appreciated.

\$\endgroup\$
7
  • \$\begingroup\$ I suspect one of the 2D languages (Turtle?) might do really well with this challenge. \$\endgroup\$ Jul 14, 2017 at 16:00
  • 1
    \$\begingroup\$ Would it be allowed to encode the four possible dx/dy values as four consecutive odd integers? How important is it that x and y are 1-indexed? \$\endgroup\$
    – Neil
    Jul 14, 2017 at 16:30
  • \$\begingroup\$ I'll drop the 1-indexed constraint if you like(?) About that first question, not sure what you mean but it sounds ok. I guess anything that is a bijection ({-1,1}x{-1,1} ≡ "Your space") would be good. \$\endgroup\$ Jul 14, 2017 at 16:36
  • \$\begingroup\$ Edited in the indexing, can you be more specific on your other question? \$\endgroup\$ Jul 14, 2017 at 16:46
  • 1
    \$\begingroup\$ I want to see a charcoal answer for this lol. \$\endgroup\$ Jul 14, 2017 at 17:05

3 Answers 3

8
\$\begingroup\$

Charcoal, 50 bytes

UONN JNN↷NW⁼ KK«*¿¬KK«↷²¶*¿¬KK«↷²¶↷²*¿¬KK«↷²¶»»»»+

Try it online! Link is to verbose version of code. Takes five inputs: w, h, x, y, a. x and y are zero-indexed. a represents dx and dy according to the following encoding:

a mod 8 == 1 => dx = 1, dy = 1
a mod 8 == 3 => dx = -1, dy = 1
a mod 8 == 5 => dx = -1, dy = -1
a mod 8 == 7 => dx = 1, dy = -1

Explanation:

UONN 

(note trailing space) Fills the background with spaces to the input width and height. (Normally each square of the background is an empty string, which is then converted to a space on output.)

JNN

Moves the cursor to the initial coordinates.

↷N

Rotates to the initial angle.

W⁼ KK«

Repeats as long as the current square is a space.

    *

Prints an asterisk and moves forward in the current direction.

    ¿¬KK«

If the cursor moved outside of the original oblong,

        ↷²¶*

Rotate the direction, then print a newline (which conveniently takes us back to the previous square) and an asterisk, which moves in the new direction.

        ¿¬KK«

If the cursor moved back outside of the original oblong,

            ↷²¶↷²*

Take the cursor back to the previous square, then rotate again, thus printing the asterisk in the other direction.

            ¿¬KK«

If the cursor is still outside of the oblong, we must be at a corner.

                ↷²¶

So go back to the previous square and give up.

»»»»+

When we can't move any more, print a "+" sign and stop.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Nice! Here's a TIO for those that want to try it. \$\endgroup\$ Jul 14, 2017 at 18:44
  • \$\begingroup\$ @BruceForte Thanks, but I didn't want to link to TIO until I had a solution using Peek() (which I do now). \$\endgroup\$
    – Neil
    Jul 15, 2017 at 0:33
  • \$\begingroup\$ Oops, Peek works again now \$\endgroup\$
    – ASCII-only
    Jul 27, 2017 at 1:58
2
\$\begingroup\$

Desmos Calculator - Non Competing to Help Further Knowledge

Try it online!

Inputs:

X as X position to Start
Y as Y position to Start
s as slope -> -1 for dX/dY = -1, +1 for dX/dY = +1
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-(X-sY)%2b| Or |b-mod(X-sY,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 - stopping at intersection point and marking with a +, so is submitted 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)

\$\endgroup\$
3
  • \$\begingroup\$ I suppose you have seen this? \$\endgroup\$ Jul 20, 2017 at 20:41
  • \$\begingroup\$ Actually, I self nerd sniped and lost about 4 days of my at-home time. I really, really liked this problem. \$\endgroup\$
    – Mark
    Jul 20, 2017 at 20:43
  • \$\begingroup\$ You're welcome ;P Also, relevant. \$\endgroup\$ Jul 20, 2017 at 20:47
1
\$\begingroup\$

Python 3, 293 279 bytes

w,h,x,y,i,j=map(int,input().split());x-=1;y-=1;l=[x[::]for x in[[' ']*w]*h]
while 1:
 a,b=((x,i)in[(0,-1),(w-1,1)]),((y,j)in[(0,-1),(h-1,1)])
 if a and b or l[y][x]!=' ':l[y][x]='+';break
 i,j=i*(-a*2+1),j*(-b*2+1);l[y][x]='*';x+=i;y+=j
print('\n'.join([''.join(x) for x in l]))

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Nice! You can save a few bytes by shortening fx,fy and replacing True by something like 1, see here \$\endgroup\$ Jul 27, 2017 at 11:09
  • \$\begingroup\$ @BruceForte thanks! I forgot to replace these. \$\endgroup\$ Jul 27, 2017 at 12:02
  • 1
    \$\begingroup\$ -13 bytes by turning it into a function. \$\endgroup\$
    – Miriam
    Jan 5, 2020 at 16:34
  • 1
    \$\begingroup\$ Wait, just seen how old this question is... Yet I got here from HNQ... \$\endgroup\$
    – Miriam
    Jan 5, 2020 at 16:36

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.