Select Git revision
minesweeper.py
-
Tanoh Mbah-ange-pascal authoredTanoh Mbah-ange-pascal authored
minesweeper.py 5.81 KiB
# Nom = TANOH PASCAL
# TP5 groupe MI 15
# date: 14/02/2024
"""
:mod:`minesweeper` module
:author: HERE YOUR NAME
:date:
This module provides functions and a class for minesweeper's game's management.
"""
import random
from enum import Enum
from cell import Cell
################################################
# Type declaration
################################################
class GameState(Enum):
"""
A class to define an enumerated type with three values :
* ``winning``
* ``losing``
* ``unfinished``
for the three state of minesweeper game.
"""
winning = 1
losing = 2
unfinished = 3
##############################################
# Function for game's setup and management
##############################################
def neighborhood(x: int, y: int, width: int, height: int) -> list[tuple[int, int]]:
"""
return the list of coordinates of the neighbors of position (x,y) in a
grid of size width*height
précondition: 0 <= x < width and 0 <= y < height
examples:
$$$ neighborhood(3, 3, 10, 10)
[(2, 2), (2, 3), (2, 4), (3, 2), (3, 4), (4, 2), (4, 3), (4, 4)]
$$$ neighborhood(0, 3, 10, 10)
[(0, 2), (0, 4), (1, 2), (1, 3), (1, 4)]
$$$ neighborhood(0, 0, 10, 10)
[(0, 1), (1, 0), (1, 1)]
$$$ neighborhood(9, 9, 10, 10)
[(8, 8), (8, 9), (9, 8)]
$$$ neighborhood(3, 9, 10, 10)
[(2, 8), (2, 9), (3, 8), (4, 8), (4, 9)]
"""
neighbors = []
for distance_x in range(-1,2):
for distance_y in range(-1,2):
x_1,y_1 = x + distance_x, y + distance_y
if 0 <= x_1 < width and 0 <= y_1 < height and (x_1,y_1) != (x,y):
neighbors.append((x_1,y_1))
return neighbors
class Minesweeper():
"""
$$$ game = Minesweeper(20, 10, 4)
$$$ game.width
20
$$$ game.height
10
$$$ game.nbombs
4
$$$ game.state == GameState.unfinished
True
$$$ cel = game.get_cell(1, 2)
$$$ cel.is_revealed
False
$$$
"""
def __init__(self, width: int=30, height: int=20, nbombs: int=99):
"""
build a minesweeper grid of size `width*height` of cells
with `nbombs` bombs randomly placed.
for each build cell, this constructor sets the number of bombs
in neighborhood.
precondition: width and height must be positive integers, and
nbombs <= width * height
example:
$$$ game = Minesweeper(20, 10, 4)
$$$ game.width
20
$$$ game.height
10
$$$ game.nbombs
4
$$$ game.state == GameState.unfinished
True
"""
self.width= width
self.height= height
self.nbombs= nbombs
self.state= GameState.unfinished
self.grid = [[cell() for i in range(width)] for j in range(height)]
n=0
while n<nbombs:
y=random.randint(0,width-1)
x=random.randint(0,height-1)
if not self.grid[x][y].is_bomb:
self._put_a_bomb_at(x,y)
n=n+1
def get_cell(self, x: int, y: int) -> Cell:
"""
return: the cell of coordinates (x,y) in the game's grid
precondition: 0 <= x < width of game and O <= y < height of game
$$$ game = Minesweeper(20, 10, 4)
$$$ sum(1 for x in range(20) for y in range(10) if game.get_cell(x, y).is_bomb)
4
"""
...
def _put_a_bomb_at(self, x: int, y: int):
"""
this method change the cells's state at x, y to a bomb,
if the cell is already a bomb, nothing append.
otherwise it change cell's state and increments by one every
cells in its neighborhood.
precondition: 0 <= x < self.width and 0 <= y < self.height
exemples:
$$$ game = Minesweeper(10, 5, 0)
$$$ voisins = neighborhood(1, 1, game.width, game.height)
$$$ all(game.get_cell(x, y).nbombs_in_neighborhood == 0 for x, y in voisins)
True
$$$ game._put_a_bomb_at(1, 1)
$$$ all(game.get_cell(x, y).nbombs_in_neighborhood == 1 for x, y in voisins)
True
$$$ game._put_a_bomb_at(1, 1)
$$$ all(game.get_cell(x, y).nbombs_in_neighborhood == 1 for x, y in voisins)
True
"""
...
def all_cells_are_revealed_or_bomb(self) -> bool:
"""
return True iff all cells are revealed or bomb.
précondition: none
"""
...
def reveal_all_cells_from(self, x, y):
"""
recursively reveal all cells of game game from the initial cell (x,y).
* if the cell is a bomb one, update game's state to losing.
* otherwise if the cell's neighborhood doesn't contains bomb,
recursively reveal all neighboors.
* and finally, if all cell's are revealed, update game's state to
winning
precondition: 0 <= x < width of game and O <= y < height of game
exemples:
$$$ game = Minesweeper(20, 10, 0)
$$$ game._put_a_bomb_at(1, 1)
$$$ game.state
GameState.unfinished
$$$ game.all_cells_are_revealed_or_bomb()
False
$$$ game.reveal_all_cells_from(5, 5)
$$$ game.all_cells_are_revealed_or_bomb()
False
$$$ game.reveal_all_cells_from(0, 0)
$$$ game.reveal_all_cells_from(1, 0)
$$$ game.reveal_all_cells_from(0, 1)
$$$ game.all_cells_are_revealed_or_bomb()
True
$$$ game.state
GameState.winning
$$$ game = Minesweeper(20, 10, 0)
$$$ game._put_a_bomb_at(1, 1)
$$$ game.reveal_all_cells_from(1, 1)
$$$ game.state
GameState.losing
"""
...
if (__name__ == '__main__'):
import apl1test
apl1test.testmod('minesweeper.py')