Skip to content
Merged
Binary file added PyGamesScripts/Minesweeper/Images/GameOver.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PyGamesScripts/Minesweeper/Images/Input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions PyGamesScripts/Minesweeper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Minesweeper Game
- Minesweeper Game is a python program i.e, developed in python programming language using random module and some user inputs.

### About the game
- It's a basic python program which takes the random input as row and column, and iterate it over the game .

### How to play?
- Just run the program and enter any row and column .
- Step 1: create the board and plant the bombs
- Step 2: show the user the board and ask for where they want to dig
- Step 3a: if location is a bomb, show game over message
- Step 3b: if location is not a bomb, dig recursively until each square is at least next to a bomb
- Step 4: repeat steps 2 and 3a/b until there are no more places to dig -> VICTORY!


### Setup instructions
1. Install Python 3.x (recommended) from <a href="https://www.python.org/downloads/">here</a>
2. Download this repository as zip and extract.
3. Use Python IDLE or PyCharm to run the program.
4. Run the code and start taking input as Row and Column.<br>
5. Have fun!!


### Output
![GameOver](Images/GameOver.png)
![Input](Images/Input.png)


### Author👨‍
[Shubhankar Poddar](https://github.com/codeaholic-shub)
204 changes: 204 additions & 0 deletions PyGamesScripts/Minesweeper/minesweeper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import random
import re


# lets create a board object to represent the minesweeper game
# this is so that we can just say "create a new board object", or
# "dig here", or "render this game for this object"
class Board:
def __init__(self, dim_size, num_bombs):
# let's keep track of these parameters. they'll be helpful later
self.dim_size = dim_size
self.num_bombs = num_bombs

# let's create the board
# helper function!
self.board = self.make_new_board() # plant the bombs
self.assign_values_to_board()

# initialize a set to keep track of which locations we've uncovered
# we'll save (row,col) tuples into this set
self.dug = set() # if we dig at 0, 0, then self.dug = {(0,0)}

def make_new_board(self):
# construct a new board based on the dim size and num bombs
# we should construct the list of lists here (or whatever representation you prefer,
# but since we have a 2-D board, list of lists is most natural)

# generate a new board
board = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
# this creates an array like this:
# [[None, None, ..., None],
# [None, None, ..., None],
# [... ],
# [None, None, ..., None]]
# we can see how this represents a board!

# plant the bombs
bombs_planted = 0
while bombs_planted < self.num_bombs:
loc = random.randint(0, self.dim_size ** 2 - 1) # return a random integer N such that a <= N <= b
row = loc // self.dim_size # we want the number of times dim_size goes into loc to tell us what row to look at
col = loc % self.dim_size # we want the remainder to tell us what index in that row to look at

if board[row][col] == '*':
# this means we've actually planted a bomb there already so keep going
continue

board[row][col] = '*' # plant the bomb
bombs_planted += 1

return board

def assign_values_to_board(self):
# now that we have the bombs planted, let's assign a number 0-8 for all the empty spaces, which
# represents how many neighboring bombs there are. we can precompute these and it'll save us some
# effort checking what's around the board later on :)
for r in range(self.dim_size):
for c in range(self.dim_size):
if self.board[r][c] == '*':
# if this is already a bomb, we don't want to calculate anything
continue
self.board[r][c] = self.get_num_neighboring_bombs(r, c)

def get_num_neighboring_bombs(self, row, col):
# let's iterate through each of the neighboring positions and sum number of bombs
# top left: (row-1, col-1)
# top middle: (row-1, col)
# top right: (row-1, col+1)
# left: (row, col-1)
# right: (row, col+1)
# bottom left: (row+1, col-1)
# bottom middle: (row+1, col)
# bottom right: (row+1, col+1)

# make sure to not go out of bounds!

num_neighboring_bombs = 0
for r in range(max(0, row - 1), min(self.dim_size - 1, row + 1) + 1):
for c in range(max(0, col - 1), min(self.dim_size - 1, col + 1) + 1):
if r == row and c == col:
# our original location, don't check
continue
if self.board[r][c] == '*':
num_neighboring_bombs += 1

return num_neighboring_bombs

def dig(self, row, col):
# dig at that location!
# return True if successful dig, False if bomb dug

# a few scenarios:
# hit a bomb -> game over
# dig at location with neighboring bombs -> finish dig
# dig at location with no neighboring bombs -> recursively dig neighbors!

self.dug.add((row, col)) # keep track that we dug here

if self.board[row][col] == '*':
return False
elif self.board[row][col] > 0:
return True

# self.board[row][col] == 0
for r in range(max(0, row - 1), min(self.dim_size - 1, row + 1) + 1):
for c in range(max(0, col - 1), min(self.dim_size - 1, col + 1) + 1):
if (r, c) in self.dug:
continue # don't dig where you've already dug
self.dig(r, c)

# if our initial dig didn't hit a bomb, we *shouldn't* hit a bomb here
return True

def __str__(self):
# this is a magic function where if you call print on this object,
# it'll print out what this function returns!
# return a string that shows the board to the player

# first let's create a new array that represents what the user would see
visible_board = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
for row in range(self.dim_size):
for col in range(self.dim_size):
if (row, col) in self.dug:
visible_board[row][col] = str(self.board[row][col])
else:
visible_board[row][col] = ' '

# put this together in a string
string_rep = ''
# get max column widths for printing
widths = []
for idx in range(self.dim_size):
columns = map(lambda x: x[idx], visible_board)
widths.append(
len(
max(columns, key=len)
)
)

# print the csv strings
indices = [i for i in range(self.dim_size)]
indices_row = ' '
cells = []
for idx, col in enumerate(indices):
format = '%-' + str(widths[idx]) + "s"
cells.append(format % (col))
indices_row += ' '.join(cells)
indices_row += ' \n'

for i in range(len(visible_board)):
row = visible_board[i]
string_rep += f'{i} |'
cells = []
for idx, col in enumerate(row):
format = '%-' + str(widths[idx]) + "s"
cells.append(format % (col))
string_rep += ' |'.join(cells)
string_rep += ' |\n'

str_len = int(len(string_rep) / self.dim_size)
string_rep = indices_row + '-' * str_len + '\n' + string_rep + '-' * str_len

return string_rep


# play the game
def play(dim_size=10, num_bombs=10):
# Step 1: create the board and plant the bombs
board = Board(dim_size, num_bombs)

# Step 2: show the user the board and ask for where they want to dig
# Step 3a: if location is a bomb, show game over message
# Step 3b: if location is not a bomb, dig recursively until each square is at least
# next to a bomb
# Step 4: repeat steps 2 and 3a/b until there are no more places to dig -> VICTORY!
safe = True

while len(board.dug) < board.dim_size ** 2 - num_bombs:
print(board)
# 0,0 or 0, 0 or 0, 0
user_input = re.split(',(\\s)*', input("Where would you like to dig? Input as row,col: ")) # '0, 3'
row, col = int(user_input[0]), int(user_input[-1])
if row < 0 or row >= board.dim_size or col < 0 or col >= dim_size:
print("Invalid location. Try again.")
continue

# if it's valid, we dig
safe = board.dig(row, col)
if not safe:
# dug a bomb ahhhhhhh
break # (game over rip)

# 2 ways to end loop, lets check which one
if safe:
print("CONGRATULATIONS!!!! YOU ARE VICTORIOUS!")
else:
print("SORRY GAME OVER :(")
# let's reveal the whole board!
board.dug = [(r, c) for r in range(board.dim_size) for c in range(board.dim_size)]
print(board)


if __name__ == '__main__': # good practice :)
play()
1 change: 1 addition & 0 deletions PyGamesScripts/Minesweeper/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
libraries used : random, re