From 578983a5de699647c12295a8ea460aa2b558f23f Mon Sep 17 00:00:00 2001 From: Galamian <63856130+galamian@users.noreply.github.com> Date: Sat, 22 Mar 2025 15:06:06 +0100 Subject: [PATCH 1/5] reuse boardClass in GUI --- minesweeper.py | 16 ++++++++-- minesweeperGUI.py | 77 ++--------------------------------------------- requirements.txt | 3 +- 3 files changed, 18 insertions(+), 78 deletions(-) diff --git a/minesweeper.py b/minesweeper.py index 0595dd8..30ff810 100644 --- a/minesweeper.py +++ b/minesweeper.py @@ -1,4 +1,5 @@ import random +import numpy as np class boardSpot(object): @@ -19,10 +20,17 @@ def isMine(self): class boardClass(object): - def __init__(self, m_boardSize, m_numMines): + def __init__(self, m_boardSize: int, m_numMines: int, dim: int=2): + if dim > 2: + raise ValueError(f"Only one or two dimensions supported, got {dim}") + self.board = [[boardSpot() for i in range(m_boardSize)] for j in range(m_boardSize)] self.boardSize = m_boardSize self.numMines = m_numMines + self.shape = (m_boardSize,) * dim + + self.values = np.zeros(self.shape) + self.selectableSpots = m_boardSize * m_boardSize - m_numMines i = 0 while i < m_numMines: @@ -102,9 +110,10 @@ def isWinner(self): def playGame(): boardSize = int(input("Choose the Width of the board: ")) numMines = int(input("Choose the number of mines: ")) + dim = int(input("Choose dimensions of board.")) gameOver = False winner = False - Board = boardClass(boardSize, numMines) + Board = boardClass(boardSize, numMines, dim=dim) while not gameOver: print(Board) print("Make your move:") @@ -122,4 +131,5 @@ def playGame(): else: print("You hit a mine, Game Over!") -playGame() +if __name__ == "__main__": + playGame() diff --git a/minesweeperGUI.py b/minesweeperGUI.py index 4b2f546..78f0fc9 100644 --- a/minesweeperGUI.py +++ b/minesweeperGUI.py @@ -1,41 +1,10 @@ import random import eel +from minesweeper import boardClass -class boardSpot(object): - value = 0 - selected = False - mine = False - - def __init__(self): - self.selected = False - - def __str__(self): - return str(boardSpot.value) - - def isMine(self): - if boardSpot.value == -1: - return True - return False - - -class boardClass(object): - def __init__(self, m_boardSize, m_numMines): - self.board = [[boardSpot() for i in range(m_boardSize)] - for j in range(m_boardSize)] - self.boardSize = m_boardSize - self.numMines = m_numMines - self.selectableSpots = m_boardSize * m_boardSize - m_numMines - i = 0 - while i < m_numMines: - x = random.randint(0, self.boardSize-1) - y = random.randint(0, self.boardSize-1) - if not self.board[x][y].mine: - self.addMine(x, y) - i += 1 - else: - i -= 1 +class GUIBoardClass(boardClass): def __str__(self): returnString = "" for y in range(0, self.boardSize): @@ -51,46 +20,6 @@ def __str__(self): returnString += "E" return returnString - def addMine(self, x, y): - self.board[x][y].value = -1 - self.board[x][y].mine = True - for i in range(x-1, x+2): - if i >= 0 and i < self.boardSize: - if y-1 >= 0 and not self.board[i][y-1].mine: - self.board[i][y-1].value += 1 - if y+1 < self.boardSize and not self.board[i][y+1].mine: - self.board[i][y+1].value += 1 - if x-1 >= 0 and not self.board[x-1][y].mine: - self.board[x-1][y].value += 1 - if x+1 < self.boardSize and not self.board[x+1][y].mine: - self.board[x+1][y].value += 1 - - def makeMove(self, x, y): - self.board[x][y].selected = True - self.selectableSpots -= 1 - if self.board[x][y].value == -1: - return False - if self.board[x][y].value == 0: - for i in range(x-1, x+2): - if i >= 0 and i < self.boardSize: - if y-1 >= 0 and not self.board[i][y-1].selected: - self.makeMove(i, y-1) - if y+1 < self.boardSize and not self.board[i][y+1].selected: - self.makeMove(i, y+1) - if x-1 >= 0 and not self.board[x-1][y].selected: - self.makeMove(x-1, y) - if x+1 < self.boardSize and not self.board[x+1][y].selected: - self.makeMove(x+1, y) - return True - else: - return True - - def hitMine(self, x, y): - return self.board[x][y].value == -1 - - def isWinner(self): - return self.selectableSpots == 0 - #### For UI #### eel.init('.//UI') # path of the webpage folder @@ -124,7 +53,7 @@ def clickedOnTheCell(x, y): def makeBoard(boardSize, numMines): global BOARD del BOARD - BOARD = boardClass(boardSize, numMines) + BOARD = GUIBoardClass(boardSize, numMines) web_app_options = { diff --git a/requirements.txt b/requirements.txt index b81a462..2abcaf0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -eel==0.14.0 \ No newline at end of file +eel==0.14.0 +numpy==2.2.4 \ No newline at end of file From 53cbf9eed54a1994c3a4620dfb27c16d8fd7c5c9 Mon Sep 17 00:00:00 2001 From: Galamian <63856130+galamian@users.noreply.github.com> Date: Sat, 22 Mar 2025 17:29:11 +0100 Subject: [PATCH 2/5] use numpy --- minesweeper.py | 101 +++++++++++++++++++++------------------------- minesweeperGUI.py | 6 +-- 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/minesweeper.py b/minesweeper.py index 30ff810..5b41d12 100644 --- a/minesweeper.py +++ b/minesweeper.py @@ -1,46 +1,42 @@ import random import numpy as np - -class boardSpot(object): - value = 0 - selected = False - mine = False - - def __init__(self): - self.selected = False - - def __str__(self): - return str(boardSpot.value) - - def isMine(self): - if boardSpot.value == -1: - return True - return False - - class boardClass(object): def __init__(self, m_boardSize: int, m_numMines: int, dim: int=2): if dim > 2: raise ValueError(f"Only one or two dimensions supported, got {dim}") - self.board = [[boardSpot() for i in range(m_boardSize)] for j in range(m_boardSize)] self.boardSize = m_boardSize self.numMines = m_numMines self.shape = (m_boardSize,) * dim - self.values = np.zeros(self.shape) + self.values = np.zeros(self.shape, dtype=int) - self.selectableSpots = m_boardSize * m_boardSize - m_numMines - i = 0 - while i < m_numMines: - x = random.randint(0, self.boardSize-1) - y = random.randint(0, self.boardSize-1) - if not self.board[x][y].mine: - self.addMine(x, y) - i += 1 - else: - i -= 1 + mine_indices = np.array(np.unravel_index(np.random.choice(self.values.size, size=m_numMines, replace=False), self.values.shape)) + + self.values[*mine_indices] = -1 + + self.selected = np.zeros(shape=self.values.shape, dtype=bool) + + + for m in range(mine_indices.shape[-1]): + mine_index = mine_indices[:, m] + current_index = mine_index.copy() + for k in range(dim): + for a in [-1, 0, 1]: + if mine_index[k] + a >= self.values.shape[k] or mine_index[k] + a < 0: + continue + current_index[k] = mine_index[k] + a + for j in range(k): + for b in [-1, 0, 1]: + if mine_index[j] + b >= self.values.shape[j] or mine_index[j] + b < 0: + continue + current_index[j] = mine_index[j] + b + self.values[*current_index] += 1 if self.values[*current_index] >= 0 else 0 + + + + self.selectableSpots = (m_boardSize ** dim) - m_numMines def __str__(self): returnString = " " @@ -55,56 +51,49 @@ def __str__(self): for y in range(0, self.boardSize): returnString += str(y) for x in range(0, self.boardSize): - if self.board[x][y].mine and self.board[x][y].selected: - returnString += " |" + str(self.board[x][y].value) - elif self.board[x][y].selected: - returnString += " | " + str(self.board[x][y].value) + if self.values[x, y] < 0 and self.selected[x, y]: + returnString += " |" + str(self.values[x, y]) + elif self.selected[x, y]: + returnString += " | " + str(self.values[x, y]) else: returnString += " | " returnString += " |" returnString += divider return returnString - def addMine(self, x, y): - self.board[x][y].value = -1 - self.board[x][y].mine = True - for i in range(x-1, x+2): - if i >= 0 and i < self.boardSize: - if y-1 >= 0 and not self.board[i][y-1].mine: - self.board[i][y-1].value += 1 - if y+1 < self.boardSize and not self.board[i][y+1].mine: - self.board[i][y+1].value += 1 - if x-1 >= 0 and not self.board[x-1][y].mine: - self.board[x-1][y].value += 1 - if x+1 < self.boardSize and not self.board[x+1][y].mine: - self.board[x+1][y].value += 1 - def makeMove(self, x, y): - self.board[x][y].selected = True + self.selected[x, y] = True self.selectableSpots -= 1 - if self.board[x][y].value == -1: + if self.values[x, y] == -1: return False - if self.board[x][y].value == 0: + if self.values[x, y] == 0: for i in range(x-1, x+2): if i >= 0 and i < self.boardSize: - if y-1 >= 0 and not self.board[i][y-1].selected: + if y-1 >= 0 and not self.selected[i, y-1]: self.makeMove(i, y-1) - if y+1 < self.boardSize and not self.board[i][y+1].selected: + if y+1 < self.boardSize and not self.selected[i, y+1]: self.makeMove(i, y+1) - if x-1 >= 0 and not self.board[x-1][y].selected: + if x-1 >= 0 and not self.selected[x-1,y]: self.makeMove(x-1, y) - if x+1 < self.boardSize and not self.board[x+1][y].selected: + if x+1 < self.boardSize and not self.selected[x+1, y]: self.makeMove(x+1, y) return True else: return True def hitMine(self, x, y): - return self.board[x][y].value == -1 + return self.values[x, y] == -1 def isWinner(self): return self.selectableSpots == 0 +def increment_tuple(t: tuple, index: int = 0, value: int = 1) -> tuple: + if not t or index < 0 or index >= len(t): + return t # Return original tuple if empty or index is out of range + + t_list = list(t) + t_list[index] += value + return tuple(t_list) #play game def playGame(): diff --git a/minesweeperGUI.py b/minesweeperGUI.py index 78f0fc9..e1616df 100644 --- a/minesweeperGUI.py +++ b/minesweeperGUI.py @@ -10,12 +10,12 @@ def __str__(self): for y in range(0, self.boardSize): # returnString += str(y) for x in range(0, self.boardSize): - if self.board[x][y].mine and self.board[x][y].selected: + if self.values[x, y] == -1 and self.selected[x, y]: returnString += 'B' # returnString += str(self.board[x][y].value) - elif self.board[x][y].selected: - returnString += str(self.board[x][y].value) + elif self.selected[x, y]: + returnString += str(self.values[x, y]) else: # empthy cell returnString += "E" return returnString From fb1d24366cfcbff51c60b840124a49f21828f21b Mon Sep 17 00:00:00 2001 From: Galamian <63856130+galamian@users.noreply.github.com> Date: Sat, 22 Mar 2025 18:56:41 +0100 Subject: [PATCH 3/5] add possibility to show the field open --- UI/app.js | 3 +- UI/index.html | 2 ++ __pycache__/minesweeper.cpython-312.pyc | Bin 0 -> 7425 bytes minesweeper.py | 39 +++++++++++++++--------- minesweeperGUI.py | 20 ++++++++++-- 5 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 __pycache__/minesweeper.cpython-312.pyc diff --git a/UI/app.js b/UI/app.js index 19d2553..c75b44d 100644 --- a/UI/app.js +++ b/UI/app.js @@ -9,6 +9,7 @@ function startNew(mode) { // hard -> 18X32=576 -> 100 bombs | 24 -> 100 bombs // extreme-> 26X50=1300 -> 220 bombs | 30 -> 200 bombs // const mode = element.value; + isOpen = document.getElementById('isOpen').checked; if (mode === "easy") { size = 10; bombs = 15; @@ -32,7 +33,7 @@ function startNew(mode) { document.getElementById("h1").classList.remove("won"); document.getElementById("h1").classList.remove("lost"); document.getElementById("h1").innerHTML = `Minesweeper`; - eel.makeBoard(size, bombs)(); //size, bombs + eel.makeBoard(size, bombs, isOpen)(); //size, bombs drawFirst(); } diff --git a/UI/index.html b/UI/index.html index a7d8222..dcad8c1 100644 --- a/UI/index.html +++ b/UI/index.html @@ -11,6 +11,8 @@
3yMwW$;;Z16+Vf0BgOSxmxFBT7+RA~Xua?ru_o
zOQQ9*D1LX7can_aQOvh#L<|erqIf?ZB_qIVY>$#0ezgmXS0w3+1WOPlKg9ly(8u~q
zJW9YfIVqAump53XQ~5HA4Vv;bosx=m>K>_U4rAtI{?RdEOKndD<&^1M_b7uLWKlI4
z UU%dU!+&h`d0}yp~f7-p|S$chG^vj;5y_xpY+dg_w)x2&4>Fai^
zxFlY3Q;hq6KAxmLcHD8K{0sPeV8N5(m)Z7gaoMb6#sRwFbAe>rO7WhovsmT7IQ!1b
zJIl^`h@rdZyB9r+9beP~p6y+3>L~D$tMZ|%^1D!lU`mB56zT00Xd2)JN1y?&62eQg
zHN3dG3*b^(54HS?i)c)Jtrhb?P(s(PEuL$$tq&N*YRIOrtQKK{C-5iQQIL5|cJ56x
zd%qiG0>o%qvq0>mH3XchuEIfJ0!7t5+Xl2T0A_;XrC=z;3tRT0-uN!!Mjl;NZq->2
zQ7_zEoQ-LwQPt`^jH{jtJGwlE{KLG@r&xWy;V?HgglN0ZH#+7Y(s~5+$|j&kFrgVT
zg&7gTa1E6vwBP_eNvP*SIEtuakj-PN812ZQ10 3yMwW$;;Z16+Vf0BgOSxmxFBT7+RA~Xua?ru_o
zOQQ9*D1LX7can_aQOvh#L<|erqIf?ZB_qIVY>$#0ezgmXS0w3+1WOPlKg9ly(8u~q
zJW9YfIVqAump53XQ~5HA4Vv;bosx=m>K>_U4rAtI{?RdEOKndD<&^1M_b7uLWKlI4
z UU%dU!+&h`d0}yp~f7-p|S$chG^vj;5y_xpY+dg_w)x2&4>Fai^
zxFlY3Q;hq6KAxmLcHD8K{0sPeV8N5(m)Z7gaoMb6#sRwFbAe>rO7WhovsmT7IQ!1b
zJIl^`h@rdZyB9r+9beP~p6y+3>L~D$tMZ|%^1D!lU`mB56zT00Xd2)JN1y?&62eQg
zHN3dG3*b^(54HS?i)c)Jtrhb?P(s(PEuL$$tq&N*YRIOrtQKK{C-5iQQIL5|cJ56x
zd%qiG0>o%qvq0>mH3XchuEIfJ0!7t5+Xl2T0A_;XrC=z;3tRT0-uN!!Mjl;NZq->2
zQ7_zEoQ-LwQPt`^jH{jtJGwlE{KLG@r&xWy;V?HgglN0ZH#+7Y(s~5+$|j&kFrgVT
zg&7gTa1E6vwBP_eNvP*SIEtuakj-PN812ZQ10Hb`Y*XRZE+pRjGt})x;6`-mM`PM^54#HAxtPxq^YzAfu0!
zFF6{8aJnNCI;C8=!Hb`Y*XRZE+pRjGt})x;6`-mM`PM^54#HAxtPxq^YzAfu0!
zFF6{8aJnNCI;C8=!