Puzzle

There are some mirrors located throughout a grid. A ray of light enters the grid from some position. It travels through the grid in a straight line trying to escape. On encountering with a mirror it changes its course by 90 degrees. This continues to happen until it breaks free from the maze. The challenge is simply this: Guide the light ray to an exit.

Elements

• Grid - The grid is a square composed of n x n blocks. A block is either empty or contains a mirror.

• Mirror - Both faces of the mirror are reflective. They have two orientations - 45o left or right(see figure).

• Light ray - It always travels straight and reflects from the mirror surface upon incidence (i=r=45o).

Code

• Input - The user will input 3 values - n, m and s.

n represents the value of grid's length (no of blocks). You are free to choose the type of this value; It could be a string, integer, float or any other data type. This cannot be zero/empty.

m is a sequence of two values indicating where the mirrors are and what their orientations will be. You are free to choose the sequence type. For example, if 0 and 1 are the two orientations of the mirror and each block in the grid is marked from 1 to n2, you may input a sequence such as {(5,0), (3,1), (6,0),...}. Since you're free to choose this type, you may even squeeze them in to a string and decode it properly. In other words, it only needs to be legible to your code. This can be zero for no mirrors.

s represents the starting position of the light ray. Again, you may choose this type based on the rest of your code. Any form of data is valid.

NOTE The user is responsible for inputing the correct values. If they enter an invalid value such as placing a mirror out of the grid or not providing a starting position, your code doesn't have to deal with it.

• Process - Calculate the position from which the light ray will emerge out of the grid. You are free to mark your grid (or not) in any way you like. The same goes with start and exit positions. Include these details in your answer below. How you represent these data will influence the output. See scoring rubrics for details.

• Output - Display the emerging position of the light ray. Detailed output can score more. See scoring rubrics for details.

You are free to use any libraries or extensions to implement any part of the maze, but not the entire maze. The only restriction here is this: if the library is for GUI, or implementing the Grid or anything like that it's fine. If it already contain a preset grid with mirrors (highly unlikely), you can't use it.

Scoring

• +64 for keeping your code less than 10 kilobytes (10240 bytes).
• -2 for every byte after the 10240th byte
• +16 for including the path of the ray in the output. Any representation is OK, but explain it in the answer. You may mark your grid with numbers, alphabets or in any other way you like.
• +64 for drawing the grid with the solution (see figure). It could be a GUI or CLI! The drawing must at least include the grid and the ray of light from start to exit. Numbers, markings and everything else are optional. If you do this, you shouldn't add the +16 points above.
• +128 for inventing partially reflective mirrors. These mirrors will guide the light in to two locations. One that is perpendicular to the original ray and one that passes straight through them. You may of course combine multiple mirrors like these with the normal ones for added effect. There may be 2 exit rays for this type of mirrors which you must display in your solution. If you choose to do this, change the user input m to suit the code accordingly (it must be a sequence of 3 elements rather than 2, the third value being the type of mirror). See figure below.
• +128 for inventing the absorber mirror. Absorber mirror absorbs the light ray and stops it from exiting the grid. The solution to this case should be something like 'LIGHT RAY ABSORBED!' (you can show anything as long you explain it in the answer below.) Everything else is same as the partially reflective mirror shown above.
• +128 for inventing the laser mirror. A laser mirror's reflection will destroy any other mirror that is in it's way. So, if the light strikes a laser mirror(m1) and then falls on another mirror (m2), it (m2) will be destroyed. The ray now travels straight as if that block is empty. Everything else is same as the partially reflective mirror shown above.
• +128 for inventing a new kind of mirror and explaining its action. Make it really cool. ;)

TIE BREAKER: In case of a tie, the shortest code shall win. If by some strange coincidence, that happens to be the same, the winner shall be decided based on how many numbers there are in the code (every single digit of integers, floats and even numbers in variables) - the least one wins!

Example

The first one is a typical solution with a GUI output. It marks the positions as integers from 1 to 12 and shows the path of the ray along with 2 mirrors. The second one shows the partially reflective mirror (bonus points) that has 2 exit rays. The third example is a CLI output model (this one is tough!). It shows the same thing as our GUI. The normal output without any diagrams (no bonus) could be as short as a single number or any value (eg: 7 or G) indicating from where the ray has emerged. The way you chose to name the positions must be included in your answer.

       ^
__:___ ______ ______ ______ ______
|  :   |      |      |      |      |
<...|..\\..|.<....|..\   |      |      |
|______|______|__:__ |______|______|
|      |      |  :   |      |      |
|      |      |  ^   |      |      |
|______|______|__:___|______|______|
|      |      |  :   |      |      |
....|..>...|......|../   |      |      |
|______|______|______|______|______|
|      |      |      |      |      |
|      |      |      |      |      |
|______|______|______|______|______|

/  = normal mirror
// = partially reflecting mirror

