generated from mwc/project_game
This is the FINAL version of what I'm submitting.
This is a version of minesweeper. You win by isolating every mine, which is the same as revealing all numbered spaces. There is no flag, so you have to keep track of, or figure out, what's revealed. The game ends if you win as described above or you lose by selecting a mine. I have playtested this and confirmed that the game ends in a win by meeting the above criterion. I also (not intentionally) confirmed you lose if you select a mine. I did the latter far too many times... Things to note: -I have the game in debug mode so that instructions appear. -There is no score. I don't think there's a score in minesweeper. You either survive the mines or die. -I have not implemented flagging potential locations of mines. You can technically play without them, so I don't think you lose out on any of the core gameplay. -I'm not sure why, but when the game ends, some of the mines don't show up and some of the revealed numbers disappear. -Because two displayed agents cannot occupy the same space, navigating with the cursor over mines or numbered squares may require pressing an arrow key multiple times. (I tried to not display the mines and then display them only when revealing spaces, but the revealing algorithm didn't work when I tried it like that. I promise I spent hours trying to get it to work before settling on this current iteration.) -You can lose on the first move...
This commit is contained in:
parent
8e54c5fe12
commit
374952d65a
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
12
cursor.py
12
cursor.py
|
@ -2,6 +2,7 @@
|
|||
# ------------
|
||||
# By Cory
|
||||
# This module defines a cursor agent class.
|
||||
|
||||
class Cursor:
|
||||
name = "cursor"
|
||||
character = 'O'
|
||||
|
@ -11,8 +12,10 @@ class Cursor:
|
|||
self.position = position
|
||||
|
||||
def handle_keystroke(self, keystroke, game):
|
||||
'''
|
||||
Move the cursor using arrow keys.
|
||||
'''
|
||||
x, y = self.position
|
||||
|
||||
if keystroke.name in ("KEY_LEFT", "KEY_RIGHT", "KEY_UP", "KEY_DOWN"):
|
||||
if keystroke.name == "KEY_LEFT":
|
||||
new_position = (x - 1, y)
|
||||
|
@ -25,9 +28,10 @@ class Cursor:
|
|||
if game.on_board(new_position):
|
||||
if game.is_empty(new_position):
|
||||
self.position = new_position
|
||||
game.log("The cursor is at " + str(self.position))
|
||||
for i in range(10):
|
||||
game.log("mine"+str(i) + " is located at " + str(game.get_agent_by_name("mine"+str(i)).position))
|
||||
|
||||
def hide(self):
|
||||
'''
|
||||
This is called because I was calling this method based on an agent's location, but I don't need the
|
||||
cursor to do anything.
|
||||
'''
|
||||
pass
|
|
@ -14,46 +14,28 @@ class FreeSpace:
|
|||
self.position = position
|
||||
self.width , self.height = position
|
||||
|
||||
def handle_keystroke(self, keystroke, game):
|
||||
if keystroke.name in ("KEY_ENTER"):
|
||||
if not game.is_empty(self.position):
|
||||
if self.revealed == False:
|
||||
board_width,board_height = game.board_size
|
||||
for i in range(10):
|
||||
game.get_agent_by_name("mine"+str(i)).show()
|
||||
for i in range(board_width):
|
||||
for j in range(board_height):
|
||||
try:
|
||||
game.get_agent_by_name("freespace"+str(i)+str(j)).show()
|
||||
except:
|
||||
pass
|
||||
self.reveal(game)
|
||||
for i in range(board_width):
|
||||
for j in range(board_height):
|
||||
try:
|
||||
game.get_agent_by_name("freespace"+str(i)+str(j)).hide()
|
||||
except:
|
||||
pass
|
||||
for i in range(10):
|
||||
game.get_agent_by_name("mine"+str(i)).hide()
|
||||
def name_me(self, named):
|
||||
'''
|
||||
Give a free space a name.'''
|
||||
self.name = named
|
||||
|
||||
def show(self):
|
||||
'''
|
||||
Used to turn display on. Necessary to be able to call upon a space based on its position.
|
||||
'''
|
||||
self.display = True
|
||||
|
||||
def hide(self):
|
||||
'''
|
||||
Used to hide free spaces only if they have not already been revealed.
|
||||
'''
|
||||
if self.revealed == False:
|
||||
self.display = False
|
||||
|
||||
def show(self):
|
||||
self.display = True
|
||||
|
||||
def play_turn(self, game):
|
||||
if (not game.is_empty(self.position)) and self.revealed and self.display == True:
|
||||
self.display = False
|
||||
elif game.is_empty(self.position) and self.revealed and self.neighbors > 0 and self.display == False:
|
||||
self.display = True
|
||||
|
||||
def name_me(self, named):
|
||||
self.name = named
|
||||
|
||||
def check_neighbors(self,game):
|
||||
'''
|
||||
Used to determine the number that should be shown when the space is revealed. Counts neighboring mines.
|
||||
'''
|
||||
names_of_mines = ["mine0","mine1","mine2","mine3","mine4","mine5","mine6","mine7","mine8","mine9"]
|
||||
if game.on_board((self.width + 1,self.height)):
|
||||
if len(game.get_agents_by_position()[(self.width + 1,self.height)]) != 0:
|
||||
|
@ -90,7 +72,54 @@ class FreeSpace:
|
|||
if self.neighbors > 0:
|
||||
self.character = str(self.neighbors)
|
||||
|
||||
def play_turn(self, game):
|
||||
'''
|
||||
Make sure a number is hidden when the cursor is over it. This is needed to allow the cursor to move
|
||||
over a spot where a number is.
|
||||
'''
|
||||
if (not game.is_empty(self.position)) and self.revealed and self.display == True:
|
||||
self.display = False
|
||||
elif game.is_empty(self.position) and self.revealed and self.neighbors > 0 and self.display == False:
|
||||
self.display = True
|
||||
|
||||
|
||||
def handle_keystroke(self, keystroke, game):
|
||||
'''
|
||||
When a space without a mine is selected, use a recursive algorithm defined below to reveal spaces.
|
||||
Then, check if all non-mine spaces have been revealed; if so, the game has been won.
|
||||
'''
|
||||
if keystroke.name in ("KEY_ENTER"):
|
||||
if not game.is_empty(self.position):
|
||||
if self.revealed == False:
|
||||
board_width,board_height = game.board_size
|
||||
for i in range(board_width):
|
||||
for j in range(board_height):
|
||||
try:
|
||||
game.get_agent_by_name("freespace"+str(i)+str(j)).show()
|
||||
except:
|
||||
pass
|
||||
self.reveal(game)
|
||||
win = True
|
||||
for i in range(board_width):
|
||||
for j in range(board_height):
|
||||
if len(game.get_agents_by_position()[(i,j)]) != 0:
|
||||
if not game.get_agents_by_position()[i,j][0].revealed:
|
||||
win = False
|
||||
if win == True:
|
||||
game.log("You successfully isolated every mine! Congratulations! You've won!")
|
||||
game.end()
|
||||
for i in range(board_width):
|
||||
for j in range(board_height):
|
||||
try:
|
||||
game.get_agent_by_name("freespace"+str(i)+str(j)).hide()
|
||||
except:
|
||||
pass
|
||||
|
||||
def reveal(self,game):
|
||||
'''
|
||||
Recursive algorithm to reveal squares. Reveals itself and then if it has no neighboring mines,
|
||||
it asks all 8 of its neighbors (assuming none are off the map) to reveal themselves.
|
||||
'''
|
||||
self.revealed = True
|
||||
if self.neighbors == 0:
|
||||
if game.on_board((self.width + 1,self.height)):
|
||||
|
|
52
mine.py
52
mine.py
|
@ -10,29 +10,61 @@ class Mine:
|
|||
def __init__(self, position):
|
||||
self.position = position
|
||||
|
||||
def name_me(self, named):
|
||||
'''
|
||||
Assign a name to a given mine.
|
||||
'''
|
||||
self.name = named
|
||||
|
||||
def handle_keystroke(self, keystroke, game):
|
||||
'''
|
||||
This ends the game if enter is pressed while the cursor is over a mine.
|
||||
'''
|
||||
if keystroke.name in ("KEY_ENTER"):
|
||||
if game.get_agent_by_name("cursor").position == self.position:
|
||||
for i in range(10):
|
||||
game.get_agent_by_name("mine"+str(i)).character = 'M'
|
||||
game.get_agent_by_name("cursor").character = 'M'
|
||||
game.log("You hit a mine! Game over.")
|
||||
game.end()
|
||||
|
||||
def play_turn(self, game):
|
||||
'''
|
||||
Make sure the mine is hidden when the cursor is over it. This is needed to allow the cursor to move
|
||||
over a spot where a mine is.
|
||||
'''
|
||||
if (not game.is_empty(self.position)):
|
||||
self.display = False
|
||||
elif game.is_empty(self.position):
|
||||
self.display = True
|
||||
|
||||
def hide(self):
|
||||
pass
|
||||
|
||||
def name_me(self, named):
|
||||
self.name = named
|
||||
|
||||
def check_neighbors(self,game):
|
||||
pass
|
||||
|
||||
def reveal(self):
|
||||
'''
|
||||
This is called because I was calling this method based on an agent's location, but I don't need the
|
||||
mine to do anything.
|
||||
'''
|
||||
pass
|
||||
|
||||
def show(self):
|
||||
pass
|
||||
'''
|
||||
This is called because I was calling this method based on an agent's location, but I don't need the
|
||||
mine to do anything.
|
||||
'''
|
||||
pass
|
||||
|
||||
def hide(self):
|
||||
'''
|
||||
This is called because I was calling this method based on an agent's location, but I don't need the
|
||||
mine to do anything.
|
||||
'''
|
||||
pass
|
||||
|
||||
def check_neighbors(self,game):
|
||||
'''
|
||||
This is called because I was calling this method based on an agent's location, but I don't need the
|
||||
mine to do anything.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# minesweeper_game.py
|
||||
# ------------
|
||||
# By Cory
|
||||
# This class implements a simple minesweeper game on a 9x9 grid.
|
||||
# This class implements a simple minesweeper game on a 9x9 grid with 10 mines.
|
||||
|
||||
from retro.game import Game
|
||||
from spawner import Spawner
|
||||
|
||||
board_size = (9, 9)
|
||||
spawner = Spawner(board_size)
|
||||
game = Game([spawner], {"score": 0}, board_size=board_size,debug=True)
|
||||
game = Game([spawner], {"score": 0}, board_size=board_size,debug=True) # debug is on so you can see the instructions :)
|
||||
game.play()
|
19
spawner.py
19
spawner.py
|
@ -16,26 +16,26 @@ class Spawner:
|
|||
self.board_width, self.board_height = width, height
|
||||
|
||||
def play_turn(self, game):
|
||||
# On the first turn we will spawn everything.
|
||||
'''
|
||||
Creates all other agents and prints instructions when the game begins.
|
||||
'''
|
||||
if game.turn_number == 1:
|
||||
# First spawn 10 mines
|
||||
for i in range(10):
|
||||
mine = Mine(((randint(0, self.board_width - 1)),(randint(0, self.board_height - 1))))
|
||||
mine.name_me("mine"+str(i))
|
||||
while not game.is_empty(mine.position):
|
||||
while not game.is_empty(mine.position): # Ensure mines are not in the same location
|
||||
mine = Mine(((randint(0, self.board_width - 1)),(randint(0, self.board_height - 1))))
|
||||
mine.name_me("mine"+str(i))
|
||||
game.log(str(mine.name) + " is located at " + str(mine.position))
|
||||
game.add_agent(mine)
|
||||
# Then spawn free spaces everywhere
|
||||
# Then spawn free spaces everywhere there is not a mine.
|
||||
for i in range(self.board_width):
|
||||
for j in range(self.board_height):
|
||||
if game.is_empty((i,j)):
|
||||
free_space = FreeSpace((i,j))
|
||||
free_space.name_me("freespace"+str(i)+str(j))
|
||||
game.add_agent(free_space)
|
||||
# Now ask all free spaces to keep track of their neighbors that are mines
|
||||
# and all of the mines and free spaces to hide themselves.
|
||||
# Now ask all free spaces to keep track of their neighbors that are mines and hide themselves.
|
||||
for i in range(self.board_width):
|
||||
for j in range(self.board_height):
|
||||
if len(game.get_agents_by_position()[(i,j)]) != 0:
|
||||
|
@ -44,3 +44,10 @@ class Spawner:
|
|||
# Now create a cursor.
|
||||
cursor = Cursor((self.board_width - 1, self.board_height - 1))
|
||||
game.add_agent(cursor)
|
||||
# Print instructions.
|
||||
game.log("To move, use the arrow keys. You may have to")
|
||||
game.log("press an arrow key more than once to move.")
|
||||
game.log("Please make sure the cursor is where you want it")
|
||||
game.log("before selecting a space. To select a space, ")
|
||||
game.log("press return. The game is over when all spots")
|
||||
game.log("with mines are surrounded by numbers.")
|
Loading…
Reference in New Issue