def main(): window = pygame.display.set_mode( (WINDOW_WIDTH * PIXEL_SIZE, WINDOW_HEIGHT * PIXEL_SIZE)) pygame.display.set_caption('SNAKE GAME') clock = pygame.time.Clock() score = 0 snake = Snake(WINDOW_WIDTH, WINDOW_HEIGHT, PIXEL_SIZE, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2) food = Food(WINDOW_WIDTH, WINDOW_HEIGHT, PIXEL_SIZE) run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False break elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: snake.change_direction(-1) break elif event.key == pygame.K_RIGHT: snake.change_direction(+1) break snake.move() if snake.collision_food(food.location): score += 1 food.state = False food.spawn(snake) if snake.collision_obstacles(): print('over') run = False if snake.get_length() == WINDOW_WIDTH * WINDOW_HEIGHT: print('win') run = False window.fill((0, 0, 0)) food.render(window) snake.render(window) pygame.display.set_caption('SNAKE GAME | Score: ' + str(score)) pygame.display.update() clock.tick(FPS)
class Agent: def __init__(self, code_id, log=False, visualization=False, fps=60): self.code_id = code_id self.snake = Snake(WINDOW_WIDTH, WINDOW_HEIGHT, PIXEL_SIZE, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2) self.food = Food(WINDOW_WIDTH, WINDOW_HEIGHT, PIXEL_SIZE) self.food.spawn(self.snake) self.log = log self.visualization = visualization self.window, self.clock = self.init_visualization() self.fps = fps # basic infos self.alive = True self.score = 0 self.step = 0 # useful infos self.s_obstacles = self.get_surrounding_obstacles() self.food_angle = self.get_food_angle() self.food_distance = self.get_food_distance() def init_visualization(self): if self.visualization: window = pygame.display.set_mode( (WINDOW_WIDTH * PIXEL_SIZE, WINDOW_HEIGHT * PIXEL_SIZE)) fps = pygame.time.Clock() return window, fps else: return None, None def get_random_move(self, random_n=10): # real random move, 1/random_n if random_n is not 0 and random.randint(1, random_n) == 1: return random.randint(-1, 1) s, a, d = self.get_state() # random move depend on state ops = [] # select move based on following the food angle and avoiding the obstacles if not s[0] and a < 0: ops.insert(-1, -1) if not s[1] and a == 0: ops.insert(-1, 0) if not s[2] and a > 0: ops.insert(-1, +1) # if no option if not ops: # select move based on avoiding obstacles if not s[0]: ops.insert(-1, -1) if not s[1]: ops.insert(-1, 0) if not s[2]: ops.insert(-1, +1) # again, if no option -> just die if not ops: return random.randint(-1, 1) else: return ops[random.randint(0, len(ops) - 1)] else: return ops[random.randint(0, len(ops) - 1)] def next_state(self, move_direction): self.step += 1 info = 'CodeID: {} | Step: {} | Score: {}'.format( self.code_id, self.step, self.score) self.snake.change_direction(move_direction) self.snake.move() if self.snake.collision_food(self.food.location): self.score += 1 self.food.state = False self.food.spawn(self.snake) if self.snake.collision_obstacles(): info += ' >> Game Over!' self.alive = False if self.snake.get_length() == WINDOW_WIDTH * WINDOW_HEIGHT: info += ' >> Win!' self.alive = False if self.log: print(info) if self.visualization: self.window.fill((0, 0, 0)) self.food.render(self.window) self.snake.render(self.window) pygame.display.set_caption(info) pygame.display.update() pygame.event.get() self.clock.tick(self.fps) return self.get_state() def get_state(self): return self.get_surrounding_obstacles(), self.get_food_angle( ), self.get_food_distance() def get_surrounding_obstacles(self): # check front snake_head = self.snake.head snake_heading_direction = self.snake.heading_direction left = self.snake.moves[(snake_heading_direction - 1) % len(self.snake.moves)] front = self.snake.moves[snake_heading_direction] right = self.snake.moves[(snake_heading_direction + 1) % len(self.snake.moves)] l_location = [snake_head[0] + left[0], snake_head[1] + left[1]] f_location = [snake_head[0] + front[0], snake_head[1] + front[1]] r_location = [snake_head[0] + right[0], snake_head[1] + right[1]] s_locations = [l_location, f_location, r_location] self.s_obstacles = [0, 0, 0] # check wall for i in range(0, len(s_locations)): if s_locations[i][0] < 0 or s_locations[i][0] >= WINDOW_WIDTH \ or s_locations[i][1] < 0 or s_locations[i][1] >= WINDOW_HEIGHT: self.s_obstacles[i] = 1 # check body for b in self.snake.body: if b in s_locations: self.s_obstacles[s_locations.index(b)] = 1 return self.s_obstacles def get_food_angle(self): # get direction of heading heading_direction = numpy.array( self.snake.moves[self.snake.heading_direction]) # get direction of food (distant) food_direction = numpy.array(self.food.location) - numpy.array( self.snake.head) h = heading_direction / numpy.linalg.norm(heading_direction) f = food_direction / numpy.linalg.norm(food_direction) fa = math.atan2(h[0] * f[1] - h[1] * f[0], h[0] * f[0] + h[1] * f[1]) / math.pi if fa == -1 or fa == 1: fa = 1 self.food_angle = fa return self.food_angle def get_food_distance(self): head = numpy.array(self.snake.head) food = numpy.array(self.food.location) max_dis = numpy.linalg.norm( numpy.array([0, 0]) - numpy.array([WINDOW_WIDTH - 1, WINDOW_HEIGHT - 1])) dis = numpy.linalg.norm(head - food) # normalize distance to the range 0 - 1 self.food_distance = dis / max_dis return self.food_distance