Skip to content

Instantly share code, notes, and snippets.

@mohd-akram
Last active May 4, 2022 03:49
Show Gist options
  • Save mohd-akram/3057736 to your computer and use it in GitHub Desktop.
Save mohd-akram/3057736 to your computer and use it in GitHub Desktop.
A command line version of Minesweeper in Python
"""A command line version of Minesweeper"""
import random
import re
import time
from string import ascii_lowercase
def setupgrid(gridsize, start, numberofmines):
emptygrid = [['0' for i in range(gridsize)] for i in range(gridsize)]
mines = getmines(emptygrid, start, numberofmines)
for i, j in mines:
emptygrid[i][j] = 'X'
grid = getnumbers(emptygrid)
return (grid, mines)
def showgrid(grid):
gridsize = len(grid)
horizontal = ' ' + (4 * gridsize * '-') + '-'
# Print top column letters
toplabel = ' '
for i in ascii_lowercase[:gridsize]:
toplabel = toplabel + i + ' '
print(toplabel + '\n' + horizontal)
# Print left row numbers
for idx, i in enumerate(grid):
row = '{0:2} |'.format(idx + 1)
for j in i:
row = row + ' ' + j + ' |'
print(row + '\n' + horizontal)
print('')
def getrandomcell(grid):
gridsize = len(grid)
a = random.randint(0, gridsize - 1)
b = random.randint(0, gridsize - 1)
return (a, b)
def getneighbors(grid, rowno, colno):
gridsize = len(grid)
neighbors = []
for i in range(-1, 2):
for j in range(-1, 2):
if i == 0 and j == 0:
continue
elif -1 < (rowno + i) < gridsize and -1 < (colno + j) < gridsize:
neighbors.append((rowno + i, colno + j))
return neighbors
def getmines(grid, start, numberofmines):
mines = []
neighbors = getneighbors(grid, *start)
for i in range(numberofmines):
cell = getrandomcell(grid)
while cell == start or cell in mines or cell in neighbors:
cell = getrandomcell(grid)
mines.append(cell)
return mines
def getnumbers(grid):
for rowno, row in enumerate(grid):
for colno, cell in enumerate(row):
if cell != 'X':
# Gets the values of the neighbors
values = [grid[r][c] for r, c in getneighbors(grid,
rowno, colno)]
# Counts how many are mines
grid[rowno][colno] = str(values.count('X'))
return grid
def showcells(grid, currgrid, rowno, colno):
# Exit function if the cell was already shown
if currgrid[rowno][colno] != ' ':
return
# Show current cell
currgrid[rowno][colno] = grid[rowno][colno]
# Get the neighbors if the cell is empty
if grid[rowno][colno] == '0':
for r, c in getneighbors(grid, rowno, colno):
# Repeat function for each neighbor that doesn't have a flag
if currgrid[r][c] != 'F':
showcells(grid, currgrid, r, c)
def playagain():
choice = input('Play again? (y/n): ')
return choice.lower() == 'y'
def parseinput(inputstring, gridsize, helpmessage):
cell = ()
flag = False
message = "Invalid cell. " + helpmessage
pattern = r'([a-{}])([0-9]+)(f?)'.format(ascii_lowercase[gridsize - 1])
validinput = re.match(pattern, inputstring)
if inputstring == 'help':
message = helpmessage
elif validinput:
rowno = int(validinput.group(2)) - 1
colno = ascii_lowercase.index(validinput.group(1))
flag = bool(validinput.group(3))
if -1 < rowno < gridsize:
cell = (rowno, colno)
message = ''
return {'cell': cell, 'flag': flag, 'message': message}
def playgame():
gridsize = 9
numberofmines = 10
currgrid = [[' ' for i in range(gridsize)] for i in range(gridsize)]
grid = []
flags = []
starttime = 0
helpmessage = ("Type the column followed by the row (eg. a5). "
"To put or remove a flag, add 'f' to the cell (eg. a5f).")
showgrid(currgrid)
print(helpmessage + " Type 'help' to show this message again.\n")
while True:
minesleft = numberofmines - len(flags)
prompt = input('Enter the cell ({} mines left): '.format(minesleft))
result = parseinput(prompt, gridsize, helpmessage + '\n')
message = result['message']
cell = result['cell']
if cell:
print('\n\n')
rowno, colno = cell
currcell = currgrid[rowno][colno]
flag = result['flag']
if not grid:
grid, mines = setupgrid(gridsize, cell, numberofmines)
if not starttime:
starttime = time.time()
if flag:
# Add a flag if the cell is empty
if currcell == ' ':
currgrid[rowno][colno] = 'F'
flags.append(cell)
# Remove the flag if there is one
elif currcell == 'F':
currgrid[rowno][colno] = ' '
flags.remove(cell)
else:
message = 'Cannot put a flag there'
# If there is a flag there, show a message
elif cell in flags:
message = 'There is a flag there'
elif grid[rowno][colno] == 'X':
print('Game Over\n')
showgrid(grid)
if playagain():
playgame()
return
elif currcell == ' ':
showcells(grid, currgrid, rowno, colno)
else:
message = "That cell is already shown"
if set(flags) == set(mines):
minutes, seconds = divmod(int(time.time() - starttime), 60)
print(
'You Win. '
'It took you {} minutes and {} seconds.\n'.format(minutes,
seconds))
showgrid(grid)
if playagain():
playgame()
return
showgrid(currgrid)
print(message)
playgame()
@jerrycui07
Copy link

I think this is really good, however, the letters have the wrong formatting and it is very confusing to look at.

@mohd-akram
Copy link
Author

@jerrycui07 What do you mean they have the wrong formatting?

@earifogl
Copy link

it dont work
Traceback (most recent call last):
File "python", line 219, in
File "python", line 159, in playgame
File "", line 1, in
NameError: name 'a5' is not defined

@ManuFU
Copy link

ManuFU commented Sep 24, 2018

It works in python 3.6.
I don't know what he means with "wrong formatting".
The code looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment