text:
Permutation Numbering
The Challenge
For a given set of n integers, write a program which will output its lexicographic index.
The Rules

The input must only be a set of unique non-negative integers separated by spaces.
You should output the lexicographic index (range 0 to n!-1 inclusive) of the permutation.
No permutation libraries or permutation built-ins may be used.
You may not generate the set of permutations or any subset of permutations of the input to help you find the index.
You also can't increment or decrement the given permutation to the next/previous(lexicographically) permutation.
Bonus points (-10 bytes) if you find some way to complete this without using factorials.
Runtime should be less than 1 minute for n = 100
Shortest code by byte count wins
Winner chosen Tuesday (July 22, 2014)

More About Permutations

http://www.monkeyphysics.com/articles/read/26/numbering_permutations.html
Permutation group operation
http://lin-ear-th-inking.blogspot.com/2012/11/enumerating-permutations-using.html

Examples
0 1 2 --> 0
0 2 1 --> 1
1 0 2 --> 2
1 2 0 --> 3
2 0 1 --> 4
2 1 0 --> 5
0 1 2 3 4 5 6 7 --> 0
0 1 2 3 4 5 7 6 --> 1
0 1 2 3 4 6 5 7 --> 2
1 3 5 17        --> 0
781 780 779 13  --> 23
81 62 19 12 11 8 2 0 --> 40319
195 124 719 1 51 6 3 --> 4181

Can we have more time until a winner is chosen? Three days is too little time.

