Example #1
0
    def validate (self, cord0, cord1):
        if cord0 is None or cord1 is None:
            return False
        # prevent accidental NULL_MOVE creation
        if cord0 == cord1:
            return False
        if self.getBoard()[cord0] == None:
            return False

        if self.parent.setup_position:
            to_piece = self.getBoard()[cord1]
            # prevent moving pieces inside holding
            if (cord0.x < 0 or cord0.x > self.FILES-1) and \
                (cord1.x < 0 or cord1.x > self.FILES-1):
                return False
            # prevent moving kings off board
            elif self.getBoard()[cord0].piece == KING and \
                (cord1.x < 0 or cord1.x > self.FILES-1):
                return False
            # prevent taking enemy king
            elif to_piece is not None and to_piece.piece == KING:
                return False
            else:
                return True
        
        if cord1.x < 0 or cord1.x > self.FILES-1:
            return False
        if cord0.x < 0 or cord0.x > self.FILES-1:
            # drop
            return validate(self.getBoard(), Move(lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord, DROP)))
        else:
            return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #2
0
    def validate(self, cord0, cord1):
        if cord0 is None or cord1 is None:
            return False
        # prevent accidental NULL_MOVE creation
        if cord0 == cord1 and self.parent.variant.variant != SITTUYINCHESS:
            return False
        if self.getBoard()[cord0] is None:
            return False

        if self.parent.setup_position:
            # prevent moving pieces inside holding
            if (cord0.x < 0 or cord0.x > self.FILES - 1) and \
                    (cord1.x < 0 or cord1.x > self.FILES - 1):
                return False
            else:
                return True

        if cord1.x < 0 or cord1.x > self.FILES - 1:
            return False
        if cord0.x < 0 or cord0.x > self.FILES - 1:
            # drop
            return validate(
                self.getBoard(),
                Move(
                    lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord,
                                     DROP)))
        else:
            return validate(self.getBoard(), Move(cord0, cord1,
                                                  self.getBoard()))
Example #3
0
    def validate(self, cord0, cord1):
        if cord0 is None or cord1 is None:
            return False
        # prevent accidental NULL_MOVE creation
        if cord0 == cord1:
            return False
        if self.getBoard()[cord0] is None:
            return False

        if self.parent.setup_position:
            # prevent moving pieces inside holding
            if (cord0.x < 0 or cord0.x > self.FILES - 1) and \
                    (cord1.x < 0 or cord1.x > self.FILES - 1):
                return False
            else:
                return True

        if cord1.x < 0 or cord1.x > self.FILES - 1:
            return False
        if cord0.x < 0 or cord0.x > self.FILES - 1:
            # drop
            return validate(self.getBoard(), Move(lmovegen.newMove(
                self.getBoard()[cord0].piece, cord1.cord, DROP)))
        else:
            return validate(self.getBoard(), Move(cord0, cord1,
                                                  self.getBoard()))
