class GameManager(): game_over = False food = None def __init__(self, root, res=20): self.root = root width, height = self.root.get_size() self.cols = int(width / res) self.rows = int(height / res) self.res = res self.gen_food() self.player = Snake(self.root, (400, 300), res=self.res) def reset(self): del self.player self.player = Snake(self.root, (400, 300), res=self.res) self.gen_food() self.game_over = False def gen_food(self): fx = randint(0, self.cols - 1) fy = randint(0, self.rows - 1) self.food = pygame.Rect(fx * self.res, fy * self.res, self.res, self.res) def draw_food(self): if self.food: food_color = (200, 34, 34) pygame.draw.rect(self.root, food_color, self.food) def _draw_map(self): cell_color = (200, 200, 200, 10) for row in range(self.rows): for col in range(self.cols): cell = pygame.Rect(col * self.res, row * self.res, self.res, self.res) pygame.draw.rect(self.root, cell_color, cell, 1) def update(self, dt, events): for event in events: if event.key == pygame.K_ESCAPE: self.reset() return self.player.update(dt, events) head = self.player.body[-1] if head and head.colliderect(self.food): self.player.grow() self.gen_food() def draw(self): # self._draw_map() self.draw_food() self.player.draw()
class Game: def __init__(self, visible=True, waitForEyes=False): self.visible= visible self.waitForEyes= waitForEyes self.iterations_count = 0 self.score = 0 #self.main_snake = Snake(4, 4 ) self.main_snake = Snake(random.randint(4,11), random.randint(3,4) ) self.apple_eaten = False self.apple = self.spawn_apple() self.running = True # self.last_info = self.get_info() self.grow_snake = False pygame.init() pygame.display.set_caption("Snake") pygame.font.init() if (not self.visible): pygame.display.iconify() random.seed() self.main_screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.HWSURFACE) self.score_font = pygame.font.Font(None, 25) self.score_area_font = pygame.font.Font(None, 25) self.game_over_font = pygame.font.Font(None, 45) self.play_again_font = self.score_area_font self.score_msg = self.score_font.render("Score:", 1, pygame.Color("white")) self.score_msg_size = self.score_font.size("Score") self.background_color = pygame.Color(100, 100, 100) image_path = os.path.dirname(__file__) self.apple_image = pygame.transform.scale( pygame.image.load(os.path.join(image_path, "apple.png")).convert_alpha(), (BLOCK_SIZE, BLOCK_SIZE)) self.snake_image = pygame.transform.scale( pygame.image.load(os.path.join(image_path, "snake_box.jpg")).convert_alpha(), (BLOCK_SIZE, BLOCK_SIZE)) def get_info(self): closest_right = 1 closest_left = 1 closest_up = 1 closest_down = 1 head = self.main_snake.elements[0] while closest_right <= BOARD_WIDTH - head.x: if self.main_snake.collides_with_body(Segment(head.x + closest_right, head.y)): break closest_right += 1 while closest_left <= head.x + 1: if self.main_snake.collides_with_body(Segment(head.x - closest_left, head.y)): break closest_left += 1 while closest_down <= BOARD_HEIGHT - head.y: if self.main_snake.collides_with_body(Segment(head.x, head.y + closest_down)): break closest_down += 1 while closest_up <= head.y + 1: if self.main_snake.collides_with_body(Segment(head.x, head.y - closest_up)): break closest_up += 1 closest_right = min(closest_right, BOARD_WIDTH - head.x) closest_left = min(closest_left, head.x + 1) closest_down = min(closest_down, BOARD_HEIGHT - head.y) closest_up = min(closest_up, head.y + 1) apple_x_dist = abs(self.main_snake.elements[0].x - self.apple.x) apple_y_dist = abs(self.main_snake.elements[0].y - self.apple.y) info = { "right_crash": closest_right, "left_crash": closest_left, "down_crash": closest_down, "up_crash": closest_up, "reward": 0, "lost_game": False, "apple_x": apple_x_dist, "apple_y": apple_y_dist, "score": self.score, "iterations_count": self.iterations_count } print("\nRight crash: {0}, left crash: {1}, up crash: {2}, " "down crash: {3}. Reward: {4}, lost game: {5}. Apple x: {6}, " "apple y: {7}, score: {8}, number of iterations {9}".format(info["right_crash"], info["left_crash"], info["up_crash"], info["down_crash"], info["reward"], info["lost_game"], info["apple_x"], info["apple_y"], info["score"], info["iterations_count"])) return info def get_action(self, action): if action == KEY["UP"]: event = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_UP) elif action == KEY["DOWN"]: event = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_DOWN) elif action == KEY["LEFT"]: event = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_LEFT) elif action == KEY["RIGHT"]: event = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_RIGHT) # make the move pygame.event.post(event) def wait_for_action(self): while True: event = pygame.event.wait() if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: return KEY["UP"] elif event.key == pygame.K_DOWN: return KEY["DOWN"] elif event.key == pygame.K_LEFT: return KEY["LEFT"] elif event.key == pygame.K_RIGHT: return KEY["RIGHT"] elif event.key == pygame.K_ESCAPE: return KEY["EXIT"] elif event.key == pygame.K_y: return KEY["YES"] elif event.key == pygame.K_n: return KEY["NO"] if event.type == pygame.QUIT: sys.exit() def spawn_apple(self): valid_apple = False x = 0 y = 0 while not valid_apple: valid_apple = True x = random.randint(0, BOARD_WIDTH - 1) y = random.randint(0, BOARD_HEIGHT - 1) for segment in self.main_snake.elements: if check_collision(segment, Segment(x, y)): valid_apple = False break return Apple(x, y, True) def rerun(self): self.__init__(self.visible, self.waitForEyes) def end_game(self): # self.get_info() self.running = False def get_snake_size(self): return len(self.main_snake.elements) def draw_score(self): score_area = self.score_area_font.render(str(self.score), 1, pygame.Color("white")) self.main_screen.blit(self.score_msg, (SCREEN_WIDTH - self.score_msg_size[0] - 60, 10)) self.main_screen.blit(score_area, (SCREEN_WIDTH - 45, 10)) def redraw_game(self): self.main_screen.fill(self.background_color) if self.apple.exists: self.apple.draw(self.main_screen, self.apple_image) self.main_snake.draw(self.main_screen, self.snake_image) self.draw_score() if DISPLAY: pygame.display.flip() pygame.display.update() def action(self, action_key): if action_key == KEY["EXIT"]: self.running = False # Move snake if self.grow_snake: self.main_snake.grow() if action_key: self.main_snake.set_direction(action_key) self.main_snake.move() return self.last_info def run(self, action): # Draw game self.redraw_game() # print(self.send_state(), action) # Check apple availability self.grow_snake = False if self.apple.exists: if check_collision(self.main_snake.get_head(), self.apple): self.grow_snake = True self.apple.exists = False self.score += 5 self.apple_eaten = True # Spawn apple if self.apple_eaten: self.apple_eaten = False self.apple = self.spawn_apple() print("Wow, you've eaten an apple! Next apple: ({0}, {1})".format(self.apple.x, self.apple.y)) self.redraw_game() # Wait for user input (here goes agent's move) # self.main_snake.display_log() self.iterations_count += 1 if self.waitForEyes: time.sleep(0.3) # Here agent is telling what to do self.get_action(action) key_pressed = self.wait_for_action() if key_pressed == "exit": self.running = False if (key_pressed != action): print("error when getting key presed", key_pressed, action) # Move snake if self.grow_snake: self.main_snake.grow() if key_pressed in range(0, 4): self.main_snake.set_direction(key_pressed) self.main_snake.move() # Check collisions (walls and self) if self.main_snake.check_crash(): self.end_game() reward = self.send_reward() return (self.send_state(), reward) def send_reward(self): # reward = 0 # apple_part =0 # apple_distance = abs(self.apple.x - self.main_snake.get_head().x) + abs(self.apple.y - self.main_snake.get_head().y) # if apple_distance==1: # apple_part= REWARD["EAT"] # if self.running: # reward= REWARD["LIVE"] + apple_part # else: # reward = REWARD["DEATH"]+ apple_part # return reward apple_part =0 if(self.running == False): return REWARD["DEATH"] apple_distance = abs(self.apple.x - self.main_snake.get_head().x) + abs(self.apple.y - self.main_snake.get_head().y) # ------DIFFICULT SCENARIO--------- if apple_distance == 0: apple_part = REWARD["EAT"] # --------------------------------- #if self.apple.x == self.main_snake.get_head().x || self.apple.y == self.main_snake.get_head().y: # apple_part+=REWARD["EAT"]*0.2 # # -------EASIER SCENARIO----------- # apple_part = (1-(apple_distance/(BOARD_HEIGHT+BOARD_WIDTH))) * REWARD["EAT"] # # --------------------------------- return REWARD["LIVE"] + apple_part # when snake eats an apple => true # that is when the head of the snake is on the apple def snake_eating(self): return self.apple.x == self.main_snake.get_head().x and self.apple.y == self.main_snake.y # Sends state to agent # List of collisions (U, R, D L) and apple distances (U, R, D, L) def send_state(self): collisions = self.check_collisions_all_directions() apple_distance = self.check_apple_all_directions() if len(collisions) != 4 or len(apple_distance) != 4: print(collisions) print(apple_distance) return collisions + apple_distance def check_apple_all_directions(self): # distance = [0,0,0,0] distance = [] # snake is eating the apple now => no reward for that if self.snake_eating(): return [TOOBIG,TOOBIG,TOOBIG,TOOBIG] #return self.check_apple() # UP distance.append(self.distance_calc(self.apple.x, self.apple.y,self.main_snake.get_head().x, self.main_snake.get_head().y-1)) #distance.append(self.distance_give(self.apple.x, self.apple.y,self.main_snake.get_head().x, self.main_snake.get_head().y,KEY["UP"])) # DOWN distance.append(self.distance_calc(self.apple.x,self.apple.y, self.main_snake.get_head().x, self.main_snake.get_head().y+1)) #distance.append(self.distance_give(self.apple.x,self.apple.y, self.main_snake.get_head().x, self.main_snake.get_head().y, KEY["DOWN"])) # LEFT distance.append(self.distance_calc(self.apple.x,self.apple.y, self.main_snake.get_head().x-1, self.main_snake.get_head().y)) #distance.append(self.distance_give(self.apple.x,self.apple.y, self.main_snake.get_head().x, self.main_snake.get_head().y, KEY["LEFT"])) # RIGHT distance.append(self.distance_calc(self.apple.x, self.apple.y,self.main_snake.get_head().x+1, self.main_snake.get_head().y)) #distance.append(self.distance_give(self.apple.x, self.apple.y,self.main_snake.get_head().x, self.main_snake.get_head().y, KEY["RIGHT"])) colissions= self.check_collisions_all_directions() for i in range(len(colissions)): if(colissions[i]<=0): distance[i]=TOOBIG print(distance) return distance def distance_calc(self, applex, appley, snakex, snakey): return abs(applex - snakex) + abs(appley - snakey) def distance_give(self, applex, appley, snakex,snakey, direction): #distances= [] snake_elements_without_tail = self.main_snake.elements[:-1] if direction == KEY["UP"] : if applex==snakex and appley <= snakey: for segment in snake_elements_without_tail: if segment.x == applex and segment.y < snakey and segment.y > appley: return 0 return 1 return 0 if direction == KEY["DOWN"]: if applex==snakex and appley >= snakey: for segment in snake_elements_without_tail: if segment.x == applex and segment.y > snakey and segment.y < appley: return 0 return 1 return 0; if direction == KEY["LEFT"]: if appley==snakey and applex <= snakex: for segment in snake_elements_without_tail: if segment.y == appley and segment.x < snakex and segment.x > applex: return 0 return 1 return 0 if direction == KEY["RIGHT"]: if appley==snakey and applex >= snakex: for segment in snake_elements_without_tail: if segment.y == appley and segment.x > snakex and segment.x < applex: return 0 return 1 return 0 def check_apple(self): apple = [] applex = self.apple.x appley = self.apple.y # UP distance = TOOBIG new_head = (self.main_snake.get_head().x, self.main_snake.get_head().y - 1) if applex==new_head[0] and appley <= new_head[1]: distance= abs(new_head[1]- appley) apple.append(distance) # DOWN distance = TOOBIG new_head = (self.main_snake.get_head().x, self.main_snake.get_head().y + 1) if applex==new_head[0] and appley >= new_head[1]: distance= abs(new_head[1]- appley) apple.append(distance) # LEFT distance = TOOBIG new_head = (self.main_snake.get_head().x - 1, self.main_snake.get_head().y) if appley==new_head[1] and applex <= new_head[0]: distance= abs(new_head[0]- applex) apple.append(distance) # RIGHT distance = TOOBIG new_head = (self.main_snake.get_head().x + 1, self.main_snake.get_head().y) if appley==new_head[1] and applex >= new_head[0]: distance= abs(new_head[0]- applex) apple.append(distance) return apple def check_collisions_all_directions(self): collision = [] # UP distance = self.main_snake.get_head().y new_head = (self.main_snake.get_head().x, self.main_snake.get_head().y - 1) snake_elements_without_tail = self.main_snake.elements[:-1] for segment in snake_elements_without_tail: if segment.x == new_head[0] and segment.y < self.main_snake.get_head().y: distance = min(distance, abs(segment.y - new_head[1])) collision.append(distance) # DOWN distance = BOARD_HEIGHT - self.main_snake.get_head().y - 1 new_head = (self.main_snake.get_head().x, self.main_snake.get_head().y + 1) for segment in snake_elements_without_tail: if segment.x == new_head[0] and segment.y > self.main_snake.get_head().y: distance = min(distance, abs(segment.y - new_head[1])) collision.append(distance) # LEFT distance = self.main_snake.get_head().x new_head = (self.main_snake.get_head().x - 1, self.main_snake.get_head().y) for segment in snake_elements_without_tail: if segment.y == new_head[1] and segment.x < self.main_snake.get_head().x: distance = min(distance, abs(new_head[0] - segment.x)) collision.append(distance) # RIGHT distance = BOARD_WIDTH - self.main_snake.get_head().x - 1 new_head = (self.main_snake.get_head().x + 1, self.main_snake.get_head().y) for segment in snake_elements_without_tail: if segment.y == new_head[1] and segment.x > self.main_snake.get_head().x: distance = min(distance, abs(new_head[0] - segment.x)) collision.append(distance) return collision