示例#1
0
 def __init__(self, conf):
     self._conf = conf
     self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
     self._snake = Snake(self._map, conf.init_direc, conf.init_bodies,
                         conf.init_types)
     self._pause = False
     self._solver = globals()[self._conf.solver_name](self._snake)
     self._episode = 1
示例#2
0
def test_copy():
    m = Map(5, 5)
    m.point(Pos(1, 1)).type = PointType.FOOD
    m_copy = m.copy()
    assert id(m) != id(m_copy)
    assert m.num_rows == m_copy.num_rows
    assert m.num_cols == m_copy.num_cols
    assert m.capacity == m_copy.capacity
    for i in range(m.num_rows):
        for j in range(m.num_cols):
            assert m.point(Pos(i, j)).type == m_copy.point(Pos(i, j)).type
示例#3
0
def test_init():
    with pytest.raises(TypeError):
        m = Map(5, 1.5)
    with pytest.raises(ValueError):
        m = Map(4, 5)
    m = Map(12, 12)
    for i in range(m.num_rows):
        for j in range(m.num_cols):
            if i == 0 or i == m.num_rows - 1 or j == 0 or j == m.num_cols - 1:
                assert m.point(Pos(i, j)).type == PointType.WALL
            else:
                assert m.point(Pos(i, j)).type == PointType.EMPTY