Example #4
0
    def test_getstatus2(self):
        """Testing bare white king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN3)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxg7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kg8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kh7')))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_STALEMATE))
Example #5
0
    def test_getstatus2(self):
        """Testing bare white king is not draw in Atomic variant"""

        board = AtomicBoard(setup=FEN3)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxg7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kg8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kh7')))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_STALEMATE))
Example #6
0
    def test_validate1(self):
        """Testing castling rights lose in explosion in Atomic variant"""

        board = AtomicBoard(setup=FEN1)
        board = board.move(parseSAN(board, 'Nxa7'))
        print(board)
        # Rook exploded, no O-O-O anymore!
        self.assertTrue(validate(board, parseSAN(board, 'b6')))
        self.assertTrue(not validate(board, parseSAN(board, 'a6')))
        self.assertTrue(not validate(board, parseSAN(board, 'Rb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'O-O-O')))
Example #7
0
    def test_validate2(self):
        """Testing explode king vs mate in Atomic variant"""

        board = AtomicBoard(setup=FEN1)
        board = board.move(parseSAN(board, 'Nc7+'))
        print(board)
        # King explosion takes precedence over mate!
        self.assertTrue(validate(board, parseSAN(board, 'Qxd2')))
        self.assertTrue(validate(board, parseSAN(board, 'Qxf2')))
        self.assertTrue(not validate(board, parseSAN(board, 'Qxb2')))
        self.assertTrue(not validate(board, parseSAN(board, 'Qe4+')))
Example #8
0
    def test_validate1(self):
        """Testing castling rights lose in explosion in Atomic variant"""

        board = AtomicBoard(setup=FEN1)
        board = board.move(parseSAN(board, 'Nxa7'))
        print(board)
        # Rook exploded, no O-O-O anymore!
        self.assertTrue(validate(board, parseSAN(board, 'b6')))
        self.assertTrue(not validate(board, parseSAN(board, 'a6')))
        self.assertTrue(not validate(board, parseSAN(board, 'Rb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'O-O-O')))
Example #9
0
    def test_validate2(self):
        """Testing explode king vs mate in Atomic variant"""

        board = AtomicBoard(setup=FEN1)
        board = board.move(parseSAN(board, 'Nc7+'))
        print(board)
        # King explosion takes precedence over mate!
        self.assertTrue(validate(board, parseSAN(board, 'Qxd2')))
        self.assertTrue(validate(board, parseSAN(board, 'Qxf2')))
        self.assertTrue(not validate(board, parseSAN(board, 'Qxb2')))
        self.assertTrue(not validate(board, parseSAN(board, 'Qe4+')))
Example #10
0
    def test_validate(self):
        """Testing validate move in Crazyhouse variant"""

        board = CrazyhouseBoard(setup=FEN0)
        print(board)
        # Drop can save mate
        self.assertTrue(validate(board, parseSAN(board, 'R@b8')))
        self.assertTrue(validate(board, parseSAN(board, 'Ka7')))
        self.assertTrue(validate(board, parseSAN(board, 'Kb7')))
        self.assertTrue(not validate(board, parseSAN(board, 'P@b8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
Example #11
0
 def validate (self, cord0, cord1):
     assert cord0 != None and cord1 != None, "cord0: " + str(cord0) + ", cord1: " + str(cord1)
     if self.getBoard()[cord0] == None:
         return False
     if cord1.x < 0 or cord1.x > self.FILES-1:
         return False
     if cord0.x < 0 or cord0.x > self.FILES-1:
         # drop
         return validate(self.getBoard(), Move(lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord, DROP)))
     else:
         return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #12
0
 def test_validate(self):
     """Testing validate move in Crazyhouse variant"""
     
     board = CrazyhouseBoard(setup=FEN0)
     print(board)
     # Drop can save mate
     self.assertTrue(validate(board, parseSAN(board, 'R@b8')))
     self.assertTrue(validate(board, parseSAN(board, 'Ka7')))
     self.assertTrue(validate(board, parseSAN(board, 'Kb7')))
     self.assertTrue(not validate(board, parseSAN(board, 'P@b8')))
     self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
Example #13
0
 def validate (self, cord0, cord1):
     if cord0 is None or cord1 is None:
         return False
     if self.getBoard()[cord0] == None:
         return False
     if cord1.x < 0 or cord1.x > self.FILES-1:
         return False
     if cord0.x < 0 or cord0.x > self.FILES-1:
         # drop
         return validate(self.getBoard(), Move(lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord, DROP)))
     else:
         return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #14
0
 def validate (self, cord0, cord1):
     if cord0 is None or cord1 is None:
         return False
     # prevent accidental NULL_MOVE creation
     if cord0 == cord1:
         return False
     if self.getBoard()[cord0] == None:
         return False
     if cord1.x < 0 or cord1.x > self.FILES-1:
         return False
     if cord0.x < 0 or cord0.x > self.FILES-1:
         # drop
         return validate(self.getBoard(), Move(lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord, DROP)))
     else:
         return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #15
0
    def test1(self):
        """Testing both king goes to 8.row draw in racingkings variant"""

        board = RacingKingsBoard(setup=FEN)
        board = board.move(parseSAN(board, 'Kh8'))
        print(board)
        # White king reached 8th row, but this is not a win
        # because black can reach 8th row also with hes next move
        self.assertEqual(getStatus(board), (RUNNING, UNKNOWN_REASON))

        self.assertTrue(validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kd8')))

        board = board.move(parseSAN(board, 'Kb8'))
        print(board)
        self.assertEqual(getStatus(board), (DRAW, DRAW_KINGSINEIGHTROW))
Example #16
0
    def makeMove(self, board1, move, board2):
        log.debug("Human.makeMove: move=%s, board1=%s board2=%s" % (
            move, board1, board2))
        if self.board.view.premove_piece and self.board.view.premove0 and \
                self.board.view.premove1 and \
                self.color == self.board.view.premove_piece.color:
            if validate(board1,
                        Move(self.board.view.premove0,
                             self.board.view.premove1,
                             board1,
                             promotion=self.board.view.premove_promotion)):
                log.debug("Human.makeMove: Setting move to premove %s %s" % (
                    self.board.view.premove0, self.board.view.premove1))
                self.board.emit_move_signal(
                    self.board.view.premove0,
                    self.board.view.premove1,
                    promotion=self.board.view.premove_promotion)
            # reset premove
            self.board.view.setPremove(None, None, None, None)
        self.gmwidg.setLocked(False)

        item = yield from self.move_queue.get()
        self.gmwidg.setLocked(True)

        if item == "del":
            log.debug("Human.makeMove got: del")
            raise PlayerIsDead
        elif item == "int":
            log.debug("Human.makeMove got: int")
            raise TurnInterrupt
        elif item == "pass":
            log.debug("Human.makeMove got: pass")
            raise PassInterrupt
        return item
Example #17
0
 def makeMove(self, board1, move, board2):
     log.debug("Human.makeMove: move=%s, board1=%s board2=%s" % (
         move, board1, board2))
     if self.board.view.premove_piece and self.board.view.premove0 and \
             self.board.view.premove1 and \
             self.color == self.board.view.premove_piece.color:
         if validate(board1,
                     Move(self.board.view.premove0,
                          self.board.view.premove1,
                          board1,
                          promotion=self.board.view.premove_promotion)):
             log.debug("Human.makeMove: Setting move to premove %s %s" % (
                 self.board.view.premove0, self.board.view.premove1))
             self.board.emit_move_signal(
                 self.board.view.premove0,
                 self.board.view.premove1,
                 promotion=self.board.view.premove_promotion)
         # reset premove
         self.board.view.setPremove(None, None, None, None)
     self.gmwidg.setLocked(False)
     item = self.queue.get(block=True)
     self.gmwidg.setLocked(True)
     if item == "del":
         raise PlayerIsDead("Killed by foreign forces")
     if item == "int":
         log.debug("Human.makeMove: %s: raise TurnInterrupt" % self)
         raise TurnInterrupt
     return item
Example #18
0
    def makeMove(self, board1, move, board2):
        log.debug("Human.makeMove: move=%s, board1=%s board2=%s" %
                  (move, board1, board2))
        if self.board.view.premove_piece and self.board.view.premove0 and \
                self.board.view.premove1 and \
                self.color == self.board.view.premove_piece.color:
            if validate(
                    board1,
                    Move(self.board.view.premove0,
                         self.board.view.premove1,
                         board1,
                         promotion=self.board.view.premove_promotion)):
                log.debug("Human.makeMove: Setting move to premove %s %s" %
                          (self.board.view.premove0, self.board.view.premove1))
                self.board.emit_move_signal(
                    self.board.view.premove0,
                    self.board.view.premove1,
                    promotion=self.board.view.premove_promotion)
            # reset premove
            self.board.view.setPremove(None, None, None, None)
        self.gmwidg.setLocked(False)

        item = yield from self.move_queue.get()
        self.gmwidg.setLocked(True)

        if item == "del":
            log.debug("Human.makeMove got: del")
            raise PlayerIsDead
        elif item == "int":
            log.debug("Human.makeMove got: int")
            raise TurnInterrupt
        elif item == "pass":
            log.debug("Human.makeMove got: pass")
            raise PassInterrupt
        return item
Example #19
0
 def makeMove(self, board1, move, board2):
     log.debug("Human.makeMove: move=%s, board1=%s board2=%s" %
               (move, board1, board2))
     if self.board.view.premove_piece and self.board.view.premove0 and \
             self.board.view.premove1 and \
             self.color == self.board.view.premove_piece.color:
         if validate(
                 board1,
                 Move(self.board.view.premove0,
                      self.board.view.premove1,
                      board1,
                      promotion=self.board.view.premove_promotion)):
             log.debug("Human.makeMove: Setting move to premove %s %s" %
                       (self.board.view.premove0, self.board.view.premove1))
             self.board.emit_move_signal(
                 self.board.view.premove0,
                 self.board.view.premove1,
                 promotion=self.board.view.premove_promotion)
         # reset premove
         self.board.view.setPremove(None, None, None, None)
     self.gmwidg.setLocked(False)
     item = self.queue.get(block=True)
     self.gmwidg.setLocked(True)
     if item == "del":
         raise PlayerIsDead("Killed by foreign forces")
     if item == "int":
         log.debug("Human.makeMove: %s: raise TurnInterrupt" % self)
         raise TurnInterrupt
     return item
Example #20
0
 def key_pressed (self, keyname):
     if keyname in "PNBRQKMFSOox12345678abcdefgh":
         self.keybuffer += keyname
     elif keyname == "minus":
         self.keybuffer += "-"
     elif keyname == "at":
         self.keybuffer += "@"
     elif keyname == "equal":
         self.keybuffer += "="
     elif keyname == "Return":
         color = self.view.model.boards[-1].color
         board = self.view.model.getBoardAtPly(self.view.shown, self.view.shownVariationIdx)
         try:
             move = parseAny(board, self.keybuffer)
         except:
             self.keybuffer = ""
             return
         if validate(board, move):
             if self.view.shownIsMainLine() and self.view.model.boards[-1] == board:
                 self.emit("piece_moved", move, color)
             else:
                 if board.board.next is None and not self.view.shownIsMainLine():
                     self.view.model.add_move2variation(board, move, self.view.shownVariationIdx)
                     self.view.shown += 1
                 else:
                     new_vari = self.view.model.add_variation(board, (move,))
                     self.view.setShownBoard(new_vari[-1])
         self.keybuffer = ""
     elif keyname == "BackSpace":
         self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Example #21
0
 def validate(self, cord0, cord1):
     if cord0 is None or cord1 is None:
         return False
     if self.getBoard()[cord0] == None:
         return False
     if cord1.x < 0 or cord1.x > self.FILES - 1:
         return False
     if cord0.x < 0 or cord0.x > self.FILES - 1:
         # drop
         return validate(
             self.getBoard(),
             Move(
                 lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord,
                                  DROP)))
     else:
         return validate(self.getBoard(), Move(cord0, cord1,
                                               self.getBoard()))
Example #22
0
    def test_check_evasions(self):
        """Testing check evasions in Crazyhouse variant"""
        board = CrazyhouseBoard(setup=FEN1)
        print(board)
        # invalid drop
        self.assertTrue(validate(board, parseSAN(board, 'Q@b1')))
        self.assertTrue(validate(board, parseSAN(board, 'Q@c1')))
        self.assertTrue(validate(board, parseSAN(board, 'Kxb2')))
        self.assertTrue(not validate(board, parseSAN(board, 'P@b1')))
        self.assertTrue(not validate(board, parseSAN(board, 'P@c1')))

        evasions = [move for move in genCheckEvasions(board.board)]
        self.assertTrue(parseSAN(board, 'Q@b1').move in evasions)
        self.assertTrue(parseSAN(board, 'Q@c1').move in evasions)
        self.assertTrue(parseSAN(board, 'Kxb2').move in evasions)
        self.assertTrue(parseSAN(board, 'P@b1').move not in evasions)
        self.assertTrue(parseSAN(board, 'P@c1').move not in evasions)
Example #23
0
    def test_check_evasions(self):
        """Testing check evasions in Crazyhouse variant"""
        board = CrazyhouseBoard(setup=FEN1)
        print(board)
        # invalid drop
        self.assertTrue(validate(board, parseSAN(board, 'Q@b1')))
        self.assertTrue(validate(board, parseSAN(board, 'Q@c1')))
        self.assertTrue(validate(board, parseSAN(board, 'Kxb2')))
        self.assertTrue(not validate(board, parseSAN(board, 'P@b1')))
        self.assertTrue(not validate(board, parseSAN(board, 'P@c1')))

        evasions = [move for move in genCheckEvasions(board.board)]
        self.assertTrue(parseSAN(board, 'Q@b1').move in evasions)
        self.assertTrue(parseSAN(board, 'Q@c1').move in evasions)
        self.assertTrue(parseSAN(board, 'Kxb2').move in evasions)
        self.assertTrue(parseSAN(board, 'P@b1').move not in evasions)
        self.assertTrue(parseSAN(board, 'P@c1').move not in evasions)
Example #24
0
 def validate(self, cord0, cord1):
     if cord0 is None or cord1 is None:
         return False
     # prevent accidental NULL_MOVE creation
     if cord0 == cord1:
         return False
     if self.getBoard()[cord0] == None:
         return False
     if cord1.x < 0 or cord1.x > self.FILES - 1:
         return False
     if cord0.x < 0 or cord0.x > self.FILES - 1:
         # drop
         return validate(
             self.getBoard(),
             Move(
                 lmovegen.newMove(self.getBoard()[cord0].piece, cord1.cord,
                                  DROP)))
     else:
         return validate(self.getBoard(), Move(cord0, cord1,
                                               self.getBoard()))
Example #25
0
    def test_validate(self):
        """Testing validate move in Losers variant"""

        board = LosersBoard(setup=FEN0)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Kxa7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb7')))

        board = LosersBoard(setup=FEN1)
        print(board)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxa7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(validate(board, parseSAN(board, 'Kb7')))

        board = LosersBoard(setup=FEN2)
        print(board)
        self.assertTrue(not validate(board, parseSAN(board, 'Kxb7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(validate(board, parseSAN(board, 'Rxb7')))
Example #26
0
    def test_validate(self):
        """Testing validate move in Suicide variant"""

        board = SuicideBoard(setup=FEN0)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Kxa7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb7')))

        board = SuicideBoard(setup=FEN1)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Kxa7')))
        self.assertTrue(validate(board, parseSAN(board, 'Kxb8')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb7')))

        board = SuicideBoard(setup=FEN2)
        print(board)
        self.assertTrue(not validate(board, parseSAN(board, 'Ka7')))
        self.assertTrue(not validate(board, parseSAN(board, 'Kb8')))
        self.assertTrue(validate(board, parseSAN(board, 'Kxb7')))

        board = SuicideBoard(setup=FEN3)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Ked2')))
Example #27
0
 def isAPotentiallyLegalNextMove(self, cord0, cord1):
     """ Determines whether the given move is at all legally possible
         as the next move after the player who's turn it is makes their move
         Note: This doesn't always return the correct value, such as when 
         BoardControl.setLocked() has been called and we've begun a drag,
         but view.shown and BoardControl.lockedPly haven't been updated yet """
     if cord0 == None or cord1 == None: return False
     if not self.parent.lockedPly in self.parent.possibleBoards:
         return False
     for board in self.parent.possibleBoards[self.parent.lockedPly]:
         if not board[cord0]:
             return False
         if validate(board, Move(cord0, cord1, board)):
             return True
     return False
 def isAPotentiallyLegalNextMove (self, cord0, cord1):
     """ Determines whether the given move is at all legally possible
         as the next move after the player who's turn it is makes their move
         Note: This doesn't always return the correct value, such as when 
         BoardControl.setLocked() has been called and we've begun a drag,
         but view.shown and BoardControl.lockedPly haven't been updated yet """
     if cord0 == None or cord1 == None: return False
     if not self.parent.lockedPly in self.parent.possibleBoards:
         return False
     for board in self.parent.possibleBoards[self.parent.lockedPly]:
         if not board[cord0]:
             return False
         if validate(board, Move(cord0, cord1, board)):
             return True
     return False
