| 23 | 25 | second being a set of coordinates, representing |
| 24 | 26 | the owner's territories. |
| 25 | 27 | """ |
| 26 | | pass |
| 28 | # Edge Case: Invalid coordinates (negative) |
| 29 | if x < 0 or y < 0: |
| 30 | raise ValueError('Invalid coordinate') |
| 31 | |
| 32 | # Edge Case: Invalid coordinates (outside board boundaries) |
| 33 | if y >= self.rows or x >= self.cols: |
| 34 | raise ValueError('Invalid coordinate') |
| 35 | |
| 36 | # If the coordinate is not empty, it's not territory |
| 37 | if self.board[y][x] != ' ': |
| 38 | return ('', set()) |
| 39 | |
| 40 | visited = set() |
| 41 | territory_coords = set() |
| 42 | |
| 43 | def dfs(cx, cy): |
| 44 | # Edge Case: Out of bounds or already visited |
| 45 | if (cx < 0 or cx >= self.cols or |
| 46 | cy < 0 or cy >= self.rows or |
| 47 | (cx, cy) in visited): |
| 48 | return |
| 49 | |
| 50 | # If it's an empty space, continue DFS |
| 51 | if self.board[cy][cx] == ' ': |
| 52 | visited.add((cx, cy)) |
| 53 | territory_coords.add((cx, cy)) |
| 54 | # Check all four directions |
| 55 | dfs(cx+1, cy) |
| 56 | dfs(cx-1, cy) |
| 57 | dfs(cx, cy+1) |
| 58 | dfs(cx, cy-1) |
| 59 | |
| 60 | dfs(x, y) |
| 61 | |
| 62 | # Check all borders of the territory to determine ownership |
| 63 | bordering_colors = set() |
| 64 | |
| 65 | for (tx, ty) in territory_coords: |
| 66 | # Check all four neighbors of each territory space |
| 67 | for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]: |
| 68 | nx, ny = tx + dx, ty + dy |
| 69 | |
| 70 | # If neighbor is out of bounds, territory is not enclosed |
| 71 | if nx < 0 or nx >= self.cols or ny < 0 or ny >= self.rows: |
| 72 | bordering_colors.add('') # Mark as neutral |
| 73 | break |
| 74 | |
| 75 | # If neighbor is a stone, add its color |
| 76 | if self.board[ny][nx] in 'WB': |
| 77 | bordering_colors.add(self.board[ny][nx]) |
| 78 | |
| 79 | # Determine owner |
| 80 | if len(bordering_colors) == 1 and '' not in bordering_colors: |
| 81 | owner = list(bordering_colors)[0] |
| 82 | else: |
| 83 | owner = '' |
| 84 | |
| 85 | return (owner, territory_coords) |
| 27 | 86 | |
| 28 | 87 | def territories(self) -> dict[str, set[tuple[int, int]]]: |
| 29 | 88 | """Find the owners and the territories of the whole board |
| 36 | 95 | , i.e. "W", "B", "". The value being a set |
| 37 | 96 | of coordinates owned by the owner. |
| 38 | 97 | """ |
| 39 | | pass |
| 98 | result = {'W': set(), 'B': set(), '': set()} |
| 99 | visited = set() |
| 100 | |
| 101 | # Edge Case: Empty board |
| 102 | if self.rows == 0 or self.cols == 0: |
| 103 | return result |
| 104 | |
| 105 | for y in range(self.rows): |
| 106 | for x in range(self.cols): |
| 107 | # Only process empty spaces that haven't been visited |
| 108 | if self.board[y][x] == ' ' and (x, y) not in visited: |
| 109 | owner, territory_set = self.territory(x, y) |
| 110 | result[owner].update(territory_set) |
| 111 | visited.update(territory_set) |
| 112 | |
| 113 | return result |
| 114 | # Handled Edge Cases: Invalid coordinates outside board boundaries, Empty board with no stones |