From d62c8aefb0fb332697585fe1f01c0bad3a3e509e Mon Sep 17 00:00:00 2001
From: Dahmane Lynda <lynda.dahmane.etu@118p28.fil.univ-lille.fr>
Date: Wed, 14 Feb 2024 09:53:11 +0100
Subject: [PATCH] Tp5

---
 Tp5/minesweeper.zip               | Bin 0 -> 12993 bytes
 Tp5/minesweeper/apl1test.py       |  89 +++++++++++++
 Tp5/minesweeper/cell.py           | 125 ++++++++++++++++++
 Tp5/minesweeper/graphicalboard.py | 174 +++++++++++++++++++++++++
 Tp5/minesweeper/icons/0.gif       | Bin 0 -> 99 bytes
 Tp5/minesweeper/icons/1.gif       | Bin 0 -> 404 bytes
 Tp5/minesweeper/icons/10.gif      | Bin 0 -> 393 bytes
 Tp5/minesweeper/icons/11.gif      | Bin 0 -> 879 bytes
 Tp5/minesweeper/icons/12.gif      | Bin 0 -> 658 bytes
 Tp5/minesweeper/icons/13.gif      | Bin 0 -> 648 bytes
 Tp5/minesweeper/icons/2.gif       | Bin 0 -> 668 bytes
 Tp5/minesweeper/icons/3.gif       | Bin 0 -> 639 bytes
 Tp5/minesweeper/icons/4.gif       | Bin 0 -> 649 bytes
 Tp5/minesweeper/icons/5.gif       | Bin 0 -> 418 bytes
 Tp5/minesweeper/icons/6.gif       | Bin 0 -> 660 bytes
 Tp5/minesweeper/icons/7.gif       | Bin 0 -> 420 bytes
 Tp5/minesweeper/icons/8.gif       | Bin 0 -> 427 bytes
 Tp5/minesweeper/icons/9.gif       | Bin 0 -> 337 bytes
 Tp5/minesweeper/minesweeper.py    | 204 ++++++++++++++++++++++++++++++
 19 files changed, 592 insertions(+)
 create mode 100644 Tp5/minesweeper.zip
 create mode 100644 Tp5/minesweeper/apl1test.py
 create mode 100755 Tp5/minesweeper/cell.py
 create mode 100644 Tp5/minesweeper/graphicalboard.py
 create mode 100644 Tp5/minesweeper/icons/0.gif
 create mode 100644 Tp5/minesweeper/icons/1.gif
 create mode 100644 Tp5/minesweeper/icons/10.gif
 create mode 100644 Tp5/minesweeper/icons/11.gif
 create mode 100644 Tp5/minesweeper/icons/12.gif
 create mode 100644 Tp5/minesweeper/icons/13.gif
 create mode 100644 Tp5/minesweeper/icons/2.gif
 create mode 100644 Tp5/minesweeper/icons/3.gif
 create mode 100644 Tp5/minesweeper/icons/4.gif
 create mode 100644 Tp5/minesweeper/icons/5.gif
 create mode 100644 Tp5/minesweeper/icons/6.gif
 create mode 100644 Tp5/minesweeper/icons/7.gif
 create mode 100644 Tp5/minesweeper/icons/8.gif
 create mode 100644 Tp5/minesweeper/icons/9.gif
 create mode 100755 Tp5/minesweeper/minesweeper.py