Example #29
0
    def key_pressed(self, keyname):
        if keyname in "PNBRQKMFSOox12345678abcdefgh":
            self.keybuffer += keyname

        elif keyname == "minus":
            self.keybuffer += "-"

        elif keyname == "at":
            self.keybuffer += "@"

        elif keyname == "equal":
            self.keybuffer += "="

        elif keyname == "Return":
            color = self.view.model.boards[-1].color
            board = self.view.model.getBoardAtPly(
                self.view.shown, self.view.shown_variation_idx)
            try:
                move = parseAny(board, self.keybuffer)
            except ParsingError:
                self.keybuffer = ""
                return

            if validate(board, move):
                if ((self.view.model.curplayer.__type__ == LOCAL
                     or self.view.model.examined)
                        and self.view.shownIsMainLine()
                        and self.view.model.boards[-1] == board
                        and self.view.model.status == RUNNING):
                    # emit move
                    self.emit("piece_moved", move, color)
                    if self.view.model.examined:
                        self.view.model.connection.bm.sendMove(
                            toAN(board, move))
                else:
                    self.play_or_add_move(board, move)
            self.keybuffer = ""

        elif keyname == "BackSpace":
            self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Example #30
0
    def key_pressed(self, keyname):
        if keyname in "PNBRQKMFSOox12345678abcdefgh":
            self.keybuffer += keyname

        elif keyname == "minus":
            self.keybuffer += "-"

        elif keyname == "at":
            self.keybuffer += "@"

        elif keyname == "equal":
            self.keybuffer += "="

        elif keyname == "Return":
            color = self.view.model.boards[-1].color
            board = self.view.model.getBoardAtPly(
                self.view.shown, self.view.shown_variation_idx)
            try:
                move = parseAny(board, self.keybuffer)
            except:
                self.keybuffer = ""
                return

            if validate(board, move):
                if (self.view.model.curplayer.__type__ == LOCAL or self.view.model.examined) and \
                        self.view.shownIsMainLine() and \
                        self.view.model.boards[-1] == board and \
                        self.view.model.status == RUNNING:
                    # emit move
                    self.emit("piece_moved", move, color)
                    if self.view.model.examined:
                        self.view.model.connection.bm.sendMove(toAN(board, move))
                else:
                    play_or_add_move(self.view, board, move)
            self.keybuffer = ""

        elif keyname == "BackSpace":
            self.keybuffer = self.keybuffer[:-1] if self.keybuffer else ""
Example #31
0
    def test_validate(self):
        """Testing validate move in Sittuyin variant"""

        board = SittuyinBoard(setup=FEN0)
        print(board)
        # no promotion if we have Met (queen)
        self.assertTrue(validate(board, parseAN(board, 'f4f3')))
        self.assertTrue(validate(board, parseAN(board, 'b2b1')))
        self.assertTrue(validate(board, parseAN(board, 'b2c1')))

        self.assertFalse(validate(board, parseAN(board, 'b2b2f')))
        self.assertFalse(validate(board, parseAN(board, 'b2a1f')))
        self.assertFalse(validate(board, parseAN(board, 'f4f3f')))
        self.assertFalse(validate(board, parseAN(board, 'b2b1f')))
        self.assertFalse(validate(board, parseAN(board, 'b2c1f')))

        board = SittuyinBoard(setup=FEN1)
        print(board)
        # but (optional) promotion if we don't have Met (queen)
        self.assertTrue(validate(board, parseAN(board, 'b2b2f')))
        self.assertTrue(validate(board, parseSAN(board, 'b2=f')))
        self.assertEqual(parseAN(board, 'b2b2f'), parseSAN(board, 'b2=f'))
        self.assertTrue(validate(board, parseAN(board, 'b2a1f')))
        self.assertTrue(validate(board, parseSAN(board, 'a1=f')))
        self.assertEqual(parseAN(board, 'b2a1f'), parseSAN(board, 'a1=f'))
        self.assertTrue(validate(board, parseAN(board, 'b2c1')))
        self.assertTrue(validate(board, parseAN(board, 'f4f3')))

        self.assertFalse(validate(board, parseAN(board, 'f4f3f')))
        self.assertFalse(validate(board, parseAN(board, 'b2b2')))
        self.assertFalse(validate(board, parseAN(board, 'b2b1f')))
        self.assertFalse(validate(board, parseAN(board, 'b2c1f')))
