예제 #1
0
    def test_add_snake_collision(self):
        self.board.snakes = []

        self.board.add_object("snake", Point(x=20, y=20))
        self.board.add_object("snake", Point(x=20, y=20))

        snake_1 = self.board.objects['snake'].pop()
        snake_2 = self.board.objects['snake'].pop()

        self.assertEqual(False, snake_1 in snake_2, "These are the same snakes")
    def test_snake_eat_apple(self):
        self.board = Board(width=50, height=50)
        self.board.add_object("snake", Point(x=20, y=33))
        self.board.add_object("apple", Point(x=20, y=32))

        snake = self.board.objects['snake'][0]
        _, reward, _, _ = self.board.step(constants.GET_ACTION_MEANING.index("UP"))

        self.assertEqual(constants.DEFAULT_REWARD_PER_APPLE + constants.DEFAULT_REWARD_PER_STEP, reward,
                         "Snake eating apple incorrect points awarded")

        self.assertEqual(LEN_SNAKE_START+1, len(snake),
                         "Snake length is not increased after eating apple")
예제 #3
0
    def obs(self):
        """
            Generates the output array.
            The output will be a (24,) numpy array, with 3 times 8 directions.

            wall distance, snake distance, food distance
            ["UP", "DOWN", "LEFT", "LEFT UP", "LEFT DOWN", "RIGHT", "RIGHT UP", "RIGHT DOWN"]
        """
        object_types = [
            v for k, v in self.board.object_types.items() if k != "ground"
        ]
        obs_directions = [x
                          for x in itertools.product([0, 1, -1], repeat=2)][1:]
        obs_out = np.zeros((len(object_types), len(obs_directions)),
                           dtype=np.int)

        snake = self.board.objects['snake'][0]
        for idx_direction, direction in enumerate(obs_directions):
            scan_direction = Point(*direction)
            object_found = False
            scan_counter = 1
            while not object_found:
                scan_x = snake.position.x + scan_direction.x * scan_counter
                scan_y = snake.position.y + scan_direction.y * scan_counter
                for idx_object, object_type in enumerate(object_types):
                    if isinstance(self.board.board[scan_x, scan_y],
                                  object_type):
                        obs_out[idx_object, idx_direction] = scan_counter
                        object_found = True
                scan_counter += 1
        return obs_out.flatten()
    def test_collide_body(self):
        collide = self.snake.collide(
            type("", (), dict(position=Point(43, 150))))
        self.assertEqual(False, collide, "Collide body wrongly detected")

        collide = self.snake.collide(
            type("", (), dict(position=Point(50, 150))))
        self.assertEqual(False, collide, "Collide body wrongly detected")

        collide = self.snake.collide(
            type("", (), dict(position=Point(80, 120))))
        self.assertEqual(False, collide, "Collide body wrongly detected")

        collide = self.snake.collide(
            type("", (), dict(position=self.pos_start)))
        self.assertEqual(True, collide, "Collide body not detected")
예제 #5
0
    def add_object(self, name, position=None):
        """
            Add an object to the board

            :param name: str
                Name of the object you want to add, valid options are currently
                'wall', 'snake', 'ground', 'apple'

            :param position: Point
                Defines the position of the object on the board, if none is provided
                it will pick a random position on the board
        """
        start_pos = position if position is not None else self._random_point()

        if self.object_types.get(name.lower().strip(), None):
            new_object = self.object_types.get(name.lower().strip())(start_pos)

            if not self._collision_new_object(new_object):
                self.objects[name].append(new_object)
                self.board[start_pos.x, start_pos.y] = new_object
            else:
                options = self._locate_object(Ground)
                if not options:
                    raise ValueError("No space to put the new object.")
                new_pos = np.random.choice(range(len(options)))
                self.add_object(name, position=Point(*options[new_pos]))
        else:
            raise ValueError(f"Object '{name}' not familiar")
예제 #6
0
    def _create_board(width, height):
        """
            Creates a numpy array with only ground objects, can be populated by
            other Objects
        """
        board = np.zeros((width, height), dtype=np.object)

        for x in range(width):
            for y in range(height):
                border_row = (y % (height - 1)) == 0
                border_col = (x % (width - 1)) == 0

                if border_row or border_col:
                    board[x, y] = Wall(Point(x, y))
                else:
                    board[x, y] = Ground(Point(x, y))
        return board
예제 #7
0
    def test_add_snake_specific(self):
        self.board.snakes = []

        self.board.add_object("snake", Point(x=10, y=15))
        snake = self.board.objects['snake'].pop()

        self.assertEqual(10, snake.get_head().x, "x position not set correctly")
        self.assertEqual(15, snake.get_head().y, "y position not set correctly")
        self.assertEqual(constants.LEN_SNAKE_START, len(snake), "Snake is not start length")
    def test_snake_wall(self):
        self.board = Board(width=50, height=50)
        self.board.add_object("snake", Point(x=1, y=30))

        snake = self.board.objects['snake'][0]
        _, _, done, _ = self.board.step(constants.GET_ACTION_MEANING.index("LEFT"))
        self.board.step(1)

        self.assertEqual(True, done, "Game over is not detected upon dying")
        self.assertEqual(False, snake.alive,
                         "Snake didn't die upon hitting the wall")
    def setUp(self) -> None:
        self.objects_name = ["wall", "ground", "apple", "snake"]

        self.wall = Wall(Point(0, 0))
        self.ground = Ground(Point(10, 10))
        self.apple = Apple(Point(20, 20))
        self.snake = Snake(Point(30, 30))

        self.wall_same = Wall(Point(0, 0))
        self.ground_same = Ground(Point(0, 0))
        self.apple_same = Apple(Point(0, 0))
        self.snake_same = Snake(Point(0, 0))

        self.objects_diff = [getattr(self, name) for name in self.objects_name]
        self.objects_same = [getattr(self, name + "_same") for name in self.objects_name]
예제 #10
0
    def _random_point(self, min_distance=constants.MIN_SPAWN_WALL_DISTANCE):
        """
            Returns a random point on the board at least min_distance away from the sides.

            :param min_distance: int
                The minimum distance to the borders of the snake

            :return Point
                A position on the board at least min_distance away from the boarder
        """
        return Point(x=np.random.randint(min_distance,
                                         self.width - min_distance),
                     y=np.random.randint(min_distance,
                                         self.height - min_distance))
    def test_contains(self):
        # Please note that we can't swap 'UP' and 'DOWN' or 'LEFT' and 'RIGHT'
        # Due to the restriction that the snake can not turn 180 degrees from the previous direction.
        snake_diff = Snake(Point(self.pos_start.x, self.pos_start.y + 5))
        snake_diff.direction = self.start_direction

        for _ in range(4):
            snake_diff.step()
            self.assertEqual(False, self.snake in snake_diff,
                             "A Faulty collision detected")

        snake_diff.step()
        self.assertEqual(True, self.snake in snake_diff,
                         "Collision not detected")
        self.assertEqual(True, self.snake in self.snake,
                         "Snake doesn't contain itself")
 def setUp(self) -> None:
     self.pos_start = Point(50, 120)
     self.pos_diff = Point(50, 115)
     self.start_direction = "UP"
     self.snake = Snake(self.pos_start)