def __init__(self): """Initialize a default configuration.""" # Size self.map_rows = 5 self.map_cols = self.map_rows self.map_width = 190 # pixels self.map_height = self.map_width self.info_panel_width = 170 # pixels self.window_width = self.map_width + self.info_panel_width self.window_height = self.map_height self.grid_pad_ratio = 0.25 # AI self.enable_AI = True self.solver_name = 'HamiltonSolver' # GUI Switch self.show_gui = False # GUI Options self.show_grid_line = True self.show_info_panel = True # Delay self.interval_draw = 40 # ms self.interval_draw_max = 200 # ms # Color self.color_bg = '#000000' self.color_txt = '#F5F5F5' self.color_line = '#424242' self.color_wall = '#F5F5F5' self.color_food = '#FFF59D' self.color_head = '#F5F5F5' self.color_body = '#F5F5F5' # Initial snake self.init_direc = Direc.RIGHT self.init_bodies = [Pos(1, 2), Pos(1, 1)] self.init_types = [PointType.HEAD_R, PointType.BODY_HOR] # Font self.font_info = ('Helvetica', 9) # Info self.info_str = ("<w/a/s/d>: up/left/down/right\n" "<space>: pause/resume\n" "<r>: restart <esc>: exit\n" "---------------------------------\n" "solver: %s\n" "status: %s\n" "steps: %d\n" "length: %d/%d (" + str(self.map_rows) + "x" + str(self.map_cols) + ")\n" "---------------------------------\n" "move delay:") self.info_status = ['eating', 'dead', 'full']
def _state(self): """Return a vector indicating current state.""" # Visual state visual_state = np.zeros(self._SHAPE_VISUAL_STATE, dtype=np.int32) for i in range(1, self.map.num_rows - 1): for j in range(1, self.map.num_cols - 1): pos = Pos(i, j) if self._USE_RELATIVE: if self.snake.direc == Direc.LEFT: pos = Pos(self.map.num_rows - 1 - j, i) elif self.snake.direc == Direc.UP: pos = Pos(i, j) elif self.snake.direc == Direc.RIGHT: pos = Pos(j, self.map.num_cols - 1 - i) elif self.snake.direc == Direc.DOWN: pos = Pos(self.map.num_rows - 1 - i, self.map.num_cols - 1 - j) t = self.map.point(pos).type if t == PointType.EMPTY: visual_state[i - 1][j - 1][0] = 1 elif t == PointType.FOOD: visual_state[i - 1][j - 1][1] = 1 elif t == PointType.HEAD_L or t == PointType.HEAD_U or \ t == PointType.HEAD_R or t == PointType.HEAD_D: visual_state[i - 1][j - 1][2] = 1 elif t == PointType.BODY_LU or t == PointType.BODY_UR or \ t == PointType.BODY_RD or t == PointType.BODY_DL or \ t == PointType.BODY_HOR or t == PointType.BODY_VER: visual_state[i - 1][j - 1][3] = 1 else: raise ValueError("Unsupported PointType: {}".format(t)) if self._USE_VISUAL_ONLY: return visual_state.flatten() else: # Important state important_state = np.zeros(self._NUM_IMPORTANT_FEATURES, dtype=np.int32) head = self.snake.head() if self._USE_RELATIVE: for i, action in enumerate( [SnakeAction.LEFT, SnakeAction.FORWARD, SnakeAction.RIGHT]): direc = SnakeAction.to_direc(action, self.snake.direc) if not self.map.is_safe(head.adj(direc)): important_state[i] = 1 else: for i, direc in enumerate( [Direc.LEFT, Direc.UP, Direc.RIGHT, Direc.DOWN]): if not self.map.is_safe(head.adj(direc)): important_state[i] = 1 return np.hstack((visual_state.flatten(), important_state))
def __init__(self): """Initialize a default configuration.""" # Game mode self.mode = GameMode.NORMAL # Solver # self.solver_name = 'HamiltonSolver' # Class name of the solver self.solver_name = 'AStarSolver' # Size self.map_rows = 8 self.map_cols = self.map_rows self.map_width = 160 # pixels self.map_height = self.map_width self.info_panel_width = 155 # pixels self.window_width = self.map_width + self.info_panel_width self.window_height = self.map_height self.grid_pad_ratio = 0.25 # Switch self.show_grid_line = True #False self.show_info_panel = True # Delay self.interval_draw = 50 # ms self.interval_draw_max = 200 # ms # Color self.color_bg = '#000000' self.color_txt = '#F5F5F5' self.color_line = '#424242' self.color_wall = '#F5F5F5' self.color_food = '#FFF59D' self.color_head = '#F5F5F5' self.color_body = '#F5F5F5' # Initial snake self.init_direc = Direc.RIGHT self.init_bodies = [Pos(1, 4), Pos(1, 3), Pos(1, 2), Pos(1, 1)] self.init_types = [PointType.HEAD_R] + [PointType.BODY_HOR] * 3 # Font self.font_info = ('Arial', 9) # Info self.info_str = ("<w/a/s/d>: snake direction\n" "<space>: pause/resume\n" "<r>: restart <esc>: exit\n" "-----------------------------------\n" "status: %s\n" "episode: %d step: %d\n" "length: %d/%d (" + str(self.map_rows) + "x" + str(self.map_cols) + ")\n" "-----------------------------------") self.info_status = ['eating', 'dead', 'full']
def test_arithmetic(): p1 = Pos(-5, 10) p2 = Pos(5, -10) p3 = p1 + p2 p4 = p1 - p2 p5 = p2 - p1 assert p3 == Pos(0, 0) assert p3 - p1 == p2 assert p3 - p2 == p1 assert p4 == Pos(-10, 20) assert p5 == -Pos(-10, 20) assert p4 + p2 == p1 assert p5 + p1 == p2
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]
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
def test_init(): p = Pos(-5, 5) assert p == Pos(-5, 5) p.x = -10 p.y = 10 assert p != Pos(-5, 5) assert p == Pos(-10, 10)
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
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())
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())
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")
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
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)
def test_adj(): p = Pos(0, 0) adjs = p.all_adj() assert len(adjs) == 4 hit = [False] * 4 assert hit.count(False) == 4 for adj in adjs: if adj == Pos(-1, 0): assert p.direc_to(adj) == Direc.UP hit[0] = True elif adj == Pos(1, 0): assert p.direc_to(adj) == Direc.DOWN hit[1] = True elif adj == Pos(0, 1): assert p.direc_to(adj) == Direc.RIGHT hit[2] = True elif adj == Pos(0, -1): assert p.direc_to(adj) == Direc.LEFT hit[3] = True else: raise ValueError("error adj Pos") assert hit.count(False) == 0
def test_dist(): p1 = Pos(-5, 20) p2 = Pos(10, 8) assert Pos.manhattan_dist(p1, p2) == 27
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()
def _draw_map_contents(self): for i in range(self._map.num_rows - 2): for j in range(self._map.num_cols - 2): self._draw_grid(j * self._grid_width, i * self._grid_height, self._map.point(Pos(i + 1, j + 1)).type)
def test_manhattanDistance(): p1 = Pos(-5, 20) p2 = Pos(10, 8) assert Pos.manhattanDistance(p1, p2) == 27