Example #32
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                if line[0:1] == "#":
                    # Debug line which we shall ignore as specified in CECPv2 specs
                    continue

        #        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
                parts = whitespaces.split(line.strip())
                if parts[0] == "pong":
                    self.lastpong = int(parts[1])
                    continue

                # Illegal Move
                if parts[0].lower().find("illegal") >= 0:
                    log.warning("__parseLine: illegal move: line=\"%s\", board=%s" % (
                        line.strip(), self.board), extra={"task": self.defname})
                    if parts[-2] == "sd" and parts[-1].isdigit():
                        print("depth", parts[-1], file=self.engine)
                    continue

                # A Move (Perhaps)
                if self.board:
                    if parts[0] == "move":
                        movestr = parts[1]
                    # Old Variation
                    elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                        movestr = parts[2]
                    else:
                        movestr = False

                    if movestr:
                        self.waitingForMove = False
                        self.readyForMoveNowCommand = False
                        if self.engineIsInNotPlaying:
                            # If engine was set in pause just before the engine sent its
                            # move, we ignore it. However the engine has to know that we
                            # ignored it, and thus we step it one back
                            log.info("__parseLine: Discarding engine's move: %s" %
                                     movestr,
                                     extra={"task": self.defname})
                            print("undo", file=self.engine)
                            continue
                        else:
                            try:
                                move = parseAny(self.board, movestr)
                            except ParsingError:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: ParsingError engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                            if validate(self.board, move):
                                self.board = None
                                self.queue.put_nowait(move)
                                continue
                            else:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: can't validate engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                # Analyzing
                if self.engineIsInNotPlaying:
                    if parts[:4] == ["0", "0", "0", "0"]:
                        # Crafty doesn't analyze until it is out of book
                        print("book off", file=self.engine)
                        continue

                    match = anare.match(line)
                    if match:
                        depth, score, moves = match.groups()

                        if "mat" in score.lower() or "#" in moves:
                            # Will look either like -Mat 3 or Mat3
                            scoreval = MATE_VALUE
                            if score.startswith('-'):
                                scoreval = -scoreval
                        else:
                            scoreval = int(score)

                        mvstrs = movere.findall(moves)
                        if mvstrs:
                            self.emit("analyze", [(mvstrs, scoreval, depth.strip())])

                        continue

                # Offers draw
                if parts[0:2] == ["offer", "draw"]:
                    self.emit("accept", Offer(DRAW_OFFER))
                    continue

                # Resigns
                if parts[0] == "resign" or \
                        (parts[0] == "tellics" and parts[1] == "resign"):  # buggy crafty

                    # Previously: if "resign" in parts,
                    # however, this is too generic, since "hint", "bk",
                    # "feature option=.." and possibly other, future CECPv2
                    # commands can validly contain the word "resign" without this
                    # being an intentional resign offer.

                    self.emit("offer", Offer(RESIGNATION))
                    continue

                # if parts[0].lower() == "error":
                #    continue

                # Tell User Error
                if parts[0] == "tellusererror":
                    # We don't want to see our stop analyzer hack as an error message
                    if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                        continue
                    # Create a non-modal non-blocking message dialog with the error:
                    dlg = Gtk.MessageDialog(parent=None,
                                            flags=0,
                                            type=Gtk.MessageType.WARNING,
                                            buttons=Gtk.ButtonsType.CLOSE,
                                            message_format=None)

                    # Use the engine name if already known, otherwise the defname:
                    displayname = self.name
                    if not displayname:
                        displayname = self.defname

                    # Compose the dialog text:
                    dlg.set_markup(GObject.markup_escape_text(_(
                        "The engine %s reports an error:") % displayname) + "\n\n" +
                        GObject.markup_escape_text(" ".join(parts[1:])))

                    # handle response signal so the "Close" button works:
                    dlg.connect("response", lambda dlg, x: dlg.destroy())

                    dlg.show_all()
                    continue

                # Tell Somebody
                if parts[0][:4] == "tell" and \
                        parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

                    log.info("Ignoring tell %s: %s" %
                             (parts[0][4:], " ".join(parts[1:])))
                    continue

                if "feature" in parts:
                    # Some engines send features after done=1, so we will iterate after done=1 too
                    done1 = False
                    # We skip parts before 'feature', as some engines give us lines like
                    # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
                    parts = parts[parts.index("feature"):]
                    for i, pair in enumerate(parts[1:]):

                        # As "parts" is split with no thoughs on quotes or double quotes
                        # we need to do some extra handling.

                        if pair.find("=") < 0:
                            continue
                        key, value = pair.split("=", 1)

                        if key not in self.features:
                            continue

                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]

                        # If our pair was unfinished, like myname="GNU, we search the
                        # rest of the pairs for a quotating mark.
                        elif value[0] == '"':
                            rest = value[1:] + " " + " ".join(parts[2 + i:])
                            j = rest.find('"')
                            if j == -1:
                                log.warning("Missing endquotation in %s feature",
                                            extra={"task": self.defname})
                                value = rest
                            else:
                                value = rest[:j]

                        elif value.isdigit():
                            value = int(value)

                        if key in self.supported_features:
                            print("accepted %s" % key, file=self.engine)
                        else:
                            print("rejected %s" % key, file=self.engine)

                        if key == "done":
                            if value == 1:
                                done1 = True
                                continue
                            elif value == 0:
                                log.info("Adds %d seconds timeout" % TIME_OUT_SECOND,
                                         extra={"task": self.defname})
                                # This'll buy you some more time
                                self.queue.put_nowait("not ready")
                                break

                        if key == "smp" and value == 1:
                            self.options["cores"] = {"name": "cores",
                                                     "type": "spin",
                                                     "default": 1,
                                                     "min": 1,
                                                     "max": 64}
                        elif key == "memory" and value == 1:
                            self.options["memory"] = {"name": "memory",
                                                      "type": "spin",
                                                      "default": 32,
                                                      "min": 1,
                                                      "max": 4096}
                        elif key == "option" and key != "done":
                            option = self.__parse_option(value)
                            self.options[option["name"]] = option
                        else:
                            self.features[key] = value

                        if key == "myname" and not self.name:
                            self.setName(value)

                    if done1:
                        # Start a new game before using the engine:
                        # (CECPv2 engines)
                        print("new", file=self.engine)

                        # We are now ready for play:
                        self.emit("readyForOptions")
                        self.emit("readyForMoves")
                        self.queue.put_nowait("ready")

                # A hack to get better names in protover 1.
                # Unfortunately it wont work for now, as we don't read any lines from
                # protover 1 engines. When should we stop?
                if self.protover == 1:
                    if self.defname[0] in ''.join(parts):
                        basis = self.defname[0]
                        name = ' '.join(itertools.dropwhile(
                            lambda part: basis not in part, parts))
                        self.features['myname'] = name
                        if not self.name:
                            self.setName(name)
    def __parseLine (self, line):
        if not self.connected: return
        parts = line.split()
        if not parts: return
        
        #---------------------------------------------------------- Initializing
        if parts[0] == "id":
            self.ids[parts[1]] = " ".join(parts[2:])
            return
        
        if parts[0] == "uciok":
            self.emit("readyForOptions")
            return
        
        if parts[0] == "readyok":
            self.emit("readyForMoves")
            return
        
        #------------------------------------------------------- Options parsing
        if parts[0] == "option":
            dic = {}
            last = 1
            varlist = []
            for i in xrange (2, len(parts)+1):
                if i == len(parts) or parts[i] in OPTKEYS:
                    key = parts[last]
                    value = " ".join(parts[last+1:i])
                    if "type" in dic and dic["type"] in TYPEDIC:
                        value = TYPEDIC[dic["type"]](value)
                        
                    if key == "var":
                        varlist.append(value)
                    else:
                        dic[key] = value
                        
                    last = i
            if varlist:
                dic["vars"] = varlist
            
            name = dic["name"]
            del dic["name"]
            self.options[name] = dic
            return
        
        #---------------------------------------------------------------- A Move
        if self.mode == NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                self.needBestmove = False
                self.__sendQueuedGo()
                
                if self.ignoreNext:
                    log.debug("__parseLine: line='%s' self.ignoreNext==True, returning\n" % \
                        line.strip(), self.defname)
                    self.ignoreNext = False
                    self.readyForStop = True
                    return
                
                if not self.waitingForMove:
                    log.warn("__parseLine: self.waitingForMove==False, ignoring move=%s\n" % \
                        parts[1], self.defname)
                    self.pondermove = None
                    return
                self.waitingForMove = False
                
                move = parseAN(self.board, parts[1])
                
                if not validate(self.board, move):
                    # This is critical. To avoid game stalls, we need to resign on
                    # behalf of the engine.
                    log.error("__parseLine: move=%s didn't validate, putting 'del' in returnQueue. self.board=%s\n" % \
                        (repr(move), self.board), self.defname)
                    self.returnQueue.put('del')
                    return
                
                self.board = self.board.move(move)
                log.debug("__parseLine: applied move=%s to self.board=%s\n" % \
                    (move, self.board), self.defname)
                
                if self.getOption('Ponder'):
                    self.pondermove = None
                    # An engine may send an empty ponder line, simply to clear.
                    if len(parts) == 4 and self.board:
                        # Engines don't always check for everything in their
                        # ponders. Hence we need to validate.
                        # But in some cases, what they send may not even be
                        # correct AN - specially in the case of promotion.
                        try:
                            pondermove = parseAN(self.board, parts[3])
                        except ParsingError:
                            pass
                        else:
                            if validate(self.board, pondermove):
                                self.pondermove = pondermove
                                self._startPonder()
                
                self.returnQueue.put(move)
                log.debug("__parseLine: put move=%s into self.returnQueue=%s\n" % \
                    (move, self.returnQueue.queue), self.defname)
                return
        
        #----------------------------------------------------------- An Analysis
        if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
            scoretype = parts[parts.index("score")+1]
            if scoretype in ('lowerbound', 'upperbound'):
                score = None
            else:
                score = int(parts[parts.index("score")+2])
                if scoretype == 'mate':
#                    print >> self.engine, "stop"
                    sign = score/abs(score)
                    score = sign * (MATE_VALUE-abs(score))
            
            movstrs = parts[parts.index("pv")+1:]
            try:
                moves = listToMoves (self.board, movstrs, AN, validate=True, ignoreErrors=False)
            except ParsingError, e:
                # ParsingErrors may happen when parsing "old" lines from
                # analyzing engines, which haven't yet noticed their new tasks
                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s\n" % \
                    (' '.join(movstrs),e), self.defname)
                return
            
            self.emit("analyze", moves, score)
            return
