Reputation: 41
I have the following python code but I'm really struggling to get it to work.
It's a basic minesweeper game in terminal. This version is a little different to the others out there in that it's supposed to start by asking the user how big the grid, then how many mines to insert. The rest of it is your good old basic minesweeper.
def display():
for x in range(SIZE):
if x == 0:
print(" ", end="")
for i in range(SIZE):
print(" " + str(i), end="")
print("\n |-" + "--|-" * (SIZE - 1) + "--|")
print("0 |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + "|", end="")
print("\n |-" + "--|-" * (SIZE -1) + "--|")
elif x == SIZE -1:
print(str(SIZE-1) + " |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + "|", end="")
print("\n |-" + "--|-" * (SIZE -1) + "--|")
else:
print(str(x) + " |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + "|", end="")
print("\n |-" + "--|-" * (SIZE-1) + "--|")
class Square:
def __init__(self, x, y):
self.status = "- "
self.row = x
self.column = y
self.mine = False
self.neighbours = []
self.danger = 0
def status_get(self):
return this.status
def first_move():
# establish mine locations, ignoring stating dig
print("""Where would you like to start?\n""")
while True:
a, b = input("Enter an x and y coodinate, comma separated, to dig the first square: ").split(",")
x = int(a)
y = int(b)
if x >= SIZE or y >= SIZE:
print("Out of bounds, try again.")
continue
else:
for m in range(MINES):
place_mines(x, y)
welfare(BOARD[x][y])
break
def place_mines(x, y):
# Recursively place mines, ignoring starting square
global BOARD
h = random.randint(0, SIZE - 1)
w = random.randint(0, SIZE - 1)
if h == x and w == y:
place_mines(x, y)
else:
if not BOARD[h][w].mine:
BOARD[h][w].mine = True
for sqr in BOARD[h][w].neighbours:
sqr.danger += 1
else:
place_mines(x, y)
def next_turn():
# keeps promting to dig, flag, or end the game
move = input("What would you like to do? ").lower()
if move == "!quit":
print("Thank you, come again.")
quit(0)
elif move == "d":
dig()
display()
elif move == "f":
flag()
display()
elif move == "r":
unflag()
display()
elif move == "!help":
print("!quit = Quit game.")
print("d = Uncover a square.")
print("f = Plant a flag marking a square as containing a mine.")
print("r = Remove a flag.")
else:
print("You'll have to speak up... Try again.")
def unflag():
# Unflags a previously flagged square
while True:
a, b = input("Supply an x and y coordinate to unflag: ").split(",")
x = int(a)
y = int(b)
if x >= SIZE or y >= SIZE:
print("Out of bounds, try again.")
continue
else:
global BOARD
if BOARD[x][y].status == "F ":
BOARD[x][y].status = "- "
break
def flag():
# flag a square to indicate a mine
while True:
a, b = input("Supply an x and y coordinate to flag: ").split(",")
x = int(a)
y = int(b)
if x >= SIZE or y >= SIZE:
print("Out of bounds, try again.")
continue
else:
global BOARD
BOARD[x][y].status = "F "
global FLAGS
if BOARD[x][y].mine and BOARD[x][y].status == "F ":
FLAGS += 1
break
def dig():
# Uncover a square. If it's a bomb it's game over. Otherwise, reveal nearby squares
while True:
a, b = input("Supply an x and y coordinate to dig: ").split(",")
x = int(a)
y = int(b)
if x >= SIZE or y >= SIZE:
print("Out of bounds, try again.")
continue
else:
if BOARD[x][y].mine is True:
print("BANG! You have died!")
for x in range(SIZE):
for y in range(SIZE):
sqr = BOARD[x][y]
if sqr.mine:
sqr.status = "@"
display()
quit(0)
else:
BOARD[x][y].status = "x"
welfare(BOARD[x][y])
break
def welfare(sqr, history=[]):
# update square state after each dig to reveal mine status
if sqr.danger == 0:
sqr.status = "x "
for box in sqr.neighbours:
if box not in history:
history.append(box)
welfare(box, history)
else:
if not sqr.mine:
sqr.status = str(sqr.danger) + " "
#for box in sqr.neighbours:
# if not box.mine:
# if box not in history:
# history.append(box)
# welfare(box, history)
def win_state():
# is it over, can I go home now?
global FLAGS
global MINES
global BOARD
correct = 0
if FLAGS == MINES:
for x in range(SIZE):
for y in range(SIZE):
sqr = BOARD[x][y]
if sqr.mine and sqr.status == "F ":
correct += 1
if correct == MINES:
print("Congratulations!\n")
print("You found " + str(MINES) + " mines and didn't die.")
exit(0)
def startup():
# set game parameters, give all the squares their neighbours
print("It's Minesweeper, how wide do you want the board?")
global SIZE
while True:
SIZE = int(input("Give me a size, between 3 and 10 inclusive "))
if SIZE not in range(3, 11):
print("Did I stutter? Try again. ")
continue
else:
global MINES
while True:
MINES = int(input("How many mines do you want? "))
if MINES >= SIZE ** 2:
print("Whoa! That's too many. Try Again. ")
continue
else:
break
print("OKAY")
# initialise an empty board
global BOARD
BOARD = [[None for _ in range(SIZE)] for _ in range(SIZE)]
# fill that board with square objects
for s in range(SIZE):
for d in range(SIZE):
BOARD[s][d] = Square(s, d)
# link each square to it's neighbour
for a in range(SIZE):
for b in range(SIZE):
sqr = BOARD[a][b]
if a == 0:
sqr.neighbours.append(BOARD[a + 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a + 1][b + 1])
sqr.neighbours.append(BOARD[a][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a][b - 1])
sqr.neighbours.append(BOARD[a + 1][b - 1])
elif a == SIZE - 1:
sqr.neighbours.append(BOARD[a - 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a][b + 1])
sqr.neighbours.append(BOARD[a - 1][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a - 1][b - 1])
sqr.neighbours.append(BOARD[a][b - 1])
else:
sqr.neighbours.append(BOARD[a + 1][b])
sqr.neighbours.append(BOARD[a - 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a - 1][b + 1])
sqr.neighbours.append(BOARD[a][b + 1])
sqr.neighbours.append(BOARD[a + 1][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a - 1][b - 1])
sqr.neighbours.append(BOARD[a][b - 1])
sqr.neighbours.append(BOARD[a + 1][b - 1])
startup()
while True:
next_turn()
win_state()
Upvotes: 0
Views: 509
Reputation: 54645
Here's a slightly reorganized version of your code that works. You forgot to call first_move
. You were inconsistent in whether status
had to include the trailing blank (I'm not using it). If changes all your while
loops so they break
on success; that avoids the confusion. Notice there is only one global
here.
import random
def display():
for x in range(SIZE):
if x == 0:
print(" ", end="")
for i in range(SIZE):
print(" " + str(i), end="")
print("\n |-" + "--|-" * (SIZE - 1) + "--|")
print("0 |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + " |", end="")
print("\n |-" + "--|-" * (SIZE -1) + "--|")
elif x == SIZE -1:
print(str(SIZE-1) + " |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + " |", end="")
print("\n |-" + "--|-" * (SIZE -1) + "--|")
else:
print(str(x) + " |", end="")
for y in range(SIZE):
print(" " + str(BOARD[x][y].status) + " |", end="")
print("\n |-" + "--|-" * (SIZE-1) + "--|")
class Square:
def __init__(self, x, y):
self.status = "-"
self.row = x
self.column = y
self.mine = False
self.neighbours = []
self.danger = 0
def status_get(self):
return this.status
def first_move():
# establish mine locations, ignoring stating dig
print("""Where would you like to start?\n""")
while True:
a, b = input("Enter an x and y coodinate, comma separated, to dig the first square: ").split(",")
x = int(a)
y = int(b)
if x < SIZE and y < SIZE:
break
print("Out of bounds, try again.")
for m in range(MINES):
place_mines(x, y)
welfare(BOARD[x][y])
def place_mines(x, y):
# Recursively place mines, ignoring starting square
h = random.randint(0, SIZE - 1)
w = random.randint(0, SIZE - 1)
if h == x and w == y:
place_mines(x, y)
else:
if not BOARD[h][w].mine:
BOARD[h][w].mine = True
for sqr in BOARD[h][w].neighbours:
sqr.danger += 1
else:
place_mines(x, y)
def next_turn():
# keeps promting to dig, flag, or end the game
display()
move = input("What would you like to do? ").lower()
if move == "!quit":
print("Thank you, come again.")
quit(0)
elif move == "d":
dig()
elif move == "f":
flag()
elif move == "r":
unflag()
elif move == "!help":
print("!quit = Quit game.")
print("d = Uncover a square.")
print("f = Plant a flag marking a square as containing a mine.")
print("r = Remove a flag.")
else:
print("You'll have to speak up... Try again.")
def unflag():
# Unflags a previously flagged square
while True:
a, b = input("Supply an x and y coordinate to unflag: ").split(",")
x = int(a)
y = int(b)
if x < SIZE and y < SIZE:
break
print("Out of bounds, try again.")
if BOARD[x][y].status == "F":
BOARD[x][y].status = "-"
def flag():
# flag a square to indicate a mine
while True:
a, b = input("Supply an x and y coordinate to flag: ").split(",")
x = int(a)
y = int(b)
if x < SIZE and y < SIZE:
break
print("Out of bounds, try again.")
BOARD[x][y].status = "F"
global FLAGS
if BOARD[x][y].mine and BOARD[x][y].status == "F":
FLAGS += 1
def dig():
# Uncover a square. If it's a bomb it's game over. Otherwise, reveal nearby squares
while True:
a, b = input("Supply an x and y coordinate to dig: ").split(",")
x = int(a)
y = int(b)
if x < SIZE and y < SIZE:
break
print("Out of bounds, try again.")
if BOARD[x][y].mine:
print("BANG! You have died!")
for x in range(SIZE):
for y in range(SIZE):
sqr = BOARD[x][y]
if sqr.mine:
sqr.status = "@"
display()
quit(0)
else:
BOARD[x][y].status = "x"
welfare(BOARD[x][y])
def welfare(sqr, history=[]):
# update square state after each dig to reveal mine status
if sqr.danger == 0:
sqr.status = "x"
for box in sqr.neighbours:
if box not in history:
history.append(box)
welfare(box, history)
else:
if not sqr.mine:
sqr.status = str(sqr.danger)
#for box in sqr.neighbours:
# if not box.mine:
# if box not in history:
# history.append(box)
# welfare(box, history)
def win_state():
# is it over, can I go home now?
correct = 0
if FLAGS == MINES:
for x in range(SIZE):
for y in range(SIZE):
sqr = BOARD[x][y]
if sqr.mine and sqr.status == "F":
correct += 1
if correct == MINES:
print("Congratulations!\n")
print("You found " + str(MINES) + " mines and didn't die.")
exit(0)
def startup():
# set game parameters, give all the squares their neighbours
print("It's Minesweeper, how wide do you want the board?")
while True:
SIZE = int(input("Give me a size, between 3 and 10 inclusive "))
if SIZE in range(3, 11):
break
print("Did I stutter? Try again. ")
while True:
MINES = int(input("How many mines do you want? "))
if MINES < SIZE ** 2:
break
print("Whoa! That's too many. Try Again. ")
print("OKAY")
# initialise an empty board
BOARD = [[None for _ in range(SIZE)] for _ in range(SIZE)]
# fill that board with square objects
BOARD = []
for s in range(SIZE):
row = []
for d in range(SIZE):
row.append( Square(s, d) )
BOARD.append(row)
# link each square to it's neighbour
for a in range(SIZE):
for b in range(SIZE):
sqr = BOARD[a][b]
if a == 0:
sqr.neighbours.append(BOARD[a + 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a + 1][b + 1])
sqr.neighbours.append(BOARD[a][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a][b - 1])
sqr.neighbours.append(BOARD[a + 1][b - 1])
elif a == SIZE - 1:
sqr.neighbours.append(BOARD[a - 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a][b + 1])
sqr.neighbours.append(BOARD[a - 1][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a - 1][b - 1])
sqr.neighbours.append(BOARD[a][b - 1])
else:
sqr.neighbours.append(BOARD[a + 1][b])
sqr.neighbours.append(BOARD[a - 1][b])
if b != SIZE - 1:
sqr.neighbours.append(BOARD[a - 1][b + 1])
sqr.neighbours.append(BOARD[a][b + 1])
sqr.neighbours.append(BOARD[a + 1][b + 1])
if b != 0:
sqr.neighbours.append(BOARD[a - 1][b - 1])
sqr.neighbours.append(BOARD[a][b - 1])
sqr.neighbours.append(BOARD[a + 1][b - 1])
return SIZE, MINES, BOARD
FLAGS = 0
SIZE, MINES, BOARD = startup()
first_move()
while True:
next_turn()
win_state()
Upvotes: 1