GolfScript, 12 (22 characters - 10 bonus)
~]0\.,{.,@*\.(@$?@+\}*

Bonus points for not using factorials. Input must be given on STDIN in the format desriped in the question. You can try the code online.

Haha not quite what I was looking for when I said "without using factorials" but I suppose it counts. Kudos

CJam, 31, with factorials
q~]{__(f<0+:+\,,(;1+:**\(;}h]:+

Why am I still getting upvote? The GolfScript answer can be rewritten in CJam with only 23 characters.

Because people like your answer.

Python 2 (77 = 87-10)
p=map(int,raw_input().split())
s=0
while p:s=s*len(p)+sorted(p).index(p.pop(0))
print s

Such readable. Much built-in. Wow.
We use the fact that the lexicographic index of a permutation is the sum over the elements of the permutations of the number of inversions above that element (values after it but below it) multiplied by the factorial of the number of elements after it. Rather than evaluate this polynomial-like expression term by term, we use something akin to Horner's method.
Rather then looping over array indices, we repeatedly remove the first element of the list and process the remaining elements. The expression sorted(p).index(p.pop(0)) counts the number of inversions past the first index by taking its position in the sorted list, while at the same time doing the removal.
Sadly, I had to use Python 2 and take 4 more characters for raw_input (though -1 for print) because in Python 3 the map(int,...) produces a map object, which doesn't support list operations,

Pyth (13 = 23-10)
JVPwdWJ=Z+*ZlJXovNJ;J)Z

A port of my Python answer.
A Python translation (with some irrelevant stuff filtered out):
Z=0
J=rev(split(input()," "))
while J:
 Z=plus(times(Z,len(J)),index(order(lambda N:eval(N),J),J.pop()))
print(Z)

The input numbers stay strings but are sorted as ints by using eval as the key. The list is reversed so that pop takes the the front rather than the back.

Cobra - 202
Obviously Cobra isn't really competing in this one.
class P
    var n=0
    var t=CobraCore.commandLineArgs[1:]
    def main
        .f(.t[0:0])
    def f(l as List<of String>)
        if.t.count==l.count,print if(.t<>l,'',.n+=1)
        else,for i in.t.sorted,if i not in l,.f(l+[i])

J, 5 bytes (15 - 10)
#\.#.+/@(<{.)\.

This runs in O(n2) time and is able to handle n = 100 easily.
Usage
   f =: #\.#.+/@(<{.)\.
   f 0 1 2
0
   f 0 2 1
1
   f 1 0 2
2
   f 1 2 0
3
   f 2 0 1
4
   f 2 1 0
5
   f 0 1 2 3 4 5 6 7
0
   f 0 1 2 3 4 5 7 6
1
   f 0 1 2 3 4 6 5 7
2
   f 1 3 5 17
0
   f 781 780 779 13
23
   f 81 62 19 12 11 8 2 0
40319
   f 195 124 719 1 51 6 3
4181
   NB. A. is the builtin for permutation indexing
   timex 'r =: f 927 A. i. 100'
0.000161
   r
927

Explanation
#\.#.+/@(<{.)\.  Input: array P
             \.  For each suffix of P
          {.       Take the head
         <         Test if it is greater than each of that suffix
     +/@           Sum, count the number of times it is greater
#\.              Get the length of each suffix of P
   #.            Convert to decimal using a mixed radix


text:
Where does the laser go?
Take a 2-dimensional grid and draw a number of line segments on it to represent mirrors. Now pick a point to place a theoretical laser and an angle to define the direction it's pointing. The question is: if your follow the laser beam path for some specified distance, what coordinate point are you at?
Example:

In this image, L is the location of the laser, t is it's angle (measured from the positive X axis), M1, M2, and M3 are all line segment mirrors, and E is the point on the laser beam path after D = d1 + d2 + d3 + d4 units, starting from L.
Goal
Write the shortest program (in bytes) that outputs E given L, t, D, and a list of mirrors.
(Use http://mothereff.in/byte-counter to count bytes.)
Input Format
Input will come from stdin in the format:
Lx Ly t D M1x1 M1y1 M1x2 M1y2 M2x1 M2y1 M2x2 M2y2 ...

All the values will be floating points matching this regex: [-+]?[0-9]*\.?[0-9]+.
There is always exactly one space between each number.
Requiring quotes around the input is allowed.
t is in degrees, but not necessarily in the [0, 360) range. (If you prefer you may use radians instead, just say so in your answer.)
D may be negative, effectively rotating the laser 180 degrees. D may also be 0.
There may be arbitrarily many mirrors (including none at all).
The order of the mirrors should not matter.
You may assume the input will come in multiples of 4 numbers. e.g. Lx Ly t or Lx Ly t D M1x1 are invalid and will not be tested. No input at all is also invalid.

The layout above might be input as:
1 1 430 17 4.8 6.3 6.2 5.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3

(Note that the image was drawn freehand and these values are only approximations. Martin Büttner's input values of
1 1 430 17 4.8 5.3 6.2 4.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3

will give more collisions though they do not match the sketch.)
Output Format
Output should go to stdout in the format:
Ex Ey

These are also floats and may be in exponential form.
Notes

Mirrors may intersect each other.
Both sides of mirrors are reflective.
The beam may hit the same mirror many times.
The beam goes on forever.

Undefined Cases
You may assume that the cases where

the laser starts on a mirror line segment
the laser beam hits the endpoint of a mirror
the laser beam hits the intersection between two mirrors

are undefined and will not be tested. Your program may do anything if these occur, including throw an error.
Bonus
Just for fun, I will award 200 bounty points to the highest voted submission that outputs a graphical representation of the problem (you could even write an interactive script). These bonus submission do not need to be golfed and can be lenient with how input and output are handled. They are distinct from the actual golfed submissions but both should be submitted in the same answer.
Note: Only submitting a bonus answer is fine, you just wont be the accepted answer. To be accepted you must exactly follow the input/output spec (e.g. output only involves Ex Ey, not images), and be the shortest.

Why degrees? I don't like degrees :-(

It was mainly so it would be easier to visualize. I'll change it so you can do radians or degrees.

Having golfed and ungolfed submissions in one questions is imho going to become a huge mess. The 200 bounty points are so attractive the the golfing becomes the minor point.

@Howard That may be true, so to combat that I've told people to submit their bonus answer along with their golfed answer. Hopefully that will keep things a bit tidier.

@Calvin'sHobbies If you want to update your example, feel free to pick the first three mirrors from the example in my answer. They are similar to your positions, but the laser actually hits all three of them (which is not the case with your numbers).

@MartinBüttner Thanks, I've mentioned them. I'd use your numbers exclusively if I didn't have to bother redrawing the image so they were accurate.

No-one has actually submitted the golfed answer. I think you need to threaten not to award the bounty to anyone who only does the "bonus" part.

@PeterTaylor and that was worth downvoting all answers? will you be keeping an eye on the question to remove them if someone does include a golfed answer later on?

@MartinBüttner, yes, it was. None of them are attempts to answer the question: as you said yesterday, that's worth voting to delete them, so it's certainly worth a downvote.

@PeterTaylor You're quoting me well out of context. I read the OP's section bonus answers as the two submissions being completely distinct but belonging in the same post if both are attempted (which would mean just the popcon answer would be fine as well). Anyway, they're your votes and it's up to you how you use them, and I'll probably add a golfed version anyway at some point. But I guess the OP could clarify whether he intended, popcon-only answers to be valid or not.

@MartinBüttner, "bonus" means "additional, extra". It's not part of the main challenge. And the question has only one tag, [tag:code-golf].

@PeterTaylor MartinBüttner is right. Answering only the bonus part of the question is fine. I said the bonus answers can be un-golfed and lenient with the i/o, and all the current bonus submissions look fine to me. The shortest submission that does exactly follow the spec will be the accepted answer. Currently no submissions do, but that's ok with me.

In that case "bonus" is the wrong word to use and you're asking people to break the rules, which is not helpful.

@PeterTaylor Well the bonus was just an afterthought, I had no idea it would be so popular. Perhaps a popularity contest for the best images would have suited this question better but it seems too late to change it all now.

Ruby, 327 bytes
(scroll to the bottom)
Mathematica, bonus answer

I'm only going for the graphical submission right now. I might port this to Ruby later and golf it if I feel like it.
(* This function tests for an intersection between the laser beam
   and a mirror. r contains the end-points of the laser, s contains
   the end-points of the mirror. *)
intersect[r_, s_] := Module[
   {lr, dr, nr, ds, ns, \[Lambda]},
   (* Get a unit vector in the direction of the beam *)
   dr = r[[2]] - r[[1]];
   lr = Norm@dr;
   dr /= lr;
   (* Get a normal to that vector *)
   nr = {dr[[2]], -dr[[1]]};

   (* The sign of dot product in here depends on whether that end-point
      of the mirror is to the left or to the right of the array. Return
      infinity if both ends of s are on the same side of the beam. *)
   If[Apply[Times, (s - {r[[1]], r[[1]]}).nr] > 0,
    Return[\[Infinity]]];

   (* Get a unit vector along the mirror. *)
   ds = s[[2]] - s[[1]];
   ds /= Norm@ds;
   (* And a normal to that. *)
   ns = {ds[[2]], -ds[[1]]};
   (* We can write the beam as p + λ*dr and mirror as q + μ*ds,
      where λ and μ are real parameters. If we set those equal and
      solve for λ we get the following equation. Since dr is a unit
      vector, λ is also the distance to the intersection. *)
   \[Lambda] = ns.(r[[1]] - s[[1]])/nr.ds;
   (* Make sure that the intersection is before the end of the beam.
      This check could actually be slightly simpler (see Ruby version). *)
   If[\[Lambda] != 0 && lr/\[Lambda] < 1, Infinity, \[Lambda]]
   ];

(* This function actually does the simulation and generates the plot. *)
plotLaser[L_, t_, distance_, M_] := Module[
   {coords, plotRange, points, e, lastSegment, dLeft, \[Lambda], m, p,
     d, md, mn, segments, frames, durations},

   (* This will contain all the intersections along the way, as well
      as the starting point. *)
   points = {L};
   (* The tentative end point. *)
   e = L + distance {Cos@t, Sin@t};
   (* This will always be the currently last segment for which we need
      to check for intersections. *)
   lastSegment = {L, e};
   (* Keep track of the remaining beam length. *)
   dLeft = distance;

   While[True,
    (* Use the above function to find intersections with all mirrors
       and pick the first one (we add a small tolerance to avoid
       intersections with the most recent mirror). *)
    {\[Lambda], m} =
     DeleteCases[
       SortBy[{intersect[lastSegment, #], #} & /@ M, #[[1]] &],
       i_ /; i[[1]] < 1*^-10][[1]];
    (* If no intersection was found, we're done. *)
    If[\[Lambda] == \[Infinity], Break[]];
    (* Reduce remaining beam length. *)
    dLeft -= \[Lambda];
    (* The following lines reflect the beam at the mirror and add
       the intersection to our list of points. We also update the
       end-point and the last segment. *)
    p = lastSegment[[1]];
    d = -Subtract @@ lastSegment;
    d /= Norm@d;
    md = -Subtract @@ m;
    md /= Norm@md;
    mn = {md[[2]], -md[[1]]};
    AppendTo[points, p + \[Lambda]*d];
    d = -d + 2*(d - d.mn*mn);
    e = Last@points + dLeft*d;
    lastSegment = {Last@points, e};
    ];
   (* Get a list of all points in the set up so we can determine
      the plot range. *)
   coords = Transpose@Join[Flatten[M, 1], {L, e}];
   (* Turn the list of points into a list of segments. *)
   segments = Partition[points, 2, 1];
   (* For each prefix of that list, generate a frame. *)
   frames = Map[
     Graphics[
       {Line /@ M,
        Red,
        Point@L,
        Line /@ segments[[1 ;; #]]},
       PlotRange -> {
         {Min@coords[[1]] - 1, Max@coords[[1]] + 1},
         {Min@coords[[2]] - 1, Max@coords[[2]] + 1}
         }
       ] &,
     Range@Length@segments];
   (* Generate the initial frame, without any segments. *)
   PrependTo[frames,
    Graphics[
     {Line /@ M,
      Red,
      Point@L},
     PlotRange -> {
       {Min@coords[[1]] - 1, Max@coords[[1]] + 1},
       {Min@coords[[2]] - 1, Max@coords[[2]] + 1}
       }
     ]
    ];
   (* Generate the final frame including lastSegment. *)
   AppendTo[frames,
    Graphics[
     {Line /@ M,
      Red,
      Point@L,
      Line /@ segments,
      Line[lastSegment],
      Point@e},
     PlotRange -> {
       {Min@coords[[1]] - 1, Max@coords[[1]] + 1},
       {Min@coords[[2]] - 1, Max@coords[[2]] + 1}
       }
     ]];

   (*Uncomment to only view the final state *)
   (*Last@frames*)

   (* Export the frames as a GIF. *)
   durations = ConstantArray[0.1, Length@frames];
   durations[[-1]] = 1;
   Export["hardcoded/path/to/laser.gif", frames,
    "GIF", {"DisplayDurations" -> durations, ImageSize -> 600}];

   (* Generate a Mathematica animation form the frame. *)
   ListAnimate@frames
   ];

You can call it like
plotLaser[{1, 1}, 7.50492, 95, {
  {{4.8, 5.3}, {6.2, 4.3}}, {{1.5, 4.8}, {3.5, 6}}, {{6.3, 1.8}, {7.1, 3}},
  {{5, 1}, {4, 3}}, {{7, 6}, {5, 6.1}}, {{8.5, 2.965}, {8.4, 2}},
  {{8.5, 3.035}, {8.6, 4}}, {{8.4, 2}, {10.5, 3}}, {{8.6, 4}, {10.5, 3}}
}]

That will give you an animation in Mathematica and also export a GIF (the one at the top for this input). I've slightly extended the OPs example for this, to make it a bit more interesting.
More examples
A tube with slightly diverging walls but a closed end:
plotLaser[{0, 0}, 1.51, 200, {
  {{0, 1}, {20, 1.1}},
  {{0, -1}, {20, -1.1}},
  {{20, 1.1}, {20, -1.1}}
}]

An equilateral triangle and an initial direction that is almost parallel to one of the sides.
plotLaser[{-1, 0}, Pi/3 + .01, 200, {
  {{-2.5, 5 Sqrt[3]/6}, {2.5, 5 Sqrt[3]/6}},
  {{0, -5 Sqrt[3]/3}, {-2.5, 5 Sqrt[3]/6}},
  {{0, -5 Sqrt[3]/3}, {2.5, 5 Sqrt[3]/6}}
}]

One more:
plotLaser[
 {0, 10}, -Pi/2, 145,
 {
   {{-1, 1}, {1, -1}}, {{4.5, -1}, {7.5, Sqrt[3] - 1}},
   {{11, 10}, {13, 10}}, {{16.5, Sqrt[3] - 1}, {19.5, -1}},
   {{23, -1}, {25, 1}}, {{23, 6}, {25, 4}}, {{18, 6}, {20, 4}}, {{18, 9}, {20, 11}},
   {{31, 9}, {31.01, 11}}, {{24.5, 10.01}, {25.52, 11.01}}, {{31, 4}, {31, 6}}, {{25, 4.6}, {26, 5.6}}, {{24.5, 0.5}, {25.5, -0.5}},
   {{31, -1}, {33, 1}}, {{31, 9}, {33, 11}}, {{38, 10.5}, {38.45, 9}}
 }
]

Ruby, golfed answer
x,y,t,p,*m=gets.split.map &:to_f
u=q=Math.cos t
v=r=Math.sin t
loop{k=i=p
u=x+q*p
v=y+r*p
m.each_slice(4){|a,b,c,d|((a-u)*r-(b-v)*q)*((c-u)*r-(d-v)*q)>0?next: g=c-a
h=d-b
l=(h*(x-a)-g*(y-b))/(r*g-q*h)
f=(g*g+h*h)**0.5
t,k,i=g/f,h/f,l if l.abs>1e-9&&l/i<1}
i==p ?abort([u,v]*' '): p-=i
x+=q*i
y+=r*i
n=q*k-r*t
q-=2*n*k
r+=2*n*t}

This is basically a direct translation of the Mathematica solution to Ruby, plus some golfing and making sure it meets the I/O criteria.

How do you have the lazer cross the mirror triangle at the end of the first example?

@AJMansfield There's a small hole in the triangle, which you can see at the beginning of the animation.

It would be great if you could write a paragraph explaining how it works.

@JeffSB I've documented the Mathematica code now. The Ruby version does pretty much exactly the same thing with obscure variable names and without plotting.

@MartinBüttner Thanks.  It's interesting to see how other people do it.  Did you realize before it happened that you have to exclude the last mirror you bounced off of?  I did not, but I figured it out soon enough.  I noticed the very small number in your code and that's why I asked to see how it works.

@JeffSB Yes, in fact I expected something like this to happen, so I had included that tolerance right away. I recently wrote a simple collision detector for a game prototype that uses a lot of the same maths as this, so I could skip a few of the pitfalls. ;) (I'm pretty sure I made that mistake back then, though.)

It's a pity that the android client app can only display the first frame of GIFs.

Python 3(421C 390C,366C)

Use builtin.complex as 2d vector. So
dot = lambda a, b: (a.conjugate() * b).real
cross = lambda a, b: (a.conjugate() * b).imag

In order to beat the 368C Ruby solution, I've find a quite compact method to calculate point reflection along a mirror. And also used some complex algebra to reduce more characters. These can be easily found in the ungolfed code.
Here's the golfed version.
C=lambda a,b:(abs(a)**2/a*b).imag
J=1j
x,y,r,d,*a=map(float,input().split())
p=x+y*J
q=p+d*2.718281828459045**(r*J)
M=[]
while a:x,y,z,w,*a=a;M+=[(x+y*J,z-x+w*J-y*J)]
def T(m):x,y=m;d=C(y,r)+1e-9;t=C(y,x-p)/d;s=C(r,x-p)/d;return[1,t][(1e-6<t<1)*(0<s<1)]
while 1:
 r=q-p;m=f,g=min(M,key=T)
 if T(m)==1:break
 p+=r*T(m);q=(q/g-f/g).conjugate()*g+f
print(q.real,q.imag)

Ungolfed
# cross product of two vector
# abs(a)**2 / a == a.conjugate()
cross = lambda a, b: (abs(a)**2 / a * b).imag
# Parse input
x, y, angle, distance, *rest = map(float, input().split())
start = x + y * 1j
# e = 2.718281828459045
# Using formula: e**(r*j) == cos(r) + sin(r) * j
end = start + distance * 2.718281828459045 ** (angle * 1j)
mirrors = []
while rest:
    x1, y1, x2, y2, *rest = rest
    # Store end point and direction vector for this mirror
    mirrors.append((x1 + y1 * 1j, (x2 - x1) + (y2 - y1) * 1j))

def find_cross(mirror):
    # a: one end of mirror
    # s: direction vector of mirror
    a, s = mirror
    # Solve (t, r) for equation: start + t * end == a + r * s
    d = cross(s, end - start) + 1e-9 # offset hack to "avoid" dividing by zero
    t = cross(s, a - start) / d
    r = cross(end - start, a - start) / d
    return t if 1e-6 < t < 1 and 0 < r < 1 else 1

def reflect(p, mirror):
    a, s = mirror
    # Calculate reflection point:
    #  1. Project r = p - a onto a coordinate system that use s as x axis, as r1.
    #  2. Take r1's conjugate as r2.
    #  3. Recover r2 to original coordinate system as r3
    #  4. r3 + a is the final result
    #
    # So we got conjugate((p - a) * conjugate(s)) / conjugate(s) + a
    # which can be reduced to conjugate((p - a) / s) * s + a
    return ((p - a) / s).conjugate() * s + a

while 1:
    mirror = min(mirrors, key=find_cross)
    if find_cross(mirror) == 1:
        break
    start += (end - start) * find_cross(mirror)
    end = reflect(end, mirror)
print(end.real, end.imag)

Bonus: HTML, Coffeescript, Realtime Adjustment & Calculation
This is, you drag any end points(or lazer, mirros), then the track is rendered.
It also support two types of input, the one described in the question and the one used by @Martin Büttner.
The scaling is also adjusted automatically.
For now it doesn't has animation. Maybe I'll improve it later. However, dragging the white points and you can see another type of animation. Try it online here yourself, it's funny!
The whole project can be found Here

Update
Here I provide an interesting case:
0 0.6 -0.0002 500.0 0.980785280403 -0.195090322016 1.0 0.0 1.0 0.0 0.980785280403 0.195090322016 0.980785280403 0.195090322016 0.923879532511 0.382683432365 0.923879532511 0.382683432365 0.831469612303 0.55557023302 0.831469612303 0.55557023302 0.707106781187 0.707106781187 0.707106781187 0.707106781187 0.55557023302 0.831469612303 0.55557023302 0.831469612303 0.382683432365 0.923879532511 0.382683432365 0.923879532511 0.195090322016 0.980785280403 0.195090322016 0.980785280403 6.12323399574e-17 1.0 6.12323399574e-17 1.0 -0.195090322016 0.980785280403 -0.195090322016 0.980785280403 -0.382683432365 0.923879532511 -0.382683432365 0.923879532511 -0.55557023302 0.831469612303 -0.55557023302 0.831469612303 -0.707106781187 0.707106781187 -0.707106781187 0.707106781187 -0.831469612303 0.55557023302 -0.831469612303 0.55557023302 -0.923879532511 0.382683432365 -0.923879532511 0.382683432365 -0.980785280403 0.195090322016 -0.980785280403 0.195090322016 -1.0 1.22464679915e-16 -1.0 1.22464679915e-16 -0.980785280403 -0.195090322016 -0.980785280403 -0.195090322016 -0.923879532511 -0.382683432365 -0.923879532511 -0.382683432365 -0.831469612303 -0.55557023302 -0.831469612303 -0.55557023302 -0.707106781187 -0.707106781187 -0.707106781187 -0.707106781187 -0.55557023302 -0.831469612303 -0.55557023302 -0.831469612303 -0.382683432365 -0.923879532511 -0.382683432365 -0.923879532511 -0.195090322016 -0.980785280403 -0.195090322016 -0.980785280403 -1.83697019872e-16 -1.0 -1.83697019872e-16 -1.0 0.195090322016 -0.980785280403 0.195090322016 -0.980785280403 0.382683432365 -0.923879532511 0.382683432365 -0.923879532511 0.55557023302 -0.831469612303 0.55557023302 -0.831469612303 0.707106781187 -0.707106781187 0.707106781187 -0.707106781187 0.831469612303 -0.55557023302 0.831469612303 -0.55557023302 0.923879532511 -0.382683432365 0.923879532511 -0.382683432365 0.980785280403 -0.195090322016

And the result is:

-1 doesn't meet spec for input or output.

@Ray As a bonus answer this is fine. It only must exactly meet the spec to become the code-golf answer.

@PeterTaylor Meet spec now.

That is really cool how you can move the mirrors around!  Yours is my first +1 vote.

HTML JavaScript, 10,543, 947 889
I fixed a bug and made sure the output meets the question spec.  The webpage below has the golfed version and also the graphical bonus version. I also fixed a bug pointed out by @Ray which saved 58 characters. (Thanks Ray.) You can also run the golfed code in a JavaScript console.  (Now I'm using a 2mW green laser.)
Golf Code
a=prompt().split(" ").map(Number);M=Math,Mc=M.cos,Ms=M.sin,P=M.PI,T=2*P,t=true;l=new S(a[0],a[1],a[0]+a[3]*Mc(a[2]),a[1]+a[3]*Ms(a[2]));m=[];for(i=4;i<a.length;)m.push(new S(a[i++],a[i++],a[i++],a[i++]));f=-1;for(;;){var h=!t,d,x,y,n,r={};for(i=0;i<m.length;i++)if(i!=f)if(I(l,m[i],r))if(!h||r.d<d){h=t;d=r.d;x=r.x;y=r.y;n=i}if(h){l.a=x;l.b=y;l.e-=d;l.f=2*(m[f=n].f+P/2)-(l.f+P);l.c=l.a+l.e*Mc(l.f);l.d=l.b+l.e*Ms(l.f);}else break;}alert(l.c+" "+l.d);function S(a,b,c,d){this.a=a;this.b=b;this.c=c;this.d=d;this.e=D(a,b,c,d);this.f=M.atan2(d-b,c-a)}function D(a,b,c,d){return M.sqrt((a-c)*(a-c)+(b-d)*(b-d))}function I(l,m,r){A=l.a-l.c,B=l.b-l.d,C=m.a-m.c,L=m.b-m.d,E=l.a*l.d-l.b*l.c,F=m.a*m.d-m.b*m.c,G=A*L-B*C;if(!G)return!t;r.x=(E*C-A*F)/G;r.y=(E*L-B*F)/G;H=r.d=D(l.a,l.b,r.x,r.y),O=D(l.c,l.d,r.x,r.y),J=D(m.a,m.b,r.x,r.y),K=D(m.c,m.d,r.x,r.y);return(H<l.e)&&(O<l.e)&&(J<m.e)&&(K<m.e);}

Input
1 1 7.50492 17 4.8 6.3 6.2 5.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3

Output
14.743305098514739 3.759749038188634

You can test it here: http://goo.gl/wKgIKD

Explanation
The code in the webpage is commented.  Basically I calculate the intersection of the laser with every mirror assuming the laser and mirrors are infinitely long.  Then I check if the intersection is within the finite length of the mirror and the laser.  Then I take the closest intersection, move the laser to that point, and continue until the laser misses all the mirrors.
Very fun project.  Thanks for asking this question!
Readable code
// a = input array
// M = Math, Mc = M.cos, Ms = M.sin, P=M.PI, T=2*P, t=true
// l = laser segment
// m = array of mirror segments
// i = loop variable
// S = segment class (this.a=x1,b=y1,c=x2,d=y2,e=len,f=theta)
// D = distance function
// I = intersect function
// f = last mirror bounced from
// h = hits a mirror
// n = next intersecing mirror
// d = distance to mirror
// x = intersection point x
// y = intersection point y
// r = mirror intersection result (d,x,y)
// b = number of bounces (FOR DEBUGGING)
// A,B,C,E,F,G,H,J,K,L,O temp variables
// s = laser segment array

// get input array
var a = prompt().split(" ").map(Number);

// some constants
var M = Math, Mc = M.cos, Ms = M.sin, P = M.PI, T = 2 * P, t = true;

// laser segment
var l = new S(a[0], a[1], a[0] + a[3] * Mc(a[2]), a[1] + a[3] * Ms(a[2])), s = [];

// mirror segments
var m = []; for (var i = 4; i < a.length;) m.push(new S(a[i++], a[i++], a[i++], a[i++]));

// bounce until miss
var f = -1, b = 0; for (; ;) {

    // best mirror found
    var h = !t, d, x, y, n, r = {};

    // loop through mirrors, skipping last one bounced from
    for (var i = 0; i < m.length; i++)
        if (i != f)
            if (I(l, m[i], r))
                if (!h || r.d < d) { h = t; d = r.d; x = r.x; y = r.y; n = i }

    // a mirror is hit
    if (h) {

        // add to draw list, inc bounces
        s.push(new S(l.a, l.b, x, y)); b++;

        // move and shorten mirror
        l.a = x; l.b = y; l.e -= d;

        // calculate next angle
        l.f = 2 * (m[f = n].f + P / 2) - (l.f + P);

        // laser end point
        l.c = l.a + l.e * Mc(l.f); l.d = l.b + l.e * Ms(l.f);

    } else {

        // add to draw list, break
        s.push(new S(l.a, l.b, l.c, l.d));
        break;
    }
}
// done, print result
alert("X = " + l.c.toFixed(6) + ",  Y = " + l.d.toFixed(6) + ",  bounces = " + b);
PlotResult();

// segment class
function S(a, b, c, d) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = D(a, b, c, d); this.f = M.atan2(d - b, c - a) }

// distance function
function D(a, b, c, d) { return M.sqrt((a - c) * (a - c) + (b - d) * (b - d)) }

// intersect function
function I(l, m, r) {

    // some values
    var A = l.a - l.c, B = l.b - l.d, C = m.a - m.c, L = m.b - m.d, E = l.a * l.d - l.b * l.c, F = m.a * m.d - m.b * m.c, G = A * L - B * C;

    // test if parallel
    if (!G) return !t;

    // intersection
    r.x = (E * C - A * F) / G; r.y = (E * L - B * F) / G;

    // distances
    var H = r.d = D(l.a, l.b, r.x, r.y), O = D(l.c, l.d, r.x, r.y), J = D(m.a, m.b, r.x, r.y), K = D(m.c, m.d, r.x, r.y);

    // return true if intersection is with both segments
    return (H < l.e) && (O < l.e) && (J < m.e) && (K < m.e);
}

Pretty cool, I love the web interface. Another fun input: 0 0 0.4 100 1 1 1 -1 1 -1 -1 -1 -1 -1 -1 1 -1 1 1 1.

Where's the actual program?

It's in the web page here: http://goo.gl/wKgIKD

Answers on this site should generally include all of the code required to answer the question. In the case of this question, that's a program which reads from stdin and writes to stdout. In addition, since it's a [tag:code-golf] question you should minimise the code as much as possible: at the very least, removing comments and unnecessary whitespace and using one-character identifiers where possible.

@JeffSB This submission is valid for the bonus answer, just not the accepted answer. (Though you may want to include all your code.)

Bugs may not be a huge priority, but switching what laser inputs are being used and starting a new render while it is already rendering one can lead to some interesting results.

@Dispensador I see what you mean.  I fixed it.  Thanks for telling me.

@PeterTaylor  I minimized the code and made sure the golfed version outputs the correct format.  I don't think JavaScript can access the stdin and stdout, so I used prompt() and alert() for the input and output.  When the code runs by itself in a console then the prompt and alert work normally.  When the same code runs in the webpage I supplied, then the input comes from an HTML textarea and the output goes to an HTML pre.  If you click the "graphic" radio button then the non-golfed version will run that also shows the path of the laser.

I believe there is a bug in the N function. The second while condition should be -P. And actually it can be calculated directly: return (e+P)%T-P

@Ray, you are right.  Thanks for noticing.  And your proposed alternative is shorter function N(e) { return e>0 ? (e+P)%T-P : (e-P)%T+P } which I verified for various positive and negative numbers.  Interestingly, this function is not needed at all. I wasn't sure if it was needed when I wrote the program, and I forgot to look at it closer.  (I always finish late at night and just want to go to bed.)

Python - 765
Good challenge. This is my solution which gets input from stdin and outputs to stdout. Using @Martin Büttner's example:
python mirrors.py 1 1 70.00024158332184 95 4.8 5.3 6.2 4.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3     5 1 4 3 7 6 5 6.1 8.5 2.965 8.4 2 8.5 3.035 8.6 4 8.4 2 10.5 3 8.6 4 10.5 3

7.7094468894 3.84896396639

Here is the golfed code:
import sys;from cmath import*
l=[float(d) for d in sys.argv[1:]];c=180/pi;p=phase;q=exp;u=len;v=range
def o(l):
 L=l[0]+1j*l[1];t=l[2]/c;D=l[3];S=[L,L+D*q(1j*t)];N=[[l[i]+1j*l[i+1],l[i+2]+1j*l[i+3]] for i in v(4,u(l),4)];a=[];b=[]
 for M in N:
  z=S[1].real-S[0].real;y=M[0].real-M[1].real;x=S[1].imag-S[0].imag;w=M[0].imag-M[1].imag;d=M[0].real-S[0].real;f=M[0].imag-S[0].imag;g=z*w-x*y;h=w/g;j=-y/g;m=-x/g;n=z/g;a.append(h*d+j*f);b.append(m*d+n*f)
 i=1;e=-1
 for k in v(u(N)):
  if 1>b[k]>0:
   if i>a[k]>1e-14:
    i=a[k];e=k
 if e>-1:
  L=S[0]+i*(S[1]-S[0]);M=N[e];l[0]=L.real;l[1]=L.imag;l[2]=c*(p(M[1]-M[0])+p(q(1j*p(M[1]-M[0]))*q(1j*-t)));l[3]=D*(1-i)
  return l
 J=S[0]+i*(S[1]-S[0])
 print J.real, J.imag
 return J.real, J.imag
while u(l)>2:
 l=o(l)

And here is the ungolfed code with a bonus figure

import sys
from cmath import*
import matplotlib
import matplotlib.pyplot as plt
l=[float(d) for d in sys.argv[1:]]
def nextpos(l):
    L=l[0]+1j*l[1]
    t=l[2]/180*pi
    D=l[3]
    S=[L,L + D * exp(1j * t)]
    MM=[[l[i]+1j*l[i+1],l[i+2]+1j*l[i+3]] for i in range(4,len(l), 4)]
    a=[]
    b=[]
    for M in MM:
        #determine intersections
        a11 = S[1].real-S[0].real
        a12 = M[0].real-M[1].real
        a21 = S[1].imag-S[0].imag
        a22 = M[0].imag-M[1].imag
        b1  = M[0].real-S[0].real
        b2  = M[0].imag-S[0].imag
        deta = a11*a22-a21*a12
        ai11 = a22/deta
        ai12 = -a12/deta
        ai21 = -a21/deta
        ai22 = a11/deta
        a.append(ai11*b1+ai12*b2)
        b.append(ai21*b1+ai22*b2)
    #determine best intersection
    mina = 1
    bestk = -1
    for k in range(len(MM)):
        if 1>b[k]>0:
            if mina>a[k]>1e-14:
                mina=a[k]
                bestk=k
    if bestk>-1:
        #determine new input set
        L=S[0]+mina*(S[1]-S[0])
        M=MM[bestk]
        l[0]=L.real
        l[1]=L.imag
        angr=phase(exp(1j*phase(M[1]-M[0]))*exp(1j *-t))
        l[2]=180/pi*(phase(M[1]-M[0])+angr)
        l[3]=D*(1-mina)
        return l
    J= S[0]+mina*(S[1]-S[0])
    print J.real, J.imag
    return J.real, J.imag
#plotting
xL = [l[0]]
yL = [l[1]]
fig = plt.figure()
ax = fig.add_subplot(111,aspect='equal')
for i in range(4,len(l), 4):
    plt.plot([l[i],l[i+2]],[l[i+1],l[i+3]], color='b')
while len(l)>2:
    #loop until out of lasers reach
    l = nextpos(l)
    xL.append(l[0])
    yL.append(l[1])
plt.plot(xL,yL, color='r')
plt.show()

-1: doesn't meet spec. The specified output is two numbers, not two numbers and an image.

@PeterTaylor So you mean stdin/stdout?

@willem As a bonus answer this is fine. It only must exactly meet the spec to become the code-golf answer.

I have updated the code

Note that sys.argv is not stdin.

Matlab (388)
Plot

Concepts
Reflection Points
For calculating the reflection points we basically have to interesect two straight lines. One with the point p0 and vector v, the other between the two points p1,p2. So the equation to solve is (s,t are parameters): p0+tv = sp1+(1-s)*p2.
The parameter s is then a barycentric coordinate of the mirror so if 0

Mirroring
The mirroring of v is pretty simple. Let us assume that ||v|| = ||n|| = 1 where n is the normal vector of the current mirror. Then you can just use the formula v := v-2**n where <,> is the dot product.
Validity of step
While computing the nearest 'valid' mirror we have to consider some criterias that make it valid. First the interception point of the mirror must lie between the two endpoints, so it must be 0

Program
p = [1 1 430 17 4.8 5.3 6.2 4.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3];
hold on
grid on
for i=2:length(p)/4
    i = i*4+1-4
    p2=p(i+2:i+3)';
    p1=p(i:i+1)'
    plot([p1(1),p2(1)],[p1(2),p2(2)],'r-')
    text(p1(1),p1(2),['m' num2str((i+3)/4-1)])
end
%hold off

history = p(1:2)';

currentPosition = p(1:2)';%current
currentDirection=[cos(p(3)*pi/180);sin(p(3)*pi/180)];
while p(4)>0%as long as we do not have finished our distance
   distanceBuffer = Inf%distance next point buffer
   intersectionBuffer = NaN %next point buffer
   for i=2:length(p)/4%number of mirrors
       i = i*4+1-4 %i is now the index of the firs coordinate of the mirror
       %calculate all crosspoints
       p2=p(i+2:i+3)';
       mirrorVector = p2-p(i:i+1)';
       % idea: p0+s*currentDirection = s*p1+(1-s)*p2 solving for s,t
       r=[currentDirection,mirrorVector]\[p2-currentPosition];
       if r(1)<distanceBuffer && 0.001< r(1) && r(1)<p(4) &&0<=r(2) && r(2)<=1 %search for the nearest intersection
           distanceBuffer=r(1);
           intersectionBuffer=r(1)*currentDirection+currentPosition;
           mirrorBuffer = mirrorVector
       end
   end
   if distanceBuffer == Inf %no reachable mirror found
       endpoint = currentPosition+p(4)*currentDirection;
       counter = counter+1
       history = [history,endpoint];
       break
   else %mirroring takes place
       counter = counter+1
       history = [history,intersectionBuffer];
       currentPosition=intersectionBuffer;
       normal = [0,-1;1,0]*mirrorBuffer;%normal vector of mirror
       normal = normal/norm(normal)
       disp('arccos')
       currentDirection = currentDirection-2*(currentDirection'*normal)*normal;
       %v = v/norm(v)
       p(4)=p(4)-distanceBuffer
   end
end
history
plot(history(1,:),history(2,:))

Slightly golfed (388)
p=[1 1 430 17 4.8 5.3 6.2 4.3 1.5 4.8 3.5 6 6.3 1.8 7.1 3];
c=p(1:2)'
b=pi/180
v=[cos(p(3)*b);sin(p(3)*b)]
f=p(4)
while f>0
q=Inf
for i=2:length(p)/4
b=p(i+2:i+3)'
u=b-p(i:i+1)'
r=[v,u]\[b-c]
s=r(1)
t=r(2)
if s<q&&0.001<s&&s<f&&0<=t&&t<=1
q=s
n=s*v+c
m=u
end
end
if q==Inf
disp(c+f*v)
break
else
c=n
g=[0,-1;1,0]*m
g=g/norm(g)
v=v-2*(v'*g)*g
f=f-q
end
end

This takes me back. My first experience with Matlab was modeling the path of a laser through a system of mirrors and lenses while in a research position during my undergraduate studies. Your graphics in particular look very familiar. :) Anyway, just an aside. Nice work here, +1.

Haha thanks! I just didn't even remember I did this when I saw your comment pop up=)

Haha then my comment probably takes you back! (To when you posted this.)

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes