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
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")
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")
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")
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")
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()
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.create_food(Pos(1, 3)) assert m.has_food() s.move(Direc.RIGHT) assert not m.has_food() 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.is_full() 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.create_food(pos) s.move(move_direc[i]) assert m.is_full() assert s.len() == 9 and s.steps == 25 and not s.dead