diff --git a/tp5_AP/__pycache__/cell.cpython-310.pyc b/tp5_AP/__pycache__/cell.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..081254be76b64ce50e79f216b06113190308e0cb
Binary files /dev/null and b/tp5_AP/__pycache__/cell.cpython-310.pyc differ
diff --git a/tp5_AP/__pycache__/graphicalboard.cpython-310.pyc b/tp5_AP/__pycache__/graphicalboard.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..74143f7ab1ec5291a7d9b062c86c5c4a543a7f0b
Binary files /dev/null and b/tp5_AP/__pycache__/graphicalboard.cpython-310.pyc differ
diff --git a/tp5_AP/__pycache__/minesweeper.cpython-310.pyc b/tp5_AP/__pycache__/minesweeper.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e0f4179752d9545e5b5f786320a1a22dac906f47
Binary files /dev/null and b/tp5_AP/__pycache__/minesweeper.cpython-310.pyc differ
diff --git a/tp5_AP/apl1test.py b/tp5_AP/apl1test.py
new file mode 100644
index 0000000000000000000000000000000000000000..8533ccaca5d99e7cfb83d6d86aa9334bb6a73a40
--- /dev/null
+++ b/tp5_AP/apl1test.py
@@ -0,0 +1,89 @@
+import thonnycontrib
+from thonnycontrib.backend.evaluator import Evaluator
+import thonnycontrib.backend.l1test_backend
+from thonny.plugins.cpython_backend.cp_back import MainCPythonBackend
+import thonnycontrib.backend.doctest_parser
+from thonnycontrib.backend.doctest_parser import ExampleWithExpected, ExampleWithoutExpected
+import thonnycontrib.backend.ast_parser
+from thonnycontrib.backend.ast_parser import L1DocTest
+import thonnycontrib.backend.verdicts
+from thonnycontrib.backend.verdicts.ExceptionVerdict import ExceptionVerdict
+
+import inspect
+import tempfile
+import os
+import sys
+
+class MockBackend(MainCPythonBackend):
+ """
+ Fake backend.
+ """
+ def __init__(self):
+ ...
+
+ def send_message(self, msg) -> None:
+ ...
+
+# register backend
+thonnycontrib.backend.l1test_backend.BACKEND = MockBackend()
+
+def l1test_to_org(filename: str, source: str=""):
+ """
+ Return an org abstract of the tests presents in `filename` file.
+ """
+ abstract = {'total': 0,
+ 'success': 0,
+ 'failures': 0,
+ 'errors': 0,
+ 'empty': 0}
+
+ if source == "":
+ with open(filename, 'rt') as fin:
+ source = fin.read()
+ evaluator = Evaluator(filename=filename,
+ source=source)
+ tests = evaluator.evaluate()
+ n = len(tests)
+ abstract['total'] = n
+ res = ""
+ for test in tests:
+ examples = test.get_examples()
+ res_examples = ""
+ nb_test, nb_test_ok = 0, 0
+ empty = True
+ for example in examples:
+ verdict = test.get_verdict_from_example(example)
+ if isinstance(example, ExampleWithExpected):
+ nb_test += 1
+ if verdict.isSuccess():
+ nb_test_ok += 1
+ abstract['success'] += 1
+ else:
+ abstract['failures'] += 1
+ empty = False
+ if isinstance(verdict, ExceptionVerdict):
+ abstract['errors'] += 1
+ empty = False
+ res_examples += f"** {verdict}\n\n"
+ if not verdict.isSuccess():
+ res_examples += f" {verdict.get_details()}\n\n"
+ if not empty:
+ res += f"* {test.get_name()} ~ {nb_test_ok}/{nb_test} réussis\n\n"
+ else:
+ abstract['empty'] += 1
+ res += f"* {test.get_name()}\n\n Aucun test trouvé !\n\n"
+ res += res_examples
+ res = f"Tests exécutés : {abstract['total']}\nSuccès: {abstract['success']}, \
+Echecs: {abstract['failures']}, Erreurs: {abstract['errors']}, \
+Vide: {abstract['empty']}\n\n" + res
+ return res
+
+
+def testmod(modulename: str):
+ """
+ mimic the doctest.testmod function
+ for `modulename` module
+ """
+ print(l1test_to_org(modulename))
+
+
diff --git a/tp5_AP/cell.py b/tp5_AP/cell.py
new file mode 100755
index 0000000000000000000000000000000000000000..586daa5caedadef546c63b084c3b2761d60eaca1
--- /dev/null
+++ b/tp5_AP/cell.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`cell` module
+
+:author: koffi gantchou
+
+:date: 13/02/2025
+
+
+"""
+
+class Cell:
+
+ def __init__(self):
+ """
+ initialize a new hidden cell of a minesweeper's grid.
+ existence of a bomb, number of bombs in neighborhood
+ have to be stated later.
+
+ precondition: none
+ Examples:
+
+ $$$ cel = Cell()
+ $$$ cel.is_bomb
+ False
+ $$$ cel.is_revealed
+ False
+ $$$ cel.nbombs_in_neighborhood
+ 0
+ """
+ self.is_bomb = False
+ self.is_revealed = False
+ self.nbombs_in_neighborhood = 0
+
+ def incr_number_of_bombs_in_neighborhood(self):
+ """
+ :return: None
+ :side effect: increment the number of bombs in neighborhood of self
+ precondition: none
+ Examples:
+
+ $$$ cel = Cell()
+ $$$ cel.nbombs_in_neighborhood
+ 0
+ $$$ cel.incr_number_of_bombs_in_neighborhood()
+ $$$ cel.nbombs_in_neighborhood
+ 1
+ """
+
+ self.nbombs_in_neighborhood +=1
+
+
+
+
+ def reveal(self):
+ """
+ modify reveal state of self
+ precondition: none
+ Examples:
+
+ $$$ cel = Cell()
+ $$$ cel.is_revealed
+ False
+ $$$ cel.reveal()
+ $$$ cel.is_revealed
+ True
+ """
+ self.is_revealed = True
+
+
+
+ def set_bomb(self):
+ """
+ put a bomb in self
+
+ precondition: none
+ Examples:
+
+ $$$ cel = Cell()
+ $$$ cel.is_bomb
+ False
+ $$$ cel.set_bomb()
+ $$$ cel.is_bomb
+ True
+ """
+ self.is_bomb = True
+
+ def __str__(self)->str:
+ """
+ :return: a string representation of self state
+ :rtype: str
+ precondition: none
+ Examples:
+
+ $$$ cel = Cell()
+ $$$ str(cel) == ' '
+ True
+ $$$ cel.reveal()
+ $$$ str(cel) == '0'
+ True
+ $$$ cel.incr_number_of_bombs_in_neighborhood()
+ $$$ str(cel) == '1'
+ True
+ $$$ cel.set_bomb()
+ $$$ str(cel) == 'B'
+ True
+ """
+ if not(self.is_revealed):
+ return' '
+ else:
+ if self.is_bomb:
+ return 'B'
+ else:
+ return str(self.nbombs_in_neighborhood)
+
+
+
+def fibo(n:int)->int:
+ """ renvoie le terme fn de la suite
+
+ Précondition :
+ Exemple(s) :
+ $$$
+ """
+ if n==0:
+ return 0
+ elif n==1:
+ return 1
+ else:
+ return fibo(n-1) + fibo(n-2)
+
+
+
+
+if (__name__ == '__main__'):
+ import apl1test
+ apl1test.testmod('cell.py')
+
diff --git a/tp5_AP/graphical_main.py b/tp5_AP/graphical_main.py
new file mode 100644
index 0000000000000000000000000000000000000000..d57cc9f05688156198e45cd7aaa4b929de92b83b
--- /dev/null
+++ b/tp5_AP/graphical_main.py
@@ -0,0 +1,18 @@
+from minesweeper import Minesweeper
+import graphicalboard
+
+import sys
+
+def main():
+ width = int(sys.argv[1])
+ height = int(sys.argv[2])
+ nb_bomb = int(sys.argv[3])
+ print(f"vous avez une grille de jeu de dimmension {width}*{height} {nb_bomb} nombre de bombes")
+ game = Minesweeper(width, height, nb_bomb)
+ graphicalboard.create(game)
+
+if __name__ == "__main__":
+ if len(sys.argv) != 4:
+ print("Usage : python3 graphical_main.py <width> <height> <nb_bomb>")
+ else:
+ main()
diff --git a/tp5_AP/graphicalboard.py b/tp5_AP/graphicalboard.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b353af27cb18b6b3ae50a9a291b72da60073505
--- /dev/null
+++ b/tp5_AP/graphicalboard.py
@@ -0,0 +1,174 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`graphicalboard` module
+
+:author: `FIL - IEEA - Univ. Lille1.fr <http://portail.fil.univ-lille1.fr>`_
+
+:date: 2015, september, last revision: 2024, february
+
+This module implements some functions to draw a minesweeper game. The
+graphical board uses buttons to draw each cell and maps the left-click
+and right-click events to interact with the minesweeper.
+
+This module uses from :mod:`minesweeper`:
+
+* :method:`Minesweeper.reveal_all_cells_from`
+
+To draw and run a minesweeper game, one has to:
+
+* create a minesweeper game g
+* create a graphical board from the minesweeper g
+
+"""
+
+import os
+import tkinter as tk
+from functools import partial
+from cell import Cell
+from minesweeper import *
+
+# the list of icons
+img = []
+
+def create(game: Minesweeper):
+ """
+ This function creates the graphical board from a game. It also
+ launches the event loop. Thus, this is the only function to run to
+ have a functional graphical board.
+ """
+ global img
+ # create a new Tk window
+ win = tk.Tk()
+ # define the window title
+ win.title('Minesweeper ({:d} bombs)'.format(game.nbombs))
+ # load images
+ iconpath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "icons")
+ img = [
+ tk.PhotoImage(file=os.path.join(iconpath, "0.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "1.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "2.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "3.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "4.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "5.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "6.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "7.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "8.gif")),
+ tk.PhotoImage(file=os.path.join(iconpath, "9.gif")), # unrevealed
+ tk.PhotoImage(file=os.path.join(iconpath, "10.gif")), # bomb explosed
+ tk.PhotoImage(file=os.path.join(iconpath, "11.gif")), # bomb discovered
+ tk.PhotoImage(file=os.path.join(iconpath, "12.gif")), # flag
+ tk.PhotoImage(file=os.path.join(iconpath, "13.gif")) # question
+ ]
+ # create the graphical board made of Tk buttons
+ width, height = game.width, game.height
+ board = []
+ for i in range(width):
+ board.insert(i, [])
+ for j in range(height):
+ button = tk.Button(win, padx=0, pady=0, width=19, height=19, image=img[9])
+ button.grid(column=i, row=j)
+ board[i].insert(j, button)
+ # bind the right-click event
+ button.bind("<Button-3>",
+ partial(__changeflag, board=board, game=game, x=i, y=j))
+ # bind the left-click event
+ button.config(command=partial(__changestate, board, game, i, j))
+ # event loop
+ win.mainloop()
+
+def __test_end(board: list[list[tk.Button]], game: Minesweeper):
+ """
+ This function tests if the game is finished or not. In the first
+ case, depending on the state of the game, all graphical cells are
+ disabled or events are unbinded.
+ """
+ state = game.state
+ if state == GameState.losing:
+ __disable_game(board, game)
+ elif state == GameState.winning:
+ __block_game(board, game)
+
+def __changestate(board: list[list[tk.Button]],
+ game: Minesweeper,
+ x: int, y: int):
+ """
+ This function is called on left-click on a button.
+
+ """
+ game.reveal_all_cells_from(x, y)
+ __redraw(board, game, x, y)
+ __test_end(board, game)
+
+def __changeflag(evt, board: list[list[tk.Button]],
+ game: Minesweeper,
+ x: int, y: int):
+ """
+ This function is called on right-click on a button.
+ """
+ cel = game.get_cell(x, y)
+ # if not cel.is_hypothetic():
+ # cel.set_hypothetic()
+ # else:
+ # cel.unset_hypothetic()
+ __redraw(board, game, x, y)
+ __test_end(board, game)
+
+
+def __block_game(board: list[list[tk.Button]],
+ game: Minesweeper):
+ """
+ This function is called once the player wins. The chosen behavior
+ is to let the board as it and to unbind events.
+ """
+ width, height = (game.width, game.height)
+ for i in range(width):
+ for j in range(height):
+ button = board[i][j]
+ game.get_cell(i, j).reveal()
+ button.config(command="")
+ button.bind("<Button-3>", "")
+ __redraw(board, game, -1, -1)
+
+def __disable_game(board: list[list[tk.Button]],
+ game: Minesweeper):
+ """
+ This function is called once the player looses. The chosen behavior
+ is to shade the board and to unbind events.
+ """
+ width, height = game.width, game.height
+ for i in range(width):
+ for j in range(height):
+ button = board[i][j]
+ button.config(state=tk.DISABLED)
+ button.bind("<Button-3>", "")
+
+
+def __redraw(board: list[list[tk.Button]],
+ game: Minesweeper,
+ x: int, y: int):
+ """
+ This function draws the board. Positions x and y are used to test
+ which bomb icon has to be drawn.
+ """
+ width, height = (game.width, game.height)
+ for i in range(width):
+ for j in range(height):
+ cel = game.get_cell(i, j)
+ button = board[i][j]
+ if cel.is_revealed:
+ if cel.is_bomb:
+ new_img = img[10]
+ if x == j and y == i:
+ new_img = img[11]
+ else:
+ new_img = img[cel.nbombs_in_neighborhood]
+ button.config(relief=tk.FLAT, image=new_img, command="")
+ else:
+ button.config(image=img[9])
+
+
+if __name__ == "__main__":
+ import apl1test
+ apl1test.testmod('graphicalboard.py')
diff --git a/tp5_AP/icons/0.gif b/tp5_AP/icons/0.gif
new file mode 100644
index 0000000000000000000000000000000000000000..26d8a1024c3e988cc71d1f44e5eb9785a24920e8
Binary files /dev/null and b/tp5_AP/icons/0.gif differ
diff --git a/tp5_AP/icons/1.gif b/tp5_AP/icons/1.gif
new file mode 100644
index 0000000000000000000000000000000000000000..fc817675c6f607b73904f16c369713edf2f914fc
Binary files /dev/null and b/tp5_AP/icons/1.gif differ
diff --git a/tp5_AP/icons/10.gif b/tp5_AP/icons/10.gif
new file mode 100644
index 0000000000000000000000000000000000000000..10d928aa589648fbfd4e0c37a997cfa5e0eeaf2f
Binary files /dev/null and b/tp5_AP/icons/10.gif differ
diff --git a/tp5_AP/icons/11.gif b/tp5_AP/icons/11.gif
new file mode 100644
index 0000000000000000000000000000000000000000..51fb6a928424a34021239bbb290456976666bcc1
Binary files /dev/null and b/tp5_AP/icons/11.gif differ
diff --git a/tp5_AP/icons/12.gif b/tp5_AP/icons/12.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2854de27bbf73d5d8a9c21db979ab75f144a8a9f
Binary files /dev/null and b/tp5_AP/icons/12.gif differ
diff --git a/tp5_AP/icons/13.gif b/tp5_AP/icons/13.gif
new file mode 100644
index 0000000000000000000000000000000000000000..947d01285d2ba0b83ccd14bf3fde61887798ad16
Binary files /dev/null and b/tp5_AP/icons/13.gif differ
diff --git a/tp5_AP/icons/2.gif b/tp5_AP/icons/2.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2ef31056ccd581f2df4fe0f10e03f9ae831ac7ef
Binary files /dev/null and b/tp5_AP/icons/2.gif differ
diff --git a/tp5_AP/icons/3.gif b/tp5_AP/icons/3.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4abac7be126376b0b3c7a8dd202c91e51c401810
Binary files /dev/null and b/tp5_AP/icons/3.gif differ
diff --git a/tp5_AP/icons/4.gif b/tp5_AP/icons/4.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4e942e211f7d29940e2f0868ad8888d6dc396064
Binary files /dev/null and b/tp5_AP/icons/4.gif differ
diff --git a/tp5_AP/icons/5.gif b/tp5_AP/icons/5.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9b6b607be42cfbd7aed2dd30c2bafc1ce9d3e4c9
Binary files /dev/null and b/tp5_AP/icons/5.gif differ
diff --git a/tp5_AP/icons/6.gif b/tp5_AP/icons/6.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2cc9004893ede6904937f1f6c3fdfea9d517e0de
Binary files /dev/null and b/tp5_AP/icons/6.gif differ
diff --git a/tp5_AP/icons/7.gif b/tp5_AP/icons/7.gif
new file mode 100644
index 0000000000000000000000000000000000000000..aa755b7661dc088e2c73f8650f3b563bd3f2395e
Binary files /dev/null and b/tp5_AP/icons/7.gif differ
diff --git a/tp5_AP/icons/8.gif b/tp5_AP/icons/8.gif
new file mode 100644
index 0000000000000000000000000000000000000000..283c520e31c108effb9d477e4359a3654ce8470e
Binary files /dev/null and b/tp5_AP/icons/8.gif differ
diff --git a/tp5_AP/icons/9.gif b/tp5_AP/icons/9.gif
new file mode 100644
index 0000000000000000000000000000000000000000..50ac94d02f9e29ba36133da6281c3f0b9b2026ec
Binary files /dev/null and b/tp5_AP/icons/9.gif differ
diff --git a/tp5_AP/minesweeper.py b/tp5_AP/minesweeper.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8a9772229d42d22c7ddb1fc5df5bb31b1b5520d
--- /dev/null
+++ b/tp5_AP/minesweeper.py
@@ -0,0 +1,278 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`minesweeper` module
+
+:author: gantchou koffi
+
+:date: 13/03/2025
+
+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)]
+ """
+ res=[]
+ for dx in [-1,0,1]:
+ for dy in [-1,0,1]:
+ if dx==0 and dy==0:
+ continue
+ nx,ny = x + dx , y + dy
+
+ if (0 <= nx < width) and (0 <= ny < height):
+ res.append((nx,ny))
+ return res
+
+
+
+
+
+
+
+
+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
+ $$$
+ """
+
+
+
+
+
+ import random
+ 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.grille = [[Cell() for _ in range(height)] for _ in range(width)]
+
+
+ bombs_cell = random.sample(range(width*height),nbombs)
+ for nub_bomb in bombs_cell:
+ x = nub_bomb//height
+ y = nub_bomb%height
+ self._put_a_bomb_at(x,y)
+
+
+
+ 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
+ """
+ if x>=0 and x < self.width and y>=0 and y < self.height:
+ return self.grille[x][y]
+
+
+
+
+
+
+ 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
+ """
+ cell = self.get_cell(x,y)
+
+ if cell.is_bomb:
+ return
+ cell.is_bomb = True
+ voisins = neighborhood(x,y,self.width,self.height)
+ for nx,ny in voisins:
+ neighbor_cell = self.get_cell(nx,ny)
+ neighbor_cell.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
+
+ """
+ for i in range(self.width):
+ for j in range(self.height):
+ if self.grille[i][j].is_revealed or self.grille[i][j].is_bomb:
+ continue
+ else:
+ return False
+ return True
+
+
+ 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 self.grille[x][y].is_bomb:
+ self.state = GameState.losing
+ print('vous avez perdu !')
+ return
+ else:
+ self.grille[x][y].is_revealed = True
+ voisins=neighborhood(x,y,self.width,self.height)
+
+ if all(not(self.get_cell(elt[0],elt[1]).is_bomb) for elt in voisins):
+ for vx,vy in voisins:
+ if not(self.get_cell(vx,vy).is_revealed):
+ self.reveal_all_cells_from(vx,vy)
+ if self.all_cells_are_revealed_or_bomb():
+ self.state = GameState.winning
+ print('vous avez gagné')
+
+
+
+
+
+
+
+
+
+
+
+
+if (__name__ == '__main__'):
+ import apl1test
+ apl1test.testmod('minesweeper.py')
+
diff --git a/tp5_AP/p1.py b/tp5_AP/p1.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391