diff --git a/Tp5/minesweeper.zip b/Tp5/minesweeper.zip
new file mode 100644
index 0000000000000000000000000000000000000000..687e5f0b46b39c599e0898f6bbf214e5d9e55113
GIT binary patch
literal 12993
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
Z)@is5WMu=DC_)TE498g+7@mMTd;o(4zv2J@

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/apl1test.py b/Tp5/minesweeper/apl1test.py
new file mode 100644
index 0000000..8533cca
--- /dev/null
+++ b/Tp5/minesweeper/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/minesweeper/cell.py b/Tp5/minesweeper/cell.py
new file mode 100755
index 0000000..d182698
--- /dev/null
+++ b/Tp5/minesweeper/cell.py
@@ -0,0 +1,125 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+:mod:`cell` module
+
+:author: 
+
+:date: 
+
+
+"""
+    
+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):
+        """
+        :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 self.is_revealed:
+            if self.is_bomb:
+                return'B'
+            else:
+                return str(self.nbombs_in_neighborhood)
+        else:
+            
+            return' '
+           
+if (__name__ == '__main__'):
+    import apl1test
+    apl1test.testmod('cell.py')
+
diff --git a/Tp5/minesweeper/graphicalboard.py b/Tp5/minesweeper/graphicalboard.py
new file mode 100644
index 0000000..3ec2941
--- /dev/null
+++ b/Tp5/minesweeper/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
+    doctest.testmod('graphicalboard.py')
diff --git a/Tp5/minesweeper/icons/0.gif b/Tp5/minesweeper/icons/0.gif
new file mode 100644
index 0000000000000000000000000000000000000000..26d8a1024c3e988cc71d1f44e5eb9785a24920e8
GIT binary patch
literal 99
zcmZ?wbhEHb6lM@+_{hM}-Q7KB&YYb)ckbG?OYtWQ0|@AV2#`DjlZi{;%Jj$li>;k+
zbbns3^RaBmJoc`|$L40NSeK?f<%8<^LaXbRe6MZqe`3{~^hh}&LPM~DiNP8G+AJkq

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/1.gif b/Tp5/minesweeper/icons/1.gif
new file mode 100644
index 0000000000000000000000000000000000000000..fc817675c6f607b73904f16c369713edf2f914fc
GIT binary patch
literal 404
zcmZ?wbhEHb6lM@+_{zY*$oP+e;Xfnee`e-?tgL^zxqtKW{t^-SE-(LCQu3>$<Tn|a
zFFHE!%*|if+P+Xw_#7X9J1XjKM8v(=*gKh-*K=~NrKH>}E4x%#d9kA6lB?@eH@7F<
z-Q9EM%$_r6&dQbhSFhf;YSsSr>-X;6yM6oiUE8+p-mqcMjvYI9?%cU+*N)x0ckJ4=
zbN6mAZ`ZCpdv@&Ev$LV$Tw~+8&d$>_W*nU}=g9Kq2Ue^&z<>iN{$v5m=zvI&pBUIS
zI`pM`sFYb9U3lSYmR0PUpp!RCc%xV3l$Caw>Zt3kDivMrBH-*Gd~K5LjWw&DNw8dd
z`^MUDlI^?loTO?EEeY0!#>(VWEfFqmPL{6bR1GyVa}(|<dDFDDwG=t#R!xhRUs5r(
zAW3`W(w?;%n)=ELtE9E`HJ7c`HW8N;WiRIu7dO$~6rnH7$iUFRbV*qMjK;an+t+Sr
h8Vd<NdMqepyf@!RSI6M(yLURFa!#IKJ!KpjtO0VirM>_F

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/10.gif b/Tp5/minesweeper/icons/10.gif
new file mode 100644
index 0000000000000000000000000000000000000000..10d928aa589648fbfd4e0c37a997cfa5e0eeaf2f
GIT binary patch
literal 393
zcmZ?wbhEHb6lM@+_{snRjEsy-Oiawo%q%P{tgNhTY-}7H9Gsk-TwGi{JUqO-ynK9o
z{QUevLPEmA!s6oM5)u-Ul9IBrvhwosii(QL%E~G#Dr#zKnwpy0+S>a1`UVCDCMG7P
zrluAa7M7NlR#sLvHZ~3p4vvnFE-o(a?(UwRo_>CQ{{H@ffq@Yb5m8Z5+1c5-xw#<M
zkcbt3vM@3*=ribm^nv`uz_#qb^a2kZsa}>tg_<@BGn}0gU$F47A7?teU_pw3&=H1(
zHd0CpE_XiJX|n9JtH;r#rEW4@hpLv$iO|#4R+AOyXLM!ZV3(}d)sR<}6%$}%VG88n
zkWkUomX}hJ7M;pE!-YXePFYP=NmfFbufv^FTt-$_T0%sKv&M~?S43P)R9J|I`G6}2
nD+j-T0ACW@a#v;+1_nkpHpbhGTLOXt+?lRFd-dAek--`OQ*cI4

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/11.gif b/Tp5/minesweeper/icons/11.gif
new file mode 100644
index 0000000000000000000000000000000000000000..51fb6a928424a34021239bbb290456976666bcc1
GIT binary patch
literal 879
zcmZ?wbhEHb6krfw_|5<U)eH>(8LAno85pXotM~5Rd+*-8{|pTO|1<m_1*0J_tV2Kt
zlmkF{fq^50fty3dW5WUm77k&pn1}>LCk8%2lM;@L4_#OU7&ESP7(R6Ekv7-bvm&su
wX@aP#nogzB688xj$*XE4CM!ElG7YX<V_Br?(`Ti;?2V`4qvIW1%uEc{0D652vj6}9

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/12.gif b/Tp5/minesweeper/icons/12.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2854de27bbf73d5d8a9c21db979ab75f144a8a9f
GIT binary patch
literal 658
zcmZ?wbhEHb6lM@+_{IPN%*@Q}?Cjj!+;Vbqii(OVDk`d~syaG4Mmjo%hK5#FR@T<m
zB_$=LrKOdXl~q+$)z#ItwY3{nRQ@wC{9|VR%f|LyMC7}u=yx%(PfAK}jEo)z1Uv{1
zzL}bOv9hwcxq05adAmD07A#n>aN)v*ix)3iv}oy~MN5_}S-pDonl)?Iu3fus-MYPt
z7VTTJX3x5H+qZAuy?OJVO`CRZ-MVZ0_8mKR>;%D`J9qBfwR6{wUAuPf+O=c%?wz}L
z@7lF%*KQElvuDrg&d%c#CLCP6_|T$7$BrF4e*E~clP6D{IC1IHrEg!q{rLXl=Z~L1
zfByXY=kLG2|3H2oG+6N`3)n3>AQBWO4D9b4{F|CvTKxlj%$odsd;9wPyv+ps{k+`V
zXU_DPHPh2lh}YlO&A@cIm9ewF`EpYWO#!~e?(3~>TxFzOtSt7~X>HoF-cVjjL~_qQ
zivx#z-OY_;#Y9e=+JA8Kc~cW7Y0+zYZ=Bm|VWTG}E^+<L&BObwZIy&|AH99DexJQ6
zr@H;=vs<Qq7G+^&5^-eMb^F+wV;ll(4m~R#KAv|VSjR_0LLi}mNmxfi&xR?Rk&%%h
zh)ZFE0_%iU&jv${ga-}2%&ZbCI5s(nO;NQBTB0DhXvIYVm7p~W9}hSxaSAB7%<!6;
Wb!8c!nrXp-t*fuE=VM}Ium%8KhvqW?

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/13.gif b/Tp5/minesweeper/icons/13.gif
new file mode 100644
index 0000000000000000000000000000000000000000..947d01285d2ba0b83ccd14bf3fde61887798ad16
GIT binary patch
literal 648
zcmZ?wbhEHb6lM@+_{PA%#l^+T%PS-#BrGf}Dk>@`C#R^WsI084qN1Xqp`oLrqpPcH
zY;0_4X=!U~>+bIE?d|RB>zkC6l#-HCP*6}(Qc_x4T3K0HRaI46TU%dW-_p|3*4Eb9
z+1cOUKWWmW$&)8fojP^Kj2Sa$&YU}U?)>@l7cN}5Xwjl2OO~u$xpMXD)oa$QS-W=a
z`t|EKZQ8VX^X4sEwrt(Hb^G@1J9g~Yxnt+fojZ5!+_h`huHCzL@7c3w@7}$~jvYIG
z{P>9zCr+I_b?VfqOP4Nv`}*z2_a8rh{QUXz=ifhn|NZ^PFm!<8PZqFabwDI2P8isq
zHn=u5x3s#tIhi!MIQRDT_c@wKxVku4+sw4Jv$waMX=7_9DeCHMZDee0rY$Kfs&2Z<
zR7*l^nT@fjxh5YICo_kl#cu6wJ9e21F^KEQF!G-~w%vKBnE@}iu7xf;x1O2#<rAhx
zO3KC-vW$Y4j$hqnYVlctl}pw9==+_ff6aAy-U(iI?~S*YQRK+EaIs&(vR*@D#fj(n
zGJD!ga~^DH47{_i;**Vog5iaSN9!z2Bz^>3Qr;@JJMTozM5Q*LnHI|=Ig^}^cFnhs
jWZ=zu)YR%CX`m5%s$^v#_hhYz8D3jgg>pACFjxZsaZJjg

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/2.gif b/Tp5/minesweeper/icons/2.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2ef31056ccd581f2df4fe0f10e03f9ae831ac7ef
GIT binary patch
literal 668
zcmZ?wbhEHb6lM@+_{PA%(7?dZ$iUFVz}Upd)WpQp%*4{n!rIKr*22c#!p_;s$<@Ne
z)yl=)%FWZt!`sHo*TyH)B_rD{tJI^U(xal<tE$$krrxKn(W{}`udCOuXFAc;bdss<
z6kEF~c23irT&B6WO?L~L6%;%>IAnH6*zB<IIpGm=BBJL;$Igq5n-`ZfKPhKXPX6Nj
z!X<@8ONvUDmX<9ot65%CyS%n;MO}Ay_nbL%=FXYhu%e-9WmD^_){fO3-K)FjY?!lT
z^OB{Tm#*2iX6?4M>$a_1zis`7?He|2-?VxA<}KT|Y~HbX%Z@EucWm9ZW83x}+qduB
zzGLT(ojZ5#+PQ1@&fU9q?b^L-_nuvQ_U+ooFrYy3Ckxnq9S{kM69)F54W?$zEv;?M
zO+i7ye%^ik{eHn+%|YJA@-nk#&sMPX32F{D<Y8oFSh12}8NW$zv!^s86SJtC><(FB
zCMHHXUo&%OiPhXT{yrxItT^^cxo*%=RnxK$^!LB6&vx#DSx{hb@bw$PcFF>K*|q(r
z-gqDAV<E=8Oi<5l;r;ji!S+hLKB^oSmAOP}gEkyJU6|;g&uP%-bFgj0e10K5A4P_X
z$y`&)IrKvdG#DOD(h3O*ni<mB+7!toH)nyNbDQsM>nSYClNgsVFtKrQ$Z8#Mnjmf7
vB4B)U%SufKk%l`P7CvF^5{cNH<=eQ3b&{9X;jU0guL}z|w`8#}F<1it-)Pab

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/3.gif b/Tp5/minesweeper/icons/3.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4abac7be126376b0b3c7a8dd202c91e51c401810
GIT binary patch
literal 639
zcmZ?wbhEHb6lM@+_{PBSpMl{&BjZ0NroSvKe_2`ova$VPXaCK`^_!df4=3j@Uf%B_
zB0mKMe+UVEla%}-BlAU0?!A`QJ6+w+3JPzGjbEFXyf!tx8y$ToCgx6T>|<~52Z4bP
z0|Orf1>H_axRsQ2D>?aQYU=f@tn1m?*K%{O=I5WUtGirWe6h0fLUna_clYc$Ah3Vs
z%6+R>?_0BG_vX!eHf-3tVZ)w{8+UKnvU}UMUE8;B-?wk)&Yin<?%c6!*UnwLcI@80
zbNB9DyLRo^vuEd?J?9!4&NnoiYivB*+InK*#1oSy9h))Z@Z7nF=g&VfckY2@%MPqq
z!7x~X;!hT^({w;2C{7sI?=)!XXt%Vswd!;>*_oO4^-nOhw6(PBv{n@nn>}Z)l&gj1
zbQy-F%a$+YcekCcARxS9;|88(at@t#hPu1=?AF&{T`Ijs$I{x$+S<ncjJ>%V`%)R}
zPD_jH7DgUkcRW>C4js96-QJm-_XRKKGR5sjZ`f-xtys$9Xn*yC8W+c34(4SB9f!9a
zcAePl+Ec^8kr1^{_Iim)F`KW{)+CdpGdE5YvhgUgd6g<`b9Q0j)CgWw5}<W}quko#
sqP6IPLqd~W^ipn|-29wV&B|rthl|OJE~ZV<;q*GPWo58yBLjmq08zQwi~s-t

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/4.gif b/Tp5/minesweeper/icons/4.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4e942e211f7d29940e2f0868ad8888d6dc396064
GIT binary patch
literal 649
zcmZ?wbhEHb6lM@+_{PA%z|h3N(9FQl!pPXd%-q7n)XKur%F5cx$=Sxm)y~J)&coBe
z%iF=n*C8O#AuQY}D%vF>(Jd#}D=*)xtlX!f(x<B0Z)iBl*m$yu$z*HmskXLL?d+!6
z+fQ?FnC9d(-P?PnukS2>|Je}{bK~RZCnYUNO<kClwy>aJNoD2o?(Xh6bLPyQJ7?a!
zIrHbwnLmGSW8=!^=2a~%t2#SZcXqCsFk$VKDeI<AT|aHw`svfx&zP}()~pSS7HwL(
zbn~)hTb3{1vSP)SRjanHS+jNR+HD&)Y}>G5`{vEtH*emtWy_9j+jeZ<zGK_Ao!htX
z+_7Wl&Ye4V?E(|KcJ1E1YtNot`}XYu1;Bt}#h)x-`*lDhC{7sIpEYP{H@CF5H8%wY
zbO-u+_WSsGPY4KX4)F5}a8s6$l(Mpsm6T9&@t;03$bf^9LDJQdYn`am3hf#G&f<(r
zoJJv*yiAN+x6cUDU^^o35q#*#vFZM{B76BvgU=sk6mt%m9-zW}#?HafnCFPFnR|1P
zwII`HeqkXYLDtV~0w#Le-VO{L4i`il8b3c1?D*Jpv|m8R%45z8#>0)3+-46lHZJO%
z)URM~we#RwCjsvrMk_-!S)&Z2SB7mW(bQe)6KaxpYmX-D@io(r=cQFKJ#pa_*6djj
ZvSmf)WsO@~TsNw`m=Nlu#l*;94FJ{F(dhsH

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/5.gif b/Tp5/minesweeper/icons/5.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9b6b607be42cfbd7aed2dd30c2bafc1ce9d3e4c9
GIT binary patch
literal 418
zcmZ?wbhEHb6lM@+_{zZ0#K6$Zz|g|L(89>r%FNu#!qUdh-p<L{&duG<!_&df-z_fQ
zEg{jTtUTG+c(SSK6m#<_78X;jtfpF9&v192>FGJk$7hzG-|T>Z*@1y`BO>NSN6(9i
znI9WFKQ3-Ta`K{#jK$g6i}Ui9m6mpQch8wKXJtdf%Erc(O--wsn^$*qteZS}{j_Q8
zr%&H7bLOT63pOuVvSrz_Ez6g0S+Qc<h7CKmZQHqh`_7#^cY*LO5ZJwY*PcDQ_wQ!_
z1I3>#U|I)6g8an5w%;Kr(?dt9-D&RHV>wo{&F+3+E3#R4<IQ2lUA~$P4HZ6o3>x<?
z^$H1a@O164nRj5x^|ua3ufF;ntz%#jUnyg2)6v;s*_@Tb#3*58FlDNNNl!~2C(qn@
zJlq2M*71p{$$5<OHo=O5LK`*;3G*^f5D!wd@b>pH*J7U_)@xzi)n%*Aap;Jyy2gcz
z8k$n96C{^pi88U=y?1vT6SLBqzGcgknE4EEnyX36e*E-FPT6>-s@1XMf2=KnoccIa
JoRl~itN|%@qD24z

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/6.gif b/Tp5/minesweeper/icons/6.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2cc9004893ede6904937f1f6c3fdfea9d517e0de
GIT binary patch
literal 660
zcmZ?wbhEHb6lM@+_{PA%(9p!t(9F=-%+S=r*wn(@+{)72%GT1x-qOa=(#F-=&fVJ1
z)7sA8)*;Z=A<*6-*xo7B-YL@2CDGX}*WDx6-K)^ktJu@4(%Yxr*RRt*QMZ4h>7>b)
zlc!iso?<;^s@wD#9@A%f&Y0;nW2X0vnPIc%#LS%+J8ypC`~?{c7v(KpT(Eda;gTiA
zOP1CwU(wy&J!j6GmX)j8SFP?`y}EbJnh9&yP6VNKlh&@Ay<x-LjT`4}+&F*Z#)X?U
zE!wns+2$=Pw`^ItW$UUfTUT%0x@POvwOhAt+`fI&_U+qt?AX3z$M&5&ckBd#T|0N~
z-nnzvu3fu#?b@?z*S=l5_V3=!FbII+PZqE%bU-91P8irfHs~8Px3so3H~ISq_;~d7
z_xl8NHT!!TDag#4JzK%Z+rK%$SdeKM<BAo_m;{XjntfE5n3?&-wr}TKuI$t7CAXPP
z*TwOuvz~;gu(H=a+07g#!GTu-y<Hvbo%b4eoo8m%w6S{f#M;Tvcj4Xp%$$NBJ_?HK
zc)q^3dCTf$zjzD-&wUaN*s$P16Z0>Zg2V3GM|h<L3fBY}I5@PYz4^3phMR8}Kc}ev
zuU`}Rj|wVl^k2yc_{e-rUG<aWg$)azv2n3zO^aYxb#LopV&D*!N(gI{S)X8&dCB=G
gr*OdHSr!WyweRxkUX^*(N^{Br=LF8Z94rjh0PvmatpET3

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/7.gif b/Tp5/minesweeper/icons/7.gif
new file mode 100644
index 0000000000000000000000000000000000000000..aa755b7661dc088e2c73f8650f3b563bd3f2395e
GIT binary patch
literal 420
zcmZ?wbhEHb6lM@+_{zZ0%+TDz(9*)#(#qW0%GTP((bmr0-p<?JA<)q&*x4o8)vMUs
zr_|T4(LdRE@??|AlT9a2v79o^ZrXIm>9hT3&k3G0Cv?ud=y~&E=FN|tKR<5%{Dk=n
zQx+~vTevWN;iAk%i?S9iDOj?kaLLl5rOT_9cXxNsnKNf)<H}X7tJZX_S<|y-{nYgv
zXK&m%XXD0s8#gW7v~|taZELq}Tfc4lrtLen?bxw>$Icx)L15R;T|0My!0uhU_UziV
zcNYT~DE?#t(>fp$<R=EUg9j#Mdgw^CJI(DqmSZ*B?Cyl}Du;D9bdESa@^x(3P@(g!
z!q=uC;cVV|=e-Z}j;_3IEz10Rg4Oc^o5n_46A`9tW+~GkHB0mU3Fh)FIl@L3md<?>
ztu;8Z8F=-r&1d$`(cxyu=F(cSbk+n51HsjdtjZP>md&;>5o>2;5;NJ=zo*|qiFJXX
z!Lj2Tt+luo@aV4JJ<D33cN?e1&0A_#hC)d!3KJ(Tv(}TAkQ7%mzVOD`%Brc+%JSd;
Qe@i$lohEp6Dlk|B03blLf&c&j

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/8.gif b/Tp5/minesweeper/icons/8.gif
new file mode 100644
index 0000000000000000000000000000000000000000..283c520e31c108effb9d477e4359a3654ce8470e
GIT binary patch
literal 427
zcmZ?wbhEHb6lM@+_{zXgTwGjIQc_x4T2@w8US3{NQBhf0SzTRSQ&Uq{SJ&9s*xcOQ
z*4Eb1(b3h_)!p6Q-`_uB!i33_Cr_C&W%~5#vuDqqGiT1+xpU{wpTB6)qUFn%uUxru
z)v8tN)~#E=e*K0G8#Zs=yk*OlZQHhO-@bjvjvYI9?%cI&*Y4fB8K?vlf3kp0(gBem
zKQXYKIMANzp(EAqG<lOtmepL<rI{I8nF_sY!niNGteoYXz@st!cw=)~mZmEc(?Lha
z<?@djJu*Ft4zNooDl{ufFf%dosnpalu}Z54sY|nVboJDW%FUiF+TPhMrY2O-$FY3*
z)DEE>b@9TEjEoK9>dvYHOF4P=?BT2ss1~a&V3AZ-I;kwlGHv0Jz6q12oU7rl7m<;^
zEh93Yf1#T2Qf9Vi&)PeLbJS$HH*VU@E&E1QUR>nouV3Qw@r%6tIAlBwCJAvn^=YVl
JQs7{)1^}Q{kkkMG

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/icons/9.gif b/Tp5/minesweeper/icons/9.gif
new file mode 100644
index 0000000000000000000000000000000000000000..50ac94d02f9e29ba36133da6281c3f0b9b2026ec
GIT binary patch
literal 337
zcmZ?wbhEHb6lM@+_{zXwYisM^;Na-!=;!Ab5fKp|AD@trkeHa5pPye=R#s6_(b(A7
z)YR16+}zR8(b?JA)z#J0(=&DI)M?YEO`kq}=FFM1XV0E9XU^QYbLY>Wzi{EgMT-_K
zUc7kOvSn-5tXa2i-R8}kckbMI=+L3VhYue+c8r1AK=CIF*hn1^3Gx#ITb{!u4;LM&
z-o*lJS1#tvyPz>e*|9=rQfJxeyFoIn=Tn_DXP<w@bwojJ@qH1~YM%Pjw@bgwo#(&)
zV{K}6USo4(Q+-WqXG?8cdw+LvZ)K6Zr0C39vuBG5vP<%F^DJ4qY$-1n3nw!p)A|h?
LH!?CfGFSrugVS!t

literal 0
HcmV?d00001

diff --git a/Tp5/minesweeper/minesweeper.py b/Tp5/minesweeper/minesweeper.py
new file mode 100755
index 0000000..f0ab0dc
--- /dev/null
+++ b/Tp5/minesweeper/minesweeper.py
@@ -0,0 +1,204 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+: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)]
+    """
+    res =[]
+    if x>0:
+        res.append(x-1,y)
+    if x< width-1:
+        res.append(x+1,y)
+    if y>0:
+        res.append(x,y-1)
+    if y<height-1:
+        res.append(x,y+1)
+    return res
+class Minesweeper():
+    """
+    $$$ game = Minesweeper(20, 10, 4)
+    $$$ game.width
+    20
+    $$$ game.height
+    10
+    $$$ game.nbombs
+    4
+    $$$ game == 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
+        """
+        ...
+
+    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')
+
-- 
GitLab