Example #34
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.bestmove_event.set()
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning"
                            % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning(
                            "__parseLine: self.waitingForMove==False, ignoring move=%s"
                            % movestr,
                            extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        log.info(
                            "__parseLine: ParsingError engine move: %s %s" %
                            (movestr, self.board),
                            extra={"task": self.defname})
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error(
                            "__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" %
                            (repr(move), self.board),
                            extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" %
                              (move, self.board),
                              extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" %
                              (move, self.queue),
                              extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * (MATE_VALUE - abs(score))

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if "nps" in parts:
                        nps = parts[parts.index("nps") + 1]
                    else:
                        nps = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (self.board.ply, movstrs,
                                                      score, depth, nps)
                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug(
                        "__parseLine: processing analyzer bestmove='%s'" %
                        line.strip(),
                        extra={"task": self.defname})
                    self.needBestmove = False
                    self.bestmove_event.set()
                    if parts[1] == "(none)":
                        self.emit("analyze", [])
                    else:
                        self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
 def validate (self, cord0, cord1):
     assert cord0 != None and cord1 != None, "cord0: " + str(cord0) + ", cord1: " + str(cord1)
     if self.getBoard()[cord0] == None: return False
     return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #36
0
    def test_getstatus4(self):
        """Testing possible move into check when king touch saves the king"""

        board = AtomicBoard(setup=FEN5)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Kg5')))
Example #37
0
    def __parseLine(self, line):
        if not self.connected: return
        parts = line.split()
        if not parts: return

        #---------------------------------------------------------- Initializing
        if parts[0] == "id":
            self.ids[parts[1]] = " ".join(parts[2:])
            return

        if parts[0] == "uciok":
            self.emit("readyForOptions")
            return

        if parts[0] == "readyok":
            self.emit("readyForMoves")
            return

        #------------------------------------------------------- Options parsing
        if parts[0] == "option":
            dic = {}
            last = 1
            varlist = []
            for i in xrange(2, len(parts) + 1):
                if i == len(parts) or parts[i] in OPTKEYS:
                    key = parts[last]
                    value = " ".join(parts[last + 1:i])
                    if "type" in dic and dic["type"] in TYPEDIC:
                        value = TYPEDIC[dic["type"]](value)

                    if key == "var":
                        varlist.append(value)
                    else:
                        dic[key] = value

                    last = i
            if varlist:
                dic["vars"] = varlist

            name = dic["name"]
            del dic["name"]
            self.options[name] = dic
            return

        #---------------------------------------------------------------- A Move
        if self.mode == NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                self.needBestmove = False
                self.__sendQueuedGo()

                if self.ignoreNext:
                    log.debug("__parseLine: line='%s' self.ignoreNext==True, returning\n" % \
                        line.strip(), self.defname)
                    self.ignoreNext = False
                    self.readyForStop = True
                    return

                if not self.waitingForMove:
                    log.warn("__parseLine: self.waitingForMove==False, ignoring move=%s\n" % \
                        parts[1], self.defname)
                    self.pondermove = None
                    return
                self.waitingForMove = False

                move = parseAN(self.board, parts[1])

                if not validate(self.board, move):
                    # This is critical. To avoid game stalls, we need to resign on
                    # behalf of the engine.
                    log.error("__parseLine: move=%s didn't validate, putting 'del' in returnQueue. self.board=%s\n" % \
                        (repr(move), self.board), self.defname)
                    self.returnQueue.put('del')
                    return

                self.board = self.board.move(move)
                log.debug("__parseLine: applied move=%s to self.board=%s\n" % \
                    (move, self.board), self.defname)

                if self.getOption('Ponder'):
                    self.pondermove = None
                    # An engine may send an empty ponder line, simply to clear.
                    if len(parts) == 4 and self.board:
                        # Engines don't always check for everything in their
                        # ponders. Hence we need to validate.
                        # But in some cases, what they send may not even be
                        # correct AN - specially in the case of promotion.
                        try:
                            pondermove = parseAN(self.board, parts[3])
                        except ParsingError:
                            pass
                        else:
                            if validate(self.board, pondermove):
                                self.pondermove = pondermove
                                self._startPonder()

                self.returnQueue.put(move)
                log.debug("__parseLine: put move=%s into self.returnQueue=%s\n" % \
                    (move, self.returnQueue.queue), self.defname)
                return

        #----------------------------------------------------------- An Analysis
        if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
            scoretype = parts[parts.index("score") + 1]
            if scoretype in ('lowerbound', 'upperbound'):
                score = None
            else:
                score = int(parts[parts.index("score") + 2])
                if scoretype == 'mate':
                    #                    print >> self.engine, "stop"
                    sign = score / abs(score)
                    score = sign * (MATE_VALUE - abs(score))

            movstrs = parts[parts.index("pv") + 1:]
            try:
                moves = listToMoves(self.board,
                                    movstrs,
                                    AN,
                                    validate=True,
                                    ignoreErrors=False)
            except ParsingError, e:
                # ParsingErrors may happen when parsing "old" lines from
                # analyzing engines, which haven't yet noticed their new tasks
                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s\n" % \
                    (' '.join(movstrs),e), self.defname)
                return

            self.emit("analyze", moves, score)
            return
    def __parseLine (self, line):
#        log.debug("__parseLine: line=\"%s\"\n" % line.strip(), self.defname)
        parts = whitespaces.split(line.strip())
        
        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return
        
        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warn("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), self.defname)
            if parts[-2] == "sd" and parts[-1].isdigit():
                print >> self.engine, "depth", parts[-1] 
            return
        
        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False
            
            if movestr:
                log.debug("__parseLine: acquiring self.boardLock\n", self.defname)
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.log("__parseLine: Discarding engine's move: %s\n" % movestr, self.defname)
                        print >> self.engine, "undo"
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError, e:
                            raise PlayerIsDead, e
                        
                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        raise PlayerIsDead, "Board didn't validate after move"
                finally:
                    log.debug("__parseLine(): releasing self.boardLock\n", self.defname)
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()
        
        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0","0","0","0"]:
                # Crafty doesn't analyze until it is out of book
                print >> self.engine, "book off"
                return
            
            match = anare.match(line)
            if match:
                score, moves = match.groups()
                
                if "mat" in score.lower():
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE - int("".join(c for c in score if c.isdigit()))
                    if score.startswith('-'): scoreval = -scoreval
                else:
                    scoreval = int(score)
                
                mvstrs = movere.findall(moves)
                try:
                    moves = listToMoves (self.board, mvstrs, type=None, validate=True, ignoreErrors=False)
                except ParsingError, e:
                    # ParsingErrors may happen when parsing "old" lines from
                    # analyzing engines, which haven't yet noticed their new tasks
                    log.debug("Ignored a line from analyzer: ParsingError%s\n" % e, self.defname)
                    return
                
                # Don't emit if we weren't able to parse moves, or if we have a move
                # to kill the opponent king - as it confuses many engines
                if moves and not self.board.board.opIsChecked():
                    self.emit("analyze", moves, scoreval)
                
                return
Example #39
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.bestmove_event.set()
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning" % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning("__parseLine: self.waitingForMove==False, ignoring move=%s" % movestr,
                                    extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        log.info(
                            "__parseLine: ParsingError engine move: %s %s"
                            % (movestr, self.board),
                            extra={"task": self.defname})
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error("__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" % (
                            repr(move), self.board), extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" % (
                        move, self.board), extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" % (
                        move, self.queue), extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * (MATE_VALUE - abs(score))

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if "nps" in parts:
                        nps = parts[parts.index("nps") + 1]
                    else:
                        nps = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (self.board.ply, movstrs, score, depth, nps)
                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug("__parseLine: processing analyzer bestmove='%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.needBestmove = False
                    self.bestmove_event.set()
                    if parts[1] == "(none)":
                        self.emit("analyze", [])
                    else:
                        self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
Example #40
0
    def parseLine(self, engine, line):
        if line[0:1] == "#":
            # Debug line which we shall ignore as specified in CECPv2 specs
            return

#        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
        parts = whitespaces.split(line.strip())

        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return

        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warning("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), extra={"task":self.defname})
            if parts[-2] == "sd" and parts[-1].isdigit():
                print("depth", parts[-1], file=self.engine)
            return

        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False

            if movestr:
                log.debug("__parseLine: acquiring self.boardLock",
                          extra={"task": self.defname})
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.info("__parseLine: Discarding engine's move: %s" %
                                 movestr,
                                 extra={"task": self.defname})
                        print("undo", file=self.engine)
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError as e:
                            self.invalid_move = movestr
                            log.info(
                                "__parseLine: ParsingError engine move: %s %s"
                                % (movestr, self.board),
                                extra={"task": self.defname})
                            self.end(
                                WHITEWON if self.board.color == BLACK else
                                BLACKWON, WON_ADJUDICATION)
                            return

                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        else:
                            self.invalid_move = movestr
                            log.info(
                                "__parseLine: can't validate engine move: %s %s"
                                % (movestr, self.board),
                                extra={"task": self.defname})
                            self.end(
                                WHITEWON if self.board.color == BLACK else
                                BLACKWON, WON_ADJUDICATION)
                            return
                finally:
                    log.debug("__parseLine(): releasing self.boardLock",
                              extra={"task": self.defname})
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()

        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0", "0", "0", "0"]:
                # Crafty doesn't analyze until it is out of book
                print("book off", file=self.engine)
                return

            match = anare.match(line)
            if match:
                depth, score, moves = match.groups()

                if "mat" in score.lower() or "#" in moves:
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE
                    if score.startswith('-'):
                        scoreval = -scoreval
                else:
                    scoreval = int(score)

                mvstrs = movere.findall(moves)
                if mvstrs:
                    self.emit("analyze", [(mvstrs, scoreval, depth.strip())])

                return

        # Offers draw
        if parts[0:2] == ["offer", "draw"]:
            self.emit("accept", Offer(DRAW_OFFER))
            return

        # Resigns
        if parts[0] == "resign" or \
            (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty

            # Previously: if "resign" in parts,
            # however, this is too generic, since "hint", "bk",
            # "feature option=.." and possibly other, future CECPv2
            # commands can validly contain the word "resign" without this
            # being an intentional resign offer.

            self.emit("offer", Offer(RESIGNATION))
            return

        #if parts[0].lower() == "error":
        #    return

        #Tell User Error
        if parts[0] == "tellusererror":
            # We don't want to see our stop analyzer hack as an error message
            if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                return
            # Create a non-modal non-blocking message dialog with the error:
            dlg = Gtk.MessageDialog(parent=None,
                                    flags=0,
                                    type=Gtk.MessageType.WARNING,
                                    buttons=Gtk.ButtonsType.CLOSE,
                                    message_format=None)

            # Use the engine name if already known, otherwise the defname:
            displayname = self.name
            if not displayname:
                displayname = self.defname

            # Compose the dialog text:
            dlg.set_markup(
                GObject.markup_escape_text(
                    _("The engine %s reports an error:") % displayname) +
                "\n\n" + GObject.markup_escape_text(" ".join(parts[1:])))

            # handle response signal so the "Close" button works:
            dlg.connect("response", lambda dlg, x: dlg.destroy())

            dlg.show_all()
            return

        # Tell Somebody
        if parts[0][:4] == "tell" and \
                parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

            log.info("Ignoring tell %s: %s" %
                     (parts[0][4:], " ".join(parts[1:])))
            return

        if "feature" in parts:
            # Some engines send features after done=1, so we will iterate after done=1 too
            done1 = False
            # We skip parts before 'feature', as some engines give us lines like
            # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
            parts = parts[parts.index("feature"):]
            for i, pair in enumerate(parts[1:]):

                # As "parts" is split with no thoughs on quotes or double quotes
                # we need to do some extra handling.

                if pair.find("=") < 0:
                    continue
                key, value = pair.split("=", 1)

                if not key in self.features:
                    continue

                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]

                # If our pair was unfinished, like myname="GNU, we search the
                # rest of the pairs for a quotating mark.
                elif value[0] == '"':
                    rest = value[1:] + " " + " ".join(parts[2 + i:])
                    j = rest.find('"')
                    if j == -1:
                        log.warning("Missing endquotation in %s feature",
                                    extra={"task": self.defname})
                        value = rest
                    else:
                        value = rest[:j]

                elif value.isdigit():
                    value = int(value)

                if key in self.supported_features:
                    print("accepted %s" % key, file=self.engine)
                else:
                    print("rejected %s" % key, file=self.engine)

                if key == "done":
                    if value == 1:
                        done1 = True
                        continue
                    elif value == 0:
                        log.info("Adds %d seconds timeout" % TIME_OUT_SECOND,
                                 extra={"task": self.defname})
                        # This'll buy you some more time
                        self.timeout = time.time() + TIME_OUT_SECOND
                        self.returnQueue.put("not ready")
                        return

                if key == "smp" and value == 1:
                    self.options["cores"] = {
                        "name": "cores",
                        "type": "spin",
                        "default": 1,
                        "min": 1,
                        "max": 64
                    }
                elif key == "memory" and value == 1:
                    self.options["memory"] = {
                        "name": "memory",
                        "type": "spin",
                        "default": 32,
                        "min": 1,
                        "max": 4096
                    }
                elif key == "option" and key != "done":
                    option = self.__parse_option(value)
                    self.options[option["name"]] = option
                else:
                    self.features[key] = value

                if key == "myname" and not self.name:
                    self.setName(value)

            if done1:
                # Start a new game before using the engine:
                # (CECPv2 engines)
                print("new", file=self.engine)

                # We are now ready for play:
                self.emit("readyForOptions")
                self.emit("readyForMoves")
                self.returnQueue.put("ready")

        # A hack to get better names in protover 1.
        # Unfortunately it wont work for now, as we don't read any lines from
        # protover 1 engines. When should we stop?
        if self.protover == 1:
            if self.defname[0] in ''.join(parts):
                basis = self.defname[0]
                name = ' '.join(
                    itertools.dropwhile(lambda part: basis not in part, parts))
                self.features['myname'] = name
                if not self.name:
                    self.setName(name)
Example #41
0
    def __parseLine (self, line):
        if not self.connected: return
        parts = line.split()
        if not parts: return
        
        #---------------------------------------------------------- Initializing
        if parts[0] == "id":
            self.ids[parts[1]] = " ".join(parts[2:])
            if parts[1] == "name":
                self.setName(self.ids["name"])
            return
        
        if parts[0] == "uciok":
            self.emit("readyForOptions")
            return
        
        if parts[0] == "readyok":
            self.emit("readyForMoves")
            return
        
        #------------------------------------------------------- Options parsing
        if parts[0] == "option":
            dic = {}
            last = 1
            varlist = []
            for i in range (2, len(parts)+1):
                if i == len(parts) or parts[i] in OPTKEYS:
                    key = parts[last]
                    value = " ".join(parts[last+1:i])
                    if "type" in dic and dic["type"] in TYPEDIC:
                        value = TYPEDIC[dic["type"]](value)
                        
                    if key == "var":
                        varlist.append(value)
                    elif key == "type" and value == "string":
                        dic[key] = "text"
                    else:
                        dic[key] = value
                        
                    last = i
            if varlist:
                dic["choices"] = varlist
            
            self.options[dic["name"]] = dic
            return
        
        #---------------------------------------------------------------- A Move
        if self.mode == NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                self.needBestmove = False
                self.__sendQueuedGo()
                
                if self.ignoreNext:
                    log.debug("__parseLine: line='%s' self.ignoreNext==True, returning" % \
                        line.strip(), extra={"task":self.defname})
                    self.ignoreNext = False
                    self.readyForStop = True
                    return
                
                if not self.waitingForMove:
                    log.warning("__parseLine: self.waitingForMove==False, ignoring move=%s" % \
                        parts[1], extra={"task":self.defname})
                    self.pondermove = None
                    return
                self.waitingForMove = False

                try:
                    move = parseAny(self.board, parts[1])
                except ParsingError as e:
                    self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                    return
                
                if not validate(self.board, move):
                    # This is critical. To avoid game stalls, we need to resign on
                    # behalf of the engine.
                    log.error("__parseLine: move=%s didn't validate, putting 'del' in returnQueue. self.board=%s" % \
                        (repr(move), self.board), extra={"task":self.defname})
                    self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                    return
                
                self._recordMove(self.board.move(move), move, self.board)
                log.debug("__parseLine: applied move=%s to self.board=%s" % \
                    (move, self.board), extra={"task":self.defname})
                
                if self.ponderOn:
                    self.pondermove = None
                    # An engine may send an empty ponder line, simply to clear.
                    if len(parts) == 4:
                        # Engines don't always check for everything in their
                        # ponders. Hence we need to validate.
                        # But in some cases, what they send may not even be
                        # correct AN - specially in the case of promotion.
                        try:
                            pondermove = parseAny(self.board, parts[3])
                        except ParsingError:
                            pass
                        else:
                            if validate(self.board, pondermove):
                                self.pondermove = pondermove
                                self._startPonder()
                
                self.returnQueue.put(move)
                log.debug("__parseLine: put move=%s into self.returnQueue=%s" % \
                    (move, self.returnQueue.queue), extra={"task":self.defname})
                return
        
        #----------------------------------------------------------- An Analysis
        if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
            multipv = 1
            if "multipv" in parts:
                multipv = int(parts[parts.index("multipv")+1])
            scoretype = parts[parts.index("score")+1]
            if scoretype in ('lowerbound', 'upperbound'):
                score = None
            else:
                score = int(parts[parts.index("score")+2])
                if scoretype == 'mate':
#                    print >> self.engine, "stop"
                    if score != 0:
                        sign = score/abs(score)
                        score = sign*MATE_VALUE
            
            movstrs = parts[parts.index("pv")+1:]
            try:
                moves = listToMoves (self.board, movstrs, AN, validate=True, ignoreErrors=False)
            except ParsingError as e:
                # ParsingErrors may happen when parsing "old" lines from
                # analyzing engines, which haven't yet noticed their new tasks
                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                    (' '.join(movstrs),e), extra={"task":self.defname})
                return

            if "depth" in parts:
                depth = parts[parts.index("depth")+1]
            else:
                depth = ""
                
            if multipv <= len(self.analysis):
                self.analysis[multipv - 1] = (moves, score, depth)

            self.emit("analyze", self.analysis)
            return
        
        #-----------------------------------------------  An Analyzer bestmove
        if self.mode != NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                log.debug("__parseLine: processing analyzer bestmove='%s'" % \
                    line.strip(), extra={"task":self.defname})
                self.needBestmove = False
                self.__sendQueuedGo(sendlast=True)
                return
        
        #  Stockfish complaining it received a 'stop' without a corresponding 'position..go'
        if line.strip() == "Unknown command: stop":
            with self.moveLock:
                log.debug("__parseLine: processing '%s'" % line.strip(), extra={"task":self.defname})
                self.ignoreNext = False
                self.needBestmove = False
                self.readyForStop = False
                self.__sendQueuedGo()
                return
Example #42
0
    def test_validate(self):
        """Testing validate move in Sittuyin variant"""

        board = SittuyinBoard(setup=FEN0)
        print(board)
        self.assertTrue(validate(board, parseAN(board, 'f4f3')))
        self.assertTrue(validate(board, parseAN(board, 'b2b1')))
        self.assertTrue(validate(board, parseAN(board, 'b2c1')))

        # no promotion if we have Met (queen)
        self.assertFalse(validate(board, parseAN(board, 'b2b2f')))
        self.assertFalse(validate(board, parseAN(board, 'b2a1f')))
        self.assertFalse(validate(board, parseAN(board, 'f4f3f')))
        self.assertFalse(validate(board, parseAN(board, 'b2b1f')))
        self.assertFalse(validate(board, parseAN(board, 'b2c1f')))

        board = SittuyinBoard(setup=FEN1)
        print(board)
        # but (optional) promotion if we don't have Met (queen)
        self.assertFalse(validate(board, parseAN(board, 'b2b2f')))
        self.assertFalse(validate(board, parseSAN(board, 'b2=f')))
        self.assertEqual(parseAN(board, 'b2b2f'), parseSAN(board, 'b2=f'))
        self.assertTrue(validate(board, parseAN(board, 'b2a1f')))
        self.assertTrue(validate(board, parseSAN(board, 'a1=f')))
        self.assertEqual(parseAN(board, 'b2a1f'), parseSAN(board, 'a1=f'))
        self.assertTrue(validate(board, parseAN(board, 'b2c1')))
        self.assertTrue(validate(board, parseAN(board, 'f4f3')))

        self.assertFalse(validate(board, parseAN(board, 'f4f3f')))
        self.assertFalse(validate(board, parseAN(board, 'b2b2')))
        self.assertFalse(validate(board, parseAN(board, 'b2b1f')))
        self.assertFalse(validate(board, parseAN(board, 'b2c1f')))

        board = SittuyinBoard(setup=FEN2)
        print(board)
        # simple pawn move can give check
        self.assertTrue(validate(board, parseAN(board, 'd6d7')))
        # pawn can promote in place
        self.assertTrue(validate(board, parseAN(board, 'd6d6f')))
        # pawn promotion move can't give check
        self.assertFalse(validate(board, parseAN(board, 'd6c7f')))
        self.assertFalse(validate(board, parseAN(board, 'd6e7f')))

        board = SittuyinBoard(setup=FEN3)
        print(board)
        self.assertTrue(validate(board, parseAN(board, 'd6d7')))
        # last pawn being enywhere can promote
        self.assertTrue(validate(board, parseAN(board, 'd6d6f')))
        self.assertTrue(validate(board, parseAN(board, 'd6c7f')))
        self.assertTrue(validate(board, parseAN(board, 'd6c5f')))
        self.assertTrue(validate(board, parseAN(board, 'd6e5f')))
        # pawn promotion move can't give check
        self.assertFalse(validate(board, parseAN(board, 'd6e7f')))
Example #43
0
    def __parseLine (self, line):
        if line[0:1] == "#":
            # Debug line which we shall ignore as specified in CECPv2 specs
            return

#        log.debug("__parseLine: line=\"%s\"\n" % line.strip(), self.defname)
        parts = whitespaces.split(line.strip())
        
        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return
        
        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warn("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), self.defname)
            if parts[-2] == "sd" and parts[-1].isdigit():
                print >> self.engine, "depth", parts[-1] 
            return
        
        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False
            
            if movestr:
                log.debug("__parseLine: acquiring self.boardLock\n", self.defname)
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.info("__parseLine: Discarding engine's move: %s\n" % movestr, self.defname)
                        print >> self.engine, "undo"
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError, e:
                            self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                            return
                        
                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                        return
                finally:
                    log.debug("__parseLine(): releasing self.boardLock\n", self.defname)
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()
        
        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0","0","0","0"]:
                # Crafty doesn't analyze until it is out of book
                print >> self.engine, "book off"
                return
            
            match = anare.match(line)
            if match:
                score, moves = match.groups()
                
                if "mat" in score.lower() or "#" in moves:
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE
                    if score.startswith('-'):
                        scoreval = -scoreval
                else:
                    scoreval = int(score)
                
                mvstrs = movere.findall(moves)
                try:
                    moves = listToMoves (self.board, mvstrs, type=None, validate=True, ignoreErrors=False)
                except:
                    # Errors may happen when parsing "old" lines from
                    # analyzing engines, which haven't yet noticed their new tasks
                    log.debug('Ignored an "old" line from analyzer: %s\n' % mvstrs, self.defname)
                    return
                
                # Don't emit if we weren't able to parse moves, or if we have a move
                # to kill the opponent king - as it confuses many engines
                if moves and not self.board.board.opIsChecked():
                    #self.emit("analyze", [(moves, scoreval)])
                
                return
        
        # Offers draw
        if parts[0:2] == ["offer", "draw"]:
            #self.emit("accept", Offer(DRAW_OFFER))
            return
        
        # Resigns
        if parts[0] == "resign" or \
            (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty

            # Previously: if "resign" in parts,
            # however, this is too generic, since "hint", "bk",
            # "feature option=.." and possibly other, future CECPv2
            # commands can validly contain the word "resign" without this
            # being an intentional resign offer.

            #self.emit("offer", Offer(RESIGNATION))
            return
        
        #if parts[0].lower() == "error":
        #    return
        
        #Tell User Error
        if parts[0] == "tellusererror":
            # Create a non-modal non-blocking message dialog with the error:
            dlg = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_CLOSE, message_format=None)

            # Use the engine name if already known, otherwise the defname:
            displayname = self.name
            if not displayname:
                displayname = self.defname

            # Compose the dialog text:
            dlg.set_markup(gobject.markup_escape_text(_("The engine %s reports an error:") % displayname) + "\n\n" + gobject.markup_escape_text(" ".join(parts[1:])))

            # handle response signal so the "Close" button works:
            dlg.connect("response", lambda dlg, x: dlg.destroy())

            dlg.show_all()
            return
        
        # Tell Somebody
        if parts[0][:4] == "tell" and \
                parts[0][4:] in ("others", "all", "ics", "icsnoalias"):
            
            log.info("Ignoring tell %s: %s\n" % (parts[0][4:], " ".join(parts[1:])))
            return
        
        if "feature" in parts:
            # Some engines send features after done=1, so we will iterate after done=1 too
            done1 = False
            # We skip parts before 'feature', as some engines give us lines like
            # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
            parts = parts[parts.index("feature"):]
            for i, pair in enumerate(parts[1:]):
                
                # As "parts" is split with no thoughs on quotes or double quotes
                # we need to do some extra handling.
                
                if pair.find("=") < 0: continue
                key, value = pair.split("=",1)
                
                if value[0] in ('"',"'") and value[-1] in ('"',"'"):
                    value = value[1:-1]
                
                # If our pair was unfinished, like myname="GNU, we search the
                # rest of the pairs for a quotating mark.
                elif value[0] in ('"',"'"):
                    rest = value[1:] + " " + " ".join(parts[2+i:])
                    i = rest.find('"')
                    j = rest.find("'")
                    if i + j == -2:
                        log.warn("Missing endquotation in %s feature", self.defname)
                        value = rest
                    elif min(i, j) != -1:
                        value = rest[:min(i, j)]
                    else:
                        l = max(i, j)
                        value = rest[:l]
                
                elif value.isdigit():
                    value = int(value)
                
                if key in self.supported_features:
                    print >> self.engine, "accepted %s" % key
                else:
                    print >> self.engine, "rejected %s" % key
                
                if key == "done":
                    if value == 1:
                        done1 = True
                        continue
                    elif value == 0:
                        log.info("Adds %d seconds timeout\n" % TIME_OUT_SECOND, self.defname)
                        # This'll buy you some more time
                        self.timeout = time.time()+TIME_OUT_SECOND
                        self.returnQueue.put("not ready")
                        return
                
                if key == "smp" and value == 1:
                    self.options["cores"] = {"name": "cores", "type": "spin", "default": 1, "min": 1, "max": 64}
                elif key == "memory" and value == 1:
                    self.options["memory"] = {"name": "memory", "type": "spin", "default": 32, "min": 1, "max": 4096}
                elif key == "option" and key != "done":
                    option = self.__parse_option(value)
                    self.options[option["name"]] = option
                else:
                    self.features[key] = value

                if key == "myname" and not self.name:
                    self.setName(value)
        
            if done1:
                # Start a new game before using the engine:
                # (CECPv2 engines)
                print >> self.engine, "new"

                # We are now ready for play:
                #self.emit("readyForOptions")
                #self.emit("readyForMoves")
                self.returnQueue.put("ready")

        # A hack to get better names in protover 1.
        # Unfortunately it wont work for now, as we don't read any lines from
        # protover 1 engines. When should we stop?
        if self.protover == 1:
            if self.defname[0] in ''.join(parts):
                basis = self.defname[0]
                name = ' '.join(itertools.dropwhile(lambda part: basis not in part, parts))
                self.features['myname'] = name
                if not self.name:
                    self.setName(name)

    def __parse_option(self, option):
        if " -check " in option:
            name, value = option.split(" -check ")
            return {"type": "check", "name": name, "default": bool(int(value))}
        elif " -spin " in option:
            name, value = option.split(" -spin ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -slider " in option:
            name, value = option.split(" -slider ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -string " in option:
            name, value = option.split(" -string ")
            return {"type": "text", "name": name, "default": value}
        elif " -file " in option:
            name, value = option.split(" -file ")
            return {"type": "text", "name": name, "default": value}
        elif " -path " in option:
            name, value = option.split(" -path ")
            return {"type": "text", "name": name, "default": value}
        elif " -combo " in option:
            name, value = option.split(" -combo ")
            return {"type": "combo", "name": name, "default": value}
        elif " -button" in option:
            pos = option.find(" -button")
            return {"type": "button", "name": option[:pos]}
        elif " -save" in option:
            pos = option.find(" -save")
            return {"type": "button", "name": option[:pos]}
        elif " -reset" in option:
            pos = option.find(" -reset")
            return {"type": "button", "name": option[:pos]}

    #===========================================================================
    #    Info
    #===========================================================================
    
    def canAnalyze (self):
        assert self.ready, "Still waiting for done=1"
        return self.features["analyze"]
    
    def maxAnalysisLines (self):
        return 1
    
    def requestMultiPV (self, setting):
        return 1
    
    def isAnalyzing (self):
        return self.mode in (ANALYZING, INVERSE_ANALYZING)
    
    def __repr__ (self):
        if self.name:
            return self.name
        return self.features["myname"]
Example #44
0
    def test_validate(self):
        """Testing validate move in Sittuyin variant"""

        board = SittuyinBoard(setup=FEN0)
        print(board)
        # no promotion if we have Met (queen)
        self.assertTrue(validate(board, parseSAN(board, 'f4f3')))
        self.assertTrue(validate(board, parseSAN(board, 'b2b1')))
        self.assertTrue(validate(board, parseSAN(board, 'bxc1')))
        self.assertTrue(not validate(board, parseSAN(board, 'f4f3f')))
        self.assertTrue(not validate(board, parseSAN(board, 'b2b2f')))
        self.assertTrue(not validate(board, parseSAN(board, 'b2b1f')))
        self.assertTrue(not validate(board, parseSAN(board, 'bxc1f')))
        
        board = SittuyinBoard(setup=FEN1)
        print(board)
        # but (optional) promotion if we don't have Met (queen)
        self.assertTrue(validate(board, parseSAN(board, 'f4f3f')))
        self.assertTrue(validate(board, parseSAN(board, 'b2b2f')))
        self.assertTrue(validate(board, parseSAN(board, 'b2b1')))
        self.assertTrue(validate(board, parseSAN(board, 'bxc1')))
        self.assertTrue(validate(board, parseSAN(board, 'f4f3')))
        self.assertTrue(not validate(board, parseSAN(board, 'b2b2')))
        self.assertTrue(not validate(board, parseSAN(board, 'b2b1f')))
        self.assertTrue(not validate(board, parseSAN(board, 'bxc1f')))
Example #45
0
 def validate(self, cord0, cord1):
     assert cord0 != None and cord1 != None, "cord0: " + str(
         cord0) + ", cord1: " + str(cord1)
     if self.getBoard()[cord0] == None: return False
     return validate(self.getBoard(), Move(cord0, cord1, self.getBoard()))
Example #46
0
    def __parseLine(self, line):
        if not self.connected: return
        parts = line.split()
        if not parts: return

        #---------------------------------------------------------- Initializing
        if parts[0] == "id":
            self.ids[parts[1]] = " ".join(parts[2:])
            if parts[1] == "name":
                self.setName(self.ids["name"])
            return

        if parts[0] == "uciok":
            self.emit("readyForOptions")
            return

        if parts[0] == "readyok":
            self.emit("readyForMoves")
            return

        #------------------------------------------------------- Options parsing
        if parts[0] == "option":
            dic = {}
            last = 1
            varlist = []
            for i in range(2, len(parts) + 1):
                if i == len(parts) or parts[i] in OPTKEYS:
                    key = parts[last]
                    value = " ".join(parts[last + 1:i])
                    if "type" in dic and dic["type"] in TYPEDIC:
                        value = TYPEDIC[dic["type"]](value)

                    if key == "var":
                        varlist.append(value)
                    elif key == "type" and value == "string":
                        dic[key] = "text"
                    else:
                        dic[key] = value

                    last = i
            if varlist:
                dic["choices"] = varlist

            self.options[dic["name"]] = dic
            return

        #---------------------------------------------------------------- A Move
        if self.mode == NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                self.needBestmove = False
                self.__sendQueuedGo()

                if self.ignoreNext:
                    log.debug("__parseLine: line='%s' self.ignoreNext==True, returning" % \
                        line.strip(), extra={"task":self.defname})
                    self.ignoreNext = False
                    self.readyForStop = True
                    return

                if not self.waitingForMove:
                    log.warning("__parseLine: self.waitingForMove==False, ignoring move=%s" % \
                        parts[1], extra={"task":self.defname})
                    self.pondermove = None
                    return
                self.waitingForMove = False

                try:
                    move = parseAny(self.board, parts[1])
                except ParsingError as e:
                    self.end(
                        WHITEWON if self.board.color == BLACK else BLACKWON,
                        WON_ADJUDICATION)
                    return

                if not validate(self.board, move):
                    # This is critical. To avoid game stalls, we need to resign on
                    # behalf of the engine.
                    log.error("__parseLine: move=%s didn't validate, putting 'del' in returnQueue. self.board=%s" % \
                        (repr(move), self.board), extra={"task":self.defname})
                    self.end(
                        WHITEWON if self.board.color == BLACK else BLACKWON,
                        WON_ADJUDICATION)
                    return

                self._recordMove(self.board.move(move), move, self.board)
                log.debug("__parseLine: applied move=%s to self.board=%s" % \
                    (move, self.board), extra={"task":self.defname})

                if self.ponderOn:
                    self.pondermove = None
                    # An engine may send an empty ponder line, simply to clear.
                    if len(parts) == 4:
                        # Engines don't always check for everything in their
                        # ponders. Hence we need to validate.
                        # But in some cases, what they send may not even be
                        # correct AN - specially in the case of promotion.
                        try:
                            pondermove = parseAny(self.board, parts[3])
                        except ParsingError:
                            pass
                        else:
                            if validate(self.board, pondermove):
                                self.pondermove = pondermove
                                self._startPonder()

                self.returnQueue.put(move)
                log.debug("__parseLine: put move=%s into self.returnQueue=%s" % \
                    (move, self.returnQueue.queue), extra={"task":self.defname})
                return

        #----------------------------------------------------------- An Analysis
        if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
            multipv = 1
            if "multipv" in parts:
                multipv = int(parts[parts.index("multipv") + 1])
            scoretype = parts[parts.index("score") + 1]
            if scoretype in ('lowerbound', 'upperbound'):
                score = None
            else:
                score = int(parts[parts.index("score") + 2])
                if scoretype == 'mate':
                    #                    print >> self.engine, "stop"
                    if score != 0:
                        sign = score / abs(score)
                        score = sign * MATE_VALUE

            movstrs = parts[parts.index("pv") + 1:]
            try:
                moves = listToMoves(self.board,
                                    movstrs,
                                    AN,
                                    validate=True,
                                    ignoreErrors=False)
            except ParsingError as e:
                # ParsingErrors may happen when parsing "old" lines from
                # analyzing engines, which haven't yet noticed their new tasks
                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                    (' '.join(movstrs),e), extra={"task":self.defname})
                return

            if "depth" in parts:
                depth = parts[parts.index("depth") + 1]
            else:
                depth = ""

            if multipv <= len(self.analysis):
                self.analysis[multipv - 1] = (moves, score, depth)

            self.emit("analyze", self.analysis)
            return

        #-----------------------------------------------  An Analyzer bestmove
        if self.mode != NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                log.debug("__parseLine: processing analyzer bestmove='%s'" % \
                    line.strip(), extra={"task":self.defname})
                self.needBestmove = False
                self.__sendQueuedGo(sendlast=True)
                return

        #  Stockfish complaining it received a 'stop' without a corresponding 'position..go'
        if line.strip() == "Unknown command: stop":
            with self.moveLock:
                log.debug("__parseLine: processing '%s'" % line.strip(),
                          extra={"task": self.defname})
                self.ignoreNext = False
                self.needBestmove = False
                self.readyForStop = False
                self.__sendQueuedGo()
                return
Example #47
0
    def test_getstatus4(self):
        """Testing possible move into check when king touch saves the king"""

        board = AtomicBoard(setup=FEN5)
        print(board)
        self.assertTrue(validate(board, parseSAN(board, 'Kg5')))
Example #48
0
    def test_validate(self):
        """Testing validate move in Placement variant"""

        board = PlacementBoard(setup=FEN0)
        print(board)
        # only drop moves to base line allowed
        self.assertTrue(validate(board, parseSAN(board, 'K@a1')))
        self.assertTrue(validate(board, parseSAN(board, 'K@b1')))
        self.assertTrue(validate(board, parseSAN(board, 'K@h1')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a2')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a3')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a8')))
        self.assertTrue(not validate(board, parseSAN(board, 'b4')))

        board = PlacementBoard(setup=FEN1)
        print(board)
        # only drop moves to base line allowed
        self.assertTrue(validate(board, parseSAN(board, 'K@a8')))
        self.assertTrue(validate(board, parseSAN(board, 'K@b8')))
        self.assertTrue(validate(board, parseSAN(board, 'K@h8')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a7')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a6')))
        self.assertTrue(not validate(board, parseSAN(board, 'K@a1')))
        self.assertTrue(not validate(board, parseSAN(board, 'b5')))

        board = PlacementBoard(setup=FEN2)
        print(board)
        # bishops have to be placed on opposite colored fields
        self.assertTrue(validate(board, parseSAN(board, 'B@a1')))
        self.assertTrue(validate(board, parseSAN(board, 'B@b1')))
        self.assertTrue(validate(board, parseSAN(board, 'B@c1')))
        self.assertTrue(validate(board, parseSAN(board, 'B@g1')))
        self.assertTrue(validate(board, parseSAN(board, 'N@a1')))
        self.assertTrue(validate(board, parseSAN(board, 'N@c1')))
        self.assertTrue(validate(board, parseSAN(board, 'N@g1')))
        self.assertTrue(not validate(board, parseSAN(board, 'N@b1')))

        board = PlacementBoard(setup=FEN3)
        print(board)
        # bishops have to be placed on opposite colored fields
        self.assertTrue(validate(board, parseSAN(board, 'B@b1')))
        self.assertTrue(validate(board, parseSAN(board, 'N@c1')))
        self.assertTrue(validate(board, parseSAN(board, 'N@g1')))
        self.assertTrue(not validate(board, parseSAN(board, 'B@c1')))
        self.assertTrue(not validate(board, parseSAN(board, 'B@g1')))
        self.assertTrue(not validate(board, parseSAN(board, 'N@b1')))
Example #49
0
    def __parseLine (self, line):
        if not self.connected: return
        parts = line.split()
        if not parts: return
        
        #---------------------------------------------------------- Initializing
        if parts[0] == "id":
            self.ids[parts[1]] = " ".join(parts[2:])
            if parts[1] == "name":
                self.setName(self.ids["name"])
            return
        
        if parts[0] == "uciok":
            #self.emit("readyForOptions")
            return
        
        if parts[0] == "readyok":
            #self.emit("readyForMoves")
            return
        
        #------------------------------------------------------- Options parsing
        if parts[0] == "option":
            dic = {}
            last = 1
            varlist = []
            for i in xrange (2, len(parts)+1):
                if i == len(parts) or parts[i] in OPTKEYS:
                    key = parts[last]
                    value = " ".join(parts[last+1:i])
                    if "type" in dic and dic["type"] in TYPEDIC:
                        value = TYPEDIC[dic["type"]](value)
                        
                    if key == "var":
                        varlist.append(value)
                    elif key == "type" and value == "string":
                        dic[key] = "text"
                    else:
                        dic[key] = value
                        
                    last = i
            if varlist:
                dic["choices"] = varlist
            
            self.options[dic["name"]] = dic
            return
        
        #---------------------------------------------------------------- A Move
        if self.mode == NORMAL and parts[0] == "bestmove":
            with self.moveLock:
                self.needBestmove = False
                self.__sendQueuedGo()
                
                if self.ignoreNext:
                    log.debug("__parseLine: line='%s' self.ignoreNext==True, returning\n" % \
                        line.strip(), self.defname)
                    self.ignoreNext = False
                    self.readyForStop = True
                    return
                
                if not self.waitingForMove:
                    log.warn("__parseLine: self.waitingForMove==False, ignoring move=%s\n" % \
                        parts[1], self.defname)
                    self.pondermove = None
                    return
                self.waitingForMove = False

                try:
                    move = parseAN(self.board, parts[1])
                except ParsingError, e:
                    self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                    return
                
                if not validate(self.board, move):
                    # This is critical. To avoid game stalls, we need to resign on
                    # behalf of the engine.
                    log.error("__parseLine: move=%s didn't validate, putting 'del' in returnQueue. self.board=%s\n" % \
                        (repr(move), self.board), self.defname)
                    self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                    return
                
                self._recordMove(self.board.move(move), move, self.board)
                log.debug("__parseLine: applied move=%s to self.board=%s\n" % \
                    (move, self.board), self.defname)
                
                if self.ponderOn:
                    self.pondermove = None
                    # An engine may send an empty ponder line, simply to clear.
                    if len(parts) == 4:
                        # Engines don't always check for everything in their
                        # ponders. Hence we need to validate.
                        # But in some cases, what they send may not even be
                        # correct AN - specially in the case of promotion.
                        try:
                            pondermove = parseAN(self.board, parts[3])
                        except ParsingError:
                            pass
                        else:
                            if validate(self.board, pondermove):
                                self.pondermove = pondermove
                                self._startPonder()
                
                self.returnQueue.put(move)
                log.debug("__parseLine: put move=%s into self.returnQueue=%s\n" % \
                    (move, self.returnQueue.queue), self.defname)
                return