예제 #1
0
파일: Form.py 프로젝트: Afey/pyjs
class Form(FormPanel):

    def __init__(self, svc, **kwargs):

        self.describe_listeners = []
        if kwargs.has_key('listener'):
            listener = kwargs.pop('listener')
            self.addDescribeListener(listener)

        if kwargs.has_key('data'):
            data = kwargs.pop('data')
        else:
            data = None

        FormPanel.__init__(self, **kwargs)
        self.svc = svc
        self.grid = Grid()
        self.grid.resize(0, 3)
        self.add(self.grid)
        self.describer = FormDescribeGrid(self)
        self.saver = FormSaveGrid(self)
        self.getter = FormGetGrid(self)
        self.formsetup(data)

    def addDescribeListener(self, l):
        self.describe_listeners.append(l)

    def add_widget(self, description, widget):
        """ adds a widget, with error rows interspersed
        """

        num_rows = self.grid.getRowCount()
        self.grid.resize((num_rows+1), 3)
        self.grid.setHTML(num_rows, 0, description)
        self.grid.setWidget(num_rows, 1, widget)

    def get(self, **kwargs):
        writebr(repr(kwargs))
        self.svc({}, {'get': kwargs}, self.getter)

    def save(self, data=None):
        self.clear_errors()
        if data is None:
            data = self.getValue()
        self.data = data
        writebr(repr(self.data))
        self.svc(data, {'save': None}, self.saver)

    def save_respond(self, response):

        if not response['success']:
            errors = response['errors']
            self.set_errors(errors)
            for l in self.describe_listeners:
                l.onErrors(self, errors)
            return

        for l in self.describe_listeners:
            l.onSaveDone(self, response)

    def formsetup(self, data=None):

        if data is None:
            data = {}
        self.data = data
        self.svc(data, {'describe': None}, self.describer)

    def clear_errors(self):

        for idx, fname in enumerate(self.fields):
            self.grid.setHTML(idx, 2, None)

    def set_errors(self, errors):

        offsets = {}
        for idx, fname in enumerate(self.fields):
            offsets[fname] = idx
        for k, err in errors.items():
            err = "<br />".join(err)
            idx = offsets[k]
            self.grid.setHTML(idx, 2, err)

    def update_values(self, data = None):
        if data is not None:
            self.data = data

        for idx, fname in enumerate(self.fields):
            val = None
            if self.data.has_key(fname):
                val = self.data[fname]
            w = self.grid.getWidget(idx, 1)
            w.setValue(val)

    def do_get(self, response):
        fields = response.get('instance', None)
        if fields:
            self.update_values(fields)
        for l in self.describe_listeners:
            l.onRetrieveDone(self, fields)

    def do_describe(self, fields):

        self.fields = fields.keys()
        for idx, fname in enumerate(self.fields):
            field = fields[fname]
            if self.data and self.data.has_key(fname):
                field['initial'] = self.data[fname]
            field_type = field['type']
            widget_kls = widget_factory.get(field_type, CharField)
            fv = {}
            for (k, v) in field.items():
                fv[str(k)] = v
            w = widget_kls(**fv)
            self.add_widget(field['label'], w)

        for l in self.describe_listeners:
            l.onDescribeDone(self)

    def getValue(self):

        res = {}
        for idx, fname in enumerate(self.fields):
            w = self.grid.getWidget(idx, 1)
            val = w.getValue()
            res[fname] = val
            self.data[fname] = val

        return res
