abbarnes icon

Zombie Apocalypse Sim [codeskulptor]

abbarnes | PRO | 12/13/17 03:22:14 PM UTC | 0 ⭐ | 251 👁️ | Never ⏰ | []
Python |

7.9 KB

|

None

|

0 👍

/

0 👎

"""
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