class Game: def __init__(self, numOfSnakes: int = Constants.numberOfSnakes, gridSize: int = Constants.gridSize, maxEpisodeLength: int = Constants.globalEpisodeLength): """ Initializes the game with the number of snakes, size of game window, pieces of food, and maximum length of game :param numOfSnakes: number of snake to initialize :param gridSize: size of the game window :param maxEpisodeLength: maximum length of time the game lasts """ self.snakes: list = [] # empty list of snakes for idx in range(numOfSnakes): self.snakes.append(Snake(idx)) # adds snakes to the list self.food = Food( Snake.snakeList ) # initializes the food points on screen? (can't find declaration of Food()) self.gameLength: int = maxEpisodeLength self.time_step: int = 0 # int to keep track of the length of the game return def __str__(self) -> str: """ Prints a message displaying the status of the game (amount of time steps, food, and snakes) :return: returns the message to be printed """ print_message = "Time " + str( self.time_step ) + "\n" # adds the amount of time steps to the message print_message += "Food = " + str(map( str, self.food.foodList)) + "\n" # adds location of food to the message for s in self.snakes: print_message += str(s) + "\n" # adds number of snakes to message return print_message def move(self, actionsList: list = []) -> (List[int], bool): """ Takes in a list of actions corresponding to each snake in the game. If a snake is dead, then its corresponding position in actionsList simply holds None. Returns boolean indicating whether the game has ended The Game ends if the time step has reached the specified length of the game, or if all snakes are dead. :param actionsList: list of potential actions snake can take :return: """ assert len(actionsList) == len( self.snakes), "Deficiency of actions provided." action_validity_check = [] # sifts through list of possible actions of each snake and throws an error if there are any invalid ones for i in range(len(self.snakes)): s = self.snakes[i] if s.alive: permissible_actions = s.permissible_actions() action_validity_check.append( actionsList[i] in permissible_actions) assert all(action_validity_check), "At least one action is invalid" self.time_step += 1 # increment time steps single_step_rewards = [0] * len( self.snakes ) # gives list of zeros with length equal to the number of snakes """ Increments through each snake and their corresponding actions and performs necessary actions """ for i in range(len(actionsList)): snake = self.snakes[i] if snake.alive: snake.moveInDirection( actionsList[i]) # moves snake based on chosen action # if the snake ate food, grow snake, destroy food, and reward agent if snake.didEatFood(self.food): snake.incrementScore(10) snake.growSnake() self.food.eatFood(snake.head, Snake.snakeList) single_step_rewards[i] = 10 # if the snake hit a wall, kill snake and punish agent elif snake.didHitWall(): snake.backtrack() snake.killSnake(self.food) snake.incrementScore(-10) single_step_rewards[i] = -10 # iterates through each snake to see if two snakes hit each other for i in range(len(self.snakes)): for j in range(len(self.snakes)): if i == j: continue if not (self.snakes[i].alive and self.snakes[j].alive): continue # if one snake hits another, kill the snake (not clear which one) if self.snakes[i].didHitSnake(self.snakes[j]): self.snakes[i].backtrack() self.snakes[i].killSnake(self.food) return (single_step_rewards, not (self.time_step == self.gameLength or all([not s.alive for s in self.snakes]))) def endGame(self) -> list: """ Deletes food and snakes, returns final scores :return: list of each snakes final score """ scoreboard: list = [s.score for s in self.snakes] del self.food # deletes the food on screen del self.snakes # deletes the snakes on the screen return scoreboard
class Game: def __init__(self, numOfSnakes=Constants.numberOfSnakes, gridSize=Constants.gridSize, maxEpisodeLength=Constants.globalEpisodeLength): self.snakes = [] for idx in range(numOfSnakes): self.snakes.append(Snake(idx)) self.food = Food(Snake.snakeList) self.gameLength = maxEpisodeLength self.time_step = 0 return def __str__(self): print_message = "Time " + str(self.time_step) + "\n" print_message += "Food = " + str(map(str, self.food.foodList)) + "\n" for s in self.snakes: print_message += str(s) + "\n" return print_message def move(self, actionsList=[]): """ Takes in a list of actions corresponding to each snake in the game. If a snake is dead, then its corresponding position in actionsList simply holds None. Returns boolean indicating whether the game has ended """ assert len(actionsList) == len( self.snakes), "Deficiency of actions provided." action_validity_check = [] for i in range(len(self.snakes)): s = self.snakes[i] if s.alive: permissible_actions = s.permissible_actions() action_validity_check.append( actionsList[i] in permissible_actions) assert all(action_validity_check), "At least one action is invalid" self.time_step += 1 single_step_rewards = [0] * len(self.snakes) for i in range(len(actionsList)): snake = self.snakes[i] if snake.alive: snake.moveInDirection(actionsList[i]) if snake.didEatFood(self.food): snake.incrementScore(1) snake.growSnake() self.food.eatFood(snake.head, Snake.snakeList) single_step_rewards[i] = 1 elif snake.didHitWall(): snake.backtrack() snake.killSnake(self.food) snake.incrementScore(-10) single_step_rewards[i] = -10 for i in range(len(self.snakes)): for j in range(len(self.snakes)): if i == j: continue if not (self.snakes[i].alive and self.snakes[j].alive): continue if self.snakes[i].didHitSnake(self.snakes[j]): self.snakes[i].backtrack() self.snakes[i].killSnake(self.food) return (single_step_rewards, not (self.time_step == self.gameLength or all([not s.alive for s in self.snakes]))) def endGame(self): scoreboard = [s.score for s in self.snakes] del self.food del self.snakes return scoreboard
class SnakeGame: # constructor def __init__(self, width, height, secs, border): self.width = width self.height = height self.secs = secs self.playing = True self.reseting = False self.border = border self.buildGrid() self.move = Move() self.snake = Snake(width, height, border) self.food = Food(width, height, self.snake) self.score = 0 def play(self): while self.playing: self.reseting = False while self.playing and not self.isMoving(): time.sleep(self.secs) while self.playing and self.isMoving(): time.sleep(self.secs) self.moveSnake() while self.playing and not self.reseting: time.sleep(self.secs) print("stop playing") def stop(self): self.playing = False def reset(self): self.move = Move() time.sleep(self.secs) self.buildGrid() self.move = Move() self.snake = Snake(self.width, self.height, self.border) self.food = Food(self.width, self.height, self.snake) self.score = 0 self.reseting = True def isMoving(self): return self.move.isMoving() # return len of snake body def lenOfSnake(self): return self.snake.lenOfBody() # build grid for game def buildGrid(self): addBorder = 0 if self.border: addBorder = 2 self.grid = [[]] * (self.height + addBorder) for line in range(self.height + addBorder): self.grid[line] = [0] * (self.width + addBorder) if self.border: self.buildGridBorder() # build grid border def buildGridBorder(self): for line in range(self.height + 2): for column in range(self.width + 2): if line == 0 or line == self.height + 1 or column == 0 or column == self.width + 1: self.grid[line][column] = -1 def changeMoveOfSnake(self, newMove): turnBack = self.snake.lenOfBody() == 1 self.move.changeMove(newMove, turnBack) # move snake def moveSnake(self): movement = self.move.getMove() if self.snake.move(movement): head = self.snake.head() scoreFood = self.food.eatFood(head[0], head[1]) if scoreFood > 0: self.score += 1 self.snake.addPArt(movement, scoreFood) return True self.move.stop() return False