diff --git a/src/Fire.java b/src/Fire.java index b968c51..b393abf 100644 --- a/src/Fire.java +++ b/src/Fire.java @@ -1,17 +1,27 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import javax.management.Query; + public class Fire { /** * Returns how long it takes for all vulnerable trees to be set on fire if a * match is lit at a given location. * - * The forest is represented via a rectangular 2d char array where t represents a tree + * The forest is represented via a rectangular 2d char array where t represents + * a tree * and . represents an empty space. * - * At time 0, the tree at location [matchR, matchC] is set on fire. At every subsequent - * time step, any tree that is adjacent (up/down/left/right) to a burning tree is also - * set on fire. + * At time 0, the tree at location [matchR, matchC] is set on fire. At every + * subsequent + * time step, any tree that is adjacent (up/down/left/right) to a burning tree + * is also + * set on fire. * * - * EXAMPLE + * EXAMPLE * forest: * * t..tttt.t @@ -25,12 +35,16 @@ public class Fire { * Result: 8 * * Explanation: - * At time 0, the tree at (2, 6) is set on fire. At time 1, its adjacent trees also catch on fire - * At time 2, the trees adjacent to those catch as well. At time 8, the last tree to catch is at - * (0,6). In this example, there is one tree that never burns, so it is not included in the time calculation. + * At time 0, the tree at (2, 6) is set on fire. At time 1, its adjacent trees + * also catch on fire + * At time 2, the trees adjacent to those catch as well. At time 8, the last + * tree to catch is at + * (0,6). In this example, there is one tree that never burns, so it is not + * included in the time calculation. * * - * @param forest a 2d array where t represents a tree and . represents the ground + * @param forest a 2d array where t represents a tree and . represents the + * ground * @param matchR The row the match is lit at * @param matchC The column the match is lit at * @return the time at which the final tree to be incinerated starts burning @@ -38,6 +52,66 @@ public class Fire { 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; + + int maxCol = 0; + for(char[] row: forest){ + if(maxCol < row.length){ + maxCol = row.length; + } + } + + boolean[][] visited = new boolean[forest.length][maxCol]; + + Queue queue = new LinkedList<>(); + + int unburnStarter = 0; + int[] match = {matchR, matchC, 0}; + queue.add(match); + + while (!queue.isEmpty()) { + int[] current = queue.poll(); + int curR = current[0]; + int curC = current[1]; + + if(visited[curR][curC]){ + continue; + } + + visited[curR][curC] = true; + + queue.addAll(neighborTrees(forest, current)); + + unburnStarter = current[2]; + } + + return unburnStarter; + } + + public static List neighborTrees(char[][] forest, int[] location) { + int curR = location[0]; + int curC = location[1]; + int depth = location[2] + 1; + List neighbors = new ArrayList<>(); + + int[][] directions = { + { -1, 0 }, + { 1, 0 }, + { 0, -1 }, + { 0, 1 } + }; + + for (int[] move : directions) { + int newR = curR + move[0]; + int newC = curC + move[1]; + + if (newR >= 0 && newR < forest.length && + newC >= 0 && newC < forest[newR].length && + forest[newR][newC] == 't') { + int[] validMove = { newR, newC, depth }; + neighbors.add(validMove); + } + } + + return neighbors; } } \ No newline at end of file diff --git a/src/FireTest.java b/src/FireTest.java index b3b9085..fe05bb2 100644 --- a/src/FireTest.java +++ b/src/FireTest.java @@ -1,15 +1,112 @@ +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.List; + import org.junit.jupiter.api.Test; public class FireTest { @Test public void testTimeToBurnExample() { char[][] forest = { - {'t','.','.','t','t','t','t','.','t'}, - {'.','.','t','t','.','.','.','.','t'}, - {'.','.','t','t','t','t','t','t','t'}, - {'t','t','t','t','.','.','.','.','.'} + { 't', '.', '.', 't', 't', 't', 't', '.', 't' }, + { '.', '.', 't', 't', '.', '.', '.', '.', 't' }, + { '.', '.', 't', 't', 't', 't', 't', 't', 't' }, + { 't', 't', 't', 't', '.', '.', '.', '.', '.' } + }; + + int matchR = 2; + int matchC = 6; + + int expected = 8; + int actual = Fire.timeToBurn(forest, matchR, matchC); + + assertEquals(expected, actual); + } + + @Test + public void testNeighborTrees_bottomRightCornerBlocked() { + char[][] forest = { + { 't', '.', '.', 't', 't', 't', 't', '.', 't' }, + { '.', '.', 't', 't', '.', '.', '.', '.', 't' }, + { '.', '.', 't', 't', 't', 't', 't', 't', '.' }, + { 't', 't', 't', 't', '.', '.', '.', '.', 't' } + }; + + int[] location = { 3, 8, 0 }; + List result = Fire.neighborTrees(forest, location); + + assertEquals(0, result.size()); + + } + + @Test + public void testNeighborTrees_bottomRightCornerUpOnly() { + char[][] forest = { + { 't', '.', '.', 't', 't', 't', 't', '.', 't' }, + { '.', '.', 't', 't', '.', '.', '.', '.', 't' }, + { '.', '.', 't', 't', 't', 't', 't', 't', 't' }, + { 't', 't', 't', 't', '.', '.', '.', '.', 't' } + }; + + int[] location = { 3, 8, 2 }; + List result = Fire.neighborTrees(forest, location); + + assertEquals(1, result.size()); + assertEquals(2, result.get(0)[0]); + assertEquals(8, result.get(0)[1]); + assertEquals(3, result.get(0)[2]); + } + + @Test + public void testNeighborTrees_middleAllPossible() { + char[][] forest = { + { 't', '.', '.', 't', 't', 't', 't', '.', 't' }, + { '.', '.', 't', 't', 't', '.', '.', '.', 't' }, + { '.', '.', 't', 't', 't', 't', 't', 't', 't' }, + { 't', 't', 't', 't', 't', '.', '.', '.', 't' } + }; + + int[] location = { 2, 4, 4 }; + List result = Fire.neighborTrees(forest, location); + + assertEquals(4, result.size()); + assertEquals(1, result.get(0)[0]); + assertEquals(4, result.get(0)[1]); + assertEquals(5, result.get(0)[2]); + assertEquals(3, result.get(1)[0]); + assertEquals(4, result.get(1)[1]); + assertEquals(5, result.get(1)[2]); + assertEquals(2, result.get(2)[0]); + assertEquals(3, result.get(2)[1]); + assertEquals(5, result.get(2)[2]); + assertEquals(2, result.get(3)[0]); + assertEquals(5, result.get(3)[1]); + assertEquals(5, result.get(3)[2]); + } + + @Test + public void testNeighborTrees_middleNonePossible() { + char[][] forest = { + { 't', '.', '.', 't', 't', 't', 't', '.', 't' }, + { '.', '.', 't', '.', '.', '.', '.', '.', 't' }, + { '.', '.', 't', '.', 't', '.', 't', 't', 't' }, + { 't', 't', 't', 't', '.', '.', '.', '.', 't' } + }; + + int[] location = { 2, 4, 4 }; + List result = Fire.neighborTrees(forest, location); + + assertEquals(0, result.size()); + } + + public void outboundJaggedCol() { + char[][] forest = { + { 't', '.', '.', 't', 't', 't', 't', '.' }, + { '.', '.', 't', 't', '.', '.', '.', '.', 't' }, + { '.', '.', 't', 't', 't', 't', 't', 't', 't' }, + { 't', 't', 't', 't' } }; int matchR = 2;