1use crate::board::{Board, BoardSize, Point};
2use crate::solver::{GameResult, Solver};
3use crate::{check_interact, Cell, CellState, CellType, GameState, GameStatus, Minsweeper};
4use std::collections::HashSet;
5use std::ops::{Deref, DerefMut};
6use std::sync::Arc;
7
8trait InternalMinsweeper {
9
10 fn start(&mut self) -> &GameState;
11
12 fn on_win(&self);
13 fn on_lose(&self);
14
15 fn player_gamestate(&self) -> &GameState;
16 fn gamestate_mut(&mut self) -> impl DerefMut<Target = GameState>;
17
18 fn reveal(&mut self, point: Point) -> Result<&GameState, &GameState> {
19 if check_interact(self, point).is_err() {
20 return Err(self.player_gamestate())
21 }
22
23
24 let success = self.internal_reveal(point);
25
26 if !success {
27 self.gamestate_mut().status = GameStatus::Lost;
28
29 self.on_lose();
30
31 return Ok(self.player_gamestate())
32 }
33
34 if self.gamestate_mut().board.has_won() {
35 self.gamestate_mut().status = GameStatus::Won;
36
37 self.on_win();
38
39 return Ok(self.player_gamestate())
40 }
41
42 Ok(self.player_gamestate())
43
44 }
45
46 fn reveal_empty(board: &mut Board, point: Point) {
47 if !matches!(board[point], Cell { cell_type: CellType::EMPTY, cell_state: state } if state != CellState::Revealed) {
48 return
49 }
50
51 let empty_cell = Cell::new(CellType::EMPTY, CellState::Revealed);
52 board[point] = empty_cell;
53
54 let mut flood = HashSet::new();
55
56 flood.insert(point);
57
58 while !flood.is_empty() {
59 let point = *flood.iter().next().unwrap();
60 flood.remove(&point);
61
62 for point in board.size().neighbours(point) {
63 if let Cell { cell_type: CellType::Safe(number), cell_state: state } = board[point]
64 && state != CellState::Revealed {
65 board[point] = Cell::new(CellType::Safe(number), CellState::Revealed);
66
67 if number == 0 {
68 flood.insert(point);
69 }
70 }
71 }
72 }
73
74 }
75
76 fn internal_reveal(&mut self, point: Point) -> bool {
77 let mut state = self.gamestate_mut();
78 let board = &mut state.board;
80 if board[point].cell_state != CellState::Unknown {
81 return true
82 }
83
84 match board[point].cell_type {
85 CellType::Safe(number) => {
86 if number == 0 {
87 Self::reveal_empty(board, point)
88 } else {
89 board[point] = Cell::new(CellType::Safe(number), CellState::Revealed)
90 }
91 true
92 }
93 CellType::Mine => {
94 board[point] = Cell::new(CellType::Mine, CellState::Revealed);
95 false
96 }
97 _ => unreachable!()
98 }
99 }
100
101 fn clear_around(&mut self, point: Point) -> Result<&GameState, &GameState> {
102 if check_interact(self, point).is_err() {
103 return Err(self.player_gamestate())
104 }
105
106 let Cell { cell_type: CellType::Safe(number), cell_state: CellState::Revealed } = self.player_gamestate().board[point] else {
107 return Err(self.player_gamestate())
108 };
109
110 let flags = self.count_flags(point);
111
112 if flags != number as usize {
113 return Err(self.player_gamestate())
114 }
115
116 let mut success = true;
117
118 for point in self.player_gamestate().board.size().neighbours(point) {
119 success &= self.internal_reveal(point);
120 }
121
122 if !success {
123 self.gamestate_mut().status = GameStatus::Lost;
124
125 self.on_lose();
126
127 return Ok(self.player_gamestate())
128 }
129
130 if self.gamestate_mut().board.has_won() {
131 self.gamestate_mut().status = GameStatus::Won;
132
133 self.on_win();
134
135 return Ok(self.player_gamestate())
136 }
137
138 Ok(self.player_gamestate())
139 }
140
141 fn set_flagged(&mut self, point: Point, flagged: bool) -> Result<&GameState, &GameState> {
142 if check_interact(self, point).is_err() {
143 return Err(self.player_gamestate())
144 }
145
146 let mut mewo = self.gamestate_mut();
147 let state = mewo.deref_mut();
148 let cell = &mut state.board[point];
149
150 if cell.cell_state == CellState::Revealed {
151 drop(mewo);
152 return Err(self.player_gamestate())
153 }
154
155
156 if flagged != (cell.cell_state == CellState::Flagged) {
157 if flagged { state.remaining_mines -= 1 } else { state.remaining_mines += 1 }
158 }
159
160 cell.cell_state = if flagged { CellState::Flagged } else { CellState::Unknown };
161
162 drop(mewo);
163 Ok(self.player_gamestate())
164 }
165
166 fn count_flags(&self, point: Point) -> usize {
167 self.player_gamestate().board.size().neighbours(point)
168 .filter(|e| self.player_gamestate().board[*e].cell_state == CellState::Flagged)
169 .count()
170 }
171}
172
173impl<T: InternalMinsweeper + ?Sized> Minsweeper for T {
174 fn start(&mut self) -> &GameState {
175 self.start()
176 }
177
178 fn gamestate(&self) -> &GameState {
179 self.player_gamestate()
180 }
181
182 fn reveal(&mut self, point: Point) -> Result<&GameState, &GameState> {
183 self.reveal(point)
184 }
185
186 fn clear_around(&mut self, point: Point) -> Result<&GameState, &GameState> {
187 self.clear_around(point)
188 }
189
190 fn set_flagged(&mut self, point: Point, flagged: bool) -> Result<&GameState, &GameState> {
191 self.set_flagged(point, flagged)
192 }
193}
194
195
196pub fn generate_game(board_size: BoardSize) -> GameState {
197 let mut board = Board::empty(board_size);
198
199 let mine = Cell::new(CellType::Mine, CellState::Unknown);
200 let mut mines = 0usize;
201 while mines < board_size.mines().into() {
202 let point = (fastrand::usize(0..board_size.width().into()),
203 fastrand::usize(0..board_size.height().into()));
204
205 if matches!(board[point].cell_type, CellType::Safe(_)) {
206 board[point] = mine;
207 mines += 1;
208 }
209 };
210
211 generate_nmbers(&mut board);
212
213 GameState::new(GameStatus::Playing, board, usize::from(board_size.mines()).try_into().unwrap())
214}
215
216fn generate_nmbers(board: &mut Board) {
217 let empty_unknown = Cell::new(CellType::EMPTY, CellState::Unknown);
218 for point in board.size().points() {
219 let cell = &mut board[point];
220
221 if matches!(cell.cell_type, CellType::Safe(_)) {
222 *cell = empty_unknown;
223 }
224 }
225 for point in board.size().points() {
226 if board[point].cell_type == CellType::Mine {
227 for point in board.size().neighbours(point) {
228 if let CellType::Safe(number) = board[point].cell_type {
229 board[point] = Cell::new(CellType::Safe(number + 1), CellState::Unknown);
230 }
231 }
232 }
233 }
234}
235
236pub struct MinsweeperGame<
237 S: Solver = Box<dyn Solver>,
238 OnWin: Fn() = Box<dyn Fn()>,
239 OnLose: Fn() = Box<dyn Fn()>,
240> {
241 board_size: BoardSize,
242 game_state: GameState,
243 player_game_state: GameState,
244 on_win: OnWin,
245 on_lose: OnLose,
246 first: bool,
247 solver: Option<S>
248}
249
250impl<S: Solver, OnWin: Fn(), OnLose: Fn()> MinsweeperGame<S, OnWin, OnLose> {
251
252 pub fn new(board_size: BoardSize, on_win: OnWin, on_lose: OnLose) -> Self {
253 Self {
254 board_size,
255 game_state: GameState::new(GameStatus::Never, Board::empty(board_size), 0),
256 player_game_state: GameState::new(GameStatus::Never, Board::empty(board_size), 0),
257 on_win,
258 on_lose,
259 first: true,
260 solver: None
261 }
262 }
263
264 fn internal_start(&mut self, solver: Option<S>) -> &GameState {
265 *self.gamestate_mut() = GameState::new(GameStatus::Playing, Board::empty(self.board_size),
266 usize::from(self.board_size.mines()).try_into().unwrap());
267
268 self.first = true;
269 self.solver = solver;
270
271 self.player_gamestate()
272 }
273
274 pub fn start_with_solver(&mut self, solver: S) -> &GameState {
275 self.internal_start(solver.into())
276 }
277}
278
279impl<S: Solver, OnWin: Fn(), OnLose: Fn()> InternalMinsweeper for MinsweeperGame<S, OnWin, OnLose> {
280 fn start(&mut self) -> &GameState {
281 self.internal_start(None)
282 }
283
284 fn on_win(&self) {
285 (self.on_win)()
286 }
287
288 fn on_lose(&self) {
289 (self.on_lose)()
290 }
291
292 fn player_gamestate(&self) -> &GameState {
293 if self.game_state.status == GameStatus::Playing {
294 &self.player_game_state
295 } else {
296 &self.game_state
297 }
298 }
299
300 fn gamestate_mut(&mut self) -> impl DerefMut<Target = GameState> {
301 GameStateHandle {
302 game_state: &mut self.game_state,
303 obfuscated_game_state: &mut self.player_game_state
304 }
305 }
306
307 fn reveal(&mut self, point: Point) -> Result<&GameState, &GameState> {
308 if check_interact(self, point).is_err() {
309 return Err(self.player_gamestate())
310 }
311
312 if self.first {
313 self.first = false;
314
315 if let Some(solver) = &self.solver {
316 *self.gamestate_mut() = generate_solvable_game(self.board_size, solver, point);
317 } else {
318 *self.gamestate_mut() = generate_game(self.board_size);
319 }
320 }
321
322
323 let success = self.internal_reveal(point);
324
325 if !success {
326 self.gamestate_mut().status = GameStatus::Lost;
327
328 self.on_lose();
329
330 return Ok(self.player_gamestate())
331 }
332
333 if self.gamestate_mut().board.has_won() {
334 self.gamestate_mut().status = GameStatus::Won;
335
336 self.on_win();
337
338 return Ok(self.player_gamestate())
339 }
340
341 Ok(self.player_gamestate())
342 }
343
344 fn set_flagged(&mut self, point: Point, flagged: bool) -> Result<&GameState, &GameState> {
345 if check_interact(self, point).is_err() || self.first {
346 return Err(self.player_gamestate())
347 }
348
349 let mut mewo = self.gamestate_mut();
350 let state = mewo.deref_mut();
351 let cell = &mut state.board[point];
352
353 if cell.cell_state == CellState::Revealed {
354 drop(mewo);
355 return Err(self.player_gamestate())
356 }
357
358
359 if flagged != (cell.cell_state == CellState::Flagged) {
360 if flagged { state.remaining_mines -= 1 } else { state.remaining_mines += 1 }
361 }
362
363 cell.cell_state = if flagged { CellState::Flagged } else { CellState::Unknown };
364
365 drop(mewo);
366 Ok(self.player_gamestate())
367 }
368}
369
370pub fn generate_solvable_game(board_size: BoardSize, solver: &dyn Solver, point: Point) -> GameState {
371 loop {
372 let state = generate_game(board_size);
373
374 let mut game = SetMinsweeperGame::new(state.clone());
375 Minsweeper::reveal(&mut game, point)
376 .expect("should always be able to successfully reveal");
377
378 let result = solver.solve_game(&mut game);
379
380 if result == GameResult::Won {
381 return state;
382 }
383 }
384}
385
386#[derive(Clone, Debug)]
387pub struct SetMinsweeperGame {
388 game_state: GameState,
389 player_game_state: GameState
390}
391
392impl SetMinsweeperGame {
393 pub fn new(game_state: GameState) -> Self {
394 Self { player_game_state: game_state.hide_mines(), game_state }
395 }
396}
397
398impl InternalMinsweeper for SetMinsweeperGame {
399 fn start(&mut self) -> &GameState {
400 unimplemented!()
401 }
402
403 fn on_win(&self) {
404
405 }
406
407 fn on_lose(&self) {
408
409 }
410
411 fn player_gamestate(&self) -> &GameState {
412 &self.player_game_state
413 }
414
415 fn gamestate_mut(&mut self) -> impl DerefMut<Target = GameState> {
416 GameStateHandle {
417 game_state: &mut self.game_state,
418 obfuscated_game_state: &mut self.player_game_state,
419 }
420 }
421}
422
423struct GameStateHandle<'a> {
424 game_state: &'a mut GameState,
425 obfuscated_game_state: &'a mut GameState
426}
427
428impl AsMut<GameState> for GameStateHandle<'_> {
429 fn as_mut(&mut self) -> &mut GameState {
430 self.game_state
431 }
432}
433
434impl Deref for GameStateHandle<'_> {
435 type Target = GameState;
436
437 fn deref(&self) -> &Self::Target {
438 self.game_state
439 }
440}
441
442impl DerefMut for GameStateHandle<'_> {
443 fn deref_mut(&mut self) -> &mut Self::Target {
444 self.game_state
445 }
446}
447
448impl Drop for GameStateHandle<'_> {
449 fn drop(&mut self) {
450 *self.obfuscated_game_state = self.game_state.hide_mines()
451 }
452}
453