title: Google Foobar: Bringing a Gun to a Guard Fight
body: <h2>My Situation</h2>
  <p>I've been working on this challenge on and off for about 9 days now, and I'm out of ideas. So far my solution passes 9 / 10 of the test cases. My optimized solution runs quickly enough, so the error is the actual solution, not that it runs out of time to compute. I would greatly appreciate it if someone could tell me what I'm missing or if my algorithm doesn't actually solve the problem given. Also, I realize some bits of my code aren't perfect - I plan to fix everything up once I have a working solution.</p>
  <h2>Problem</h2>
  <p>Uh-oh - you've been cornered by one of Commander Lambdas elite guards! Fortunately, you grabbed a beam weapon from an abandoned guardpost while you were running through the station, so you have a chance to fight your way out. But the beam weapon is potentially dangerous to you as well as to the elite guard: its beams reflect off walls, meaning you'll have to be very careful where you shoot to avoid bouncing a shot toward yourself!</p>
  <p>Luckily, the beams can only travel a certain maximum distance before becoming too weak to cause damage. You also know that if a beam hits a corner, it will bounce back in exactly the same direction. And of course, if the beam hits either you or the guard, it will stop immediately (albeit painfully).</p>
  <p>Write a function answer(dimensions, your_position, guard_position, distance) that gives an array of 2 integers of the width and height of the room, an array of 2 integers of your x and y coordinates in the room, an array of 2 integers of the guard's x and y coordinates in the room, and returns an integer of the number of distinct directions that you can fire to hit the elite guard, given the maximum distance that the beam can travel.</p>
  <p>The room has integer dimensions [1 &lt; x_dim &lt;= 1000, 1 &lt; y_dim &lt;= 1000]. You and the elite guard are both positioned on the integer lattice at different distinct positions (x, y) inside the room such that [0 &lt; x &lt; x_dim, 0 &lt; y &lt; y_dim]. Finally, the maximum distance that the beam can travel before becoming harmless will be given as an integer 1 &lt; distance &lt;= 10000.</p>
  <p>For example, if you and the elite guard were positioned in a room with dimensions [3, 2], you_position [1, 1], guard_position [2, 1], and a maximum shot distance of 4, you could shoot in seven different directions to hit the elite guard (given as vector bearings from your location): [1, 0], [1, 2], [1, -2], [3, 2], [3, -2], [-3, 2], and [-3, -2]. As specific examples, the shot at bearing [1, 0] is the straight line horizontal shot of distance 1, the shot at bearing [-3, -2] bounces off the left wall and then the bottom wall before hitting the elite guard with a total shot distance of sqrt(13), and the shot at bearing [1, 2] bounces off just the top wall before hitting the elite guard with a total shot distance of sqrt(5).</p>
  <h2>My Unfinished Solution (Java)</h2>
  <pre><code>public class Answer {  
  
  public static int answer(int[] dimensions, int[] captain_position, int[] badguy_position, int distance) { 
      
      int parallelDimensionX = (2 * (distance / dimensions[0])) + 1;
      int parallelDimensionY = (2 * (distance / dimensions[1])) + 1;  
      int numDirections = 0;
      int distanceSquared = (int) Math.pow(distance, 2);      
      ArrayList&lt;ArrayList&lt;Double&gt;&gt; directions = new ArrayList&lt;ArrayList&lt;Double&gt;&gt;();
      ArrayList&lt;ArrayList&lt;Double&gt;&gt; sourceDirections = new ArrayList&lt;ArrayList&lt;Double&gt;&gt;();
      ArrayList&lt;ArrayList&lt;int[]&gt;&gt; sourceTracker = new ArrayList&lt;ArrayList&lt;int[]&gt;&gt;();
      
      for(int i = 0; i &lt; 4; i++) {
          
          directions.add(new ArrayList&lt;Double&gt;());
          sourceDirections.add(new ArrayList&lt;Double&gt;());
          sourceTracker.add(new ArrayList&lt;int[]&gt;());
      }       
      
      ArrayList&lt;ArrayList&lt;int[]&gt;&gt; mirroredPlanes = MirroredPlanes(badguy_position, dimensions, new int[]{parallelDimensionX, parallelDimensionY});
      ArrayList&lt;ArrayList&lt;int[]&gt;&gt; mirroredSources = MirroredPlanes(captain_position, dimensions, new int[]{parallelDimensionX, parallelDimensionY});
      
      for(int i = 0; i &lt; parallelDimensionX; i++) {
          
          for(int j = 0; j &lt; parallelDimensionY; j++) {
              
              int[] sourcePoint = mirroredSources.get(j).get(i);
              
              if(sourcePoint[0] == captain_position[0] &amp;&amp; sourcePoint[1] == captain_position[1]) {
                  
                  continue;
              }
              
              int[] vecA = new int[] {sourcePoint[0] - captain_position[0], sourcePoint[1] - captain_position[1]};
              
              double direction = Math.atan2(vecA[1], vecA[0]);
              int quadrant = 0;
              if(vecA[0] &lt; 0) {
                  
                  quadrant++;
              }
              if(vecA[1] &lt; 0) {
                  
                  quadrant += 2;
              }
              
              if(!sourceDirections.get(quadrant).contains(direction)) {
                  
                  sourceDirections.get(quadrant).add(direction);
                  sourceTracker.get(quadrant).add(new int[]{j, i});
              } else {
                  
                  int sourceIndex = sourceDirections.get(quadrant).indexOf(direction);
                  
                  if((sourceTracker.get(quadrant).get(sourceIndex)[0] &lt; j &amp;&amp; j &lt; parallelDimensionY / 2) || (sourceTracker.get(quadrant).get(sourceIndex)[0] &gt; j &amp;&amp; j &gt; parallelDimensionY / 2)) {
                      
                      sourceTracker.get(quadrant).get(sourceIndex)[0] = j;
                  }
                  
                  if((sourceTracker.get(quadrant).get(sourceIndex)[1] &lt; i &amp;&amp; i &lt; parallelDimensionX / 2) || (sourceTracker.get(quadrant).get(sourceIndex)[1] &gt; i &amp;&amp; i &gt; parallelDimensionX / 2)) {
                      
                      sourceTracker.get(quadrant).get(sourceIndex)[1] = i;
                  }
              }
          }
      }
      
      for(int i = 0; i &lt; parallelDimensionX; i++) {
          
          for(int j = 0; j &lt; parallelDimensionY; j++) {
              
              int[] currPoint = mirroredPlanes.get(j).get(i);             
              
              if(captain_position[0] == badguy_position[0] &amp;&amp; currPoint[0] == captain_position[0] &amp;&amp; currPoint[1] != badguy_position[1]) {
                  
                  continue;
              }
              
              if(captain_position[1] == badguy_position[1] &amp;&amp; currPoint[1] == captain_position[1] &amp;&amp; currPoint[0] != badguy_position[0]) {
                  
                  continue;
              }
              
              if(Math.pow(currPoint[0] - captain_position[0], 2) + Math.pow(currPoint[1] - captain_position[1], 2) &lt;= distanceSquared) {              
                  
                  int [] vecA = new int[] {currPoint[0] - captain_position[0], currPoint[1] - captain_position[1]};
                  
                  double direction = Math.atan2(vecA[1], vecA[0]);
                  int quadrant = 0;
                  if(vecA[0] &lt; 0) {
                      
                      quadrant++;
                  }
                  if(vecA[1] &lt; 0) {
                      
                      quadrant += 2;
                  }
                  
                  
                  if(directions.get(quadrant).contains(direction)) {
                      
                      continue;
                  } else {
                      
                      directions.get(quadrant).add(direction);
                  }       
                  
                  if(sourceDirections.get(quadrant).contains(direction)) {
                      
                      int index = sourceDirections.get(quadrant).indexOf(direction);
                      
                      int[] sourceIndex = sourceTracker.get(quadrant).get(index);
                      int[] sourcePoint = mirroredSources.get(sourceIndex[0]).get(sourceIndex[1]);
                          
                      if(Math.pow(sourcePoint[0], 2) + Math.pow(sourcePoint[1], 2) &lt; Math.pow(currPoint[0], 2) + Math.pow(currPoint[1], 2)) {
                              
                          continue;
                      }
                      
                  }
                  
                  numDirections++;
              }
          }
      }
      
      return numDirections;
  }
  
  public static ArrayList&lt;ArrayList&lt;int[]&gt;&gt; MirroredPlanes(int[] startingLocal, int[] planeDimensions, int[]mirrorDimensions) {
      
      ArrayList&lt;ArrayList&lt;int[]&gt;&gt; mirroredPlanes = new ArrayList&lt;ArrayList&lt;int[]&gt;&gt;();
      
      //int[][int[][]] mirroredPlanes = new int[mirrorDimensions[0]][mirrorDimensions[1]];
      int middleX = mirrorDimensions[0] / 2;
      int middleY = mirrorDimensions[1] / 2;
      
      for(int i = 0; i &lt; mirrorDimensions[1]; i++) {
          
          ArrayList&lt;int[]&gt; curXList = new ArrayList&lt;int[]&gt;(); 
          mirroredPlanes.add(curXList);
          
          for(int j = 0; j &lt; mirrorDimensions[0]; j++) {
              
              int[] curY = new int[2]; 
              
              int[] tempLocal = new int[]{startingLocal[0], startingLocal[1]};
              
              int modX = j - middleX;
              int modY = i - middleY;
                          
              if(modX % 2 != 0) {
                  
                  tempLocal[0] = planeDimensions[0] - startingLocal[0];
              }
              
              curY[0] = tempLocal[0] + (modX * planeDimensions[0]);
              
              if(modY % 2 != 0) {
                  
                  tempLocal[1] = planeDimensions[1] - startingLocal[1];
              }
              
              curY[1] = tempLocal[1] + (modY * planeDimensions[1]);
              
              curXList.add(curY);
          }
      }
      
      return mirroredPlanes; 
  }
  </code></pre>
  <p>}</p>
  <h2>Things I've tried that aren't currently in the code</h2>
  <ul>
  <li>Checking to see the if laser hits a corner</li>
  <li>Checking to see if the laser hits the captain before the guard</li>
  </ul>
  <h2>Failed Test Case</h2>
  <pre><code>int[] dimensions = new int[] {42, 59};
  int[] captain_position = new int [] {34, 44};
  int[] badguy_position = new int[] {6, 34};
  int distance = 5000;
  //Desired Output: ??? (Unknown)
  //Actual Output: 31694 (Incorrect)
  </code></pre>