Skip to content

Commit f79d098

Browse files
[Sync Iteration] python/flower-field/13
1 parent 991c374 commit f79d098

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
Flower Field is a compassionate reimagining of the popular game Minesweeper.
3+
4+
This module provides helpers to validate and annotate a rectangular garden
5+
representation, where each row is a string comprised of spaces and ``*``
6+
characters. A ``*`` denotes a flower; a space denotes an empty square.
7+
8+
The goal is to compute numeric hints indicating how many flowers are
9+
adjacent (horizontally, vertically, diagonally) to each square.
10+
"""
11+
12+
COORDINATES: tuple[tuple[int, int]] = (
13+
(-1, -1),
14+
(-1, 0),
15+
(-1, 1),
16+
(0, -1),
17+
(0, 1),
18+
(1, -1),
19+
(1, 0),
20+
(1, 1),
21+
)
22+
23+
24+
def annotate(garden: list[str]) -> list[str]:
25+
"""
26+
Annotate a garden with counts of adjacent flowers.
27+
28+
Expects a rectangular list of strings containing only spaces and ``*``.
29+
Validation errors raise a :class:`ValueError`.
30+
31+
:param list garden: A list of equal-length strings representing the garden.
32+
``*`` marks a flower; space marks empty.
33+
:returns: An annotated garden of the same shape. Empty squares are
34+
replaced by digits (``"1"``–``"8"``) when adjacent to flowers;
35+
squares with zero adjacent flowers remain spaces. Flowers
36+
(``*``) are preserved.
37+
:rtype: list[str]
38+
:raises ValueError: If the garden is non-rectangular or contains
39+
invalid characters.
40+
"""
41+
# empty list
42+
if not garden:
43+
return []
44+
# raise an error when the board receives malformed input
45+
_validate(garden)
46+
new_garden: list[str] = []
47+
for i_row, row in enumerate(garden):
48+
new_row = [
49+
str(_calc_surrounding_flowers(i_row, i_col, garden))
50+
if _calc_surrounding_flowers(i_row, i_col, garden) != 0
51+
else char
52+
for i_col, char in enumerate(row)
53+
]
54+
new_garden.append("".join(new_row))
55+
return new_garden
56+
57+
58+
def _calc_surrounding_flowers(i_row: int, i_col: int, garden: list[str]) -> int:
59+
"""
60+
Count flowers adjacent to the given cell.
61+
62+
Counts the eight neighboring positions around ``(i_row, i_col)`` when the
63+
current cell is empty (space). If the cell itself is a flower (``*``), the
64+
count remains zero as the caller preserves flowers unchanged.
65+
66+
:param int i_row: Row index of the target cell.
67+
:param int i_col: Column index of the target cell.
68+
:param list garden: The rectangular garden representation.
69+
:returns: Number of adjacent flowers (0–8).
70+
:rtype: int
71+
"""
72+
total: int = 0
73+
if garden[i_row][i_col] == " ":
74+
# Count flowers all around current position
75+
for offset_row, offset_col in COORDINATES:
76+
sum_row = i_row + offset_row
77+
sum_col = i_col + offset_col
78+
if (
79+
0 <= sum_row < len(garden) # ROW: Avoid IndexError
80+
and 0 <= sum_col < len(garden[0]) # COL: Avoid IndexError
81+
and garden[sum_row][sum_col] == "*" # Detect/count flower
82+
):
83+
total += 1
84+
return total
85+
86+
87+
def _validate(garden: list[str]) -> None:
88+
"""
89+
Validate the garden shape and contents.
90+
91+
Ensures the input is rectangular and contains only spaces and ``*``.
92+
Raise ValueError when the board receives malformed input garden is not
93+
a rectangle due to inconsistent row length or contains invalid chars
94+
inside the row.
95+
96+
:param list garden: A list of equal-length strings to validate.
97+
:raises ValueError: If rows have differing lengths or contain characters
98+
other than space or ``*``.
99+
"""
100+
garden_length = len(garden[0])
101+
if any(
102+
(len(row) != garden_length or not all(char in " *" for char in row))
103+
for row in garden
104+
):
105+
raise ValueError("The board is invalid with current input.")

0 commit comments

Comments
 (0)