From e5db2853256d1e27c3f6bacef9f2682c2234d8a6 Mon Sep 17 00:00:00 2001 From: Gantchou Koffi <koffi.gantchou.etu@116p12.fil.univ-lille.fr> Date: Tue, 18 Mar 2025 13:26:50 +0100 Subject: [PATCH] TP5 --- tp5_AP/__pycache__/cell.cpython-310.pyc | Bin 0 -> 2846 bytes .../graphicalboard.cpython-310.pyc | Bin 0 -> 4902 bytes .../__pycache__/minesweeper.cpython-310.pyc | Bin 0 -> 7570 bytes tp5_AP/apl1test.py | 89 ++++++ tp5_AP/cell.py | 140 +++++++++ tp5_AP/graphical_main.py | 18 ++ tp5_AP/graphicalboard.py | 174 +++++++++++ tp5_AP/icons/0.gif | Bin 0 -> 99 bytes tp5_AP/icons/1.gif | Bin 0 -> 404 bytes tp5_AP/icons/10.gif | Bin 0 -> 393 bytes tp5_AP/icons/11.gif | Bin 0 -> 879 bytes tp5_AP/icons/12.gif | Bin 0 -> 658 bytes tp5_AP/icons/13.gif | Bin 0 -> 648 bytes tp5_AP/icons/2.gif | Bin 0 -> 668 bytes tp5_AP/icons/3.gif | Bin 0 -> 639 bytes tp5_AP/icons/4.gif | Bin 0 -> 649 bytes tp5_AP/icons/5.gif | Bin 0 -> 418 bytes tp5_AP/icons/6.gif | Bin 0 -> 660 bytes tp5_AP/icons/7.gif | Bin 0 -> 420 bytes tp5_AP/icons/8.gif | Bin 0 -> 427 bytes tp5_AP/icons/9.gif | Bin 0 -> 337 bytes tp5_AP/minesweeper.py | 278 ++++++++++++++++++ tp5_AP/p1.py | 0 23 files changed, 699 insertions(+) create mode 100644 tp5_AP/__pycache__/cell.cpython-310.pyc create mode 100644 tp5_AP/__pycache__/graphicalboard.cpython-310.pyc create mode 100644 tp5_AP/__pycache__/minesweeper.cpython-310.pyc create mode 100644 tp5_AP/apl1test.py create mode 100755 tp5_AP/cell.py create mode 100644 tp5_AP/graphical_main.py create mode 100644 tp5_AP/graphicalboard.py create mode 100644 tp5_AP/icons/0.gif create mode 100644 tp5_AP/icons/1.gif create mode 100644 tp5_AP/icons/10.gif create mode 100644 tp5_AP/icons/11.gif create mode 100644 tp5_AP/icons/12.gif create mode 100644 tp5_AP/icons/13.gif create mode 100644 tp5_AP/icons/2.gif create mode 100644 tp5_AP/icons/3.gif create mode 100644 tp5_AP/icons/4.gif create mode 100644 tp5_AP/icons/5.gif create mode 100644 tp5_AP/icons/6.gif create mode 100644 tp5_AP/icons/7.gif create mode 100644 tp5_AP/icons/8.gif create mode 100644 tp5_AP/icons/9.gif create mode 100644 tp5_AP/minesweeper.py create mode 100644 tp5_AP/p1.py 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 GIT binary patch literal 2846 zcmd1j<>g{vU|{$$WqtZbP6md@APzESW?*1&U|?V<Heq03NMVR#aA!ziOkrwaNMUMb ziegM<N@31sDw0THNny=lj$%$_Uci#VwvdsLA%!&<j5XP-oVcuV^HZ!6l2dbX5)^Xt zQ%ZAExwxznOG`5Hi>wr~^V8BY719&)N|H13OS!nLQW8s2trQH6^$m>ljSP%TxwyEJ zk=+Dh!`)@Yz`&5o5XG3n5XA&>Srl^$a|%lfLljF2YYJNnLlkQYdkRMjLlj#IXDWLd zQwmoKcMD4tM+#3cgC_4S7U$HQoMc9jp->EBGchnQID`Bx2J$y!4MRLb3W#J(VX9$> zXG&oXX3%6wEMsI~;8K8s%)HE!%*33`s#JwUg}l^qg^bLUl+-*0khc}`(-aaFax?Q% zi_23}3sQ^Jixtv~GE?;6x>GAMi%U}Tl2ai{lk#(ubQJPRbCXhwKq4T1u|j5^LSAZS zdPY)yQAU1#3S4tWVp*y}Nxni-szPx|Vo7R>LQY~yY7xS8xXOZ})a3lUl+2RM{5&g# zy!^aWxRh%}Vs1fBYOxg;Tu4Pl1>}4MTLn-cX=tKL=w%kigIop|cT3DEMwkfI4pLQ= zT9%ralZtRMc9nS`(~9FW^Ww4k(*R-7OHgF_X)@nphq~bwcV=-s%$i$b*iBl=c#EYt zH79K)LlFl91H&&9{fzwFRQ()7eQ+w&gQY^f)RIztm;B_?+|<01V*Qc=(|E@KeNas5 z6;$5hh>r(Fc6_`5D21>wFfgzQvN3WoR`G&@Ne?EQ3`$5KXM!+@4NA1&L?y()z)-`$ z!jQ#~!f4LG1WH^?!3>(riQdQw%Bm=}q_il{O2H2~nyiX5Q&JUD)6!CtORN+!^OB2F zL5@@?$w(!XUO)*6<a>B1QaLqX4|BL}h}eTCjJ)Kcct|3T&rbs<C5*_&lIjT9V+gnL zB`DPWG#QIn85kIfKoJFwb_l`Az`$@z1r&gUoS+JdW>ASB#9yTej$&eTVMIU31W@#U z1{JyB(u5%e9PL#P;4aS1PsvQHRDh&oNM@#WtRZC^xHGWlPKc|pL<lw`LW)WeB|!)% z5?F9W0vp6&OIR>-@m6tzgBc=@Ga!q285kHenX4|t-Ca;xqL8QnDnvkKB`B>cAWAbT zr*>$$1GgJ{m=&j%fYUYhPy@LXZUAP8feH+)$(93VtQS1Y_@Jc^Oy(9Fr1-!Ydc|_! zQYed|m^Fnln4yLti?N6clpsr(Y8bMZn;F3+(k84WQldg}Nl|8Ax<XNEK~ZXPYF<eq zs78S$RY<~xd(5h+q_QB@3Zw@vMpR@#YgPrgE@;7ly+SH3Dbh$z&Cyh_wN+48P={+m z30J5IdXS`r7Aq(w7!WXlm@)vL`Gy3{heaelGn{ak@rzO67Ne6UOA$EFfs)ZJ=Hikf z+~pv9e0*_9QG9$9C_RD7CpHllMm8oEMlPl*9&lcSD)7_f1l50eiMgrq@wd3*<8#67 zx%l{7Jn`{`rHMHZnIe!GMLeJ!&j%v-L4+`f5CIXO$`?`!gIS=WxCm5MgVYv-ba60n zFmZ@-h;RrB34molmgXjA=EcVsfyz<8Dt2gXtjT(dJw84qKRG@gtguKFRIYO*7UUR~ pq!yRlVh54A`6)=&!R@@oVFPi#9msO9#VpKxTpW2EjC_nN{{SK_s(Jtb literal 0 HcmV?d00001 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 GIT binary patch literal 4902 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 B`H=ts literal 0 HcmV?d00001 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 GIT binary patch literal 7570 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 Ba9RKW literal 0 HcmV?d00001 diff --git a/tp5_AP/apl1test.py b/tp5_AP/apl1test.py new file mode 100644 index 0000000..8533cca --- /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 0000000..586daa5 --- /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 0000000..d57cc9f --- /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 0000000..7b353af --- /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 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_AP/icons/1.gif b/tp5_AP/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_AP/icons/10.gif b/tp5_AP/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_AP/icons/11.gif b/tp5_AP/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_AP/icons/12.gif b/tp5_AP/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_AP/icons/13.gif b/tp5_AP/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_AP/icons/2.gif b/tp5_AP/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_AP/icons/3.gif b/tp5_AP/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_AP/icons/4.gif b/tp5_AP/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_AP/icons/5.gif b/tp5_AP/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_AP/icons/6.gif b/tp5_AP/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_AP/icons/7.gif b/tp5_AP/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_AP/icons/8.gif b/tp5_AP/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_AP/icons/9.gif b/tp5_AP/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_AP/minesweeper.py b/tp5_AP/minesweeper.py new file mode 100644 index 0000000..f8a9772 --- /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 0000000..e69de29 -- GitLab