diff --git a/src/Search.java b/src/Search.java index cebb278..9473b8c 100644 --- a/src/Search.java +++ b/src/Search.java @@ -1,3 +1,9 @@ + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + public class Search { /** * Finds the location of the nearest reachable cheese from the rat's position. @@ -29,6 +35,83 @@ public class Search { * @throws HungryRatException if there is no reachable cheese */ public static int[] nearestCheese(char[][] maze) throws EscapedRatException, CrowdedMazeException, HungryRatException { - return null; + int[] start = findRat(maze); + + Queue queue = new LinkedList<>(); + + queue.add(start); + + boolean[][] visited = new boolean[maze.length][maze[0].length]; + + while (!queue.isEmpty()) { + int[] current = queue.poll(); + + int curR = current[0]; + int curC = current[1]; + + if (maze[curC][curR] == 'c') { + return current; + } + + if (visited[curR][curC]) { + continue; + } + + visited[curR][curC] = true; + + List nextMoves = possibleMoves(maze, current); + queue.addAll(nextMoves); + } + + throw new HungryRatException(); + } + + + public static List possibleMoves(char[][] maze, int[] currentLoc) { + List moves = new ArrayList<>(); + int[][] steps = { + {1,0}, + {-1,0}, + {0,1}, + {0,-1} + }; + + int curR = currentLoc[0]; + int curC = currentLoc[1]; + + for (int[] step : steps) { + int newR = curR + step[0]; + int newC = curC + step[1]; + + if (newR >= 0 && newR < maze.length && + newC >= 0 && newC < maze[0].length && + maze[newR][newC] != 'w') { + moves.add(new int[]{newR, newC}); + } + } + return moves; + } + + public static int[] findRat(char[][] maze) throws CrowdedMazeException, EscapedRatException { + int ratCount = 0; + int[] ratLocation = null; + + for (int r = 0; r < maze.length; r++) { + for (int c = 0; c < maze[0].length; c++) { + if (maze[r][c] == 'R') { + ratLocation = new int[]{r, c}; + ratCount++; + } + } + } + + if (ratCount > 1) throw new CrowdedMazeException(); + if (ratCount == 0) throw new EscapedRatException(); + + return ratLocation; + } + + public static void main(String[] args) { + } } \ No newline at end of file diff --git a/src/SearchTest.java b/src/SearchTest.java index 70b01de..813618a 100644 --- a/src/SearchTest.java +++ b/src/SearchTest.java @@ -1,3 +1,99 @@ +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + public class SearchTest { - + + @Test + public void testNearestCheeseBasicCase() throws Exception { + char[][] maze = { + {'o','o','o','o','c','w','c','o'}, + {'w','o','o','w','w','c','w','o'}, + {'o','o','o','o','R','w','o','o'}, + {'o','o','w','w','w','o','o','o'}, + {'o','o','o','o','c','o','o','o'} + }; + + int[] expected = {0, 4}; // Closest cheese + int[] result = Search.nearestCheese(maze); + assertArrayEquals(expected, result); + } + + @Test + public void testMultipleCheeseOptions() throws Exception { + char[][] maze = { + {'o','o','c'}, + {'R','w','c'}, + {'o','o','c'} + }; + + int[] result = Search.nearestCheese(maze); + // Either (0,2), (1,2), or (2,2) could be valid depending on shortest path + // (1,2) is the closest cheese + assertArrayEquals(new int[]{1, 2}, result); + } + + @Test + public void testOnlyOneRatAllowed() { + char[][] maze = { + {'R','o','o'}, + {'o','R','o'}, + {'o','o','c'} + }; + + assertThrows(CrowdedMazeException.class, () -> { + Search.nearestCheese(maze); + }); + } + + @Test + public void testNoRatFound() { + char[][] maze = { + {'o','o','o'}, + {'w','w','c'}, + {'o','o','o'} + }; + + assertThrows(EscapedRatException.class, () -> { + Search.nearestCheese(maze); + }); + } + + @Test + public void testNoCheeseReachable() { + char[][] maze = { + {'R','w','c'}, + {'w','w','w'}, + {'c','w','c'} + }; + + assertThrows(HungryRatException.class, () -> { + Search.nearestCheese(maze); + }); + } + + @Test + public void testCheeseAlmostSurroundedByWalls() { + char[][] maze = { + {'R','w','w'}, + {'w','c','w'}, + {'w','w','w'} + }; + + assertThrows(HungryRatException.class, () -> { + Search.nearestCheese(maze); + }); + } + + @Test + public void testRatSurroundedByWalls() { + char[][] maze = { + {'w','w','w'}, + {'w','R','w'}, + {'w','w','c'} + }; + + assertThrows(HungryRatException.class, () -> { + Search.nearestCheese(maze); + }); + } }