示例#4
0
def test_init():
    m = Map(5, 5)
    s = Snake(m, Direc.RIGHT,
              [Pos(1, 3), Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    assert not s.dead
    assert s.direc is Direc.RIGHT
    assert s.len() == 3
    assert s.head() == Pos(1, 3)
    assert s.bodies[1] == Pos(1, 2)
    assert s.tail() == Pos(1, 1)
    assert m.point(Pos(1, 1)).type == PointType.BODY_HOR
    assert m.point(Pos(1, 2)).type == PointType.BODY_HOR
    assert m.point(Pos(1, 3)).type == PointType.HEAD_R
示例#5
0
 def __init__(self, conf):
     self.__conf = conf
     self.__map = Map(conf.map_rows + 2, conf.map_cols + 2)
     self.__snake = Snake(self.__map, conf.init_direc, conf.init_bodies,
                          conf.init_types)
     self.__pause = False
     self.__window = GameWindow(
         conf, self.__map, "Snake", self.__snake, self.__on_exit,
         (('<w>', lambda e: self.__update_direc(Direc.UP)),
          ('<a>', lambda e: self.__update_direc(Direc.LEFT)),
          ('<s>', lambda e: self.__update_direc(Direc.DOWN)),
          ('<d>', lambda e: self.__update_direc(Direc.RIGHT)),
          ('<r>', lambda e: self.__reset()),
          ('<space>', lambda e: self.__toggle_pause())))
     self.__solver = globals()[self.__conf.solver_name](self.__snake)
     self.__episode = 1
     self.__init_log_file()
示例#6
0
def test_dead():
    m = Map(5, 5)
    s = Snake(m, Direc.RIGHT,
              [Pos(1, 3), Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    assert not s.dead
    s.move(s.direc)
    assert s.dead and s.len() == 3 and s.head() == Pos(1, 4)

    m.reset()
    s = Snake(m, Direc.RIGHT,
              [Pos(1, 3), Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    assert not s.dead
    s.move(Direc.UP)
    assert s.dead and s.len() == 3 and s.head() == Pos(0, 3)

    m.reset()
    s = Snake(m, Direc.DOWN,
              [Pos(3, 1), Pos(2, 1), Pos(1, 1)],
              [PointType.HEAD_D, PointType.BODY_VER, PointType.BODY_VER])
    assert not s.dead
    s.move(s.direc)
    assert s.dead and s.len() == 3 and s.head() == Pos(4, 1)

    m.reset()
    s = Snake(m, Direc.DOWN,
              [Pos(3, 1), Pos(2, 1), Pos(1, 1)],
              [PointType.HEAD_D, PointType.BODY_VER, PointType.BODY_VER])
    assert not s.dead
    s.move(Direc.LEFT)
    assert s.dead and s.len() == 3 and s.head() == Pos(3, 0)

    m.reset()
    s = Snake(
        m, Direc.LEFT,
        [Pos(2, 2), Pos(3, 2),
         Pos(3, 1), Pos(2, 1),
         Pos(1, 1)], [
             PointType.HEAD_U, PointType.BODY_LU, PointType.BODY_UR,
             PointType.BODY_VER, PointType.BODY_VER
         ])
    assert not s.dead
    s.move(s.direc)
    assert s.dead and s.len() == 5 and s.head() == Pos(2, 1)
示例#7
0
 def __init__(self, conf):
     self._conf = conf
     self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
     self._snake = Snake(self._map, conf.init_direc,
                         conf.init_bodies, conf.init_types)
     self._pause = False
     self._solver = globals()[self._conf.solver_name](self._snake)
     self._episode = 1
     self._init_log_file()
示例#8
0
def test_shortest():
    m = Map(7, 7)
    m.create_food(Pos(5, 5))
    s = Snake(m, Direc.RIGHT,
              [Pos(2, 3), Pos(2, 2), Pos(2, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    solver = PathSolver(s)
    act_path = solver.shortest_path_to_food()
    act_path = solver.shortest_path_to_food()  # Check idempotence
    expect_path = [
        Direc.RIGHT, Direc.RIGHT, Direc.DOWN, Direc.DOWN, Direc.DOWN
    ]
    assert len(act_path) == len(expect_path)
    for i, direc in enumerate(act_path):
        assert direc == expect_path[i]
    assert solver.table[5][1].dist == 5
    assert solver.table[5][1].dist == solver.table[5][5].dist
    # Empty path
    assert not solver.shortest_path_to(s.tail())
示例#9
0
def test_longest():
    m = Map(6, 6)
    m.create_food(Pos(4, 4))
    s = Snake(m, Direc.RIGHT,
              [Pos(1, 3), Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    solver = PathSolver(s)
    act_path = solver.longest_path_to_tail()
    act_path = solver.longest_path_to_tail()  # Check idempotence
    expect_path = [
        Direc.RIGHT, Direc.DOWN, Direc.DOWN, Direc.DOWN, Direc.LEFT,
        Direc.LEFT, Direc.LEFT, Direc.UP, Direc.RIGHT, Direc.RIGHT, Direc.UP,
        Direc.LEFT, Direc.LEFT, Direc.UP
    ]
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert len(act_path) == len(expect_path)
    for i, direc in enumerate(act_path):
        assert direc == expect_path[i]
    # Empty path
    assert not solver.longest_path_to(s.tail())
示例#10
0
def test_copy():
    m = Map(5, 5)
    s = Snake(m, Direc.RIGHT,
              [Pos(1, 3), Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR, PointType.BODY_HOR])
    s.move(Direc.DOWN)
    s.move(Direc.LEFT)
    s_copy, _ = s.copy()
    assert id(s) != id(s_copy)
    assert s.steps == 2 and s.steps == s_copy.steps
    assert not s.dead and s.dead == s_copy.dead
    assert s.direc == Direc.LEFT and s.direc == s_copy.direc
    assert s.direc_next == Direc.LEFT and s.direc_next == s_copy.direc_next
    for i, b in enumerate(s.bodies):
        assert b == s_copy.bodies[i]
示例#11
0
def test_cycle():
    m = Map(6, 6)
    s = Snake(m, Direc.RIGHT, [Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR])
    solver = HamiltonSolver(s, False)
    table = solver.table
    cnt = 0
    ori_head = s.head()
    while True:
        head = s.head()
        assert cnt == table[head.x][head.y].idx
        s.move(solver.next_direc())
        cnt += 1
        if s.head() == ori_head:
            break
    assert cnt == m.capacity
示例#12
0
class Game:

    def __init__(self, conf):
        self._conf = conf
        self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
        self._snake = Snake(self._map, conf.init_direc,
                            conf.init_bodies, conf.init_types)
        self._pause = False
        self._solver = globals()[self._conf.solver_name](self._snake)
        self._episode = 1
        self._init_log_file()

    @property
    def snake(self):
        return self._snake

    @property
    def episode(self):
        return self._episode

    def run(self):
        window = GameWindow("Snake", self._conf, self._map, self, self._on_exit, (
            ('<w>', lambda e: self._update_direc(Direc.UP)),
            ('<a>', lambda e: self._update_direc(Direc.LEFT)),
            ('<s>', lambda e: self._update_direc(Direc.DOWN)),
            ('<d>', lambda e: self._update_direc(Direc.RIGHT)),
            ('<r>', lambda e: self._reset()),
            ('<space>', lambda e: self._toggle_pause())
        ))
        if self._conf.mode == GameMode.NORMAL:
            window.show(self._game_main_normal)
        elif self._conf.mode == GameMode.TRAIN_DQN_GUI:
            window.show(self._game_main_dqn_train)
            self._plot_history()

    def _game_main_normal(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause or self._is_episode_end():
            return

        self._update_direc(self._solver.next_direc())

        if self._conf.mode == GameMode.NORMAL and self._snake.direc_next != Direc.NONE:
            self._write_logs()

        self._snake.move()

        if self._is_episode_end():
            self._write_logs()  # Write the last step

    def _plot_history(self):
        self._solver.plot()

    def _update_direc(self, new_direc):
        self._snake.direc_next = new_direc
        if self._pause:
            self._snake.move()

    def _toggle_pause(self):
        self._pause = not self._pause

    def _is_episode_end(self):
        return self._snake.dead or self._map.is_full()

    def _reset(self):
        self._snake.reset()
        self._episode += 1

    def _on_exit(self):
        if self._log_file:
            self._log_file.close()
        if self._solver:
            self._solver.close()

    def _init_log_file(self):
        try:
            os.makedirs("logs")
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
        try:
            self._log_file = None
            self._log_file = open('logs/snake.log', 'w')
        except FileNotFoundError:
            if self._log_file:
                self._log_file.close()

    def _write_logs(self):
        self._log_file.write("[ Episode %d / Step %d ]\n" % \
                             (self._episode, self._snake.steps))
        for i in range(self._map.num_rows):
            for j in range(self._map.num_cols):
                pos = Pos(i, j)
                t = self._map.point(pos).type
                if t == PointType.EMPTY:
                    self._log_file.write("  ")
                elif t == PointType.WALL:
                    self._log_file.write("# ")
                elif t == PointType.FOOD:
                    self._log_file.write("F ")
                elif t == PointType.HEAD_L or t == PointType.HEAD_U or \
                    t == PointType.HEAD_R or t == PointType.HEAD_D:
                    self._log_file.write("H ")
                elif pos == self._snake.tail():
                    self._log_file.write("T ")
                else:
                    self._log_file.write("B ")
            self._log_file.write("\n")
        self._log_file.write("[ last/next direc: %s/%s ]\n" % \
                              (self._snake.direc, self._snake.direc_next))
        self._log_file.write("\n")
示例#13
0
class Game:
    def __init__(self, conf):
        self._conf = conf
        self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
        self._snake = Snake(self._map, conf.init_direc, conf.init_bodies,
                            conf.init_types)
        self._pause = False
        self._solver = globals()[self._conf.solver_name](self._snake)
        self._episode = 1

    @property
    def snake(self):
        return self._snake

    @property
    def episode(self):
        return self._episode

    def run(self):

        if self._conf.mode == GameMode.BENCHMARK:
            self._run_benchmarks()
        else:
            if self._conf.mode == GameMode.NORMAL:
                window = GameWindow(
                    "Snake", self._conf, self._map, self, self._on_exit,
                    (('<w>', lambda e: self._update_direc(Direc.UP)),
                     ('<a>', lambda e: self._update_direc(Direc.LEFT)),
                     ('<s>', lambda e: self._update_direc(Direc.DOWN)),
                     ('<d>', lambda e: self._update_direc(Direc.RIGHT)),
                     ('<r>', lambda e: self._reset()),
                     ('<space>', lambda e: self._toggle_pause())))
                window.show(self._game_main_normal)

    def _run_benchmarks(self):
        STEPS_LIMIT = 3000
        NUM_EPISODES = int(input("Please input the number of episodes: "))

        print("\nMap size: %dx%d" % (self._conf.map_rows, self._conf.map_cols))
        print("Solver: %s\n" % self._conf.solver_name[:-6].lower())
        tot_suc, tot_suc_steps = 0, 0
        tot_len, tot_steps = 0, 0
        for _ in range(NUM_EPISODES):
            print("Episode %d - " % self._episode, end="")
            window = GameWindow(
                "Snake", self._conf, self._map, self, self._on_exit,
                (('<w>', lambda e: self._update_direc(Direc.UP)),
                 ('<a>', lambda e: self._update_direc(Direc.LEFT)),
                 ('<s>', lambda e: self._update_direc(Direc.DOWN)),
                 ('<d>', lambda e: self._update_direc(Direc.RIGHT)),
                 ('<r>', lambda e: self._reset()),
                 ('<space>', lambda e: self._toggle_pause())))
            while True:
                window.show(self._game_main_normal)
                if self._map.is_full():
                    tot_suc += 1
                    tot_suc_steps += self._snake.steps
                    print("FULL (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.dead:
                    print("DEAD (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.steps >= STEPS_LIMIT:
                    print("STEP LIMIT (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    break
            tot_len += self._snake.len()
            tot_steps += self._snake.steps
            self._reset()
        suc_ratio = tot_suc / (self._episode - 1)
        avg_suc_steps = 0
        if tot_suc != 0:
            avg_suc_steps = tot_suc_steps // tot_suc
        avg_len = tot_len / NUM_EPISODES
        avg_steps = tot_steps / NUM_EPISODES
        print(
            "\n[Summary]\nAverage Length: %.2f\nAverage Steps: %.2f\nTotal Runs: %d  Successful Runs: %d (%.2f%%)  \nAvg Successful steps: %d\n"
            % (avg_len, avg_steps, self._episode - 1, tot_suc, 100 * suc_ratio,
               avg_suc_steps))

        self._on_exit()

    def _game_main_normal(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause or self._is_episode_end():
            return

        self._update_direc(self._solver.next_direc())

        self._snake.move()

    def _update_direc(self, new_direc):
        self._snake.direc_next = new_direc
        if self._pause:
            self._snake.move()

    def _toggle_pause(self):
        self._pause = not self._pause

    def _is_episode_end(self):
        return self._snake.dead or self._map.is_full()

    def _reset(self):
        self._snake.reset()
        self._episode += 1

    def _on_exit(self):
        if self._solver:
            self._solver.close()
示例#14
0
def test_game_window():
    game_conf = GameConf()
    game_conf.map_rows = 15
    game_conf.map_cols = game_conf.map_rows
    game_conf.show_grid_line = True
    game_conf.show_info_panel = False

    game_map = Map(game_conf.map_rows + 2, game_conf.map_cols + 2)
    contents = (
        # Walls
        (Pos(1, 6), PointType.WALL),
        (Pos(1, 7), PointType.WALL),
        (Pos(1, 8), PointType.WALL),
        (Pos(1, 9), PointType.WALL),
        (Pos(1, 10), PointType.WALL),
        (Pos(15, 6), PointType.WALL),
        (Pos(15, 7), PointType.WALL),
        (Pos(15, 8), PointType.WALL),
        (Pos(15, 9), PointType.WALL),
        (Pos(15, 10), PointType.WALL),
        (Pos(6, 1), PointType.WALL),
        (Pos(7, 1), PointType.WALL),
        (Pos(8, 1), PointType.WALL),
        (Pos(9, 1), PointType.WALL),
        (Pos(10, 1), PointType.WALL),
        (Pos(6, 15), PointType.WALL),
        (Pos(7, 15), PointType.WALL),
        (Pos(8, 15), PointType.WALL),
        (Pos(9, 15), PointType.WALL),
        (Pos(10, 15), PointType.WALL),
        # Food
        (Pos(4, 6), PointType.FOOD),
        (Pos(4, 10), PointType.FOOD),
        (Pos(6, 4), PointType.FOOD),
        (Pos(10, 4), PointType.FOOD),
        (Pos(6, 12), PointType.FOOD),
        (Pos(10, 12), PointType.FOOD),
        (Pos(12, 6), PointType.FOOD),
        (Pos(12, 10), PointType.FOOD),
        # Top-left
        (Pos(2, 2), PointType.BODY_VER),
        (Pos(3, 2), PointType.BODY_VER),
        (Pos(4, 2), PointType.BODY_UR),
        (Pos(4, 3), PointType.BODY_LU),
        (Pos(3, 3), PointType.BODY_VER),
        (Pos(2, 3), PointType.BODY_RD),
        (Pos(2, 4), PointType.BODY_DL),
        (Pos(2, 4), PointType.BODY_DL),
        (Pos(3, 4), PointType.BODY_VER),
        (Pos(4, 4), PointType.HEAD_D),
        # Top-right
        (Pos(2, 14), PointType.BODY_VER),
        (Pos(3, 14), PointType.BODY_VER),
        (Pos(4, 14), PointType.BODY_LU),
        (Pos(4, 13), PointType.BODY_UR),
        (Pos(3, 13), PointType.BODY_VER),
        (Pos(2, 13), PointType.BODY_DL),
        (Pos(2, 12), PointType.BODY_RD),
        (Pos(3, 12), PointType.BODY_VER),
        (Pos(4, 12), PointType.HEAD_D),
        # Bottom-left
        (Pos(14, 2), PointType.BODY_VER),
        (Pos(13, 2), PointType.BODY_VER),
        (Pos(12, 2), PointType.BODY_RD),
        (Pos(12, 3), PointType.BODY_DL),
        (Pos(13, 3), PointType.BODY_VER),
        (Pos(14, 3), PointType.BODY_UR),
        (Pos(14, 4), PointType.BODY_LU),
        (Pos(13, 4), PointType.BODY_VER),
        (Pos(12, 4), PointType.HEAD_U),
        # Bottom-right
        (Pos(14, 14), PointType.BODY_VER),
        (Pos(13, 14), PointType.BODY_VER),
        (Pos(12, 14), PointType.BODY_DL),
        (Pos(12, 13), PointType.BODY_RD),
        (Pos(13, 13), PointType.BODY_VER),
        (Pos(14, 13), PointType.BODY_LU),
        (Pos(14, 12), PointType.BODY_UR),
        (Pos(13, 12), PointType.BODY_VER),
        (Pos(12, 12), PointType.HEAD_U),
        # Middle
        (Pos(10, 6), PointType.HEAD_L),
        (Pos(10, 7), PointType.BODY_HOR),
        (Pos(10, 8), PointType.BODY_HOR),
        (Pos(10, 9), PointType.BODY_HOR),
        (Pos(10, 10), PointType.BODY_LU),
        (Pos(9, 10), PointType.BODY_VER),
        (Pos(8, 10), PointType.BODY_DL),
        (Pos(8, 9), PointType.BODY_HOR),
        (Pos(8, 8), PointType.BODY_HOR),
        (Pos(8, 7), PointType.BODY_HOR),
        (Pos(8, 6), PointType.BODY_UR),
        (Pos(7, 6), PointType.BODY_VER),
        (Pos(6, 6), PointType.BODY_RD),
        (Pos(6, 7), PointType.BODY_HOR),
        (Pos(6, 8), PointType.BODY_HOR),
        (Pos(6, 9), PointType.BODY_HOR),
        (Pos(6, 10), PointType.HEAD_R)
    )
    for content in contents:
        game_map.point(content[0]).type = content[1]

    GameWindow("Basic Elements", game_conf, game_map).show()
示例#15
0
def test_predicate():
    m = Map(5, 5)
    assert not m.is_full()
    for i in range(m.num_rows):
        for j in range(m.num_cols):
            p = Pos(i, j)
            if i == 0 or i == m.num_rows - 1 or j == 0 or j == m.num_cols - 1:
                assert not m.is_inside(p) and not m.is_empty(p) \
                       and not m.is_safe(p)
            else:
                assert m.is_inside(p) and m.is_empty(p) and m.is_safe(p)
    p1, p2, p3 = Pos(1, 1), Pos(2, 2), Pos(3, 3)
    m.point(p1).type = PointType.HEAD_L
    m.point(p2).type = PointType.BODY_VER
    m.point(p3).type = PointType.FOOD
    assert m.is_inside(p1) and not m.is_empty(p1) and not m.is_safe(p1)
    assert m.is_inside(p2) and not m.is_empty(p2) and not m.is_safe(p2)
    assert m.is_inside(p3) and not m.is_empty(p3) and m.is_safe(p3)
    assert not m.is_full()
    for i in range(1, m.num_rows - 1):
        for j in range(1, m.num_cols - 1):
            if i < m.num_rows / 2:
                m.point(Pos(i, j)).type = PointType.HEAD_U
            else:
                m.point(Pos(i, j)).type = PointType.BODY_UR
    assert m.is_full()
示例#16
0
class Game:
    def __init__(self, conf):
        self._conf = conf
        self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
        self._snake = Snake(self._map, conf.init_direc, conf.init_bodies,
                            conf.init_types)
        self._pause = False
        self._solver = globals()[self._conf.solver_name](self._snake)
        self._episode = 1
        self._init_log_file()

    @property
    def snake(self):
        return self._snake

    @property
    def episode(self):
        return self._episode

    def run(self):
        if self._conf.mode == GameMode.BENCHMARK:
            self._run_benchmarks()
        elif self._conf.mode == GameMode.TRAIN_DQN:
            self._run_dqn_train()
            self._plot_history()
        else:
            window = GameWindow(
                "Snake", self._conf, self._map, self, self._on_exit,
                (('<w>', lambda e: self._update_direc(Direc.UP)),
                 ('<a>', lambda e: self._update_direc(Direc.LEFT)),
                 ('<s>', lambda e: self._update_direc(Direc.DOWN)),
                 ('<d>', lambda e: self._update_direc(Direc.RIGHT)),
                 ('<r>', lambda e: self._reset()),
                 ('<space>', lambda e: self._toggle_pause())))
            if self._conf.mode == GameMode.NORMAL:
                window.show(self._game_main_normal)
            elif self._conf.mode == GameMode.TRAIN_DQN_GUI:
                window.show(self._game_main_dqn_train)
                self._plot_history()

    def _run_benchmarks(self):
        STEPS_LIMIT = 5000
        NUM_EPISODES = int(input("Please input the number of episodes: "))

        print("\nMap size: %dx%d" % (self._conf.map_rows, self._conf.map_cols))
        print("Solver: %s\n" % self._conf.solver_name[:-6].lower())

        tot_len, tot_steps = 0, 0

        for _ in range(NUM_EPISODES):
            print("Episode %d - " % self._episode, end="")
            while True:
                self._game_main_normal()
                if self._map.is_full():
                    print("FULL (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.dead:
                    print("DEAD (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.steps >= STEPS_LIMIT:
                    print("STEP LIMIT (len: %d | steps: %d)" %
                          (self._snake.len(), self._snake.steps))
                    self._write_logs()  # Write the last step
                    break
            tot_len += self._snake.len()
            tot_steps += self._snake.steps
            self._reset()

        avg_len = tot_len / NUM_EPISODES
        avg_steps = tot_steps / NUM_EPISODES
        print("\n[Summary]\nAverage Length: %.2f\nAverage Steps: %.2f\n" %
              (avg_len, avg_steps))

        self._on_exit()

    def _run_dqn_train(self):
        try:
            while not self._game_main_dqn_train():
                pass
        except KeyboardInterrupt:
            pass
        except Exception:
            traceback.print_exc()
        finally:
            self._on_exit()

    def _game_main_dqn_train(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause:
            return

        episode_end, learn_end = self._solver.train()

        if episode_end:
            self._reset()

        return learn_end

    def _game_main_normal(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause or self._is_episode_end():
            return

        self._update_direc(self._solver.next_direc())

        if self._conf.mode == GameMode.NORMAL and self._snake.direc_next != Direc.NONE:
            self._write_logs()

        self._snake.move()

        if self._is_episode_end():
            self._write_logs()  # Write the last step

    def _plot_history(self):
        self._solver.plot()

    def _update_direc(self, new_direc):
        self._snake.direc_next = new_direc
        if self._pause:
            self._snake.move()

    def _toggle_pause(self):
        self._pause = not self._pause

    def _is_episode_end(self):
        return self._snake.dead or self._map.is_full()

    def _reset(self):
        self._snake.reset()
        self._episode += 1

    def _on_exit(self):
        if self._log_file:
            self._log_file.close()
        if self._solver:
            self._solver.close()

    def _init_log_file(self):
        try:
            os.makedirs("logs")
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
        try:
            self._log_file = None
            self._log_file = open('logs/snake.log', 'w')
        except FileNotFoundError:
            if self._log_file:
                self._log_file.close()

    def _write_logs(self):
        self._log_file.write("[ Episode %d / Step %d ]\n" % \
                             (self._episode, self._snake.steps))
        for i in range(self._map.num_rows):
            for j in range(self._map.num_cols):
                pos = Pos(i, j)
                t = self._map.point(pos).type
                if t == PointType.EMPTY:
                    self._log_file.write("  ")
                elif t == PointType.WALL:
                    self._log_file.write("# ")
                elif t == PointType.FOOD:
                    self._log_file.write("F ")
                elif t == PointType.HEAD_L or t == PointType.HEAD_U or \
                    t == PointType.HEAD_R or t == PointType.HEAD_D:
                    self._log_file.write("H ")
                elif pos == self._snake.tail():
                    self._log_file.write("T ")
                else:
                    self._log_file.write("B ")
            self._log_file.write("\n")
        self._log_file.write("[ last/next direc: %s/%s ]\n" % \
                              (self._snake.direc, self._snake.direc_next))
        self._log_file.write("\n")
示例#17
0
def test_food():
    m = Map(5, 5)
    assert not m.has_food()
    m.create_food(Pos(1, 1))
    assert m.has_food()
    m.rm_food()
    assert not m.has_food()
    fd = m.create_rand_food()
    assert m.has_food()
    assert m.point(fd).type == PointType.FOOD
    m.rm_food()
    for i in range(1, m.num_rows - 1):
        for j in range(1, m.num_cols - 1):
            assert m.point(Pos(i, j)).type == PointType.EMPTY
示例#18
0
class Game:
    def __init__(self, conf):
        self.__conf = conf
        self.__map = Map(conf.map_rows + 2, conf.map_cols + 2)
        self.__snake = Snake(self.__map, conf.init_direc, conf.init_bodies,
                             conf.init_types)
        self.__pause = False
        self.__window = GameWindow(
            conf, self.__map, "Snake", self.__snake, self.__on_exit,
            (('<w>', lambda e: self.__update_direc(Direc.UP)),
             ('<a>', lambda e: self.__update_direc(Direc.LEFT)),
             ('<s>', lambda e: self.__update_direc(Direc.DOWN)),
             ('<d>', lambda e: self.__update_direc(Direc.RIGHT)),
             ('<r>', lambda e: self.__reset()),
             ('<space>', lambda e: self.__toggle_pause())))
        self.__solver = globals()[self.__conf.solver_name](self.__snake)
        self.__episode = 1
        self.__init_log_file()

    def run(self):
        if self.__conf.show_gui:
            self.__window.show(self.__game_main)
        else:
            self.__run_batch_episodes()

    def __run_batch_episodes(self):
        STEPS_LIMIT = 500
        episodes = int(input("input the number of episodes bro: "))
        print("\nMap size: %dx%d" %
              (self.__conf.map_rows, self.__conf.map_cols))
        print("Solver: %s\n" % self.__conf.solver_name[:-6].lower())
        tot_suc, tot_suc_steps = 0, 0
        for _ in range(episodes):
            print("Episode %d - " % self.__episode, end="")
            while True:
                self.__game_main()
                if self.__map.is_full():
                    tot_suc += 1
                    tot_suc_steps += self.__snake.steps
                    print("SUC  (steps: %d)" % self.__snake.steps)
                    break
                if self.__snake.dead or self.__snake.steps >= STEPS_LIMIT:
                    print("FAIL  (steps: %d)" % self.__snake.steps)
                    if self.__snake.steps >= STEPS_LIMIT:
                        self.__write_logs()  # Write the last step
                    break
            self.__reset()
        suc_ratio = tot_suc / (self.__episode - 1)
        avg_suc_steps = 0
        if tot_suc != 0:
            avg_suc_steps = tot_suc_steps // tot_suc
        print("\n[Summary]\nTotal: %d  SUC: %d (%.2f%%)  Avg SUC steps: %d\n" % \
              (self.__episode - 1, tot_suc, 100 * suc_ratio, avg_suc_steps))
        self.__on_exit()

    def __game_main(self):
        """Main function in the game loop."""
        if not self.__map.has_food():
            self.__map.create_rand_food()

        if self.__pause or self.__episode_end():
            return

        if self.__conf.enable_AI:
            self.__update_direc(self.__solver.next_direc())

        if self.__conf.show_gui and self.__snake.direc_next != Direc.NONE:
            self.__write_logs()

        self.__snake.move()

        if self.__episode_end():
            self.__write_logs()  # Write the last step

    def __update_direc(self, new_direc):
        if Direc.opposite(new_direc) != self.__snake.direc:
            self.__snake.direc_next = new_direc
            if self.__pause:
                self.__snake.move()

    def __toggle_pause(self):
        self.__pause = not self.__pause

    def __episode_end(self):
        return self.__snake.dead or self.__map.is_full()

    def __reset(self):
        self.__snake.reset()
        self.__episode += 1

    def __on_exit(self):
        if self.__log_file:
            self.__log_file.close()

    def __init_log_file(self):
        try:
            os.makedirs("logs")
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
        try:
            self.__log_file = None
            self.__log_file = open('logs/snake.log', 'w')
        except FileNotFoundError:
            if self.__log_file:
                self.__log_file.close()

    def __write_logs(self):
        self.__log_file.write("[ Episode %d / Step %d ]\n" % \
                              (self.__episode, self.__snake.steps))
        for i in range(self.__map.num_rows):
            for j in range(self.__map.num_cols):
                pos = Pos(i, j)
                t = self.__map.point(pos).type
                if t == PointType.EMPTY:
                    self.__log_file.write("  ")
                elif t == PointType.WALL:
                    self.__log_file.write("# ")
                elif t == PointType.FOOD:
                    self.__log_file.write("F ")
                elif t == PointType.HEAD_L or t == PointType.HEAD_U or \
                    t == PointType.HEAD_R or t == PointType.HEAD_D:
                    self.__log_file.write("H ")
                elif pos == self.__snake.tail():
                    self.__log_file.write("T ")
                else:
                    self.__log_file.write("B ")
            self.__log_file.write("\n")
        self.__log_file.write("[ last/next direc: %s/%s ]\n" % \
                              (self.__snake.direc, self.__snake.direc_next))
        self.__log_file.write("\n")
示例#19
0
def test_move_eat():
    m = Map(5, 5)
    s = Snake(m, Direc.RIGHT, [Pos(1, 2), Pos(1, 1)],
              [PointType.HEAD_R, PointType.BODY_HOR])
    assert s.len() == 2
    m.createFood(Pos(1, 3))
    assert m.hasFood()

    s.move(Direc.RIGHT)
    assert not m.hasFood()
    assert s.head() == Pos(1, 3) and s.tail() == Pos(1, 1)
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert m.point(Pos(1, 2)).type == PointType.BODY_HOR
    assert m.point(s.head()).type == PointType.HEAD_R

    s.move(Direc.DOWN)
    assert s.head() == Pos(2, 3) and s.tail() == Pos(1, 2)
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert m.point(Pos(1, 3)).type == PointType.BODY_DL
    assert m.point(s.head()).type == PointType.HEAD_D

    s.move(Direc.LEFT)
    assert s.head() == Pos(2, 2) and s.tail() == Pos(1, 3)
    assert m.point(s.tail()).type == PointType.BODY_DL
    assert m.point(Pos(2, 3)).type == PointType.BODY_LU
    assert m.point(s.head()).type == PointType.HEAD_L

    s.move(Direc.LEFT)
    assert s.head() == Pos(2, 1) and s.tail() == Pos(2, 3)
    assert m.point(s.tail()).type == PointType.BODY_LU
    assert m.point(Pos(2, 2)).type == PointType.BODY_HOR
    assert m.point(s.head()).type == PointType.HEAD_L

    s.move(Direc.DOWN)
    assert s.head() == Pos(3, 1) and s.tail() == Pos(2, 2)
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert m.point(Pos(2, 1)).type == PointType.BODY_RD
    assert m.point(s.head()).type == PointType.HEAD_D

    s.move(Direc.RIGHT)
    assert s.head() == Pos(3, 2) and s.tail() == Pos(2, 1)
    assert m.point(s.tail()).type == PointType.BODY_RD
    assert m.point(Pos(3, 1)).type == PointType.BODY_UR
    assert m.point(s.head()).type == PointType.HEAD_R

    s.move(Direc.RIGHT)
    assert s.head() == Pos(3, 3) and s.tail() == Pos(3, 1)
    assert m.point(s.tail()).type == PointType.BODY_UR
    assert m.point(Pos(3, 2)).type == PointType.BODY_HOR
    assert m.point(s.head()).type == PointType.HEAD_R

    s.move(Direc.UP)
    assert s.head() == Pos(2, 3) and s.tail() == Pos(3, 2)
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert m.point(Pos(3, 3)).type == PointType.BODY_LU
    assert m.point(s.head()).type == PointType.HEAD_U

    s.move(Direc.LEFT)
    assert s.head() == Pos(2, 2) and s.tail() == Pos(3, 3)
    assert m.point(s.tail()).type == PointType.BODY_LU
    assert m.point(Pos(2, 3)).type == PointType.BODY_DL
    assert m.point(s.head()).type == PointType.HEAD_L

    s.move(Direc.LEFT)
    assert s.head() == Pos(2, 1) and s.tail() == Pos(2, 3)
    assert m.point(s.tail()).type == PointType.BODY_DL
    assert m.point(Pos(2, 2)).type == PointType.BODY_HOR
    assert m.point(s.head()).type == PointType.HEAD_L

    s.move(Direc.UP)
    assert s.head() == Pos(1, 1) and s.tail() == Pos(2, 2)
    assert m.point(s.tail()).type == PointType.BODY_HOR
    assert m.point(Pos(2, 1)).type == PointType.BODY_UR
    assert m.point(s.head()).type == PointType.HEAD_U

    s.move(Direc.RIGHT)
    assert s.head() == Pos(1, 2) and s.tail() == Pos(2, 1)
    assert m.point(s.tail()).type == PointType.BODY_UR
    assert m.point(Pos(1, 1)).type == PointType.BODY_RD
    assert m.point(s.head()).type == PointType.HEAD_R

    s.move(Direc.RIGHT)
    assert s.head() == Pos(1, 3) and s.tail() == Pos(1, 1)
    assert m.point(s.tail()).type == PointType.BODY_RD
    assert m.point(Pos(1, 2)).type == PointType.BODY_HOR
    assert m.point(s.head()).type == PointType.HEAD_R

    s.move(Direc.DOWN)
    s.move(Direc.DOWN)
    assert s.head() == Pos(3, 3) and s.tail() == Pos(1, 3)
    assert m.point(s.tail()).type == PointType.BODY_DL
    assert m.point(Pos(2, 3)).type == PointType.BODY_VER
    assert m.point(s.head()).type == PointType.HEAD_D

    s.move(Direc.LEFT)
    s.move(Direc.LEFT)
    s.move(Direc.UP)
    s.move(Direc.UP)
    assert s.head() == Pos(1, 1) and s.tail() == Pos(3, 1)
    assert m.point(s.tail()).type == PointType.BODY_UR
    assert m.point(Pos(2, 1)).type == PointType.BODY_VER
    assert m.point(s.head()).type == PointType.HEAD_U
    assert s.len() == 3

    # Eat full
    assert not m.isFull()
    food_pos = [
        Pos(1, 2),
        Pos(2, 2),
        Pos(3, 2),
        Pos(3, 3),
        Pos(2, 3),
        Pos(1, 3)
    ]
    move_direc = [
        Direc.RIGHT, Direc.DOWN, Direc.DOWN, Direc.RIGHT, Direc.UP, Direc.UP
    ]
    for i, pos in enumerate(food_pos):
        m.createFood(pos)
        s.move(move_direc[i])
    assert m.isFull()
    assert s.len() == 9 and s.steps == 25 and not s.dead
示例#20
0
def test_game_window():
    game_conf = GameConf()
    game_conf.map_rows = 15
    game_conf.map_cols = game_conf.map_rows
    game_conf.show_grid_line = True
    game_conf.show_info_panel = False

    game_map = Map(game_conf.map_rows + 2, game_conf.map_cols + 2)
    contents = (
        # Walls
        (Pos(1, 6), PointType.WALL),
        (Pos(1, 7), PointType.WALL),
        (Pos(1, 8), PointType.WALL),
        (Pos(1, 9), PointType.WALL),
        (Pos(1, 10), PointType.WALL),
        (Pos(15, 6), PointType.WALL),
        (Pos(15, 7), PointType.WALL),
        (Pos(15, 8), PointType.WALL),
        (Pos(15, 9), PointType.WALL),
        (Pos(15, 10), PointType.WALL),
        (Pos(6, 1), PointType.WALL),
        (Pos(7, 1), PointType.WALL),
        (Pos(8, 1), PointType.WALL),
        (Pos(9, 1), PointType.WALL),
        (Pos(10, 1), PointType.WALL),
        (Pos(6, 15), PointType.WALL),
        (Pos(7, 15), PointType.WALL),
        (Pos(8, 15), PointType.WALL),
        (Pos(9, 15), PointType.WALL),
        (Pos(10, 15), PointType.WALL),
        # Food
        (Pos(4, 6), PointType.FOOD),
        (Pos(4, 10), PointType.FOOD),
        (Pos(6, 4), PointType.FOOD),
        (Pos(10, 4), PointType.FOOD),
        (Pos(6, 12), PointType.FOOD),
        (Pos(10, 12), PointType.FOOD),
        (Pos(12, 6), PointType.FOOD),
        (Pos(12, 10), PointType.FOOD),
        # Top-left
        (Pos(2, 2), PointType.BODY_VER),
        (Pos(3, 2), PointType.BODY_VER),
        (Pos(4, 2), PointType.BODY_UR),
        (Pos(4, 3), PointType.BODY_LU),
        (Pos(3, 3), PointType.BODY_VER),
        (Pos(2, 3), PointType.BODY_RD),
        (Pos(2, 4), PointType.BODY_DL),
        (Pos(2, 4), PointType.BODY_DL),
        (Pos(3, 4), PointType.BODY_VER),
        (Pos(4, 4), PointType.HEAD_D),
        # Top-right
        (Pos(2, 14), PointType.BODY_VER),
        (Pos(3, 14), PointType.BODY_VER),
        (Pos(4, 14), PointType.BODY_LU),
        (Pos(4, 13), PointType.BODY_UR),
        (Pos(3, 13), PointType.BODY_VER),
        (Pos(2, 13), PointType.BODY_DL),
        (Pos(2, 12), PointType.BODY_RD),
        (Pos(3, 12), PointType.BODY_VER),
        (Pos(4, 12), PointType.HEAD_D),
        # Bottom-left
        (Pos(14, 2), PointType.BODY_VER),
        (Pos(13, 2), PointType.BODY_VER),
        (Pos(12, 2), PointType.BODY_RD),
        (Pos(12, 3), PointType.BODY_DL),
        (Pos(13, 3), PointType.BODY_VER),
        (Pos(14, 3), PointType.BODY_UR),
        (Pos(14, 4), PointType.BODY_LU),
        (Pos(13, 4), PointType.BODY_VER),
        (Pos(12, 4), PointType.HEAD_U),
        # Bottom-right
        (Pos(14, 14), PointType.BODY_VER),
        (Pos(13, 14), PointType.BODY_VER),
        (Pos(12, 14), PointType.BODY_DL),
        (Pos(12, 13), PointType.BODY_RD),
        (Pos(13, 13), PointType.BODY_VER),
        (Pos(14, 13), PointType.BODY_LU),
        (Pos(14, 12), PointType.BODY_UR),
        (Pos(13, 12), PointType.BODY_VER),
        (Pos(12, 12), PointType.HEAD_U),
        # Middle
        (Pos(10, 6), PointType.HEAD_L),
        (Pos(10, 7), PointType.BODY_HOR),
        (Pos(10, 8), PointType.BODY_HOR),
        (Pos(10, 9), PointType.BODY_HOR),
        (Pos(10, 10), PointType.BODY_LU),
        (Pos(9, 10), PointType.BODY_VER),
        (Pos(8, 10), PointType.BODY_DL),
        (Pos(8, 9), PointType.BODY_HOR),
        (Pos(8, 8), PointType.BODY_HOR),
        (Pos(8, 7), PointType.BODY_HOR),
        (Pos(8, 6), PointType.BODY_UR),
        (Pos(7, 6), PointType.BODY_VER),
        (Pos(6, 6), PointType.BODY_RD),
        (Pos(6, 7), PointType.BODY_HOR),
        (Pos(6, 8), PointType.BODY_HOR),
        (Pos(6, 9), PointType.BODY_HOR),
        (Pos(6, 10), PointType.HEAD_R)
    )
    for content in contents:
        game_map.point(content[0]).type = content[1]

    GameWindow("Basic Elements", game_conf, game_map).show()
示例#21
0
class Game:

    def __init__(self, conf):
        self._conf = conf
        self._map = Map(conf.map_rows + 2, conf.map_cols + 2)
        self._snake = Snake(self._map, conf.init_direc,
                            conf.init_bodies, conf.init_types)
        self._pause = False
        self._solver = globals()[self._conf.solver_name](self._snake)
        self._episode = 1
        self._init_log_file()

    @property
    def snake(self):
        return self._snake

    @property
    def episode(self):
        return self._episode

    def run(self):
        if self._conf.mode == GameMode.BENCHMARK:
            self._run_benchmarks()
        elif self._conf.mode == GameMode.TRAIN_DQN:
            self._run_dqn_train()
            self._plot_history()
        else:
            window = GameWindow("Snake", self._conf, self._map, self, self._on_exit, (
                ('<w>', lambda e: self._update_direc(Direc.UP)),
                ('<a>', lambda e: self._update_direc(Direc.LEFT)),
                ('<s>', lambda e: self._update_direc(Direc.DOWN)),
                ('<d>', lambda e: self._update_direc(Direc.RIGHT)),
                ('<r>', lambda e: self._reset()),
                ('<space>', lambda e: self._toggle_pause())
            ))
            if self._conf.mode == GameMode.NORMAL:
                window.show(self._game_main_normal)
            elif self._conf.mode == GameMode.TRAIN_DQN_GUI:
                window.show(self._game_main_dqn_train)
                self._plot_history()

    def _run_benchmarks(self):
        STEPS_LIMIT = 5000
        NUM_EPISODES = int(input("Please input the number of episodes: "))

        print("\nMap size: %dx%d" % (self._conf.map_rows, self._conf.map_cols))
        print("Solver: %s\n" % self._conf.solver_name[:-6].lower())

        tot_len, tot_steps = 0, 0

        for _ in range(NUM_EPISODES):
            print("Episode %d - " % self._episode, end="")
            while True:
                self._game_main_normal()
                if self._map.is_full():
                    print("FULL (len: %d | steps: %d)"
                          % (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.dead:
                    print("DEAD (len: %d | steps: %d)"
                          % (self._snake.len(), self._snake.steps))
                    break
                elif self._snake.steps >= STEPS_LIMIT:
                    print("STEP LIMIT (len: %d | steps: %d)"
                          % (self._snake.len(), self._snake.steps))
                    self._write_logs()  # Write the last step
                    break
            tot_len += self._snake.len()
            tot_steps += self._snake.steps
            self._reset()

        avg_len = tot_len / NUM_EPISODES
        avg_steps = tot_steps / NUM_EPISODES
        print("\n[Summary]\nAverage Length: %.2f\nAverage Steps: %.2f\n"
              % (avg_len, avg_steps))

        self._on_exit()

    def _run_dqn_train(self):
        try:
            while not self._game_main_dqn_train():
                pass
        except KeyboardInterrupt:
            pass
        except Exception:
            traceback.print_exc()
        finally:
            self._on_exit()

    def _game_main_dqn_train(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause:
            return

        episode_end, learn_end = self._solver.train()

        if episode_end:
            self._reset()

        return learn_end

    def _game_main_normal(self):
        if not self._map.has_food():
            self._map.create_rand_food()

        if self._pause or self._is_episode_end():
            return

        self._update_direc(self._solver.next_direc())

        if self._conf.mode == GameMode.NORMAL and self._snake.direc_next != Direc.NONE:
            self._write_logs()

        self._snake.move()

        if self._is_episode_end():
            self._write_logs()  # Write the last step

    def _plot_history(self):
        self._solver.plot()

    def _update_direc(self, new_direc):
        self._snake.direc_next = new_direc
        if self._pause:
            self._snake.move()

    def _toggle_pause(self):
        self._pause = not self._pause

    def _is_episode_end(self):
        return self._snake.dead or self._map.is_full()

    def _reset(self):
        self._snake.reset()
        self._episode += 1

    def _on_exit(self):
        if self._log_file:
            self._log_file.close()
        if self._solver:
            self._solver.close()

    def _init_log_file(self):
        try:
            os.makedirs("logs")
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
        try:
            self._log_file = None
            self._log_file = open('logs/snake.log', 'w')
        except FileNotFoundError:
            if self._log_file:
                self._log_file.close()

    def _write_logs(self):
        self._log_file.write("[ Episode %d / Step %d ]\n" % \
                             (self._episode, self._snake.steps))
        for i in range(self._map.num_rows):
            for j in range(self._map.num_cols):
                pos = Pos(i, j)
                t = self._map.point(pos).type
                if t == PointType.EMPTY:
                    self._log_file.write("  ")
                elif t == PointType.WALL:
                    self._log_file.write("# ")
                elif t == PointType.FOOD:
                    self._log_file.write("F ")
                elif t == PointType.HEAD_L or t == PointType.HEAD_U or \
                    t == PointType.HEAD_R or t == PointType.HEAD_D:
                    self._log_file.write("H ")
                elif pos == self._snake.tail():
                    self._log_file.write("T ")
                else:
                    self._log_file.write("B ")
            self._log_file.write("\n")
        self._log_file.write("[ last/next direc: %s/%s ]\n" % \
                              (self._snake.direc, self._snake.direc_next))
        self._log_file.write("\n")