• Related. – Martin Ender Oct 28 '14 at 23:26
• What happens if multiple answers implement all the laser types and get all the other points while under 10k? That's a lot of code around here, so it's a definite possibility. – Geobits Oct 28 '14 at 23:53
• I thought as much. But, if a tie occurs, I will update the question with a tie breaker. – Renae Lider Oct 29 '14 at 0:12
• To prevent the perception of choosing favorites in the event of a tie, you should probably come up with a tiebreaker before it's needed. The simplest would probably just be "shortest code". – Geobits Oct 29 '14 at 15:38
• @Geobits Excellent suggestion. – Renae Lider Oct 29 '14 at 21:15

T-SQL(2012+) Score 512 640

I hope this fits in the rules. I implemented the 3 mirrors + a super absorber. I didn't count the super absorber as a cool extra.

The input is three variables.
One int and two tables for mirror and start. The mirror table has columns for X, Y, Orientation(-1/1) and Type (1-4) -1 is Left and 1 is Right Type 0 is standard, 1 is laser, 2 is partial, 3 is absorber and 4 is super absorber EDIT: 5 is laser splitter and 6 is a splitter. These will split the beam in both directions.

The start table has columns for start X and Y, Direction(1-4) and Laser Flag(0/1) Direction 1 is north, 2 is east, 3 is south and 4 is west. It will handle more than one start point.

A function to handle mirrors. Run once.

DROP FUNCTION M;
GO
CREATE FUNCTION M(@d INT,@O INT,@t INT,@L INT) RETURNS TABLE AS RETURN
SELECT IIF(d=0,4,d)d, l FROM (
SELECT (@d+(@o*(IIF(@d%2=0,-1,1)))+4)%4d,isnull(@t,0)%2l WHERE @L=0 AND @o is not null and isnull(@t,0)not in(3,4)
UNION ALL
SELECT @d, @l WHERE isnull(@t,2)=2 OR (@l=1 AND @t<>4)
UNION ALL
SELECT (@d+(-@o*(IIF(@d%2=0,-1,1)))+4)%4,isnull(@t,0)%2 WHERE @L=0 and @t in(5,6)
)m


The grid setup and query

-- Set up Maze
DECLARE @n INT = 5
DECLARE @m TABLE (X INT, Y INT, O INT, T INT)
DECLARE @s TABLE (X INT, Y INT, D INT, L INT)
INSERT INTO @m VALUES (1,5,-1,0),(1,1,-1,0),(2,1,1,2),(3,1,1,2),(4,1,1,1),(2,3,-1,5),(4,3,-1,3),(4,5,-1,4),(4,2,1,0),(3,4,1,6);
INSERT INTO @s VALUES (0,5,2,0);
-- Solve Maze
WITH S AS (
SELECT x,y,d,l,Geometry::Parse(CONCAT('LINESTRING (',px,' ',py,',',x,' ',y,')')).STBuffer((l+1)/30.)g
FROM(
SELECT x+(d.d+1)%2*-SIGN(d.d-3)x,y+d.d%2*-SIGN(d.d-2)y,d.d,d.l,x px,y py
FROM @s s OUTER APPLY(SELECT O, T FROM @m m WHERE s.x=m.x and s.y=m.y)x CROSS APPLY(SELECT d,l FROM M(s.d,x.o,x.t,s.l))d
)g
UNION ALL
SELECT x,y,d,l,Geometry::Parse(CONCAT('LINESTRING (',px,' ',py,',',x,' ',y,')')).STBuffer((l+1)/30.)g
FROM(
SELECT x+(d.d+1)%2*-SIGN(d.d-3)x,y+d.d%2*-SIGN(d.d-2)y,d.d,d.l,x px,y py
FROM S OUTER APPLY(SELECT O, T FROM @m m WHERE s.x=m.x and s.y=m.y)x CROSS APPLY(SELECT d,l FROM M(s.d,x.o,x.t,s.l))d
WHERE s.X>0 AND s.X<=@n AND s.Y>0 AND s.y<=@n
)g
)
,E AS (SELECT *FROM(VALUES(\),(\),(\),(\),(\),(\),(\),(\),(\),(\))E(N))
,N AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT\)) N FROM E e1,E e2,E e3)
SELECT CONCAT('Exits into ',x,', ',y,' from the ',CASE d WHEN 1THEN'south'WHEN 2THEN'west'WHEN 3THEN'north'WHEN 4THEN'east'END),null
FROM S
WHERE s.X=0 OR s.X>@n OR s.Y=0 OR s.y>@n
UNION ALL
SELECT 'Beam'O,Geometry::UnionAggregate(g)G FROM S --Draw Line
UNION ALL
SELECT CONCAT('Mirror Type ',T),Geometry::Parse(CONCAT('LINESTRING (',x+(ABS(o)/3.),' ',y+(o/3.),',',x-(ABS(o)/3.),' ',y-(o/3.),')')).STBuffer(.06) FROM @m WHERE T NOT IN(3,4,5,6) --Draw Mirrors
UNION ALL
SELECT 'Blocker',Geometry::Parse(CONCAT('LINESTRING (',x+(ABS(o)/(-T+8.)),' ',y+(o/(-T+8.)),',',x-(ABS(o)/(-T+9.)),' ',y-(o/(-T+9.)),')')).STEnvelope() FROM @m WHERE T IN(3,4) --Draw Blockers
UNION ALL
SELECT CONCAT('Mirror Type ',T),Geometry::Parse(CONCAT('MULTILINESTRING ((',x+.33,' ',y+.33,',',x-.33,' ',y-.33,'),(',x+.33,' ',y-.33,',',x-.33,' ',y+.33,'))')).STBuffer(.06) FROM @m WHERE T IN(5,6) --Draw Splitters
UNION ALL
SELECT 'Grid',Geometry::UnionAggregate(g) FROM (
SELECT Geometry::Parse(CONCAT('LINESTRING (',x1,' ',y1,',',x2,' ',y1,',',x2,' ',y2,',',x1,' ',y2,',',x1,' ',y1,')'))g -- Draw Grid
FROM (SELECT TOP(@n) N-.5x1,N+.5x2 FROM N)x,(SELECT TOP(@n) N-.5y1,N+.5y2 FROM N)y
)g
OPTION (MAXRECURSION 10000)


