diff --git a/src/Fire.java b/src/Fire.java index b968c51..dd497e9 100644 --- a/src/Fire.java +++ b/src/Fire.java @@ -1,3 +1,8 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + public class Fire { /** * Returns how long it takes for all vulnerable trees to be set on fire if a @@ -35,9 +40,77 @@ public class Fire { * @param matchC The column the match is lit at * @return the time at which the final tree to be incinerated starts burning */ - public static int timeToBurn(char[][] forest, int matchR, int matchC) { - // HINT: when adding to your BFS queue, you can include more information than - // just a location. What other information might be useful? - return -1; + public static int timeToBurn(char[][] forest, int matchR, int matchC) + { + if (forest[matchR][matchC] == '.') throw new IllegalArgumentException("The match isn't lit at a tree."); + + boolean[][] visited = new boolean[forest.length][forest[0].length]; + Queue queue = new LinkedList<>(); + queue.add(new int[]{matchR, matchC}); + int count = -1; + + while (!queue.isEmpty()) + { + int[] current = queue.poll(); + int curR = current[0]; + int curC = current[1]; + + if (curR == -1) + { + count++; + continue; + } + + if (visited[curR][curC]) continue; + + visited[curR][curC] = true; + + queue.addAll(neighborTrees(forest, curR, curC, queue)); + + } + + return count; } + + public static List neighborTrees(char[][] forest, int spreadR, int spreadC, Queue queue) + { + int[][] directions = { + {-1, 0}, // North + {1, 0}, // South + {0, 1}, // East + {0, -1} // West + }; + + List possibleMoves = new ArrayList<>(); + + int check = 0; + for (int[] findBurnTurn : queue) + { + if (findBurnTurn[0] == -1) check++; + } + + if (check == 0) possibleMoves.add(new int[]{-1, 0}); + else check = 0; + + for (int[] direction : directions) + { + int changeR = direction[0]; + int changeC = direction[1]; + + int newR = spreadR + changeR; + int newC = spreadC + changeC; + + if (newR >= 0 && + newR < forest.length && + newC >= 0 && + newC < forest[newR].length && + forest[newR][newC] != '.') + { + possibleMoves.add(new int[]{newR, newC}); + } + } + + return possibleMoves; + } + } \ No newline at end of file diff --git a/src/FireTest.java b/src/FireTest.java index b3b9085..1ff89c7 100644 --- a/src/FireTest.java +++ b/src/FireTest.java @@ -1,4 +1,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; import org.junit.jupiter.api.Test; @@ -20,4 +29,135 @@ public void testTimeToBurnExample() { assertEquals(expected, actual); } + + // Match set not on a tree + @Test + public void testTimeToBurn_BadArgument() + { + char[][] forest = { + {'.', '.', '.'}, + {'.', '.', '.'}, + {'.', '.', '.'} + }; + + int spreadR = 1; + int spreadC = 1; + + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + Fire.timeToBurn(forest, spreadR, spreadC); + }); + + assertEquals("The match isn't lit at a tree.", exception.getMessage()); + + } + + // Whole forest burns down + @Test + public void testTimeToBurn_EverythingGoes() + { + char[][] forest = { + {'t', 't', 't'}, + {'t', 't', 't'}, + {'t', 't', 't'} + }; + + int spreadR = 1; + int spreadC = 1; + + int expected = 2; + int actual = Fire.timeToBurn(forest, spreadR, spreadC); + + assertEquals(expected, actual); + + } + + // Neighbors on All Sides + @Test + public void testNeighborTrees_AllSides() + { + char[][] forest = { + {'t', 't', 't'}, + {'t', 't', 't'}, + {'t', 't', 't'} + }; + + int spreadR = 1; + int spreadC = 1; + + int[] startingLocation = {spreadR, spreadC}; + Queue queue = new LinkedList<>(); + queue.add(startingLocation); + + List neighbors = Fire.neighborTrees(forest, spreadR, spreadC, queue); + Set neighborsSet = toSet(neighbors); + + assertTrue(neighborsSet.contains("0,1")); + assertTrue(neighborsSet.contains("1,0")); + assertTrue(neighborsSet.contains("1,2")); + assertTrue(neighborsSet.contains("2,1")); + + } + + // No Neighbors + @Test + public void testNeighborTrees_NoSides() + { + char[][] forest = { + {'.', '.', '.'}, + {'.', 't', '.'}, + {'.', '.', '.'} + }; + + int spreadR = 1; + int spreadC = 1; + + int[] startingLocation = {spreadR, spreadC}; + Queue queue = new LinkedList<>(); + queue.add(startingLocation); + + List neighbors = Fire.neighborTrees(forest, spreadR, spreadC, queue); + Set neighborsSet = toSet(neighbors); + + assertTrue(neighborsSet.contains("-1,0")); + assertFalse(neighborsSet.contains("0,1")); + assertFalse(neighborsSet.contains("1,0")); + assertFalse(neighborsSet.contains("1,2")); + assertFalse(neighborsSet.contains("2,1")); + + } + + // Corner Neighbors + @Test + public void testNeighborTrees_CornerTrees() + { + char[][] forest = { + {'t', 't', '.'}, + {'t', '.', '.'}, + {'.', '.', '.'} + }; + + int spreadR = 0; + int spreadC = 0; + + int[] startingLocation = {spreadR, spreadC}; + Queue queue = new LinkedList<>(); + queue.add(startingLocation); + + List neighbors = Fire.neighborTrees(forest, spreadR, spreadC, queue); + Set neighborSet = toSet(neighbors); + + assertTrue(neighborSet.contains("0,1")); + assertTrue(neighborSet.contains("1,0")); + + } + + + + private Set toSet(List list) + { + Set set = new HashSet<>(); + for (int[] arr : list) set.add(arr[0] + "," + arr[1]); + return set; + } + }