class GridEdit: def onModuleLoad(self): self.input = TextBox() self.input.setEnabled(False) self.input.addKeyboardListener(self) self.g=Grid() self.g.resize(5, 5) self.g.setHTML(0, 0, "<b>Grid Edit</b>") self.g.setBorderWidth(2) self.g.setCellPadding(4) self.g.setCellSpacing(1) self.g.setWidth("500px") self.g.setHeight("120px") self.g.addTableListener(self) self.initGrid() RootPanel().add(self.input) RootPanel().add(self.g) def onKeyDown(self, sender, keycode, modifiers): pass def onKeyUp(self, sender, keycode, modifiers): pass def onKeyPress(self, sender, keycode, modifiers): if keycode == KeyboardListener.KEY_ESCAPE: self.input.setEnabled(False) elif keycode == KeyboardListener.KEY_ENTER: self.input.setEnabled(False) val = self.input.getText() self.set_grid_value(self.row, self.col, val) def onCellClicked(self, sender, row, col): self.row = row self.col = col val = self.values[row][col] self.input.setText(val) self.input.setEnabled(True) self.input.setFocus(True) def set_grid_value(self, row, col, val): self.values[row][col] = val if val == "": val = " " self.g.setHTML(row, col, val) def initGrid(self): self.values = {} for y in range(5): self.values[y] = {} for x in range(5): self.values[y][x] = "" for y in range(5): for x in range(5): val = self.values[y][x] self.set_grid_value(y, x, val)
def __init__(self): # layed out in a grid with odd rows a different color for # visual separation #lucky = Grid(9,10, CellPadding=25, CellSpacing=1, BorderWidth=1) lucky = Grid() lucky.resize(9,10) lucky.setBorderWidth(1) lucky.setCellPadding(25) lucky.setCellSpacing(1) val = 0 for x in range(0,9): for y in range(0,10): val += 1 lucky.setText(x,y,val) grid = Grid(1,3,CellPadding=20,CellSpacing=0) rf = grid.getRowFormatter() rf.setStyleName(0, 'oddrow') # popup timer buttons ptb = PopupTimerButton(1) grid.setWidget(0, 0, CaptionPanel('Start the Lucky Number Countdown', ptb, StyleName='left')) grid.setWidget(0, 1, CaptionPanel('Current Lucky Number',ptb.box)) grid.setWidget(0, 2, lucky) # add it all to the root panel RootPanel().add(grid, lucky)
class GridWidget(AbsolutePanel): def __init__(self): AbsolutePanel.__init__(self) self.page=0 self.min_page=1 self.max_page=10 self.addb=Button("Next >", self) self.subb=Button("< Prev", self) self.clearb=Button("Clear", self) self.g=Grid() self.g.resize(5, 5) self.g.setWidget(0, 0, HTML("<b>Grid Test</b>")) self.g.setBorderWidth(2) self.g.setCellPadding(4) self.g.setCellSpacing(1) self.updatePageDisplay() self.add(self.subb) self.add(self.addb) self.add(self.clearb) self.add(self.g) def onClick(self, sender): if sender == self.clearb: print "clear" self.g.clear() return elif sender==self.addb: self.page+=1 elif sender==self.subb: self.page-=1 self.updatePageDisplay() def updatePageDisplay(self): if self.page<self.min_page: self.page=self.min_page elif self.page>self.max_page: self.page=self.max_page total_pages=(self.max_page-self.min_page) + 1 self.g.setHTML(0, 4, "<b>page %d of %d</b>" % (self.page, total_pages)) if self.page>=self.max_page: self.addb.setEnabled(False) else: self.addb.setEnabled(True) if self.page<=self.min_page: self.subb.setEnabled(False) else: self.subb.setEnabled(True) for y in range(1, 5): for x in range(5): self.g.setText(y, x, "%d (%d,%d)" % (self.page, x, y))
class RightPanel(DockPanel): def __init__(self): DockPanel.__init__(self) self.grids = {} self.g = Grid() self.g.setCellSpacing("0px") self.g.setCellPadding("8px") self.title = HTML(" ") self.title.setStyleName("rightpanel-title") self.add(self.title, DockPanel.NORTH) self.setCellWidth(self.title, "100%") self.setCellHorizontalAlignment(self.title, HasHorizontalAlignment.ALIGN_LEFT) self.add(self.g, DockPanel.CENTER) def setTitle(self, title): self.title.setHTML(title) def clear_items(self): for i in range(len(self.grids)): g = self.grids[i] if hasattr(g, "clear_items"): g.clear_items() self.grids = {} self.g.resize(0, 0) def setup_panels(self, datasets): self.grids = {} self.data = {} self.names = {} self.loaded = {} size = len(datasets) self.g.resize(size, 1) #for i in range(size): # item = datasets[i] # fname = item[0] # self.grids[i] = RightGrid(fname) # self.g.setWidget(i, 0, self.grids[i]) def add_html(self, html, name, index): self.data[index] = html self.names[index] = name self.grids[index] = HTML(html) self.g.setWidget(index, 0, self.grids[index]) def add_items(self, items, name, index): self.data[index] = items self.names[index] = name self.grids[index] = RightGrid("") self.grids[index].set_items(items) self.g.setWidget(index, 0, self.grids[index])
class GridWidget(AbsolutePanel): def __init__(self): AbsolutePanel.__init__(self) self.page = 0 self.min_page = 1 self.max_page = 10 self.addb = Button("Next >", self) self.subb = Button("< Prev", self) self.g = Grid() self.g.resize(5, 5) self.g.setHTML(0, 0, "<b>Grid Test</b>") self.g.setBorderWidth(2) self.g.setCellPadding(4) self.g.setCellSpacing(1) self.updatePageDisplay() self.add(self.subb) self.add(self.addb) self.add(self.g) def onClick(self, sender): print sender if sender == self.addb: self.page += 1 elif sender == self.subb: self.page -= 1 self.updatePageDisplay() def updatePageDisplay(self): if self.page < self.min_page: self.page = self.min_page elif self.page > self.max_page: self.page = self.max_page total_pages = (self.max_page - self.min_page) + 1 self.g.setHTML(0, 4, "<b>page %d of %d</b>" % (self.page, total_pages)) if self.page >= self.max_page: self.addb.setEnabled(False) else: self.addb.setEnabled(True) if self.page <= self.min_page: self.subb.setEnabled(False) else: self.subb.setEnabled(True) for y in range(1, 5): for x in range(5): self.g.setText(y, x, "%d (%d,%d)" % (self.page, x, y))
def state_to_grid(self, prev_x_board=-1, prev_y_board=-1, prev_x_cell=-1, prev_y_cell=-1): board = self.state.boards for y_board in range(3): for x_board in range(3): # for this mini-grid, do i make buttons or dashes? will_make_buttons = self.will_buttons(y_board, x_board) g = Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for y_cell in range(3): for x_cell in range(3): if board[y_board][x_board][y_cell][x_cell][ 'cell'] == 0: if will_make_buttons: b = HTML( '<p style="color:blue">AI %d could<br>play here.</p>' % (self.state.next_piece[2]), self) else: b = HTML('-') elif board[y_board][x_board][y_cell][x_cell][ 'cell'] == 1: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">1</p>') else: b = HTML('1') elif board[y_board][x_board][y_cell][x_cell][ 'cell'] == 2: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">2</p>') else: b = HTML('2') g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g)
def state_to_grid(self, prev_x_board=-1, prev_y_board=-1, prev_x_cell=-1, prev_y_cell=-1): board = self.state.boards for y_board in range(3): for x_board in range(3): # for this mini-grid, do i make buttons or dashes? will_make_buttons = self.will_buttons(y_board, x_board) g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for y_cell in range(3): for x_cell in range(3): if board[y_board][x_board][y_cell][x_cell]['cell'] == 0: if will_make_buttons: if self.min_player == -1: b = Button('Play 1 here.', self) else: b = Button('Play %d here.' % (self.state.next_piece[2]), self) b.point = {'x_cell':x_cell, 'y_cell':y_cell, 'y_board': y_board, 'x_board': x_board} else: b = HTML('-') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 1: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">1</p>') else: b = HTML('1') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 2: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">2</p>') else: b = HTML('2') g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g)
def init(self): '''Initializes the grid on which the game is played. ''' for y_board in range(3): for x_board in range(3): g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for x_cell in range(3): for y_cell in range(3): b = Button('Play here.', self) b.point = {'x_cell':x_cell, 'y_cell':y_cell, 'y_board': y_board, 'x_board': x_board} g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g)
class GridWidget(AbsolutePanel): def __init__(self): self.state = State() self.game_over = False self.TD_CONSTS = {'c3': 0.767944, 'c2': 1.049451, 'c1': 3.074038, 'c6': 0.220823, 'c5': 0.281883, 'c4': 0.605861} AbsolutePanel.__init__(self) StyleSheetCssText(margins) # initialize css... self.welcome_label = HTML('<H2 align="center">Welcome to Meta-Tic-Tac-Toe!</H2><p>Play first by clicking on one of the positions in the middle board or let the AI go first by clicking on "AI first". To change the difficulty click on "Increase/Decrease search depth". Note: if there is a pop-up saying that the script is taking a long time to complete, this is not a bug - the AI is just taking a while to find the next move. Select the option to continue the script.</p>', StyleName='margins_both') self.add(self.welcome_label) self.depthLimit = 3 self.human_first = True self.ai_first = Button("AI first.", self, StyleName='margins_left') self.add(self.ai_first) self.increase_depth = Button("Increase search depth", self) self.decrease_depth = Button("Decrease search depth", self) self.depth_label = HTML("""AI will search to a <a href="#depth_explanation">depth</a> of """ + str(self.depthLimit) +".") self.depth_grid = Grid(StyleName='margins_left') self.depth_grid.resize(1, 3) self.depth_grid.setBorderWidth(2) self.depth_grid.setCellPadding(9) self.depth_grid.setCellSpacing(1) self.add(self.depth_grid) self.depth_grid.setWidget(0, 0, self.decrease_depth) self.depth_grid.setWidget(0, 1, self.depth_label) self.depth_grid.setWidget(0, 2, self.increase_depth) self.new_game = Button("New game", self, StyleName='margins_left') self.add(self.new_game) self.score_label = Label("CURRENT SCORE: Human: %d | AI: %d"% (0,0), StyleName='margins_left') self.add(self.score_label) self.game_over_msg = HTML("", StyleName='margins_left') self.add(self.game_over_msg) # initialize the board grid: self.g=Grid(StyleName='margins_left') self.g.resize(3, 3) self.g.setBorderWidth(2) self.g.setCellPadding(9) self.g.setCellSpacing(1) self.init() self.add(self.g) # initialize the contstants adjustment grid: self.adj_grid = Grid(StyleName='margins_left') self.adj_grid.resize(7, 3) self.adj_grid.setBorderWidth(2) self.adj_grid.setCellPadding(9) self.adj_grid.setCellSpacing(1) self.init_constants_adj_grid() self.add(self.adj_grid) self.max_player = '-1' self.min_player = '-1' self.state_to_grid() def init_constants_adj_grid(self): '''Initializes the grid that allows the TD_CONSTS to be adjusted. ''' self.decr_buttons = {} self.adj_labels = {} self.incr_buttons = {} td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] self.adj_grid.setWidget(0, 1, HTML('''Adjust the <a href="#utility_function">constants</a> to change<br>the AI's behavior.''')) for i, key in enumerate(td_keys): j = i + 1 self.decr_buttons[key] = Button('<', self) self.adj_grid.setWidget(j, 0, self.decr_buttons[key]) self.incr_buttons[key] = Button('>', self) self.adj_grid.setWidget(j, 2, self.incr_buttons[key]) self.adj_labels[key] = Label("Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.adj_grid.setWidget(j, 1, self.adj_labels[key]) def init(self): '''Initializes the grid on which the game is played. ''' for y_board in range(3): for x_board in range(3): g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for x_cell in range(3): for y_cell in range(3): b = Button('Play here.', self) b.point = {'x_cell':x_cell, 'y_cell':y_cell, 'y_board': y_board, 'x_board': x_board} g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g) def start_new_game(self): #g.__init__() nope, can't use this :( self.state = State() self.game_over = False self.depthLimit = 3 self.human_first = True self.ai_first.setVisible(True) # new game, so we make this button visible self.check_win() self.max_player = '-1' self.min_player = '-1' self.state_to_grid() def onClick(self, sender): if sender == self.increase_depth: self.depthLimit += 1 self.depth_label.setHTML("""AI will search to a <a href="#depth_explanation">depth</a> of """ + str(self.depthLimit) +".") if sender == self.decrease_depth: self.depthLimit -= 1 self.depth_label.setHTML("""AI will search to a <a href="#depth_explanation">depth</a> of """ + str(self.depthLimit) +".") if sender == self.new_game: self.start_new_game() self.check_adjusts(sender) if not self.game_over: if sender == self.ai_first and self.min_player == -1: # we only set min_player and max_player when they are not yet initialized self.human_first = False self.max_player = '1' self.min_player = '2' self.state.next_piece[2] = self.max_player self.ai_first.setVisible(False) # can't go first any more so we make it invisible... new_state = ab(self.state, self.TD_CONSTS, depth_limit=self.depthLimit)[1] last_position = find_last_move(self.state, new_state) self.state = new_state self.state_to_grid(prev_x_board=last_position['x_board'], prev_y_board=last_position['y_board'], prev_x_cell=last_position['x_cell'], prev_y_cell=last_position['y_cell'],) if hasattr(sender, 'point'): if self.min_player == -1: # we only set min_player and max_player when they are not yet initialized self.max_player = '2' self.min_player = '1' self.ai_first.setVisible(False) # can't go first any more so we make it invisible... point = sender.point g = self.g.getWidget(point['y_board'], point['x_board']) g.setText(point['y_cell'], point['x_cell'], str(self.min_player)) self.grid_to_state(point) self.check_win() self.state.next_piece[2] = self.max_player new_state = ab(self.state, self.TD_CONSTS, depth_limit=self.depthLimit)[1] last_position = find_last_move(self.state, new_state) self.state = new_state self.state_to_grid(prev_x_board=last_position['x_board'], prev_y_board=last_position['y_board'], prev_x_cell=last_position['x_cell'], prev_y_cell=last_position['y_cell'],) self.check_win() def check_adjusts(self, sender): td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] for key in td_keys: if self.incr_buttons[key] == sender: self.change_td_const(key, '+') if self.decr_buttons[key] == sender: self.change_td_const(key, '-') self.adj_labels[key].setText("Constant %d: %f" % (key[1], self.TD_CONSTS[key])) def change_td_const(self, key, sign): if sign == '+': self.TD_CONSTS[key] += INCREMENT_AMOUNT elif sign == '-': self.TD_CONSTS[key] -= INCREMENT_AMOUNT def check_win(self): self.depth_label.setHTML("""AI will search to a <a href="#depth_explanation">depth</a> of """ + str(self.depthLimit) +".") self.check_adjusts(None) human_score = self.state.score[str(self.min_player)] ai_score = self.state.score[str(self.max_player)] self.score_label.setText("CURRENT SCORE: Human(%d): %d | AI(%d): %d" % (self.min_player, human_score, self.max_player, ai_score)) if is_over(self.state): if human_score > ai_score: msg = "Congratulations, you won! To increase the difficulty, increase the search depth." elif human_score < ai_score: msg = "You lost! Better luck next time." elif human_score == ai_score: msg = "Game ends in a tie." self.game_over_msg.setHTML("<H3>" + msg + "</H3>") self.game_over = True if self.game_over: self.game_over_msg.setVisible(True) else: self.game_over_msg.setVisible(False) def will_buttons(self, y_board, x_board): # first we determine if the next_piece points to a playable board. board = self.state.boards piece = list(self.state.next_piece) playable = True if is_win(board[piece[0]][piece[1]]) or is_full(board[piece[0]][piece[1]]): playable = False if (not is_win(board[y_board][x_board])) and (not is_full(board[y_board][x_board])): if not playable: return True if playable: return (y_board == piece[0]) and (x_board == piece[1]) return False def state_to_grid(self, prev_x_board=-1, prev_y_board=-1, prev_x_cell=-1, prev_y_cell=-1): board = self.state.boards for y_board in range(3): for x_board in range(3): # for this mini-grid, do i make buttons or dashes? will_make_buttons = self.will_buttons(y_board, x_board) g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for y_cell in range(3): for x_cell in range(3): if board[y_board][x_board][y_cell][x_cell]['cell'] == 0: if will_make_buttons: if self.min_player == -1: b = Button('Play 1 here.', self) else: b = Button('Play %d here.' % (self.state.next_piece[2]), self) b.point = {'x_cell':x_cell, 'y_cell':y_cell, 'y_board': y_board, 'x_board': x_board} else: b = HTML('-') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 1: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">1</p>') else: b = HTML('1') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 2: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">2</p>') else: b = HTML('2') g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g) def grid_to_state(self, point): board = self.state.boards for y_board in range(3): for x_board in range(3): g = self.g.getWidget(y_board, x_board) for y_cell in range(3): for x_cell in range(3): if isinstance(g.getWidget(y_cell, x_cell), Button): assert board[y_board][x_board][y_cell][x_cell]['cell'] == 0 elif (g.getText(y_cell, x_cell) == '1') or (g.getText(y_cell, x_cell) == '2'): if self.state.boards[y_board][x_board][y_cell][x_cell]['cell'] == 0: self.state.boards[y_board][x_board][y_cell][x_cell]['cell'] = int(g.getText(y_cell, x_cell)) piece = self.state.next_piece piece[0] = y_cell piece[1] = x_cell else: assert (g.getText(y_cell, x_cell) == '-') if is_win(self.state.boards[point['y_board']][point['x_board']]): self.state.score[str(self.min_player)] += 1
class GridWidget(AbsolutePanel): def __init__(self): self.state = State() self.game_round = 0 self.TD_CONSTS = { 'c3': 1., 'c2': 1., 'c1': 1., 'c6': 1., 'c5': 1., 'c4': 1. } self.CONSTS = { 'c3': .5, 'c2': 1., 'c1': 3., 'c6': .5, 'c5': .5, 'c4': .5 } self.BEST_CONSTANTS = { 'c3': 0.767944, 'c2': 1.049451, 'c1': 3.074038, 'c6': 0.220823, 'c5': 0.281883, 'c4': 0.605861 } self.ONES_CONSTS = { 'c3': 1., 'c2': 1., 'c1': 1., 'c6': 1., 'c5': 1., 'c4': 1. } AbsolutePanel.__init__(self) self.welcome_label = HTML( '<H2 align="center">Welcome to Meta-Tic-Tac-Toe!</H2>To watch the AI play itself, press either "begin game" button. Note: if there is a pop-up saying that the script is taking a long time to complete, this is not a bug - the AI is just taking a while to find the next move. Select the option to continue the script.', StyleName='margins_both') self.add(self.welcome_label) self.depth_limit = 2 self.train_td = Button("Begin game. Learning AI first!", self, StyleName='margins_left') self.add(self.train_td) self.train_static = Button("Begin game. Static AI first!", self, StyleName='margins_left') self.add(self.train_static) self.score_label = Label( "CURRENT SCORE: Learning AI: %d | Static AI: %d" % (0, 0), StyleName='margins_left') self.add(self.score_label) self.game_over_message = Label("", StyleName='margins_left') self.add(self.game_over_message) StyleSheetCssText(margins) self.increase_depth = Button("Increase ply search depth.", self) self.decrease_depth = Button("Decrease ply search depth.", self) self.depth_label = Label("Current depth is " + str(self.depth_limit) + ".") self.depth_grid = Grid(StyleName='margins_left') self.depth_grid.resize(1, 3) self.depth_grid.setBorderWidth(2) self.depth_grid.setCellPadding(9) self.depth_grid.setCellSpacing(1) self.add(self.depth_grid) self.depth_grid.setWidget(0, 0, self.decrease_depth) self.depth_grid.setWidget(0, 1, self.depth_label) self.depth_grid.setWidget(0, 2, self.increase_depth) # initialize the board grid: self.g = Grid(StyleName='margins_left') self.g.resize(3, 3) self.g.setBorderWidth(2) self.g.setCellPadding(9) self.g.setCellSpacing(1) self.init() self.add(self.g) # initialize the contstants adjustment grid: self.adj_grid = Grid(StyleName='margins_left') self.adj_grid.resize(7, 4) self.adj_grid.setBorderWidth(2) self.adj_grid.setCellPadding(9) self.adj_grid.setCellSpacing(1) self.init_constants_adj_grid() self.add(self.adj_grid) self.reset_constants = Button( "Reset all of Learning AI's constants to 1.", self, StyleName='margins_left') self.add(self.reset_constants) self.state_to_grid() def init_constants_adj_grid(self): '''Initializes the grid that allows the TD_CONSTS to be adjusted. ''' self.decr_buttons = {} self.adj_learning_labels = {} self.adj_static_labels = {} self.incr_buttons = {} td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] learning_ai_header = Label("Constant for the learning AI.") self.adj_grid.setWidget(0, 0, learning_ai_header) static_ai_header = Label("Constants for the static AI.") self.adj_grid.setWidget(0, 2, static_ai_header) for i, key in enumerate(td_keys): j = i + 1 # off by one because of header... self.adj_learning_labels[key] = Label( "Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.adj_grid.setWidget(j, 0, self.adj_learning_labels[key]) self.decr_buttons[key] = Button('<', self) self.adj_grid.setWidget(j, 1, self.decr_buttons[key]) self.adj_static_labels[key] = Label("Constant %d: %f" % (key[1], self.CONSTS[key])) self.adj_grid.setWidget(j, 2, self.adj_static_labels[key]) self.incr_buttons[key] = Button('>', self) self.adj_grid.setWidget(j, 3, self.incr_buttons[key]) def init(self): '''Initializes the grid on which the game is played. ''' for y_board in range(3): for x_board in range(3): g = Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for x_cell in range(3): for y_cell in range(3): b = Button('AI could play here.', self) b.point = { 'x_cell': x_cell, 'y_cell': y_cell, 'y_board': y_board, 'x_board': x_board } g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g) def start_new_game(self): #g.__init__() nope, can't use this :( g.state = State() g.game_over = False self.depthLimit = 2 self.human_first = True self.check_is_win() self.max_player = '-1' self.min_player = '-1' self.state_to_grid() def onClick(self, sender): self.check_adjusts(sender) if sender == self.reset_constants: self.TD_CONSTS = self.ONES_CONSTS self.sync_consts() if sender == self.increase_depth: self.depth_limit += 1 self.depth_label.setText("Current depth is " + str(self.depth_limit) + ".") if sender == self.decrease_depth: self.depth_limit -= 1 self.depth_label.setText("Current depth is " + str(self.depth_limit) + ".") if sender == self.train_td: self.state = State() self.static_ai_str = '2' self.td_ai_str = '1' self.state.next_piece = [1, 1, 1] Timer(250, notify=self.td_ai_turn) if sender == self.train_static: self.state = State() self.static_ai_str = '1' self.td_ai_str = '2' self.state.next_piece = [1, 1, 1] Timer(250, notify=self.static_ai_turn) def check_adjusts(self, sender): td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] for key in td_keys: if self.incr_buttons[key] == sender: self.change_td_const(key, '+') if self.decr_buttons[key] == sender: self.change_td_const(key, '-') self.TD_CONSTS = normalize(self.TD_CONSTS) self.adj_learning_labels[key].setText( "Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.sync_consts() def change_td_const(self, key, sign): if sign == '+': self.CONSTS[key] += INCREMENT_AMOUNT elif sign == '-': self.CONSTS[key] -= INCREMENT_AMOUNT def sync_consts(self): """Sync td rates with the current state. """ td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] for key in td_keys: self.adj_learning_labels[key].setText( "Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.adj_static_labels[key].setText("Constant %d: %f" % (key[1], self.CONSTS[key])) def check_is_win(self, last_position={}): self.state_to_grid( prev_x_board=last_position['x_board'], prev_y_board=last_position['y_board'], prev_x_cell=last_position['x_cell'], prev_y_cell=last_position['y_cell'], ) learning_ai_score = self.state.score[self.td_ai_str] static_ai_score = self.state.score[self.static_ai_str] self.score_label.setText( "CURRENT SCORE: Learning AI(%d): %d | Static AI(%d): %d" % (self.td_ai_str, learning_ai_score, self.static_ai_str, static_ai_score)) self.state.printInfo() if is_over(self.state): if learning_ai_score > static_ai_score: msg = "the learning AI won with score %d vs %d." % ( learning_ai_score, static_ai_score) elif learning_ai_score < static_ai_score: msg = "the static AI won with score %d vs %d." % ( static_ai_score, learning_ai_score) elif learning_ai_score == static_ai_score: msg = "the game ended in a tie." self.game_round += 1 game_over_message.setText("In game round " + str(self.game_round) + ", " + msg) return True else: return False def static_ai_turn(self): print "\n\nNaive AIs turn which plays the piece: ", self.state.next_piece[ 2] print "next piece is ", self.state.next_piece print "TD_CONSTS", self.TD_CONSTS (expectedUtility, next_state) = ab(self.state, self.CONSTS, depth_limit=self.depth_limit) last_position = find_last_move(self.state, next_state) self.state = next_state self.state.printInfo() over = self.check_is_win(last_position) print "back in static" if not over: self.pause_update = Timer(250, notify=self.td_ai_turn) else: return True def td_ai_turn(self): print "\n\nTD AI player starting turn. TD AI places the piece:", self.state.next_piece[ 2] print "TD_CONSTS after being adjusted are: ", self.TD_CONSTS # print, alpha-beta search etc.: (expectedUtility, state) = ab(self.state, self.TD_CONSTS, depth_limit=self.depth_limit) terminal_state = expectedUtility.terminal self.TD_CONSTS = td_learning(terminal_state, self.TD_CONSTS, self.state) self.sync_consts() # reflect the new TD_CONSTS in the game. last_position = find_last_move(self.state, state) self.state = state state.printInfo() print "TD_CONSTS after being adjusted are: ", self.TD_CONSTS over = self.check_is_win(last_position) print "back in td" print "Is over ", over if not over: return Timer(250, notify=self.static_ai_turn) else: return True def will_buttons(self, y_board, x_board): # first we determine if the next_piece points to a playable board. board = self.state.boards piece = list(self.state.next_piece) playable = True if is_win(board[piece[0]][piece[1]]) or is_full( board[piece[0]][piece[1]]): playable = False if (not is_win(board[y_board][x_board])) and (not is_full( board[y_board][x_board])): if not playable: return True if playable: return (y_board == piece[0]) and (x_board == piece[1]) return False def state_to_grid(self, prev_x_board=-1, prev_y_board=-1, prev_x_cell=-1, prev_y_cell=-1): board = self.state.boards for y_board in range(3): for x_board in range(3): # for this mini-grid, do i make buttons or dashes? will_make_buttons = self.will_buttons(y_board, x_board) g = Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for y_cell in range(3): for x_cell in range(3): if board[y_board][x_board][y_cell][x_cell][ 'cell'] == 0: if will_make_buttons: b = HTML( '<p style="color:blue">AI %d could<br>play here.</p>' % (self.state.next_piece[2]), self) else: b = HTML('-') elif board[y_board][x_board][y_cell][x_cell][ 'cell'] == 1: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">1</p>') else: b = HTML('1') elif board[y_board][x_board][y_cell][x_cell][ 'cell'] == 2: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">2</p>') else: b = HTML('2') g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g)
class GridWidget(AbsolutePanel): def __init__(self): AbsolutePanel.__init__(self) StyleSheetCssText(margins) # initialize css... header = """<div><H2 align="center">Welcome to Unbeatable Tic-Tac-Toe!</H2><br>My <a href="https://github.com/chetweger/min-max-games/blob/master/ttt/ttt.py">implementation</a> uses the min-max search algorithm with alpha beta pruning and a transposition table!</div>""" header = HTML(header, StyleName='margins_both') self.add(header) self.ai_first = Button("AI first.", self, StyleName='margins_left') self.add(self.ai_first) self.new_game = Button("New game", self, StyleName='margins_left') self.add(self.new_game) self.g=Grid(StyleName='margins_left') self.g.resize(3, 3) self.g.setBorderWidth(2) self.g.setCellPadding(4) self.g.setCellSpacing(1) self.init() self.add(self.g) self.state = State() self.game_resolution=Label("", StyleName='margins_left') self.add(self.game_resolution) def start_new_game(self): self.state = State() self.game_over = False self.ai_first.setVisible(True) self.state_to_grid(self.state) def onClick(self, sender): if sender == self.ai_first: print 'player is ', self.state.player self.state.max_v = 1 self.state.min_v = 2 self.ai_first.setVisible(False) print 'button ai_first exists', hasattr(self, 'ai_first') self.state.print_me() next_state = ab(self.state) self.state = next_state self.state_to_grid(next_state) print '[after]player is ', self.state.player elif sender == self.new_game: self.start_new_game() else: print 'player is ', self.state.player ''' self.g.setText(0, 1, 'wassup') self.g.setText(p['x'], p['y'], str(self.state.min_v)) ''' if self.ai_first.isVisible(): print 'Setting state.max_v' self.state.max_v = 2 self.state.min_v = 1 self.ai_first.setVisible(False) p = sender.point self.g.setText(p['y'], p['x'], str(self.state.player)) self.state = self.grid_to_state() self.check_for_tie() # end 1 if is_win(self.state): self.state_to_grid(self.state, game_over=True, over_message='You won! This should not happen. This is a bug. Please email [email protected] describing the conditions of the game.') self.state.player = next_player(self.state.player) self.state.print_me() next_state = ab(self.state) self.state = next_state self.state_to_grid(next_state) self.check_for_tie() # end 1 if is_win(self.state): self.state_to_grid(self.state, game_over=True, over_message='You lost! Better luck next time.') def check_for_tie(self): if is_over(self.state): self.state_to_grid(self.state, game_over=True, over_message='The game is a tie.') def state_to_grid(self, state, game_over=False, over_message=''): if over_message: self.game_resolution.setText(over_message) self.game_resolution.setVisible(True) else: self.game_resolution.setVisible(False) board = state.board for y in range(3): for x in range(3): if board[y][x] == 0: if not game_over: b = Button('Press', self) b.point = {'x':x, 'y':y} self.g.setWidget(y, x, b) else: self.g.setText(y, x, '-') elif board[y][x] == '1': self.g.setText(y, x, '1') elif board[y][x] == '2': self.g.setText(y, x, '2') else: print 'state_to_grid exception' #assert False def grid_to_state(self): next_state = State() for y in range(3): for x in range(3): if isinstance(self.g.getWidget(y, x), Button): print y, x next_state.board[y][x] = 0 elif self.g.getText(y, x) == '1' or self.g.getText(y, x) == '2': next_state.board[y][x] = int(self.g.getText(y,x)) else: print 'grid_to_state exception' #assert False next_state.min_v = self.state.min_v next_state.max_v = self.state.max_v next_state.player = self.state.player return next_state def init(self): for y in range(3): for x in range(3): b = Button('Press', self) b.point = {'x':x, 'y':y} self.g.setWidget(y, x, b)
class GridWidget(AbsolutePanel): def __init__(self): self.state = State() self.game_round = 0 self.TD_CONSTS = {'c3': 1., 'c2': 1., 'c1': 1., 'c6': 1., 'c5': 1., 'c4': 1.} self.CONSTS = {'c3': .5, 'c2': 1., 'c1': 3., 'c6': .5, 'c5': .5, 'c4': .5} self.BEST_CONSTANTS = {'c3': 0.767944, 'c2': 1.049451, 'c1': 3.074038, 'c6': 0.220823, 'c5': 0.281883, 'c4': 0.605861} self.ONES_CONSTS = {'c3': 1., 'c2': 1., 'c1': 1., 'c6': 1., 'c5': 1., 'c4': 1.} AbsolutePanel.__init__(self) self.welcome_label = HTML('<H2 align="center">Welcome to Meta-Tic-Tac-Toe!</H2>To watch the AI play itself, press either "begin game" button. Note: if there is a pop-up saying that the script is taking a long time to complete, this is not a bug - the AI is just taking a while to find the next move. Select the option to continue the script.', StyleName='margins_both') self.add(self.welcome_label) self.depth_limit = 2 self.train_td = Button("Begin game. Learning AI first!", self, StyleName='margins_left') self.add(self.train_td) self.train_static = Button("Begin game. Static AI first!", self, StyleName='margins_left') self.add(self.train_static) self.score_label = Label("CURRENT SCORE: Learning AI: %d | Static AI: %d"% (0,0), StyleName='margins_left') self.add(self.score_label) self.game_over_message = Label("", StyleName='margins_left') self.add(self.game_over_message) StyleSheetCssText(margins) self.increase_depth = Button("Increase ply search depth.", self) self.decrease_depth = Button("Decrease ply search depth.", self) self.depth_label = Label("Current depth is " + str(self.depth_limit) +".") self.depth_grid = Grid(StyleName='margins_left') self.depth_grid.resize(1, 3) self.depth_grid.setBorderWidth(2) self.depth_grid.setCellPadding(9) self.depth_grid.setCellSpacing(1) self.add(self.depth_grid) self.depth_grid.setWidget(0, 0, self.decrease_depth) self.depth_grid.setWidget(0, 1, self.depth_label) self.depth_grid.setWidget(0, 2, self.increase_depth) # initialize the board grid: self.g=Grid(StyleName='margins_left') self.g.resize(3, 3) self.g.setBorderWidth(2) self.g.setCellPadding(9) self.g.setCellSpacing(1) self.init() self.add(self.g) # initialize the contstants adjustment grid: self.adj_grid = Grid(StyleName='margins_left') self.adj_grid.resize(7, 4) self.adj_grid.setBorderWidth(2) self.adj_grid.setCellPadding(9) self.adj_grid.setCellSpacing(1) self.init_constants_adj_grid() self.add(self.adj_grid) self.reset_constants = Button("Reset all of Learning AI's constants to 1.", self, StyleName='margins_left') self.add(self.reset_constants) self.state_to_grid() def init_constants_adj_grid(self): '''Initializes the grid that allows the TD_CONSTS to be adjusted. ''' self.decr_buttons = {} self.adj_learning_labels = {} self.adj_static_labels = {} self.incr_buttons = {} td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] learning_ai_header = Label("Constant for the learning AI.") self.adj_grid.setWidget(0, 0, learning_ai_header) static_ai_header = Label("Constants for the static AI.") self.adj_grid.setWidget(0, 2, static_ai_header) for i, key in enumerate(td_keys): j = i + 1 # off by one because of header... self.adj_learning_labels[key] = Label("Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.adj_grid.setWidget(j, 0, self.adj_learning_labels[key]) self.decr_buttons[key] = Button('<', self) self.adj_grid.setWidget(j, 1, self.decr_buttons[key]) self.adj_static_labels[key] = Label("Constant %d: %f" % (key[1], self.CONSTS[key])) self.adj_grid.setWidget(j, 2, self.adj_static_labels[key]) self.incr_buttons[key] = Button('>', self) self.adj_grid.setWidget(j, 3, self.incr_buttons[key]) def init(self): '''Initializes the grid on which the game is played. ''' for y_board in range(3): for x_board in range(3): g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for x_cell in range(3): for y_cell in range(3): b = Button('AI could play here.', self) b.point = {'x_cell':x_cell, 'y_cell':y_cell, 'y_board': y_board, 'x_board': x_board} g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g) def start_new_game(self): #g.__init__() nope, can't use this :( g.state = State() g.game_over = False self.depthLimit = 2 self.human_first = True self.check_is_win() self.max_player = '-1' self.min_player = '-1' self.state_to_grid() def onClick(self, sender): self.check_adjusts(sender) if sender == self.reset_constants: self.TD_CONSTS = self.ONES_CONSTS self.sync_consts() if sender == self.increase_depth: self.depth_limit += 1 self.depth_label.setText("Current depth is " + str(self.depth_limit) +".") if sender == self.decrease_depth: self.depth_limit -= 1 self.depth_label.setText("Current depth is " + str(self.depth_limit) +".") if sender == self.train_td: self.state = State() self.static_ai_str = '2' self.td_ai_str = '1' self.state.next_piece = [1, 1, 1] Timer(250, notify=self.td_ai_turn) if sender == self.train_static: self.state = State() self.static_ai_str = '1' self.td_ai_str = '2' self.state.next_piece = [1, 1, 1] Timer(250, notify=self.static_ai_turn) def check_adjusts(self, sender): td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] for key in td_keys: if self.incr_buttons[key] == sender: self.change_td_const(key, '+') if self.decr_buttons[key] == sender: self.change_td_const(key, '-') self.TD_CONSTS = normalize(self.TD_CONSTS) self.adj_learning_labels[key].setText("Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.sync_consts() def change_td_const(self, key, sign): if sign == '+': self.CONSTS[key] += INCREMENT_AMOUNT elif sign == '-': self.CONSTS[key] -= INCREMENT_AMOUNT def sync_consts(self): """Sync td rates with the current state. """ td_keys = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6'] for key in td_keys: self.adj_learning_labels[key].setText("Constant %d: %f" % (key[1], self.TD_CONSTS[key])) self.adj_static_labels[key].setText("Constant %d: %f" % (key[1], self.CONSTS[key])) def check_is_win(self, last_position={}): self.state_to_grid(prev_x_board=last_position['x_board'], prev_y_board=last_position['y_board'], prev_x_cell=last_position['x_cell'], prev_y_cell=last_position['y_cell'],) learning_ai_score = self.state.score[self.td_ai_str] static_ai_score = self.state.score[self.static_ai_str] self.score_label.setText("CURRENT SCORE: Learning AI(%d): %d | Static AI(%d): %d" % (self.td_ai_str, learning_ai_score, self.static_ai_str, static_ai_score)) self.state.printInfo() if is_over(self.state): if learning_ai_score > static_ai_score: msg = "the learning AI won with score %d vs %d." % (learning_ai_score, static_ai_score) elif learning_ai_score < static_ai_score: msg = "the static AI won with score %d vs %d." % (static_ai_score, learning_ai_score) elif learning_ai_score == static_ai_score: msg = "the game ended in a tie." self.game_round += 1 game_over_message.setText("In game round " + str(self.game_round) + ", " + msg) return True else: return False def static_ai_turn(self): print "\n\nNaive AIs turn which plays the piece: ", self.state.next_piece[2] print "next piece is ", self.state.next_piece print "TD_CONSTS", self.TD_CONSTS (expectedUtility, next_state) = ab(self.state, self.CONSTS, depth_limit=self.depth_limit) last_position = find_last_move(self.state, next_state) self.state = next_state self.state.printInfo() over = self.check_is_win(last_position) print "back in static" if not over: self.pause_update = Timer(250, notify=self.td_ai_turn) else: return True def td_ai_turn(self): print "\n\nTD AI player starting turn. TD AI places the piece:", self.state.next_piece[2] print "TD_CONSTS after being adjusted are: ", self.TD_CONSTS # print, alpha-beta search etc.: (expectedUtility, state) = ab(self.state, self.TD_CONSTS, depth_limit=self.depth_limit) terminal_state = expectedUtility.terminal self.TD_CONSTS = td_learning(terminal_state, self.TD_CONSTS, self.state) self.sync_consts() # reflect the new TD_CONSTS in the game. last_position = find_last_move(self.state, state) self.state = state state.printInfo() print "TD_CONSTS after being adjusted are: ", self.TD_CONSTS over = self.check_is_win(last_position) print "back in td" print "Is over ", over if not over: return Timer(250, notify=self.static_ai_turn) else: return True def will_buttons(self, y_board, x_board): # first we determine if the next_piece points to a playable board. board = self.state.boards piece = list(self.state.next_piece) playable = True if is_win(board[piece[0]][piece[1]]) or is_full(board[piece[0]][piece[1]]): playable = False if (not is_win(board[y_board][x_board])) and (not is_full(board[y_board][x_board])): if not playable: return True if playable: return (y_board == piece[0]) and (x_board == piece[1]) return False def state_to_grid(self, prev_x_board=-1, prev_y_board=-1, prev_x_cell=-1, prev_y_cell=-1): board = self.state.boards for y_board in range(3): for x_board in range(3): # for this mini-grid, do i make buttons or dashes? will_make_buttons = self.will_buttons(y_board, x_board) g=Grid() g.resize(3, 3) g.setBorderWidth(2) g.setCellPadding(9) g.setCellSpacing(1) for y_cell in range(3): for x_cell in range(3): if board[y_board][x_board][y_cell][x_cell]['cell'] == 0: if will_make_buttons: b = HTML('<p style="color:blue">AI %d could<br>play here.</p>' % (self.state.next_piece[2]), self) else: b = HTML('-') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 1: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">1</p>') else: b = HTML('1') elif board[y_board][x_board][y_cell][x_cell]['cell'] == 2: if (prev_x_cell == x_cell and prev_y_cell == y_cell and prev_y_board == y_board and prev_x_board == x_board): b = HTML('<p style="color:red">2</p>') else: b = HTML('2') g.setWidget(y_cell, x_cell, b) self.add(g) self.g.setWidget(y_board, x_board, g)