1
# -*- coding: utf-8 -*-
2
__author__ = 'Robert Ancell <bob27@users.sourceforge.net>'
3
__license__ = 'GNU General Public License Version 2'
4
__copyright__ = 'Copyright 2005-2006 Robert Ancell'
7
"""CECP protocol en/decoder."""
10
MOVE_PREFIXS = ['My move is: ', 'my move is ', 'move ']
11
INVALID_MOVE_PREFIX = 'Illegal move: '
12
RESIGN_PREFIX = 'resign'
13
RESIGN_ICS_PREFIX = 'tellics resign'
14
DRAW_PREFIX = 'offer draw'
19
self.__buffer = '' # Data being accumulated to be parsed
20
# Go to simple interface mode
21
self.onOutgoingData('xboard\n')
25
def onOutgoingData(self, data):
26
"""Called when there is data to send to the CECP engine.
28
'data' is the data to give to the AI (string).
30
print 'OUT: ' + repr(data)
32
def onUnknownLine(self, line):
33
"""Called when an unknown line is received from the CECP AI.
35
'line' is the line that has not been decoded (string). There is
36
no newline on the end of the string.
38
print 'Unknown CECP line: ' + line
40
def onMove(self, move):
41
"""Called when the AI makes a move.
43
'move' is the move the AI has decided to make (string).
45
print 'CECP move: ' + move
47
def onIllegalMove(self, move):
48
"""Called when the AI rejects a move.
50
'move' is the move the AI rejected (string).
52
print 'CECP illegal move: ' + move
55
"""Called when the AI resigns"""
56
print 'CECP AI resigns'
59
"""Called when the AI requests a draw"""
60
print 'CECP AI calls a draw'
62
def logText(self, text, style):
63
print 'LOG: %s' % text
67
def sendSetSearchDepth(self, searchDepth):
68
"""Set the search depth for the AI.
70
'searchDepth' is the number of moves to look ahead (integer).
72
# This is the CECP specified method
73
self.onOutgoingData('sd %i\n' % int(searchDepth))
75
# GNUchess uses this instead
76
self.onOutgoingData('depth %i\n' % int(searchDepth))
78
def sendSetPondering(self, aiPonders):
79
"""Enable/disable AI pondering.
81
'aiPonders' is a flag to show if the AI thinks during opponent moves (True) or not (False).
84
self.onOutgoingData('hard\n')
86
self.onOutgoingData('easy\n')
88
def sendMove(self, move):
89
"""Move for the current player.
91
'move' is the move the current player has made (string).
93
self.onOutgoingData(move + '\n')
96
"""Stop the AI from automatically moving"""
97
self.onOutgoingData('force\n')
100
"""Undo the last move"""
101
self.onOutgoingData('undo\n')
103
def sendMovePrompt(self):
104
"""Get the AI to move for the current player"""
105
self.onOutgoingData('go\n')
107
def sendConventionalClock(self, moveCount, base, increment):
112
'increment' ??? (seconds)
114
self.onOutgoingData('level %d %d:%02d %d:%02d\n' % (moveCount, base / 60, base % 60, increment / 60, increment % 60))
117
"""Quit the engine"""
118
# Send 'quit' starting with a newline in case there are some characters already sent
119
self.onOutgoingData('\nquit\n')
121
def registerIncomingData(self, data):
124
self.__buffer += data
129
def __parseData(self):
131
index = self.__buffer.find(self.NEWLINE)
135
line = self.__buffer[:index]
136
self.__buffer = self.__buffer[index+1:]
138
self.__parseLine(line)
140
def __parseLine(self, line):
141
for prefix in self.MOVE_PREFIXS:
142
if line.startswith(prefix):
143
move = line[len(prefix):]
144
self.logText(line + '\n', 'move')
145
self.onMove(move.strip())
148
if line.startswith(self.INVALID_MOVE_PREFIX):
149
self.onIllegalMove(line[len(self.INVALID_MOVE_PREFIX):])
151
elif line.startswith(self.RESIGN_PREFIX) or line.startswith(self.RESIGN_ICS_PREFIX):
152
self.logText(line + '\n', 'move')
156
elif line.startswith(self.DRAW_PREFIX):
157
self.logText(line + '\n', 'move')
162
self.onUnknownLine(line)
164
self.logText(line + '\n', 'input')
166
class Connection(CECPProtocol):
174
CECPProtocol.__init__(self)
178
def logText(self, text, style):
179
"""FIXME: define style
183
def onMove(self, move):
184
"""Called when the AI makes a move.
186
'move' is the move the AI made (string).
188
print 'AI moves: ' + move
202
def configure(self, options = []):
205
for option in options:
206
self.onOutgoingData(option.value + '\n')
208
def requestMove(self, whiteTime, blackTime, ownTime):
209
"""Request the AI moves for the current player"""
212
self.sendConventionalClock(0, ownTime / 1000, 0)
214
# Prompt the AI to move
215
self.sendMovePrompt()
218
"""Undo the last move made by this AI"""
222
def reportMove(self, move, isSelf):
223
"""Report the move the current player has made.
225
'move' is the move to report (string).
226
'isSelf' is a flag to say if the move is the move this AI made (True).
228
# Don't report the move we made
232
# Stop the AI from automatically moving
240
def onUnknownLine(self, line):
241
"""Called by CECPProtocol"""
242
pass#print 'Unknown CECP line: ' + line
244
def onIllegalMove(self, move):
245
"""Called by CECPProtocol"""
246
print 'CECP illegal move: ' + move