The output Query Results tab SSMS

Spatial Results tab SSMS

• The splitter is really cool! – Renae Lider Oct 30 '14 at 1:08

C# 1669 chars, i implemented everything i think except msges(like laser has escpaed, laser got absorberbed etc...). ITS ALSO ANIMATED!

So its works like this, create a project called mirror and copy all of this into Form.cs. When you press the form with your mouse it takes the variables entered into the textbox to start everything , so dont click before you enter them. The variables are as follow:

20 2 0 0 5 0 8


The first number is the grid size, the second number is the direction the laser will be going 0 is left, 1 is up, 2 is right and 3 is down. Then come the X Y starting position of the laser and after that you got 3 numbers for every object, first two being the X and Y position of the object and the third being the type of the object:

2 = /
3 = \
4 = //
5 = \\
6 = O (absorber)
7 = X (laser mirror)
8 = T (random teleport)


I dont consider my special object as worthy of the extra points since it isnt very cool. Also side note the thread doesnt finish properly so you need to kill the process (gotta save dat space). Here is a cool one to test it out

40 2 0 0 10 0 3 10 10 2 5 10 4 4 10 5 0 10 6 4 5 2 15 5 5 15 20 2 10 20 7 8 20 3 6 20 2 4 20 4 2 20 5 35 5 8 25 5 5 25 25 2 18 25 6


CODE

    using System;using System.Collections.Generic;using System.Drawing;using System.Windows.Forms;using System.Threading;namespace mirror{partial class Form1:Form{public Form1(){InitializeComponent();this.Load+=l;}int[,]g=new int[1,1];int i;List<int[]>d=new List<int[]>();void l(object ss,EventArgs k){SetStyle(ControlStyles.AllPaintingInWmPaint,true);SetStyle(ControlStyles.OptimizedDoubleBuffer,true);this.Width=this.Height=800;TextBox t=new TextBox();this.Controls.Add(t);this.Click+=(p,e)=>{t.Hide();string[]s=t.Text.Split(' ');i=o(s[0]);g=new int[i,i];d.Add(new int[]{o(s[1]),o(s[2]),o(s[3]),0});g[d[0][1],d[0][2]]=1;for(int j=4;j<s.Length;)g[o(s[j++]),o(s[j++])]=o(s[j++]);Thread x=new Thread(r=>{while(true){for(int c=0;c<d.Count;c++){try{got:if(d[c][0]==0)d[c][1]--;if(d[c][0]==1)d[c][2]--;if(d[c][0]==2)d[c][1]++;if(d[c][0]==3)d[c][2]++;if(d[c][3]==0){int l=d[c][0];int z=g[d[c][1],d[c][2]];if(z==2)d[c][0]=l==0?3:l==1?2:l==2?1:0;if(z==3)d[c][0]=l==0?1:l==1?0:l==2?3:2;if(z==4)d.Add(new int[]{l==0?3:l==1?2:l==2?1:0,d[c][1],d[c][2],0});if(z==5)d.Add(new int[]{l==0?1:l==1?0:l==2?3:2,d[c][1],d[c][2],0});if(z==6){d.RemoveAt(c);continue;}if(z==7)d[c][3]=1;if(z==8){Random rr=new Random();d[c][1]=rr.Next(i);d[c][2]=rr.Next(i);}if(z>1)goto got;}g[d[c][1],d[c][2]]=1;}catch(Exception){}}this.Invalidate();Thread.Sleep(100);}});x.Start();};string[]ar=new string[]{" ","*","/",@"\","//",@"\\","O","X","T"};this.Paint+=(h,v)=>{Graphics z=v.Graphics;for(int q=0;q<i;q++)for (int w=0;w<i;w++){z.DrawRectangle(Pens.Black,new Rectangle(q*20,w*20,20,20));z.DrawString(ar[g[q,w]],this.Font,Brushes.Black,new Point(q*20+8,w*20+8));}};}int o(string s){return int.Parse(s);}}}


Also hope you like it was fun to make! :)