Пример #1
0
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)
Пример #2
0
class SnakeEnvironment(object):
    def __init__(self, width, height):
        self._width = width
        self._height = height
        self.game_state = 'init'
        self.action_list = ['u','d','l','r',None]

        self.snake = Snake(width, height)
        self.candy = Candy(width, height)

        self.world_map = Map(width, height)
        self.world_map.make_lst(self.snake, self.candy)

        self.done = False

    @property
    def height(self):
        return self._height

    @property
    def width(self):
        return self._width

    def _replace_item_map(self, x):
        if x in 'v^><':
            return 0
        elif x == '@':
            return 1
        elif x == '*':
            return 2
        else:
            return 3

    @property
    def state(self):
        '''
        Return state from raw map
        wall - 0
        snake - 1
        candy - 2
        '''
        state_map = self.world_map.map.copy()
        for i in range(self.height):
            state_map[i] = list(map(self._replace_item_map, state_map[i]))
        return np.array(state_map)

    def reset(self):
        '''
        Reset state (e.g. Game over)
        and return init state
        '''
        self.game_state = 'init'

        self.snake = Snake(self.width, self.height)
        self.candy = Candy(self.width, self.height)

        self.world_map = Map(self.width, self.height)
        self.world_map.make_lst(self.snake, self.candy)
        self.done = False
        return self.state

    def step(self, action):
        '''
        Input:
        Int - action

        Output:
        Float - reward

        Move an act, return state, reward & done
        '''
        self.snake.move(self.candy, self.action_list[action])
        self.candy.candy_update(self.snake)
        self.world_map.make_lst(self.snake, self.candy)

        if self.candy.candy_eaten:
            return self.state, 5, self.snake.dead, None
        
        if self.snake.dead:
            self.done = True
            # The training process will negative it
            return self.state, 5, self.snake.dead, None

        return self.state, 0, self.snake.dead, None

    
    def render(self):
        '''
        Render game from map
        '''
        clear()
        for stri in self.world_map.map:
            for char in stri:
                print(char, end='')
            print('')
Пример #3
0
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
Пример #4
0
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