"""
Student portion of Zombie Apocalypse mini-project
"""
#http://www.codeskulptor.org/#user43_yCIa8eafEzbL3Am_20.py
import random
import poc_grid
import poc_queue
import poc_zombie_gui
# global constants
EMPTY = 0
FULL = 1
FOUR_WAY = 0
EIGHT_WAY = 1
OBSTACLE = 5
HUMAN = 6
ZOMBIE = 7
class Apocalypse(poc_grid.Grid):
"""
Class for simulating zombie pursuit of human on grid with
obstacles
"""
def __init__(self, grid_height, grid_width, obstacle_list = None,
zombie_list = None, human_list = None):
"""
Create a simulation of given size with given obstacles,
humans, and zombies
"""
poc_grid.Grid.__init__(self, grid_height, grid_width)
if obstacle_list != None:
for cell in obstacle_list:
self.set_full(cell[0], cell[1])
if zombie_list != None:
self._zombie_list = list(zombie_list)
else:
self._zombie_list = []
if human_list != None:
self._human_list = list(human_list)
else:
self._human_list = []
def clear(self):
"""
Set cells in obstacle grid to be empty
Reset zombie and human lists to be empty
"""
poc_grid.Grid.clear(self)
self._zombie_list = []
self._human_list = []
return
def add_zombie(self, row, col):
"""
Add zombie to the zombie list
"""
self._zombie_list.append((row,col))
return
def num_zombies(self):
"""
Return number of zombies
"""
return len(self._zombie_list)
def zombies(self):
"""
Generator that yields the zombies in the order they were
added.
"""
for zombie in self._zombie_list:
yield zombie
def add_human(self, row, col):
"""
Add human to the human list
"""
self._human_list.append((row,col))
def num_humans(self):
"""
Return number of humans
"""
return len(self._human_list)
def humans(self):
"""
Generator that yields the humans in the order they were added.
"""
for human in self._human_list:
yield human
def print_all(self):
"""
prints out a grid showing where humans, zombies, and blocks are.
"""
grid_copy = list(self._cells)
for human in self.humans():
grid_copy[human[0]][human[1]] = 6
for zombie in self.zombies():
grid_copy[zombie[0]][zombie[1]] = 7
ans = ""
for row in range(self._grid_height):
ans += str(grid_copy[row])
ans += "\n"
return ans
def compute_distance_field(self, entity_type):
"""
Function computes and returns a 2D distance field
Distance at member of entity_list is zero
Shortest paths avoid obstacles and use four-way distances
"""
boundary = poc_queue.Queue()
visited = poc_grid.Grid(self.get_grid_height(),self.get_grid_width())
distance_field = [[self.get_grid_height()*self.get_grid_width() for dummy_col in range(self.get_grid_width())]
for dummy_row in range(self.get_grid_height())]
#Que entities to boundary
if entity_type == HUMAN:
for human in self.humans():
boundary.enqueue(human)
elif entity_type == ZOMBIE:
for zombie in self.zombies():
boundary.enqueue(zombie)
else:
print "invalid input"
return
#set entity positions in visited grid as "full" and in distance_field as "0"
for item in boundary:
visited.set_full(item[0], item[1])
distance_field[item[0]][item[1]] = 0
#iterate to add new cells surrounding boundary members to boundary
#set new cells as full in visited and #steps in dist_field; dequeue original boundary cell
while boundary:
location = boundary.dequeue()
location_dist = distance_field[location[0]][location[1]]
adjacent = visited.four_neighbors(location[0], location[1])
for adj in adjacent:
if self.is_empty(adj[0],adj[1]) and visited.is_empty(adj[0],adj[1]):
boundary.enqueue(adj)
visited.set_full(adj[0], adj[1])
distance_field[adj[0]][adj[1]] = location_dist+1
return distance_field
def is_cell_empty(self, cell):
"""
returns if a cell is empty
"""
#takes single tuple instead of row, col... allows function to be used as filter
return self.is_empty(cell[0], cell[1])
def move_humans(self, zombie_distance_field):
"""
Function that moves humans away from zombies, diagonal moves
are allowed
"""
new_humans = []
for human in self.humans():
possible_moves = filter(self.is_cell_empty, self.eight_neighbors(human[0], human[1]))
best_move = self.get_best_move(human, possible_moves, zombie_distance_field, True)
new_humans.append(best_move)
self._human_list = new_humans
def move_zombies(self, human_distance_field):
"""
Function that moves zombies towards humans, no diagonal moves
are allowed
"""
new_zombies = []
for zombie in self.zombies():
possible_moves = filter(self.is_cell_empty, self.four_neighbors(zombie[0], zombie[1]))
best_move = self.get_best_move(zombie, possible_moves, human_distance_field, False)
new_zombies.append(best_move)
self._zombie_list = new_zombies
def get_best_move(self, current_position, possible_moves, distance_field, flee):
"""
returns one of possible best moves for a zombie or human
"""
best_move = []
best_move.append(current_position)
for move in possible_moves:
if flee:
if distance_field[move[0]][move[1]] > distance_field[best_move[0][0]][best_move[0][1]]:
best_move = [move]
elif distance_field[move[0]][move[1]] == distance_field[best_move[0][0]][best_move[0][1]]:
best_move.append(move)
elif not flee:
if distance_field[move[0]][move[1]] < distance_field[best_move[0][0]][best_move[0][1]]:
best_move = [move]
elif distance_field[move[0]][move[1]] == distance_field[best_move[0][0]][best_move[0][1]]:
best_move.append(move)
random.shuffle(best_move)
return best_move.pop()
# Start up gui for simulation - You will need to write some code above
# before this will work without errors
poc_zombie_gui.run_gui(Apocalypse(30, 40))
#game = Apocalypse(3, 3, [], [(2, 2)], [(1, 1)])
#dist = [[4, 3, 2], [3, 2, 1], [2, 1, 0]]
#print game
#print
#print "Print all:"
#print game.print_all()
#print
##dist = game.compute_distance_field(HUMAN)
#print "distance field:"
#for row in range(len(dist)):
# print dist[row]
#game.move_humans(dist)
#print "Moved humans"
#print game.print_all()
#i = 0
#j = 1
#rows = 10
#cols = 10
#blocks = [(3,8)]
##zombies = [(i,col) for col in range(cols)]
##humans = [(j,col) for col in range(cols)]
#zombies = [(0,4)]
#humans = [(1,4)]
#
#game = Apocalypse(rows, cols, blocks, zombies, humans)
#dist = game.compute_distance_field(ZOMBIE)
#print "distance field:"
#for row in range(len(dist)):
# print dist[row]
#print
#print game.print_all()
#game.move_humans(dist)
#print game.print_all()
#game.clear()
#print game
Comments