예제 #2
0
class InputBox(FocusPanel):

    _props = [ ("maxLength", "Max Length", "MaxLength", int),
               ("text", "Text", "Text", None),
               ("matchPattern", "Match Pattern", "MatchPattern", None),
               ("cursorStyle", "Cursor Style", "CursorStyle", None),
             ]

    @classmethod
    def _getProps(self):
        return FocusPanel._getProps() + self._props

    def __init__(self, **kwargs):
        """ setMatchPattern - defaults to '' to match everything
            match pattern examples: '^[0-9]*$' is for digits only
                                    '^[0-9,A-Z]*$' is for digits and uppercase
            setMaxLength
            setText
OB        """

        kwargs['MatchPattern'] = kwargs.pop('MatchPattern', '')
        cs = kwargs.pop('CursorStyle', "inputbox-cursor")
        gs = kwargs.pop('StyleName', 'gwt-inputbox')

        ap = AbsolutePanel(StyleName="inputbox")
        self.tp = Grid(StyleName=gs, Width="100%", Height="100%",
                       CellPadding=0, CellSpacing=0)
        self.cursor = HTML(StyleName=cs)
        ap.add(self.tp)
        ap.add(self.cursor, 0, 0)
        self.cf = self.tp.getCellFormatter()

        FocusPanel.__init__(self, Widget=ap, **kwargs)

        self.addTableListener(self)
        self.addKeyboardListener(self)
        self.addFocusListener(self)

        self.word_selected_pos = 0
        self.ctimer = Timer(notify=self.cursorFlash)
        self.focusset = False
        self.cstate = False
        self._keypressListeners = []
  
    def addKeypressListener(self, listener):
        self._keypressListeners.append(listener)

    def removeKeypressListener(self, listener):
        self._keypressListeners.remove(listener)

    def getMatchPattern(self):
        return self.mp

    def setMatchPattern(self, mp):
        self.mp = mp
        self.rexp = re.compile(self.mp)

    def addDblTableListener(self, listener):
        self.tp.addDblTableListener(listener)

    def addTableListener(self, listener):
        self.tp.addTableListener(listener)

    def _move_cursor(self, col):
        """ moves the css-styled cursor
        """
        #old style (useful for insert mode - don't delete this line for now!)
        #self.cf.setStyleName(0, col, "inputbox-square-word-cursor", highlight)

        el = self.cf.getRawElement(0, col+1)
        w = self.getWidget()
        px = self.tp.getAbsoluteLeft()
        py = self.tp.getAbsoluteTop()
        width = DOM.getOffsetWidth(el)
        px = DOM.getAbsoluteLeft(el) -  px
        py = DOM.getAbsoluteTop(el) - py 
        w.setWidgetPosition(self.cursor, px, py)

    def _highlight_cursor(self, col, highlight):
        """ highlights (or dehighlights) the currently selected cell
        """
        #old style (useful for insert mode - don't delete this line for now!)
        #self.cf.setStyleName(0, col, "inputbox-square-word-cursor", highlight)

        print "_highlight", col, highlight
        self._move_cursor(col)
        self.cursor.setStyleName("inputbox-square-word-cursor", highlight)

    def set_grid_value(self, v, y, x):

        if v:
            w = ""
        else:
            w = "0px"
        v = v or EMPTY
        s = HTML(v, StyleName="inputbox-square")
        self.tp.setWidget(y, x, s)
        self.cf.setAlignment(y, x,  HasAlignment.ALIGN_LEFT,
                                    HasAlignment.ALIGN_MIDDLE)
        self.cf.setWidth(y, x,  w)
        s.setWidth(w)

    def onKeyDown(self, sender, keycode, modifiers):

        evt = DOM.eventGetCurrentEvent()
        DOM.eventPreventDefault(evt)

        if self.word_selected_pos is None:
            return

        val = chr(keycode)
        done = False

        if keycode == KeyboardListener.KEY_DELETE:
            self.shift_letters_back()
            done = True
        elif keycode == KeyboardListener.KEY_BACKSPACE:
            if not self.nasty_hack():
                if self.moveCursor(-1):
                    self.shift_letters_back()
            done = True
        elif keycode == KeyboardListener.KEY_LEFT:
            self.moveCursor(-1)
            done = True
        elif keycode == KeyboardListener.KEY_RIGHT:
            self.moveCursor(1)
            done = True

        print "onKeyDown", keycode, val, self.rexp.match(val)

        if not done:
            if self.rexp.match(val):
                self.press_letter(val)

        for listener in self._keypressListeners:
            listener.onKeyPressed(sender, keycode, modifiers)

    def press_letter(self, val):

        print "press letter", val
        # check the key is a letter, and there's a grid position highlighted
        if self.word_selected_pos is None:
            return

        row = 0
        col = self.word_selected_pos

        self.highlight_cursor(False)
        self.set_grid_value(val, row, col)
        self.moveCursor(1)

    def nasty_hack(self):
        """ breaking of backspace/delete rules for the final character
        """

        row = 0
        col = self.word_selected_pos

        txt = self.get_char(col)
        if txt is None or txt == EMPTY:
            return False

        self.set_grid_value(EMPTY, row, col)
        return True

    def shift_letters_back(self):
        """ this function is used by del and backspace, to move the letters
            backwards from after the cursor.  the only difference between
            backspace and delete is that backspace moves the cursor and
            _then_ does letter-moving.
        """

        self.highlight_cursor(False)

        row = 0
        col = self.word_selected_pos
        x2 = self.tp.getColumnCount()-2
        
        while (x2 != col):
            txt = self.get_char(col+1)
            self.set_grid_value(txt, row, col)
            col += 1
        self.set_grid_value(EMPTY, row, col)
            
    def setCursorPos(self, col):

        x2 = self.tp.getColumnCount()-1

        col = min(x2, col)
        col = max(col, 0)

        if self.get_char(0) is None or self.get_char(0) == EMPTY:
            col = 0

        while (self.get_char(col-1) is None or \
              self.get_char(col-1) == EMPTY) and col > 1:
            col -= 1

        self._move_cursor(col)
        self.highlight_cursor(False)
        self.word_selected_pos = col
        self.highlight_cursor(self.focusset)

        return True

    def getCursorPos(self):
        return self.word_selected_pos

    def moveCursor(self, dirn):

        x2 = self.tp.getColumnCount()-1

        row = 0
        col = self.word_selected_pos

        if dirn == 1 and x2 == col+1:
            return False

        if dirn == -1 and 0 == col+1:
            return False

        return self.setCursorPos(col+dirn)

    def onKeyUp(self, sender, keycode, modifiers):
        evt = DOM.eventGetCurrentEvent()
        DOM.eventCancelBubble(evt, True)
        DOM.eventPreventDefault(evt)

    def onKeyPress(self, sender, keycode, modifiers):
        evt = DOM.eventGetCurrentEvent()
        DOM.eventPreventDefault(evt)

    def highlight_cursor(self, highlight):
        """ highlights (or dehighlights) the currently selected cell
        """
        if self.word_selected_pos is None:
            return
        col = self.word_selected_pos
        self._highlight_cursor(col, highlight)

    def getMaxLength(self):
        return self.tp.getColumnCount()-1

    def setMaxLength(self, x):
        l = max(0, self.tp.getColumnCount()-1)
        self.tp.resize(1, x+1)
        self.clear(l)

    def clear(self, fromrange=0):
        for i in range(fromrange, self.tp.getColumnCount()):
            self.set_grid_value(EMPTY, 0, i)
        self.cf.setWidth(0, self.tp.getColumnCount()-1, "100%")

    def onCellClicked(self, listener, row, col, direction=None):
        self.setCursorPos(col)

    def cursorFlash(self, timr):
        if not self.focusset:
            return
        self.highlight_cursor(self.cstate)
        self.cstate = not self.cstate

    def onFocus(self, sender):
        print "onFocus", sender
        self.focusset = True
        self.ctimer.scheduleRepeating(800)

    def onLostFocus(self, sender):
        print "onLostFocus", sender
        self.focusset = False
        self.ctimer.cancel()
        self.highlight_cursor(False)

    def get_char(self, x):
        w = self.tp.getWidget(0, x)
        return w and w.getHTML()

    def getText(self):
        txt = ''
        for i in range(self.tp.getColumnCount()-1):
            c = self.get_char(i)
            if c is None or c == EMPTY:
                break
            txt += c
        return txt

    def setText(self, txt):
        self.highlight_cursor(False)
        self.clear()
        txt = txt[:self.getMaxLength()]
        for (i, c) in enumerate(txt):
            self.set_grid_value(c, 0, i)
        self.setCursorPos(min(self.getMaxLength()-1, len(txt)))
예제 #3
0
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
예제 #4
0
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)