def play_ai_without_ui(count): if count == 0: count = 10 game = Tetris() robot.init_model() mcts.print_info = True scores = [] for i in range(count): while not game.gameover(): robot.run_game(game) # sleep(0.5) scores.append(game.score()) print("game over, score: %d, step: %d" % (game.score(), game.step())) game.reset() del game print("max: %d, min: %d, avg: %d" % (max(scores), min(scores), float(sum(scores)) / len(scores)))
class GameGUI(object): """ Tetris game GUI environment that draws tetris board. modes: human: interactive mode played by human agent: played by RL agents """ def __init__(self, horizon=-1, drop_interval=1000, mode='human'): # Init tetris game core self.tetris = Tetris(horizon) self.mode = mode self.game_started = False self.drop_interval = drop_interval self.first_game = True self.next_queue_items = [] self.game_over_banner = None self.shape_block_border = int(GUI_HEIGHT/400) self.shape_block_unit = int(GUI_HEIGHT/20) self.shape_block_size = int(GUI_HEIGHT/20) - 2*self.shape_block_border self.next_queue_offset = self.shape_block_unit*4+2*self.shape_block_border def init_gui(self): # Init windows and tetris board canvas self.window = Tk() self.window.title("Tetris") self.window.geometry('%dx%d' % (GUI_WIDTH, GUI_HEIGHT)) self.main_board = Canvas( self.window, width=GUI_WIDTH/2, height=GUI_HEIGHT) self.main_board.pack(side=tk.LEFT) self.main_board.config(bg='black') # Init menu menubar = Menu(self.window) self.window.config(menu=menubar) tetrismenu = Menu(menubar) menubar.add_cascade(label = "Tetris", menu = tetrismenu) tetrismenu.add_command(label="Start", command=self.start_game) tetrismenu.add_command(label="Quit", command=self.window.quit) # game over banner self.game_over_banner = None # Init side board self.side_board = Canvas( self.window, width=GUI_WIDTH/2, height=GUI_HEIGHT) self.side_board.pack(side=tk.LEFT) self.side_board.config(bg='white') # help text help_text = """a : move left d : move right s : move down w : hard drop j : rotate counter-clockwise k : rotate clockwise l : hold""" if self.mode == 'human': self.side_board.create_text(int(GUI_WIDTH*11/32), 80, text=help_text) # Display score self.score = self.side_board.create_text(int(GUI_WIDTH/4), GUI_HEIGHT-12, text="Score: 0000000000", font="Helvetica 16 bold") # Next queue backgrounds self.side_board.create_rectangle(0,0, self.shape_block_unit*4, self.shape_block_unit*4, outline=BLACK, fill=BLACK) self.side_board.create_rectangle(0, self.next_queue_offset, self.shape_block_unit*4, self.shape_block_unit*4+self.next_queue_offset, outline=BLACK, fill=BLACK) self.side_board.create_rectangle(0, 2*self.next_queue_offset, self.shape_block_unit*4, self.shape_block_unit*4+2*self.next_queue_offset, outline=BLACK, fill=BLACK) # Bind events if self.mode == 'human': self.window.bind("<KeyPress>", self.gui_key_stroke) def close(self): self.window.destroy() def get_env(self): return self.tetris def update_score(self): score_str = "Score: {:010d}".format(self.tetris.get_score()) self.side_board.itemconfig(self.score, text=score_str) def gui_key_stroke(self, key): if key.char == 'a': #print("move left") _, _, done = self.tetris.step(1) elif key.char == 's': #print("move down") _, _, done = self.tetris.step(3) elif key.char == 'd': #print("move right") _, _, done = self.tetris.step(2) elif key.char == 'w': #print("hard drop") _, _, done = self.tetris.step(4) elif key.char == 'j': #print("rotate counter clock-wise") _, _, done = self.tetris.step(5) elif key.char == 'k': #print("rotate clock-wise") _, _, done = self.tetris.step(6) elif key.char == 'l': #print("hold") _, _, done = self.tetris.step(7) else: return if done: self.game_over() def draw_mainboard(self, main_board): # first delete all old items on main board self.main_board.delete(tk.ALL) # draw rectangles according to game state for i, v in enumerate(main_board): for j, c in enumerate(v): left = self.shape_block_unit*i+self.shape_block_border right = left+self.shape_block_size-self.shape_block_border top = self.shape_block_unit*j+self.shape_block_border bottom = top+self.shape_block_size-self.shape_block_border # Line of four if c == 1: self.main_board.create_rectangle(left, top, right, bottom, outline=BLUE, fill=BLUE) # S-shape (orientation 1) elif c == 2: self.main_board.create_rectangle(left, top, right, bottom, outline=RED, fill=RED) # S-shape (orientation 2) elif c == 3: self.main_board.create_rectangle(left, top, right, bottom, outline=LIGHTBLUE, fill=LIGHTBLUE) # T-shape elif c == 4: self.main_board.create_rectangle(left, top, right, bottom, outline=ORANGE, fill=ORANGE) # L-shape (orientation 1) elif c == 5: self.main_board.create_rectangle(left, top, right, bottom, outline=GREEN, fill=GREEN) # L-shape (orientation 2) elif c == 6: self.main_board.create_rectangle(left, top, right, bottom, outline=PURPLE, fill=PURPLE) # Cube elif c == 7: self.main_board.create_rectangle(left, top, right, bottom, outline=YELLOW, fill=YELLOW) else: self.main_board.create_rectangle(left, top, right, bottom, fill="black") def draw_nextqueue(self, next_queue): # first clear old items for i in self.next_queue_items: self.side_board.delete(i) self.next_queue_items.clear() # draw rectangles according to game state for queueid in range(1,4): shape = next_queue[-1*queueid] for i, line in enumerate(shape): for j, c in enumerate(line): left = self.shape_block_unit*i+self.shape_block_border right = left+self.shape_block_size-self.shape_block_border top = self.shape_block_unit*j+self.shape_block_border+(queueid-1)*self.next_queue_offset bottom = top+self.shape_block_size-self.shape_block_border item = None # Line of four if c == 1: item = self.side_board.create_rectangle(left, top, right, bottom, outline=BLUE, fill=BLUE) # S-shape (orientation 1) elif c == 2: item = self.side_board.create_rectangle(left, top, right, bottom, outline=RED, fill=RED) # S-shape (orientation 2) elif c == 3: item = self.side_board.create_rectangle(left, top, right, bottom, outline=LIGHTBLUE, fill=LIGHTBLUE) # T-shape elif c == 4: item = self.side_board.create_rectangle(left, top, right, bottom, outline=ORANGE, fill=ORANGE) # L-shape (orientation 1) elif c == 5: item = self.side_board.create_rectangle(left, top, right, bottom, outline=GREEN, fill=GREEN) # L-shape (orientation 2) elif c == 6: item = self.side_board.create_rectangle(left, top, right, bottom, outline=PURPLE, fill=PURPLE) # Cube elif c == 7: item = self.side_board.create_rectangle(left, top, right, bottom, outline=YELLOW, fill=YELLOW) if item is not None: self.next_queue_items.append(item) def draw(self): last_run = time.time() * 1000 if self.game_started: mb, nq, score = self.tetris.render(mode='gui') self.draw_mainboard(mb) self.draw_nextqueue(nq) self.update_score() draw_time = time.time() * 1000 - last_run next_run = max(int(1000/FPS-draw_time), 0) self.window.after(next_run, self.draw) def auto_drop(self): self.tetris.step(3) self.window.after(self.drop_interval, self.auto_drop) def play(self): self.init_gui() self.draw() if self.mode == 'human': self.window.mainloop() else: self.start_game() self.window.update() def update_window(self): self.window.update() def start_game(self): self.game_started = True if self.game_over_banner is not None: self.main_board.delete(self.game_over_banner) if self.first_game and self.mode == 'human': self.auto_drop() self.first_game = False return self.tetris.reset() def game_over(self): self.game_over_banner = self.main_board.create_text(GUI_WIDTH/4, GUI_HEIGHT/2, text="Game Over", fill="white", font="Helvetica 40 bold") self.game_started = False