10
10
11
11
12
12
class GameService :
13
+ """Service class to handle game logic."""
14
+
13
15
@staticmethod
14
16
def initialize_cells (game ):
17
+ """
18
+ Create the cells of the game, place the mines, and calculate adjacencies.
19
+
20
+ Args:
21
+ game (Game): The game instance for which cells are being initialized.
22
+ """
15
23
cells = GameService ._create_cells (game )
16
24
GameService ._place_mines (game , cells )
17
25
GameService ._calculate_adjacencies (cells )
18
26
19
27
@staticmethod
20
28
def _create_cells (game ):
29
+ """
30
+ Create game cells using bulk_create to optimize database access.
31
+
32
+ Args:
33
+ game (Game): The game instance for which cells are being created.
34
+
35
+ Returns:
36
+ QuerySet: A queryset of the created cells.
37
+ """
21
38
cells = [
22
39
Cell (game = game , row = row , column = col )
23
40
for row in range (game .rows )
@@ -28,13 +45,26 @@ def _create_cells(game):
28
45
29
46
@staticmethod
30
47
def _place_mines (game , cells ):
48
+ """
49
+ Randomly place mines in the game cells.
50
+
51
+ Args:
52
+ game (Game): The game instance for which mines are being placed.
53
+ cells (QuerySet): The queryset of cells in the game.
54
+ """
31
55
mine_cells = sample (list (cells ), game .mines )
32
56
for mine in mine_cells :
33
57
mine .is_mine = True
34
58
Cell .objects .bulk_update (mine_cells , ["is_mine" ])
35
59
36
60
@staticmethod
37
61
def _calculate_adjacencies (cells ):
62
+ """
63
+ Calculate the number of adjacent mines for each cell.
64
+
65
+ Args:
66
+ cells (QuerySet): The queryset of cells in the game.
67
+ """
38
68
updates = []
39
69
for cell in cells :
40
70
if not cell .is_mine :
@@ -44,18 +74,49 @@ def _calculate_adjacencies(cells):
44
74
45
75
@staticmethod
46
76
def _calculate_adjacent_mines (cell ):
77
+ """
78
+ Calculate the number of mines adjacent to a given cell.
79
+
80
+ Args:
81
+ cell (Cell): The cell for which adjacent mines are being calculated.
82
+
83
+ Returns:
84
+ int: The number of adjacent mines.
85
+ """
47
86
neighbors = Cell .objects .get_neighbors (cell )
48
87
return sum (1 for neighbor in neighbors if neighbor .is_mine )
49
88
50
89
@staticmethod
51
90
def _get_cell (game , row , column ):
91
+ """
92
+ Retrieve a cell by its row and column in a given game.
93
+
94
+ Args:
95
+ game (Game): The game instance.
96
+ row (int): The row number of the cell.
97
+ column (int): The column number of the cell.
98
+
99
+ Returns:
100
+ Cell or None: The cell if found, otherwise None.
101
+ """
52
102
try :
53
103
return Cell .objects .get (game = game , row = row , column = column )
54
104
except Cell .DoesNotExist :
55
105
return None
56
106
57
107
@staticmethod
58
108
def reveal_cell (game , row , column ):
109
+ """
110
+ Reveal a cell and handle game logic for revealing cells.
111
+
112
+ Args:
113
+ game (Game): The game instance.
114
+ row (int): The row number of the cell to reveal.
115
+ column (int): The column number of the cell to reveal.
116
+
117
+ Returns:
118
+ tuple: A tuple containing the response data and HTTP status code.
119
+ """
59
120
cell = GameService ._get_cell (game , row , column )
60
121
if not cell :
61
122
return CELL_NOT_FOUND , HTTP_404_NOT_FOUND
@@ -77,6 +138,12 @@ def reveal_cell(game, row, column):
77
138
78
139
@staticmethod
79
140
def _reveal_cells (cell ):
141
+ """
142
+ Recursively reveal cells starting from the given cell.
143
+
144
+ Args:
145
+ cell (Cell): The cell to start revealing from.
146
+ """
80
147
if cell .is_revealed :
81
148
return
82
149
cell .is_revealed = True
@@ -89,13 +156,26 @@ def _reveal_cells(cell):
89
156
90
157
@staticmethod
91
158
def _end_game (game , status ):
159
+ """
160
+ End the game with a given status and reveal all cells.
161
+
162
+ Args:
163
+ game (Game): The game instance.
164
+ status (GameStatus): The status to set for the game.
165
+ """
92
166
game .status = status
93
167
game .finished_at = now ()
94
168
game .save ()
95
169
GameService ._reveal_all_cells (game )
96
170
97
171
@staticmethod
98
172
def _reveal_all_cells (game ):
173
+ """
174
+ Reveal all cells in the game.
175
+
176
+ Args:
177
+ game (Game): The game instance.
178
+ """
99
179
cells = Cell .objects .filter (game = game )
100
180
with transaction .atomic ():
101
181
for cell in cells :
@@ -104,12 +184,32 @@ def _reveal_all_cells(game):
104
184
105
185
@staticmethod
106
186
def _check_win_condition (game ):
187
+ """
188
+ Check if the win condition is met for the game.
189
+
190
+ Args:
191
+ game (Game): The game instance.
192
+
193
+ Returns:
194
+ bool: True if the win condition is met, False otherwise.
195
+ """
107
196
return not Cell .objects .filter (
108
197
game = game , is_revealed = False , is_mine = False
109
198
).exists ()
110
199
111
200
@staticmethod
112
201
def toggle_flag (game , row , column ):
202
+ """
203
+ Toggle the flag status of a cell.
204
+
205
+ Args:
206
+ game (Game): The game instance.
207
+ row (int): The row number of the cell to flag/unflag.
208
+ column (int): The column number of the cell to flag/unflag.
209
+
210
+ Returns:
211
+ tuple: A tuple containing the response data and HTTP status code.
212
+ """
113
213
cell = GameService ._get_cell (game , row , column )
114
214
if not cell :
115
215
return CELL_NOT_FOUND , HTTP_404_NOT_FOUND
0 commit comments