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

minesweeper.py

Blame
  • minesweeper.py 6.44 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éconditi        $$$ game = Minesweeper(20, 10, 4)on: 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 i in range(x-1,x+2):
            for j in range(y-1,y+2):
                if (i,j)!=(x,y) and 0<=i<width and 0<=j<height:
                    neighbors.append((i,j))
        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
            n=0
            while n<nbombs:
                y=randint(0,width-1)
                x=randint(0,height-1)
                if not sel.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
            """
            return self._grid[y][x]
    
        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
            """
            if 0<=x<self.width and 0<=y<self.height:
                case=self.grid[y][x]
                if not case.nbombs_in_neighborhood:
                    case.nbombs_in_neighborhood=True
                
                for i in range(x-1,x+2):
                    for j in range(y-1,y+2):
                        if 0<=i<self.width and 0<=j<self.height:
                            case_voisine=self.grid[j][i]
                            if not case_voisine.nbombs_in_neighborhood:
                                case_voisine.nbombs_in_neighborhood+=1
                                
    
    
        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
            """
            res=True
            for i in range(self.width):
                for j in range(self.height):
                    cell=self.grid[j][i]
                    if not (cell.is_revealed and cell.is_bomb):
                        res=False
            return res
    
    
    
    if (__name__ == '__main__'):
        import apl1test
        apl1test.testmod('minesweeper.py')