Skip to content
Snippets Groups Projects
Select Git revision
  • f014d0f53b7067b3825927eef5685968214162d1
  • main default protected
2 results

minesweeper.py

Blame
  • 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')