[gnome-games/gnibbles-clutter] Added two files that got lost somehow along the way
- From: Guillaume Béland <guillaubel src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnome-games/gnibbles-clutter] Added two files that got lost somehow along the way
- Date: Thu, 4 Jun 2009 18:33:35 -0400 (EDT)
commit d137f02db1be021a65629143d812e1b281304879
Author: Guillaume Beland <guillaume beland gmail com>
Date: Thu Jun 4 18:25:12 2009 -0400
Added two files that got lost somehow along the way
---
glchess/src/lib/game.py | 812 +++++++++++++++++++++++++++++++++++++++++++++++
glchess/src/lib/uci.py | 185 +++++++++++
2 files changed, 997 insertions(+), 0 deletions(-)
diff --git a/glchess/src/lib/game.py b/glchess/src/lib/game.py
new file mode 100644
index 0000000..9b50726
--- /dev/null
+++ b/glchess/src/lib/game.py
@@ -0,0 +1,812 @@
+# -*- coding: utf-8 -*-
+"""
+"""
+
+__author__ = 'Robert Ancell <bob27 users sourceforge net>'
+__license__ = 'GNU General Public License Version 2'
+__copyright__ = 'Copyright 2005-2006 Robert Ancell'
+
+import chess.board
+import chess.san
+
+# Game results
+RESULT_IN_PROGRESS = '*'
+RESULT_WHITE_WINS = '1-0'
+RESULT_BLACK_WINS = '0-1'
+RESULT_DRAW = '1/2-1/2'
+
+# Reasons for the result
+RULE_CHECKMATE = 'CHECKMATE'
+RULE_STALEMATE = 'STALEMATE'
+RULE_TIMEOUT = 'TIMEOUT'
+RULE_FIFTY_MOVES = 'FIFTY_MOVES'
+RULE_THREE_FOLD_REPETITION = 'THREE_FOLD_REPETITION'
+RULE_INSUFFICIENT_MATERIAL = 'INSUFFICIENT_MATERIAL'
+RULE_RESIGN = 'RESIGN'
+RULE_DEATH = 'DEATH'
+RULE_AGREEMENT = 'AGREEMENT'
+RULE_ABANDONMENT = 'ABANDONMENT'
+
+class ChessMove:
+ """
+ """
+
+ # The move number (game starts at 0)
+ number = 0
+
+ # The player and piece that moved
+ player = None
+ piece = None
+
+ # The piece that was promoted to (or None)
+ promotion = None
+
+ # The victim piece (or None)
+ victim = None
+
+ # The start and end position of the move
+ start = None
+ end = None
+
+ # The move in CAN and SAN format
+ canMove = ''
+ sanMove = ''
+
+ # The game result after this move
+ opponentInCheck = False
+ opponentCanMove = False
+
+ # If this move can be used as a resignation
+ fiftyMoveRule = False
+ threeFoldRepetition = False
+
+ # A comment about this move
+ comment = ''
+
+ # Numeric annotation glyph for move
+ nag = ''
+
+class ChessPlayer:
+ """
+ """
+
+ def __init__(self, name):
+ """Constructor for a chess player.
+
+ 'name' is the name of the player.
+ """
+ self.__name = str(name)
+ self.__game = None
+ self.__readyToMove = False
+ self.isAlive = True
+
+ # Methods to extend
+
+ def onPieceMoved(self, piece, start, end, delete):
+ """Called when a chess piece is moved.
+
+ 'piece' is the piece that has been moved (chess.board.ChessPiece).
+ 'start' is the location the piece in LAN format (string) or None if the piece has been created.
+ 'end' is the location the piece has moved to in LAN format (string).
+ 'delete' is a flag to show if the piece should be deleted when it arrives there (boolean).
+ """
+ pass
+
+ def onPlayerMoved(self, player, move):
+ """Called when a player has moved.
+
+ 'player' is the player that has moved (ChessPlayer).
+ 'move' is the record for this move (ChessMove).
+ """
+ pass
+
+ def onUndoMove(self):
+ pass
+
+ def onPlayerStartTurn(self, player):
+ pass
+
+ def onGameEnded(self, game):
+ """Called when a chess game has ended.
+
+ 'game' is the game that has ended (Game).
+ """
+ pass
+
+ def readyToMove(self):
+ """FIXME
+ """
+ pass
+
+ # Public methods
+
+ def getName(self):
+ """Get the name of this player.
+
+ Returns the player name (string).
+ """
+ return self.__name
+
+ def getGame(self):
+ """Get the game this player is in.
+
+ Returns the game (Game) or None if not in a game.
+ """
+ return self.__game
+
+ def getRemainingTime(self):
+ """Get the amount of time this player has remaining.
+
+ Returns the amount of time in milliseconds.
+ """
+ if self is self.__game.getWhite():
+ timer = self.__game.whiteTimer
+ elif self is self.__game.getBlack():
+ timer = self.__game.blackTimer
+ else:
+ return 0
+
+ if timer is None:
+ return 0
+ else:
+ return timer.controller.getRemaining()
+
+ def isReadyToMove(self):
+ """
+ """
+ return self.__readyToMove
+
+ def canMove(self, start, end, promotionType = chess.board.QUEEN):
+ """
+ """
+ return self.__game.canMove(self, start, end, promotionType)
+
+ def move(self, move):
+ """Move a piece.
+
+ 'move' is the move to make in Normal/Long/Standard Algebraic format (string).
+ """
+ self.__game.move(self, move)
+
+ def undo(self):
+ """Undo moves until it is this players turn"""
+ self.__game.undo(self)
+
+ def endMove(self):
+ """Complete this players turn"""
+ self.__game.endMove(self)
+
+ def resign(self):
+ """Resign from the game"""
+ self.__game.resign(self)
+
+ def claimDraw(self):
+ """Claim a draw"""
+ return self.__game.claimDraw()
+
+ def outOfTime(self):
+ """Report this players timer has expired"""
+ self.__game.outOfTime(self)
+
+ def die(self):
+ """Report this player has died"""
+ self.isAlive = False
+ if self.__game is not None:
+ self.__game.killPlayer(self)
+
+ # Private methods
+
+ def _setGame(self, game):
+ """
+ """
+ self.__game = game
+
+ def _setReadyToMove(self, readyToMove):
+ if self.__readyToMove == readyToMove:
+ return
+ self.__readyToMove = readyToMove
+ if readyToMove is True:
+ self.readyToMove()
+
+class ChessGameBoard(chess.board.ChessBoard):
+ """
+ """
+
+ def __init__(self, game):
+ """
+ """
+ self.__game = game
+ chess.board.ChessBoard.__init__(self)
+
+ def onPieceMoved(self, piece, start, end, delete):
+ """Called by chess.board.ChessBoard"""
+ self.__game._onPieceMoved(piece, start, end, delete)
+
+class ChessGameSANConverter(chess.san.SANConverter):
+ """
+ """
+
+ __colourToSAN = {chess.board.WHITE: chess.san.SANConverter.WHITE,
+ chess.board.BLACK: chess.san.SANConverter.BLACK}
+ __sanToColour = {}
+ for (a, b) in __colourToSAN.iteritems():
+ __sanToColour[b] = a
+
+ __typeToSAN = {chess.board.PAWN: chess.san.SANConverter.PAWN,
+ chess.board.KNIGHT: chess.san.SANConverter.KNIGHT,
+ chess.board.BISHOP: chess.san.SANConverter.BISHOP,
+ chess.board.ROOK: chess.san.SANConverter.ROOK,
+ chess.board.QUEEN: chess.san.SANConverter.QUEEN,
+ chess.board.KING: chess.san.SANConverter.KING}
+ __sanToType = {}
+ for (a, b) in __typeToSAN.iteritems():
+ __sanToType[b] = a
+
+ def __init__(self, board, moveNumber):
+ self.board = board
+ self.moveNumber = moveNumber
+ chess.san.SANConverter.__init__(self)
+
+ def decode(self, colour, move):
+ (start, end, result, promotionType) = chess.san.SANConverter.decode(self, self.__colourToSAN[colour], move)
+ return (start, end, self.__sanToType[promotionType])
+
+ def encode(self, start, end, isTake, promotionType):
+ if promotionType is None:
+ promotion = self.QUEEN
+ else:
+ promotion = self.__typeToSAN[promotionType]
+ return chess.san.SANConverter.encode(self, start, end, isTake, promotion)
+
+ def getPiece(self, location):
+ """Called by chess.san.SANConverter"""
+ piece = self.board.getPiece(location, self.moveNumber)
+ if piece is None:
+ return None
+ return (self.__colourToSAN[piece.getColour()], self.__typeToSAN[piece.getType()])
+
+ def testMove(self, colour, start, end, promotionType, allowSuicide = False):
+ """Called by chess.san.SANConverter"""
+ move = self.board.testMove(self.__sanToColour[colour], start, end,
+ self.__sanToType[promotionType], allowSuicide, self.moveNumber)
+ if move is None:
+ return False
+
+ if move.opponentInCheck:
+ if not move.opponentCanMove:
+ return chess.san.SANConverter.CHECKMATE
+ return chess.san.SANConverter.CHECK
+ return True
+
+class ChessGame:
+ """
+ """
+
+ def __init__(self):
+ """Game constructor"""
+ self.__players = []
+ self.__spectators = []
+ self.__whitePlayer = None
+ self.__blackPlayer = None
+ self.__currentPlayer = None
+ self.__moves = []
+ self.__inCallback = False
+ self.__queuedCalls = []
+ self.board = ChessGameBoard(self)
+
+ self.__started = False
+ self.result = RESULT_IN_PROGRESS
+ self.rule = None
+ self.whiteTimer = None
+ self.blackTimer = None
+
+ def getAlivePieces(self, moveNumber = -1):
+ """Get the alive pieces on the board.
+
+ 'moveNumber' is the move to get the pieces from (integer).
+
+ Returns a dictionary of the alive pieces (board.ChessPiece) keyed by location.
+ Raises an IndexError exception if moveNumber is invalid.
+ """
+ return self.board.getAlivePieces(moveNumber)
+
+ def getDeadPieces(self, moveNumber = -1):
+ """Get the dead pieces from the game.
+
+ 'moveNumber' is the move to get the pieces from (integer).
+
+ Returns a list of the pieces (board.ChessPiece) in the order they were killed.
+ Raises an IndexError exception if moveNumber is invalid.
+ """
+ return self.board.getDeadPieces(moveNumber)
+
+ def setTimers(self, whiteTimer, blackTimer):
+ """
+ """
+ self.whiteTimer = whiteTimer
+ self.blackTimer = blackTimer
+
+ def setWhite(self, player):
+ """Set the white player in the game.
+
+ 'player' is the player to use as white.
+
+ If the game has started or there is a white player an exception is thrown.
+ """
+ assert(self.__started is False)
+ assert(self.__whitePlayer is None)
+ self.__whitePlayer = player
+ self.__connectPlayer(player)
+
+ def getWhite(self):
+ """Returns the current white player (player.Player)"""
+ return self.__whitePlayer
+
+ def setBlack(self, player):
+ """Set the black player in the game.
+
+ 'player' is the player to use as black.
+
+ If the game has started or there is a black player an exception is thrown.
+ """
+ assert(self.__started is False)
+ assert(self.__blackPlayer is None)
+ self.__blackPlayer = player
+ self.__connectPlayer(player)
+
+ def getBlack(self):
+ """Returns the current white player (player.Player)"""
+ return self.__blackPlayer
+
+ def getCurrentPlayer(self):
+ """Get the player to move"""
+ return self.__currentPlayer
+
+ def addSpectator(self, player):
+ """Add a spectator to the game.
+
+ 'player' is the player spectating.
+
+ This can be called after the game has started.
+ """
+ self.__spectators.append(player)
+ self.__connectPlayer(player)
+
+ def isStarted(self):
+ """Returns True if the game has been started"""
+ return self.__started
+
+ def start(self, moves = []):
+ """Start the game.
+
+ 'moves' is a list of moves to start with.
+
+ If there is no white or black player then an exception is raised.
+ """
+ assert(self.__whitePlayer is not None and self.__blackPlayer is not None)
+
+ # Disabled for now
+ #import network
+ #self.x = network.GameReporter('Test Game', 12345)
+ #print 'Reporting'
+
+ # Load starting moves
+ self.__currentPlayer = self.__whitePlayer
+ for move in moves:
+ self.move(self.__currentPlayer, move)
+ if self.__currentPlayer is self.__whitePlayer:
+ self.__currentPlayer = self.__blackPlayer
+ else:
+ self.__currentPlayer = self.__whitePlayer
+
+ self.__started = True
+
+ # Stop if both players aren't alive
+ if not self.__whitePlayer.isAlive:
+ self.killPlayer(self.__whitePlayer)
+ return
+ if not self.__blackPlayer.isAlive:
+ self.killPlayer(self.__blackPlayer)
+ return
+
+ # Stop if game ended on loaded moves
+ if self.result != RESULT_IN_PROGRESS:
+ self._notifyEndGame()
+ return
+
+ self.startLock()
+
+ # Inform other players of the result
+ for player in self.__players:
+ player.onPlayerStartTurn(self.__currentPlayer)
+
+ # Get the next player to move
+ self.__currentPlayer._setReadyToMove(True)
+
+ self.endLock()
+
+ def getSquareOwner(self, coord):
+ """TODO
+ """
+ piece = self.board.getPiece(coord)
+ if piece is None:
+ return None
+
+ colour = piece.getColour()
+ if colour is chess.board.WHITE:
+ return self.__whitePlayer
+ elif colour is chess.board.BLACK:
+ return self.__blackPlayer
+ else:
+ return None
+
+ def canMove(self, player, start, end, promotionType):
+ """Test if a player can move.
+
+ 'player' is the player making the move.
+ 'start' is the location to move from in LAN format (string).
+ 'end' is the location to move from in LAN format (string).
+ 'promotionType' is the piece type to promote pawns to. FIXME: Make this a property of the player
+
+ Return True if can move, otherwise False.
+ """
+ if player is not self.__currentPlayer:
+ return False
+
+ if player is self.__whitePlayer:
+ colour = chess.board.WHITE
+ elif player is self.__blackPlayer:
+ colour = chess.board.BLACK
+ else:
+ assert(False)
+
+ move = self.board.testMove(colour, start, end, promotionType = promotionType)
+
+ return move is not None
+
+ def move(self, player, move):
+ """Get a player to make a move.
+
+ 'player' is the player making the move.
+ 'move' is the move to make in SAN or LAN format (string).
+ """
+ if self.__inCallback:
+ self.__queuedCalls.append((self.move, (player, move)))
+ return
+
+ self.startLock()
+
+ if player is not self.__currentPlayer:
+ print 'Player attempted to move out of turn'
+ else:
+ self._move(player, move)
+
+ self.endLock()
+
+ def undo(self, player):
+ if self.__inCallback:
+ self.__queuedCalls.append((self.undo, (player,)))
+ return
+
+ self.startLock()
+
+ self.__whitePlayer._setReadyToMove(False)
+ self.__blackPlayer._setReadyToMove(False)
+
+ # Pretend the current player is the oponent so when endMove() is called
+ # this player will become the active player.
+ # Yes, this IS a big hack...
+ if player is self.__whitePlayer:
+ self.__currentPlayer = self.__blackPlayer
+ else:
+ self.__currentPlayer = self.__whitePlayer
+
+ # If this player hasn't moved then undo oponents move before their one
+ if len(self.__moves) > 0 and self.__moves[-1].player is not player:
+ count = 2
+ else:
+ count = 1
+
+ for i in xrange(count):
+ if len(self.__moves) != 0:
+ self.board.undo()
+ self.__moves = self.__moves[:-1]
+ for p in self.__players:
+ p.onUndoMove()
+
+ self.endLock()
+
+ def startLock(self):
+ assert(self.__inCallback is False)
+ self.__inCallback = True
+
+ def endLock(self):
+ self.__inCallback = False
+ while len(self.__queuedCalls) > 0:
+ (call, args) = self.__queuedCalls[0]
+ self.__queuedCalls = self.__queuedCalls[1:]
+ call(*args)
+
+ def _move(self, player, move):
+ """
+ """
+ if self.result != RESULT_IN_PROGRESS:
+ print 'Game completed'
+ return
+
+ if self.__currentPlayer is self.__whitePlayer:
+ colour = chess.board.WHITE
+ else:
+ colour = chess.board.BLACK
+
+ # If move is SAN process it as such
+ try:
+ (start, end, _, _, promotionType, _) = chess.lan.decode(colour, move)
+ except chess.lan.DecodeError, e:
+ converter = ChessGameSANConverter(self.board, len(self.__moves))
+ try:
+ (start, end, promotionType) = converter.decode(colour, move)
+ except chess.san.Error, e:
+ print 'Invalid move: ' + move
+ return
+
+ # Only use promotion type if a pawn move to far file
+ piece = self.board.getPiece(start)
+ promotion = None
+ if piece is not None and piece.getType() is chess.board.PAWN:
+ if colour is chess.board.WHITE:
+ if end[1] == '8':
+ promotion = promotionType
+ else:
+ if end[1] == '1':
+ promotion = promotionType
+
+ moveResult = self.board.movePiece(colour, start, end, promotionType)
+ if moveResult is None:
+ print 'Illegal move: ' + str(move)
+ return
+
+ # Re-encode for storing and reporting
+ canMove = chess.lan.encode(colour, start, end, promotionType = promotion)
+ converter = ChessGameSANConverter(self.board, len(self.__moves))
+ try:
+ sanMove = converter.encode(start, end, moveResult.victim != None, promotionType)
+ except chess.san.Error:
+ # If for some reason we couldn't make the SAN move the use the CAN move instead
+ sanMove = canMove
+
+ m = ChessMove()
+ if len(self.__moves) == 0:
+ m.number = 1
+ else:
+ m.number = self.__moves[-1].number + 1
+ m.player = self.__currentPlayer
+ m.piece = piece
+ m.victim = moveResult.victim
+ m.start = start
+ m.end = end
+ m.canMove = canMove
+ m.sanMove = sanMove
+ m.opponentInCheck = moveResult.opponentInCheck
+ m.opponentCanMove = moveResult.opponentCanMove
+ m.fiftyMoveRule = moveResult.fiftyMoveRule
+ m.threeFoldRepetition = moveResult.threeFoldRepetition
+ #FIXME: m.comment = move.comment
+ #FIXME: m.nag = move.nag
+
+ self.__moves.append(m)
+
+ # This player has now moved
+ self.__currentPlayer._setReadyToMove(False)
+
+ # Inform other players of the result
+ for player in self.__players:
+ player.onPlayerMoved(self.__currentPlayer, m)
+
+ # Check if the game has ended
+ result = RESULT_IN_PROGRESS
+ if not m.opponentCanMove:
+ if self.__currentPlayer is self.__whitePlayer:
+ result = RESULT_WHITE_WINS
+ else:
+ result = RESULT_BLACK_WINS
+ if m.opponentInCheck:
+ rule = RULE_CHECKMATE
+ else:
+ result = RESULT_DRAW
+ rule = RULE_STALEMATE
+
+ # Check able to complete
+ if not self.board.sufficientMaterial():
+ result = RESULT_DRAW
+ rule = RULE_INSUFFICIENT_MATERIAL
+
+ if result is not RESULT_IN_PROGRESS:
+ self.endGame(result, rule)
+
+ def endMove(self, player):
+ """
+ """
+ if self.__inCallback:
+ self.__queuedCalls.append((self.endMove, (player,)))
+ return
+
+ if player is not self.__currentPlayer:
+ print 'Player attempted to move out of turn'
+ return
+ if player.move is None:
+ print "Ending move when haven't made one"
+ return
+
+ if self.__currentPlayer is self.__whitePlayer:
+ self.__currentPlayer = self.__blackPlayer
+ else:
+ self.__currentPlayer = self.__whitePlayer
+
+ self.startLock()
+
+ # Inform other players of the result
+ for player in self.__players:
+ player.onPlayerStartTurn(self.__currentPlayer)
+
+ # Notify the next player they can move
+ if self.__started is True and self.result == RESULT_IN_PROGRESS:
+ self.__currentPlayer._setReadyToMove(True)
+
+ self.endLock()
+
+ def resign(self, player):
+ """Get a player to resign.
+
+ 'player' is the player resigning.
+ """
+ rule = RULE_RESIGN
+ if player is self.__whitePlayer:
+ self.endGame(RESULT_BLACK_WINS, rule)
+ else:
+ self.endGame(RESULT_WHITE_WINS, rule)
+
+ def claimDraw(self):
+ """
+ """
+ # TODO: Penalise if make an incorrect attempt
+ try:
+ move = self.__moves[-1]
+ except IndexError:
+ return False
+ else:
+ if move.fiftyMoveRule:
+ rule = RULE_FIFTY_MOVES
+ elif move.threeFoldRepetition:
+ rule = RULE_THREE_FOLD_REPETITION
+ else:
+ return False
+
+ self.endGame(RESULT_DRAW, rule)
+ return True
+
+ def killPlayer(self, player):
+ """Report a player has died
+
+ 'player' is the player that has died.
+ """
+ if player is self.__whitePlayer:
+ result = RESULT_BLACK_WINS
+ elif player is self.__blackPlayer:
+ result = RESULT_WHITE_WINS
+ self.endGame(result, RULE_DEATH)
+
+ def outOfTime(self, player):
+ """Report a player's timer has expired"""
+ if player is self.__whitePlayer:
+ result = RESULT_BLACK_WINS
+ elif player is self.__blackPlayer:
+ result = RESULT_WHITE_WINS
+ else:
+ assert(False)
+ self.endGame(result, RULE_TIMEOUT)
+
+ def abandon(self):
+ self.endGame(RESULT_DRAW, RULE_ABANDONMENT)
+
+ def endGame(self, result, rule):
+ if self.result != RESULT_IN_PROGRESS:
+ return
+ self.result = result
+ self.rule = rule
+ if self.isStarted():
+ self._notifyEndGame()
+
+ def _notifyEndGame(self):
+ self.__currentPlayer._setReadyToMove(False)
+ for player in self.__players:
+ player.onGameEnded(self)
+
+ def getMoves(self):
+ """
+ """
+ return self.__moves
+
+ def abort(self):
+ """End the game"""
+ # Inform players
+ for player in self.__players:
+ player.onGameEnded(self)
+
+ # Private methods:
+
+ def __connectPlayer(self, player):
+ """Add a player into the game.
+
+ 'player' is the player to add.
+
+ The player will be notified of the current state of the board.
+ """
+ self.__players.append(player)
+ player._setGame(self)
+
+ # Notify the player of the current state
+ # FIXME: Make the board iteratable...
+ for file in '12345678':
+ for rank in 'abcdefgh':
+ coord = rank + file
+ piece = self.board.getPiece(coord)
+ if piece is None:
+ continue
+
+ # These are moves from nowhere to their current location
+ player.onPieceMoved(piece, None, coord, False)
+
+ def _onPieceMoved(self, piece, start, end, delete):
+ """Called by the chess board"""
+
+ # Notify all players of creations and deletions
+ # NOTE: Normal moves are done above since the SAN moves are calculated before the move...
+ # FIXME: Change this so the SAN moves are done afterwards...
+ for player in self.__players:
+ player.onPieceMoved(piece, start, end, delete)
+
+class NetworkChessGame(ChessGame):
+ """
+ """
+
+ def move(self, player, move):
+ """Get a player to make a move.
+
+ 'player' is the player making the move.
+ 'move' is the move to make. It can be of the form:
+ A coordinate move in the form ((file0, rank0), (file1, rank1), promotionType) ((int, int), (int, int), chess.board.PIECE_TYPE) or
+ A SAN move (string).
+ """
+ # Send to the server
+
+
+if __name__ == '__main__':
+ game = ChessGame()
+
+ import pgn
+
+ p = pgn.PGN('black.pgn')
+ g = p.getGame(0)
+
+ class PGNPlayer(ChessPlayer):
+
+ def __init__(self, isWhite):
+ self.__isWhite = isWhite
+ self.__moveNumber = 1
+
+ def readyToMove(self):
+ if self.__isWhite:
+ move = g.getWhiteMove(self.__moveNumber)
+ else:
+ move = g.getBlackMove(self.__moveNumber)
+ self.__moveNumber += 1
+ self.move(move)
+
+ white = PGNPlayer(True)
+ black = PGNPlayer(False)
+
+ game.setWhite(white)
+ game.setBlack(black)
+
+ game.start()
diff --git a/glchess/src/lib/uci.py b/glchess/src/lib/uci.py
new file mode 100644
index 0000000..657a019
--- /dev/null
+++ b/glchess/src/lib/uci.py
@@ -0,0 +1,185 @@
+# -*- coding: utf-8 -*-
+
+class StateMachine:
+ """
+ """
+
+ STATE_IDLE = 'IDLE'
+ STATE_CONNECTING = 'CONNECTING'
+
+ def __init__(self):
+ """
+ """
+ self.options = {}
+ self.__queuedCommands = []
+ self.buffer = ''
+ self.__haveMoves = False
+ self.__readyToConfigure = False
+ self.__ready = False
+ self.__inCallback = False
+ self.__queuedCommands = None
+ self.__positionCommand = 'position startpos'
+
+ def logText(self, text, style):
+ """
+ """
+ pass
+
+ def onOutgoingData(self, data):
+ """
+ """
+ pass
+
+ def onMove(self, move):
+ """Called when the AI makes a move.
+
+ 'move' is the move the AI has decided to make (string).
+ """
+ print 'UCI move: ' + move
+
+ def registerIncomingData(self, data):
+ """
+ """
+ self.__inCallback = True
+ self.buffer += data
+ while True:
+ index = self.buffer.find('\n')
+ if index < 0:
+ break
+ line = self.buffer[:index]
+ self.buffer = self.buffer[index + 1:]
+ self.parseLine(line)
+ self.__inCallback = False
+
+ if self.__options is not None and self.__readyToConfigure:
+ options = self.__options
+ self.__options = None
+ self.configure(options)
+
+ # Send queued commands once have OK
+ if len(self.__queuedCommands) > 0 and self.__ready:
+ commands = self.__queuedCommands
+ self.__queuedCommands = []
+ for c in commands:
+ self.__sendCommand(c)
+
+ def __sendCommand(self, command):
+ """
+ """
+ if self.__ready and not self.__inCallback:
+ self.onOutgoingData(command + '\n')
+ else:
+ self.__queuedCommands.append(command)
+
+ def start(self):
+ """
+ """
+ self.onOutgoingData('uci\n')
+
+ def startGame(self):
+ """
+ """
+ self.__sendCommand('ucinewgame')
+ self.__sendCommand(self.__positionCommand)
+
+ def configure(self, options = []):
+ """
+ """
+ if not self.__readyToConfigure:
+ self.__options = options
+ return
+
+ for option in options:
+ if not hasattr(option, 'name'):
+ print 'Ignoring unnamed UCI option'
+ continue
+ if option.value == '':
+ continue
+ self.onOutgoingData('setoption ' + option.name + ' value ' + option.value + '\n')
+ self.onOutgoingData('isready\n')
+
+ def requestMove(self, whiteTime, blackTime, ownTime):
+ """
+ """
+ # Some AI's don't work unless assigned some time
+ # TODO: which ones? I think Glaurung had issues
+ if whiteTime == 0:
+ whiteTime = 30000
+ if blackTime == 0:
+ blackTime = 30000
+
+ self.__sendCommand('go wtime %d btime %d' % (whiteTime, blackTime))
+
+ def undoMove(self):
+ """
+ """
+ self.__sendCommand('stop');
+ (self.__positionCommand, _) = self.__positionCommand.rsplit(" ", 1)
+ if self.__positionCommand.endswith(' moves'):
+ self.__haveMoves = False
+ self.__positionCommand = 'position startpos'
+ self.__sendCommand(self.__positionCommand)
+
+ def reportMove(self, move, isSelf):
+ """
+ """
+ if not self.__haveMoves:
+ self.__positionCommand += ' moves'
+ self.__haveMoves = True
+ self.__positionCommand += ' ' + move
+ self.__sendCommand(self.__positionCommand)
+
+ def parseLine(self, line):
+ """
+ """
+ words = line.split()
+
+ while True:
+ if len(words) == 0:
+ self.logText(line + '\n', 'input')
+ return
+
+ style = self.parseCommand(words[0], words[1:])
+ if style is not None:
+ self.logText(line + '\n', style)
+ return
+
+ print 'WARNING: Unknown command: ' + repr(words[0])
+ words = words[1:]
+
+ def parseCommand(self, command, args):
+ """
+ """
+ if command == 'id':
+ return 'info'
+
+ elif command == 'uciok':
+ if len(args) != 0:
+ print 'WARNING: Arguments on uciok: ' + str(args)
+ self.__readyToConfigure = True
+ return 'info'
+
+ elif command == 'readyok':
+ if len(args) != 0:
+ print 'WARNING: Arguments on readyok: ' + str(args)
+ self.__ready = True
+ return 'info'
+
+ elif command == 'bestmove':
+ if len(args) == 0:
+ print 'WARNING: No move with bestmove'
+ return 'error'
+ else:
+ move = args[0]
+ self.onMove(move)
+
+ # TODO: Check for additional ponder information
+ return 'move'
+
+ elif command == 'info':
+ return 'info'
+
+ elif command == 'option':
+ return 'info'
+
+ return None
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]