Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
*.py[cod]
3 changes: 2 additions & 1 deletion UI/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
}

Expand Down
2 changes: 2 additions & 0 deletions UI/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<body id="body" oncontextmenu="return false;">
<h1 id="h1">Minesweeper</h1>

<input type="checkbox" id="isOpen" checked=true class="checkbox">Show Open</input>

<div class="board" id="board"></div>
<div class="btnContainer">
<input
Expand Down
139 changes: 73 additions & 66 deletions minesweeper.py
Original file line number Diff line number Diff line change
@@ -1,118 +1,124 @@
import random


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

import numpy as np

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
def __init__(self, m_boardSize: int | tuple[int, ...], m_numMines: int, dim: int=2):
if isinstance(m_boardSize, tuple):
dim = len(m_boardSize)
self.shape = m_boardSize
else:
self.shape = (m_boardSize,) * dim

if dim > 2:
raise ValueError(f"Only one or two dimensions supported, got {dim}")

self.dim = dim
self.numMines = m_numMines

self.values = np.zeros(self.shape, dtype=int)
self.selected = np.zeros(shape=self.values.shape, dtype=bool)

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

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 = self.values.size - m_numMines

@property
def boardSize(self):
return self.values.shape[0] # TODO generalize

def __str__(self):
if self.dim > 2:
raise ValueError(f"Only one or two dimensions supported, got {self.dim}")
returnString = " "
divider = "\n---"

for i in range(0, self.boardSize):
returnString += " | " + str(i)
divider += "----"
divider += "\n"
if len(self.values.shape > 1):

for i in range(0, self.values.shape[0]):
returnString += " | " + str(i)
divider += "----"
divider += "\n"

returnString += divider
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():
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:")
x = int(input("x: "))
y = int(input("y: "))
Board.makeMove(x, y)
gameOver = Board.hitMine(x, y)
if Board.isWinner() and gameOver == False:
if Board.isWinner() and gameOver is False:
gameOver = True
winner = True

Expand All @@ -122,4 +128,5 @@ def playGame():
else:
print("You hit a mine, Game Over!")

playGame()
if __name__ == "__main__":
playGame()
102 changes: 23 additions & 79 deletions minesweeperGUI.py
Original file line number Diff line number Diff line change
@@ -1,95 +1,36 @@
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):
# 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

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

class OpenGUIBoardClass(boardClass):
def __str__(self):
returnString = ""
for y in range(0, self.boardSize):
# returnString += str(y)
for x in range(0, self.boardSize):
if self.values[x, y] == -1:
returnString += str(0)
else:
returnString += str(self.values[x, y])
return returnString


#### For UI ####
Expand All @@ -109,7 +50,7 @@ def clickedOnTheCell(x, y):
if GO_IN:
BOARD.makeMove(x, y)
GAME_OVER = BOARD.hitMine(x, y)
if BOARD.isWinner() and GAME_OVER == False:
if BOARD.isWinner() and GAME_OVER is False:
GAME_OVER = True
WINNER = True
print("Won")
Expand All @@ -121,10 +62,13 @@ def clickedOnTheCell(x, y):


@eel.expose
def makeBoard(boardSize, numMines):
def makeBoard(boardSize, numMines, isOpen=False):
global BOARD
del BOARD
BOARD = boardClass(boardSize, numMines)
if isOpen:
BOARD = OpenGUIBoardClass(boardSize, numMines)
else:
BOARD = GUIBoardClass(boardSize, numMines) # noqa: F841


web_app_options = {
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
eel==0.14.0
eel==0.14.0
numpy==2.2.4