From 93333d265960e1172c00c9feb2eb3ee187a29010 Mon Sep 17 00:00:00 2001 From: Abdi <89213120+abdirashidexe@users.noreply.github.com> Date: Thu, 29 May 2025 12:57:35 -0700 Subject: [PATCH 1/2] added comments to setup canRead method --- src/SalamanderSearch.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SalamanderSearch.java b/src/SalamanderSearch.java index 93c9ab5..ebe1cd7 100644 --- a/src/SalamanderSearch.java +++ b/src/SalamanderSearch.java @@ -44,6 +44,10 @@ public static void main(String[] args) { * @throws IllegalArgumentException if the enclosure does not contain a salamander */ public static boolean canReach(char[][] enclosure) { + // s = start + // f = food location + // w = wall + // . = empty walkable space return false; } } From 559bae475d660d00a434284a24e8c68d364cbb3d Mon Sep 17 00:00:00 2001 From: Abdi Ahmed <89213120+abdirashidexe@users.noreply.github.com> Date: Sun, 8 Jun 2025 20:44:25 -0700 Subject: [PATCH 2/2] all tests pass --- src/SalamanderSearch.java | 99 +++++++++ src/SalamanderSearchTest.java | 394 +++++++++++++++++----------------- 2 files changed, 296 insertions(+), 197 deletions(-) diff --git a/src/SalamanderSearch.java b/src/SalamanderSearch.java index ebe1cd7..bb5742b 100644 --- a/src/SalamanderSearch.java +++ b/src/SalamanderSearch.java @@ -48,6 +48,105 @@ public static boolean canReach(char[][] enclosure) { // f = food location // w = wall // . = empty walkable space + + // 1: find where salamander is + int[] start = salamanderLocation(enclosure); + + // 2: check visited, 2-d array of booleans. + boolean[][] visited = new boolean[enclosure.length][enclosure[0].length]; + + return canReach(enclosure, start, visited); + } + + public static boolean canReach(char[][] enclosure, int[] current, boolean[][] visited) { + int curR = current[0]; + int curC = current[1]; + + if (enclosure[curR][curC] == 'f') return true; + if (visited[curR][curC]) return false; // if visited is true, return false + + visited[curR][curC] = true; + + List neighbors = possibleMoves(enclosure, current); + + for (int[] neighbor : neighbors) + { + //canReach(enclosure, neighbor, visited); + // hint: if we got a recursive method that returns something, and we call it without doing anything w return value, generally a hint we made a mistake somewhere. + boolean found = canReach(enclosure, neighbor, visited); + + if (found) + { + return true; + } // else { keep checking } + } + return false; } + + public static List possibleMoves(char[][] enclosure, int[] current) + { + // overall enclosure + where salamander is + List moves = new ArrayList<>(); + + int curR = current[0]; + int curC = current[1]; + + // Up + int newR = curR - 1; + int newC = curC; + // moved off top of array / no wall + if (newR >= 0 && enclosure[newR][newC] != 'W') { + moves.add(new int[]{newR, newC}); + } + + // Down + newR = curR + 1; + newC = curC; + + if (newR < enclosure.length && enclosure[newR][newC] != 'W') { + moves.add(new int[]{newR, newC}); + } + + // Left + newR = curR; + newC = curC - 1; + + if (newC >= 0 && enclosure[newR][newC] != 'W') { + moves.add(new int[]{newR, newC}); + } + + // Right + newR = curR; + newC = curC + 1; + + if (newC < enclosure[newR].length && enclosure[newR][newC] != 'W') { + moves.add(new int[]{newR, newC}); + } + + return moves; + } + + // if rows & columns are the same, O(n)^2 .. + // but this is the correct way: + // O(n*m) n = # of rows, m = # of columns + public static int[] salamanderLocation(char[][] enclosure) + { + // int arrays = arrays that hold a row column pair. ex. [4][3], row 4 column 3 + // would expect this method to return [4, 3] for enclosure1. + for (int r = 0; r < enclosure.length; r++) + { + for (int c = 0; c < enclosure[r].length; c++) // for each of those rows, how long is that + { + if (enclosure[r][c] == 's') + { + int[] location = new int[]{r,c}; + return location; + //return new int[enclosure[r][c]]; + } + } + } + + throw new IllegalArgumentException("No salamander present"); + } } diff --git a/src/SalamanderSearchTest.java b/src/SalamanderSearchTest.java index ddad9de..a8b5af2 100644 --- a/src/SalamanderSearchTest.java +++ b/src/SalamanderSearchTest.java @@ -34,203 +34,203 @@ public void canReach_NoPath() { assertFalse(actual); } - // @Test - // public void testSalamanderLocation_centerOfGrid() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', 's', '.'}, - // {'.', '.', '.'} - // }; - // int[] expected = {1, 1}; - // assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); - // } - - // @Test - // public void testSalamanderLocation_topLeftCorner() { - // char[][] enclosure = { - // {'s', '.', '.'}, - // {'.', '.', '.'}, - // {'.', '.', '.'} - // }; - // int[] expected = {0, 0}; - // assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); - // } - - // @Test - // public void testSalamanderLocation_notFound_throwsException() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', '.', '.'}, - // {'.', '.', '.'} - // }; - // Exception exception = assertThrows(IllegalArgumentException.class, () -> { - // SalamanderSearch.salamanderLocation(enclosure); - // }); - // assertEquals("No salamander present", exception.getMessage()); - // } - - - // @Test - // public void testSalamanderLocation_at_1_2() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', '.', 's'}, - // {'.', '.', '.'} - // }; - // int[] expected = {1, 2}; - // assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); - // } - - // @Test - // public void testPossibleMoves_allDirectionsOpen() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', 's', '.'}, - // {'.', '.', '.'} - // }; - // int[] location = {1, 1}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // Set moveSet = toSet(moves); - - // assertEquals(4, moves.size()); - // assertTrue(moveSet.contains("0,1")); // up - // assertTrue(moveSet.contains("2,1")); // down - // assertTrue(moveSet.contains("1,0")); // left - // assertTrue(moveSet.contains("1,2")); // right - // } - - // @Test - // public void testPossibleMoves_allDirectionsBlockedByWalls() { - // char[][] enclosure = { - // {'W', 'W', 'W'}, - // {'W', 's', 'W'}, - // {'W', 'W', 'W'} - // }; - // int[] location = {1, 1}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // assertTrue(moves.isEmpty()); - // } - - // @Test - // public void testPossibleMoves_partialEdge() { - // char[][] enclosure = { - // {'s', '.', '.'} - // }; - // int[] location = {0, 0}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // Set moveSet = toSet(moves); - - // assertEquals(1, moves.size()); - // assertTrue(moveSet.contains("0,1")); // only right - // } - - // @Test - // public void testPossibleMoves_oneOpen_twoWalls_oneEdge() { - // // Salamander at (1, 1) - // // Up is W, down is wall, left is edge (0), right is open - // char[][] enclosure = { - // {'W', 'W', 'W'}, - // {'.', 's', '.'}, - // {'W', 'W', 'W'} - // }; - // int[] location = {1, 1}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // Set moveSet = toSet(moves); - - // assertEquals(2, moves.size()); - // assertTrue(moveSet.contains("1,2")); - // assertTrue(moveSet.contains("1,0")); - // } - - // @Test - // public void testPossibleMoves_blockedAboveByWall() { - // char[][] enclosure = { - // {'.', 'W', '.'}, - // {'.', 's', '.'}, - // {'.', '.', '.'} - // }; - // int[] location = {1, 1}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // Set moveSet = toSet(moves); - - // assertFalse(moveSet.contains("0,1")); // up blocked - // assertTrue(moveSet.contains("2,1")); // down open - // assertTrue(moveSet.contains("1,0")); // left open - // assertTrue(moveSet.contains("1,2")); // right open - // } - - // @Test - // public void testPossibleMoves_blockedBelowByWall() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', 's', '.'}, - // {'.', 'W', '.'} - // }; - // int[] location = {1, 1}; - // Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); - - // assertTrue(moveSet.contains("0,1")); // up open - // assertFalse(moveSet.contains("2,1")); // down blocked - // assertTrue(moveSet.contains("1,0")); // left open - // assertTrue(moveSet.contains("1,2")); // right open - // } - - // @Test - // public void testPossibleMoves_blockedLeftByWall() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'W', 's', '.'}, - // {'.', '.', '.'} - // }; - // int[] location = {1, 1}; - // Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); - - // assertTrue(moveSet.contains("0,1")); // up open - // assertTrue(moveSet.contains("2,1")); // down open - // assertFalse(moveSet.contains("1,0")); // left blocked - // assertTrue(moveSet.contains("1,2")); // right open - // } - - // @Test - // public void testPossibleMoves_blockedRightByWall() { - // char[][] enclosure = { - // {'.', '.', '.'}, - // {'.', 's', 'W'}, - // {'.', '.', '.'} - // }; - // int[] location = {1, 1}; - // Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); - - // assertTrue(moveSet.contains("0,1")); // up open - // assertTrue(moveSet.contains("2,1")); // down open - // assertTrue(moveSet.contains("1,0")); // left open - // assertFalse(moveSet.contains("1,2")); // right blocked - // } - - // @Test - // public void testPossibleMoves_topLeftCornerWithOneOpen() { - // char[][] enclosure = { - // {'s', 'W'}, - // {'W', '.'} - // }; - // int[] location = {0, 0}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - - // assertTrue(moves.isEmpty()); // surrounded by walls/edges - // } - - // @Test - // public void testPossibleMoves_rightEdgeWithOpenLeft() { - // char[][] enclosure = { - // {'.', '.', 's'} - // }; - // int[] location = {0, 2}; - // List moves = SalamanderSearch.possibleMoves(enclosure, location); - // Set moveSet = toSet(moves); - - // assertEquals(1, moves.size()); - // assertTrue(moveSet.contains("0,1")); - // } + @Test + public void testSalamanderLocation_centerOfGrid() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', 's', '.'}, + {'.', '.', '.'} + }; + int[] expected = {1, 1}; + assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); + } + + @Test + public void testSalamanderLocation_topLeftCorner() { + char[][] enclosure = { + {'s', '.', '.'}, + {'.', '.', '.'}, + {'.', '.', '.'} + }; + int[] expected = {0, 0}; + assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); + } + + @Test + public void testSalamanderLocation_notFound_throwsException() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', '.', '.'}, + {'.', '.', '.'} + }; + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + SalamanderSearch.salamanderLocation(enclosure); + }); + assertEquals("No salamander present", exception.getMessage()); + } + + + @Test + public void testSalamanderLocation_at_1_2() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', '.', 's'}, + {'.', '.', '.'} + }; + int[] expected = {1, 2}; + assertArrayEquals(expected, SalamanderSearch.salamanderLocation(enclosure)); + } + + @Test + public void testPossibleMoves_allDirectionsOpen() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', 's', '.'}, + {'.', '.', '.'} + }; + int[] location = {1, 1}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + Set moveSet = toSet(moves); + + assertEquals(4, moves.size()); + assertTrue(moveSet.contains("0,1")); // up + assertTrue(moveSet.contains("2,1")); // down + assertTrue(moveSet.contains("1,0")); // left + assertTrue(moveSet.contains("1,2")); // right + } + + @Test + public void testPossibleMoves_allDirectionsBlockedByWalls() { + char[][] enclosure = { + {'W', 'W', 'W'}, + {'W', 's', 'W'}, + {'W', 'W', 'W'} + }; + int[] location = {1, 1}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + assertTrue(moves.isEmpty()); + } + + @Test + public void testPossibleMoves_partialEdge() { + char[][] enclosure = { + {'s', '.', '.'} + }; + int[] location = {0, 0}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + Set moveSet = toSet(moves); + + assertEquals(1, moves.size()); + assertTrue(moveSet.contains("0,1")); // only right + } + + @Test + public void testPossibleMoves_oneOpen_twoWalls_oneEdge() { + // Salamander at (1, 1) + // Up is W, down is wall, left is edge (0), right is open + char[][] enclosure = { + {'W', 'W', 'W'}, + {'.', 's', '.'}, + {'W', 'W', 'W'} + }; + int[] location = {1, 1}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + Set moveSet = toSet(moves); + + assertEquals(2, moves.size()); + assertTrue(moveSet.contains("1,2")); + assertTrue(moveSet.contains("1,0")); + } + + @Test + public void testPossibleMoves_blockedAboveByWall() { + char[][] enclosure = { + {'.', 'W', '.'}, + {'.', 's', '.'}, + {'.', '.', '.'} + }; + int[] location = {1, 1}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + Set moveSet = toSet(moves); + + assertFalse(moveSet.contains("0,1")); // up blocked + assertTrue(moveSet.contains("2,1")); // down open + assertTrue(moveSet.contains("1,0")); // left open + assertTrue(moveSet.contains("1,2")); // right open + } + + @Test + public void testPossibleMoves_blockedBelowByWall() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', 's', '.'}, + {'.', 'W', '.'} + }; + int[] location = {1, 1}; + Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); + + assertTrue(moveSet.contains("0,1")); // up open + assertFalse(moveSet.contains("2,1")); // down blocked + assertTrue(moveSet.contains("1,0")); // left open + assertTrue(moveSet.contains("1,2")); // right open + } + + @Test + public void testPossibleMoves_blockedLeftByWall() { + char[][] enclosure = { + {'.', '.', '.'}, + {'W', 's', '.'}, + {'.', '.', '.'} + }; + int[] location = {1, 1}; + Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); + + assertTrue(moveSet.contains("0,1")); // up open + assertTrue(moveSet.contains("2,1")); // down open + assertFalse(moveSet.contains("1,0")); // left blocked + assertTrue(moveSet.contains("1,2")); // right open + } + + @Test + public void testPossibleMoves_blockedRightByWall() { + char[][] enclosure = { + {'.', '.', '.'}, + {'.', 's', 'W'}, + {'.', '.', '.'} + }; + int[] location = {1, 1}; + Set moveSet = toSet(SalamanderSearch.possibleMoves(enclosure, location)); + + assertTrue(moveSet.contains("0,1")); // up open + assertTrue(moveSet.contains("2,1")); // down open + assertTrue(moveSet.contains("1,0")); // left open + assertFalse(moveSet.contains("1,2")); // right blocked + } + + @Test + public void testPossibleMoves_topLeftCornerWithOneOpen() { + char[][] enclosure = { + {'s', 'W'}, + {'W', '.'} + }; + int[] location = {0, 0}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + + assertTrue(moves.isEmpty()); // surrounded by walls/edges + } + + @Test + public void testPossibleMoves_rightEdgeWithOpenLeft() { + char[][] enclosure = { + {'.', '.', 's'} + }; + int[] location = {0, 2}; + List moves = SalamanderSearch.possibleMoves(enclosure, location); + Set moveSet = toSet(moves); + + assertEquals(1, moves.size()); + assertTrue(moveSet.contains("0,1")); + } private Set toSet(List list) {