generated from mwc/project_game
FINAL GAME SUBMISSION
Got the man chaser to work! Moved all global variables to nav_game.py so easier to adjust later
This commit is contained in:
Binary file not shown.
BIN
gamefiles/__pycache__/chaser.cpython-312.pyc
Normal file
BIN
gamefiles/__pycache__/chaser.cpython-312.pyc
Normal file
Binary file not shown.
BIN
gamefiles/__pycache__/helpers.cpython-312.pyc
Normal file
BIN
gamefiles/__pycache__/helpers.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
gamefiles/__pycache__/man_chaser.cpython-312.pyc
Normal file
BIN
gamefiles/__pycache__/man_chaser.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,74 +2,88 @@ from man import Man
|
|||||||
from snack import Snack
|
from snack import Snack
|
||||||
from mine import Mine
|
from mine import Mine
|
||||||
from random import shuffle
|
from random import shuffle
|
||||||
|
from chaser import Man_Chaser
|
||||||
|
|
||||||
'''This class sets up the board initially, but also is responsible for adding snacks
|
"""This class sets up the board initially, but also is responsible for adding snacks
|
||||||
and mines after they are consumed. Also increases mines as game gets more difficult.'''
|
and mines after they are consumed. Also increases mines as game gets more difficult."""
|
||||||
|
|
||||||
'''Values to call later, sets no more than 100 mines, and each list represent a level [score, num_mines],
|
|
||||||
which is called in mine_counter below.'''
|
|
||||||
MAX_MINES = 100
|
|
||||||
LEVELS = [
|
|
||||||
[5, 10],
|
|
||||||
[10, 20],
|
|
||||||
[15, 30],
|
|
||||||
[20, 40],
|
|
||||||
[30,50],
|
|
||||||
[40,60],
|
|
||||||
[50,70],
|
|
||||||
[60,80],
|
|
||||||
[70,90]
|
|
||||||
]
|
|
||||||
|
|
||||||
class Board:
|
class Board:
|
||||||
display = False
|
display = False
|
||||||
snack=False
|
snack=False
|
||||||
mine=False
|
mine=False
|
||||||
|
chaser=False
|
||||||
|
|
||||||
def __init__(self,width, height,num_snacks,state):
|
def __init__(self,width, height,num_snacks,num_chasers,MAX_MINES,LEVELS,state):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.num_snacks = num_snacks
|
self.num_snacks = num_snacks
|
||||||
|
self.num_chasers = num_chasers
|
||||||
|
self.MAX_MINES = MAX_MINES
|
||||||
|
self.LEVELS = LEVELS
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
def get_agents(self,num_snacks,state):
|
def get_agents(self,num_snacks,num_chasers,state):
|
||||||
'''Sets up all the agents (snacks, mines, and man) in the game. First, determines mines needed by
|
"""Sets up all the agents (snacks, mines, man, and chasers) in the game. First, determines mines needed by
|
||||||
calling the mine_counter function. Then generates a list of all posiitons, randomizes them, and assigns
|
calling the mine_counter function. Then generates a list of all posiitons, randomizes them, and assigns
|
||||||
the man to the first random position, the snacks to the next num_snack positions, and then the mines
|
the man to the first random position, the snacks to the next num_snack positions, the mines
|
||||||
to the required number of posiitons as specified in mine_counter. Returns these agents so they can be
|
to the required number of posiitons as specified in mine_counter, and then the chasers. Returns these
|
||||||
positioned on the board.'''
|
agents so they can be positioned on the board."""
|
||||||
num_mines = self.mine_counter(state)
|
num_mines = self.mine_counter(state)
|
||||||
all_positions = self.get_all_positions()
|
all_positions = self.get_all_positions()
|
||||||
shuffle(all_positions)
|
shuffle(all_positions)
|
||||||
man= [Man(all_positions[0])]
|
man= [Man(all_positions[0])]
|
||||||
snacks = [Snack(p) for p in all_positions[1:(num_snacks+1)]]
|
snacks = [Snack(p) for p in all_positions[1:(num_snacks+1)]]
|
||||||
mines = [Mine(p) for p in all_positions[(num_snacks + 2):(num_snacks + num_mines +2)]]
|
mines = [Mine(p) for p in all_positions[(num_snacks + 2):(num_snacks + num_mines +2)]]
|
||||||
agents = man + snacks + mines + [self]
|
chaser = [Man_Chaser(p) for p in all_positions[(num_snacks + num_mines + 2):(num_snacks + num_mines + num_chasers + 2)]]
|
||||||
|
agents = man + snacks + mines + chaser + [self]
|
||||||
return agents
|
return agents
|
||||||
|
|
||||||
def play_turn(self,game):
|
def play_turn(self,game):
|
||||||
'''Checks after every turn (turn is length of time specified in retro) if the game needs snacks
|
"""Checks after every turn (turn is length of time specified in retro) if the game needs snacks
|
||||||
or mines.'''
|
or mines or a chaser."""
|
||||||
#game.log(game.state['Score'])
|
game.log(game.state['Score'])
|
||||||
while self.game_needs_snacks(game):
|
while self.game_needs_snacks(game):
|
||||||
self.add_snack(game)
|
self.add_snack(game)
|
||||||
while self.game_needs_mines(game):
|
while self.game_needs_mines(game):
|
||||||
self.add_mine(game)
|
self.add_mine(game)
|
||||||
|
while self.game_needs_chaser(game):
|
||||||
|
self.add_chaser(game)
|
||||||
|
|
||||||
|
def add_chaser(self,game):
|
||||||
|
"""Adds a chaser by finidng all the positions, randomizing them, and adding the chaser
|
||||||
|
to the first random position."""
|
||||||
|
all_positions=self.get_all_positions()
|
||||||
|
shuffle(all_positions)
|
||||||
|
index =0
|
||||||
|
while not game.is_empty(all_positions[index]):
|
||||||
|
index = index + 1
|
||||||
|
chaser = Man_Chaser(all_positions[index])
|
||||||
|
game.add_agent(chaser)
|
||||||
|
|
||||||
|
def game_needs_chaser(self,game):
|
||||||
|
"""Returns true when the number of chasers in the game is less than the number of chasers
|
||||||
|
specified in nav_game.py."""
|
||||||
|
return self.count_chaser(game) < self.num_chasers
|
||||||
|
|
||||||
|
def count_chaser(self,game):
|
||||||
|
"""Counts the number of chases currently in the game."""
|
||||||
|
chasers = [a for a in game.agents if a.chaser]
|
||||||
|
return len(chasers)
|
||||||
|
|
||||||
def mine_counter(self,state):
|
def mine_counter(self,state):
|
||||||
'''Determines how many mines should be in the game, based on the score of the game. Refers to the
|
"""Determines how many mines should be in the game, based on the score of the game. Refers to the
|
||||||
LEVELS list above which contains the score and a correspponding number of mines. This function
|
LEVELS list above which contains the score and a correspponding number of mines. This function
|
||||||
puts a certain number of mines down based on the score. Currently, does not reduce the number
|
puts a certain number of mines down based on the score. Currently, does not reduce the number
|
||||||
of mines when the score lowers after hitting a mine. Returns the number of mines needed. '''
|
of mines when the score lowers after hitting a mine. Returns the number of mines needed."""
|
||||||
score = state['Score']
|
score = state['Score']
|
||||||
for limit, n in LEVELS:
|
for limit, n in self.LEVELS:
|
||||||
if score < limit:
|
if score < limit:
|
||||||
return n
|
return n
|
||||||
return MAX_MINES
|
return self.MAX_MINES
|
||||||
|
|
||||||
def add_mine(self,game):
|
def add_mine(self,game):
|
||||||
'''Adds a mine by finding all positions, randomizing them, and then adding a mine to the
|
"""Adds a mine by finding all positions, randomizing them, and then adding a mine to the
|
||||||
first non-occupied position.'''
|
first non-occupied position."""
|
||||||
all_positions=self.get_all_positions()
|
all_positions=self.get_all_positions()
|
||||||
shuffle(all_positions)
|
shuffle(all_positions)
|
||||||
index =0
|
index =0
|
||||||
@@ -79,18 +93,18 @@ class Board:
|
|||||||
game.add_agent(mine)
|
game.add_agent(mine)
|
||||||
|
|
||||||
def count_mines(self,game):
|
def count_mines(self,game):
|
||||||
'''Counts the number of mines currently in the game.'''
|
"""Counts the number of mines currently in the game."""
|
||||||
mines= [a for a in game.agents if a.mine]
|
mines= [a for a in game.agents if a.mine]
|
||||||
return len(mines)
|
return len(mines)
|
||||||
|
|
||||||
def game_needs_mines(self,game):
|
def game_needs_mines(self,game):
|
||||||
'''Returns true when the number of mines in the game is less than the number of mines
|
"""Returns true when the number of mines in the game is less than the number of mines
|
||||||
required based on the score.'''
|
required based on the score."""
|
||||||
return self.count_mines(game) < self.mine_counter(game.state)
|
return self.count_mines(game) < self.mine_counter(game.state)
|
||||||
|
|
||||||
def add_snack(self,game):
|
def add_snack(self,game):
|
||||||
'''Adds a snack by finding all positions, randomizing them, and then adding a snack to the
|
"""Adds a snack by finding all positions, randomizing them, and then adding a snack to the
|
||||||
first non-occupied position.'''
|
first non-occupied position."""
|
||||||
all_positions=self.get_all_positions()
|
all_positions=self.get_all_positions()
|
||||||
shuffle(all_positions)
|
shuffle(all_positions)
|
||||||
index =0
|
index =0
|
||||||
@@ -100,17 +114,17 @@ class Board:
|
|||||||
game.add_agent(snack)
|
game.add_agent(snack)
|
||||||
|
|
||||||
def count_snacks(self,game):
|
def count_snacks(self,game):
|
||||||
'''Counts the number of snacks currently in the game.'''
|
"""Counts the number of snacks currently in the game."""
|
||||||
snacks= [a for a in game.agents if a.snack]
|
snacks= [a for a in game.agents if a.snack]
|
||||||
return len(snacks)
|
return len(snacks)
|
||||||
|
|
||||||
def game_needs_snacks(self,game):
|
def game_needs_snacks(self,game):
|
||||||
'''Returns true when the number of snacks in the game is less than the number of snacks specified
|
"""Returns true when the number of snacks in the game is less than the number of snacks specified
|
||||||
in nav-game.py. In a future version, this number of snacks could vary as the game gets more difficult.'''
|
in nav-game.py. In a future version, this number of snacks could vary as the game gets more difficult."""
|
||||||
return self.count_snacks(game) < self.num_snacks
|
return self.count_snacks(game) < self.num_snacks
|
||||||
|
|
||||||
def get_all_positions(self):
|
def get_all_positions(self):
|
||||||
'''Finds all coordinate positions in the game and adds them to a list of positions.'''
|
"""Finds all coordinate positions in the game and adds them to a list of positions."""
|
||||||
positions=[]
|
positions=[]
|
||||||
for i in range(self.width):
|
for i in range(self.width):
|
||||||
for j in range(self.height):
|
for j in range(self.height):
|
||||||
|
|||||||
58
gamefiles/chaser.py
Normal file
58
gamefiles/chaser.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
from helpers import add, distance, get_occupant
|
||||||
|
from random import random, choice
|
||||||
|
|
||||||
|
class Man_Chaser:
|
||||||
|
"""Represents a man_chaser, coming after the man. Modelled after the beast in the Beast game"""
|
||||||
|
|
||||||
|
character = "H"
|
||||||
|
color = "yellow"
|
||||||
|
probability_of_moving = 0.03
|
||||||
|
probability_of_random_move = 0.2
|
||||||
|
deadly = True
|
||||||
|
snack=False
|
||||||
|
mine = False
|
||||||
|
chaser = True
|
||||||
|
|
||||||
|
def __init__(self, position):
|
||||||
|
self.position = position
|
||||||
|
|
||||||
|
def play_turn(self, game):
|
||||||
|
if self.should_move():
|
||||||
|
possible_moves = []
|
||||||
|
for position in self.get_adjacent_positions():
|
||||||
|
if game.is_empty(position) and game.on_board(position):
|
||||||
|
possible_moves.append(position)
|
||||||
|
if possible_moves:
|
||||||
|
if self.should_move_randomly():
|
||||||
|
self.position = choice(possible_moves)
|
||||||
|
else:
|
||||||
|
self.position = self.choose_best_move(possible_moves, game)
|
||||||
|
#chaser catching the man score penalty is covered in man.py unlike the beast game
|
||||||
|
|
||||||
|
|
||||||
|
def get_adjacent_positions(self):
|
||||||
|
"""Returns a list of all adjacent positions, including diagonals
|
||||||
|
"""
|
||||||
|
positions = []
|
||||||
|
for i in [-1, 0, 1]:
|
||||||
|
for j in [-1, 0, 1]:
|
||||||
|
if i or j:
|
||||||
|
positions.append(add(self.position, (i, j)))
|
||||||
|
return positions
|
||||||
|
|
||||||
|
def should_move(self):
|
||||||
|
return random() < self.probability_of_moving
|
||||||
|
|
||||||
|
def should_move_randomly(self):
|
||||||
|
return random() < self.probability_of_random_move
|
||||||
|
|
||||||
|
def choose_best_move(self, possible_moves, game):
|
||||||
|
man = game.get_agent_by_name("man")
|
||||||
|
move_distances = [[distance(man.position, move), move] for move in possible_moves]
|
||||||
|
shortest_distance, best_move = sorted(move_distances)[0]
|
||||||
|
return best_move
|
||||||
|
|
||||||
|
def die(self, game):
|
||||||
|
"""Removes the chaser if the man runs into him, man death is described in man.py"""
|
||||||
|
game.remove_agent(self)
|
||||||
|
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
'''List of helper functions to move the man, none used in this game, but here in
|
"""List of helper functions to move the man_chaser, adopted from Chris's beast game."""
|
||||||
case needed for future version'''
|
|
||||||
|
|
||||||
'''def add(vec0, vec1):
|
|
||||||
|
def add(vec0, vec1):
|
||||||
"""Adds two vectors.
|
"""Adds two vectors.
|
||||||
Got tired of doing this by hand.
|
Got tired of doing this by hand.
|
||||||
"""
|
"""
|
||||||
x0, y0 = vec0
|
x0, y0 = vec0
|
||||||
x1, y1 = vec1
|
x1, y1 = vec1
|
||||||
return (x0 + x1, y0 + y1)
|
return (x0 + x1, y0 + y1)
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def get_occupant(game, position):
|
def get_occupant(game, position):
|
||||||
"""Returns the agent at position, if there is one.
|
"""Returns the agent at position, if there is one.
|
||||||
@@ -21,7 +19,7 @@ def get_occupant(game, position):
|
|||||||
if position in positions_with_agents:
|
if position in positions_with_agents:
|
||||||
agents_at_position = positions_with_agents[position]
|
agents_at_position = positions_with_agents[position]
|
||||||
return agents_at_position[0]
|
return agents_at_position[0]
|
||||||
'''
|
|
||||||
def distance(vec0, vec1):
|
def distance(vec0, vec1):
|
||||||
"""Returns the distance between two vectors, using the
|
"""Returns the distance between two vectors, using the
|
||||||
"manhattan distance," or the distance if you can only
|
"manhattan distance," or the distance if you can only
|
||||||
@@ -30,4 +28,4 @@ def distance(vec0, vec1):
|
|||||||
"""
|
"""
|
||||||
x0, y0 = vec0
|
x0, y0 = vec0
|
||||||
x1, y1 = vec1
|
x1, y1 = vec1
|
||||||
return abs(x1 - x0) + abs(y1 - y0)'''
|
return abs(x1 - x0) + abs(y1 - y0)
|
||||||
@@ -5,8 +5,8 @@ from snack import Snack
|
|||||||
width=25
|
width=25
|
||||||
height=25
|
height=25
|
||||||
|
|
||||||
'''Establishes keyboard arrow keys as direction vectors so each arrow key corresponds with movement
|
"""Establishes keyboard arrow keys as direction vectors so each arrow key corresponds with movement
|
||||||
in a certain direction on the board.'''
|
in a certain direction on the board."""
|
||||||
direction_vectors = {
|
direction_vectors = {
|
||||||
"KEY_RIGHT": (1, 0),
|
"KEY_RIGHT": (1, 0),
|
||||||
"KEY_UP": (0, -1),
|
"KEY_UP": (0, -1),
|
||||||
@@ -19,21 +19,24 @@ class Man:
|
|||||||
color = "blue"
|
color = "blue"
|
||||||
snack=False
|
snack=False
|
||||||
mine=False
|
mine=False
|
||||||
|
chaser=False
|
||||||
|
name= "man"
|
||||||
|
|
||||||
def __init__(self,position):
|
def __init__(self,position):
|
||||||
self.position = position
|
self.position = position
|
||||||
|
|
||||||
def handle_keystroke(self, keystroke, game):
|
def handle_keystroke(self, keystroke, game):
|
||||||
'''Describes how a keystroke is received'''
|
"""Describes how a keystroke is received"""
|
||||||
if keystroke.name in direction_vectors:
|
if keystroke.name in direction_vectors:
|
||||||
vector = direction_vectors[keystroke.name]
|
vector = direction_vectors[keystroke.name]
|
||||||
self.try_to_move(vector, game)
|
self.try_to_move(vector, game)
|
||||||
|
|
||||||
def try_to_move(self, vector, game):
|
def try_to_move(self, vector, game):
|
||||||
'''Checks if a space is avialable to move. Also adds 1 point if the space
|
"""Checks if a space is avialable to move. Also adds 1 point if the space
|
||||||
contains a snack and then removes the snack. Deducts 10 points if the
|
contains a snack and then removes the snack. Deducts 10 points if the
|
||||||
space contains a mine. Checks that the score is not negative and if it
|
space contains a mine. Deducts 20 points if the space contains a chaser.
|
||||||
is, ends the game. Also stores the score so it can be used to determine if more mines are needed'''
|
Checks that the score is not negative and if it is, ends the game. Also
|
||||||
|
stores the score so it can be used to determine if more mines are needed"""
|
||||||
x,y = self.position
|
x,y = self.position
|
||||||
vx,vy = vector
|
vx,vy = vector
|
||||||
future_position = (x +vx, y+vy)
|
future_position = (x +vx, y+vy)
|
||||||
@@ -49,6 +52,13 @@ class Man:
|
|||||||
if obstacle.snack:
|
if obstacle.snack:
|
||||||
game.state['Score'] += 1
|
game.state['Score'] += 1
|
||||||
game.remove_agent(agents[0])
|
game.remove_agent(agents[0])
|
||||||
|
elif obstacle.chaser:
|
||||||
|
game.state['Score'] -= 20
|
||||||
|
game.remove_agent(agents[0])
|
||||||
|
if game.state['Score'] <0:
|
||||||
|
self.die(game)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
game.state['Score'] -= 10
|
game.state['Score'] -= 10
|
||||||
game.remove_agent(agents[0])
|
game.remove_agent(agents[0])
|
||||||
@@ -60,7 +70,7 @@ class Man:
|
|||||||
self.position = future_position
|
self.position = future_position
|
||||||
|
|
||||||
def die(self,game):
|
def die(self,game):
|
||||||
'''Indicates what happens when the game is over.'''
|
"""Indicates what happens when the game is over."""
|
||||||
game.state["Message"] = "Game Over"
|
game.state["Message"] = "Game Over"
|
||||||
self.color = "black"
|
self.color = "black"
|
||||||
game.end()
|
game.end()
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
'''Sets up the mine object.'''
|
"""Sets up the mine object."""
|
||||||
|
|
||||||
class Mine:
|
class Mine:
|
||||||
character = "*"
|
character = "*"
|
||||||
color = "green"
|
color = "green"
|
||||||
snack=False
|
snack=False
|
||||||
mine=True
|
mine=True
|
||||||
|
chaser=False
|
||||||
|
|
||||||
|
|
||||||
def __init__(self,position):
|
def __init__(self,position):
|
||||||
|
|||||||
@@ -1,18 +1,35 @@
|
|||||||
from retro.game import Game
|
from retro.game import Game
|
||||||
from board import Board
|
from board import Board
|
||||||
|
|
||||||
'''This contains the main info for setting up and running the game.'''
|
"""This contains the main info for setting up and running the game."""
|
||||||
|
|
||||||
width = 25
|
width = 25
|
||||||
height = 25
|
height = 25
|
||||||
state= {"Score": 0}
|
state= {"Score": 0}
|
||||||
num_snacks = 10
|
num_snacks = 10
|
||||||
board = Board(width,height,num_snacks,state) #sets the original board
|
num_chasers = 5
|
||||||
|
|
||||||
|
"""Values to call later, sets no more than 100 mines, and each list represent a level [score, num_mines],
|
||||||
|
which is called in mine_counter in board.py."""
|
||||||
|
MAX_MINES = 100
|
||||||
|
LEVELS = [
|
||||||
|
[5, 10],
|
||||||
|
[10, 20],
|
||||||
|
[15, 30],
|
||||||
|
[20, 40],
|
||||||
|
[30,50],
|
||||||
|
[40,60],
|
||||||
|
[50,70],
|
||||||
|
[60,80],
|
||||||
|
[70,90]
|
||||||
|
]
|
||||||
|
|
||||||
|
board = Board(width,height,num_snacks,num_chasers,MAX_MINES,LEVELS,state) #sets the original board
|
||||||
|
|
||||||
game = Game(
|
game = Game(
|
||||||
board.get_agents(num_snacks,state),
|
board.get_agents(num_snacks,num_chasers,state),
|
||||||
state,
|
state,
|
||||||
board_size = (width, height),debug=False
|
board_size = (width, height),debug=False
|
||||||
)
|
)
|
||||||
|
|
||||||
game.play()
|
game.play()
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
'''Sets up the snack object'''
|
|
||||||
|
"""Sets up the snack object"""
|
||||||
|
|
||||||
class Snack:
|
class Snack:
|
||||||
character = "o"
|
character = "o"
|
||||||
color = "red"
|
color = "red"
|
||||||
snack=True
|
snack=True
|
||||||
mine=False
|
mine=False
|
||||||
|
chaser=False
|
||||||
|
|
||||||
|
|
||||||
def __init__(self,position):
|
def __init__(self,position):
|
||||||
|
|||||||
Reference in New Issue
Block a user