Exemple #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
Exemple #2
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
Exemple #3
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]
Exemple #4
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()
Exemple #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._solver = globals()[self._conf.solver_name](self._snake)
     self._episode = 1
     self._init_log_file()
Exemple #6
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())
Exemple #7
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())
Exemple #8
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
Exemple #9
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
Exemple #10
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
Exemple #11
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)
Exemple #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):
        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")
Exemple #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.__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")
Exemple #14
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")
Exemple #15
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")
Exemple #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

    @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()