def __getBestOpening(self): totalWeight = 0 choice = None if self.board.variant not in ( ASEANCHESS, CAMBODIANCHESS, MAKRUKCHESS, HORDECHESS, PLACEMENTCHESS, SITTUYINCHESS, LOSERSCHESS, SUICIDECHESS, GIVEAWAYCHESS, ATOMICCHESS, KINGOFTHEHILLCHESS, THREECHECKCHESS, RACINGKINGSCHESS, ): for move, weight, learn in getOpenings(self.board): totalWeight += weight if totalWeight == 0: break if not move or random.randrange(totalWeight) < weight: choice = move if choice is None: self.outOfBook = True return choice
def shown_changed(self, board, shown): self.openings = getOpenings(self.board.model.getBoardAtPly(shown)) self.openings.sort(lambda a, b: sum(b[1:]) - sum(a[1:])) self.board.bluearrow = None self.store.clear() if not self.openings and self.sw.get_child() == self.tv: self.sw.remove(self.tv) label = gtk.Label(_("In this position,\nthere is no book move.")) label.set_property("yalign", 0.1) self.sw.add_with_viewport(label) self.sw.get_child().set_shadow_type(gtk.SHADOW_NONE) self.sw.show_all() return if self.openings and self.sw.get_child() != self.tv: self.sw.remove(self.sw.get_child()) self.sw.add(self.tv) i = 0 for move, wins, draws, loses in self.openings: games = wins + draws + loses if not games: continue wins, draws, loses = \ map(lambda x: x/float(games), (wins, draws, loses)) b = self.board.model.getBoardAtPly(shown) if conf.get("figuresInNotation", False): move = toFAN(b, parseSAN(b, move)) else: move = toSAN(b, parseSAN(b, move), True) self.store.append([move, str(games), (wins, draws, loses)])
def shown_changed (self, board, shown): self.openings = getOpenings(self.board.model.getBoardAtPly(shown)) self.openings.sort(lambda a, b: sum(b[1:])-sum(a[1:])) self.board.bluearrow = None self.store.clear() if not self.openings and self.sw.get_child() == self.tv: self.sw.remove(self.tv) label = gtk.Label(_("In this position,\nthere is no book move.")) label.set_property("yalign",0.1) self.sw.add_with_viewport(label) self.sw.get_child().set_shadow_type(gtk.SHADOW_NONE) self.sw.show_all() return if self.openings and self.sw.get_child() != self.tv: self.sw.remove(self.sw.get_child()) self.sw.add(self.tv) i = 0 for move, wins, draws, loses in self.openings: games = wins+draws+loses if not games: continue wins, draws, loses = \ map(lambda x: x/float(games), (wins, draws, loses)) b = self.board.model.getBoardAtPly(shown) if conf.get("figuresInNotation", False): move = toFAN(b, parseSAN(b, move)) else: move = toSAN(b, parseSAN(b, move), True) self.store.append ([move, str(games), (wins,draws,loses)])
def on_book_created(persp, event): self.assertTrue(os.path.isfile(BIN)) testcase = testcases[0] board = LBoard(Board) board.applyFen(testcase[0]) openings = book.getOpenings(board) self.assertEqual( sorted(openings), sorted([(newMove(E2, E4), 2, 0), (newMove(A2, A4), 0, 0)])) testcase = testcases[-1] board = LBoard(Board) board.applyFen(testcase[0]) openings = book.getOpenings(board) self.assertEqual(openings, []) event.set()
def __getBestOpening (self): score = 0 move = None for m, w, d, l in getOpenings(self.board): s = (w+d/3.0)*random.random() if not move or s > score: move = m score = s return move
def on_book_created(persp, event): self.assertTrue(os.path.isfile(BIN)) book.path = BIN book.bookfile = True testcase = testcases[0] board = LBoard(Board) board.applyFen(testcase[0]) openings = book.getOpenings(board) self.assertEqual(sorted(openings), sorted([(newMove(E2, E4), 2, 0), (newMove(A2, A4), 0, 0)])) testcase = testcases[-1] board = LBoard(Board) board.applyFen(testcase[0]) openings = book.getOpenings(board) self.assertEqual(openings, []) event.set()
def __getBestOpening (self): totalWeight = 0 choice = None if self.board.variant not in (LOSERSCHESS, SUICIDECHESS, ATOMICCHESS): for move, weight, histGames, histScore in getOpenings(self.board): totalWeight += weight if totalWeight == 0: break if not move or random.randrange(totalWeight) < weight: choice = move return choice
def __getBestOpening(self): totalWeight = 0 choice = None if self.board.variant not in (LOSERSCHESS, SUICIDECHESS, ATOMICCHESS, KINGOFTHEHILLCHESS): for move, weight, histGames, histScore in getOpenings(self.board): totalWeight += weight if totalWeight == 0: break if not move or random.randrange(totalWeight) < weight: choice = move return choice
def shownChanged(self, boardview, shown): m = boardview.model if m is None or m.isPlayingICSGame(): return b = m.getBoardAtPly(shown, boardview.shown_variation_idx) parent = self.empty_parent() openings = getOpenings(b.board) openings.sort(key=lambda t: t[1], reverse=True) if not openings: return totalWeight = 0.0 # Polyglot-formatted books have space for learning data. # See version ac31dc37ec89 for an attempt to parse it. # In this version, we simply ignore it. (Most books don't have it.) for move, weight, learn in openings: totalWeight += weight self.opening_names = [] for move, weight, learn in openings: if totalWeight != 0: weight /= totalWeight goodness = min(float(weight * len(openings)), 1.0) weight = "%0.1f%%" % (100 * weight) opening = get_eco(b.move(Move(move)).board.hash) if opening is None: eco = "" # self.opening_names.append("") else: eco = "%s - %s %s" % (opening[0], opening[1], opening[2]) # self.opening_names.append("%s %s" % (opening[1], opening[2])) self.store.append( parent, [ (b, Move(move), None), (weight, 1, goodness), 0, False, eco, False, False, ], ) tp = Gtk.TreePath(self.path) self.tv.expand_row(tp, False)
def __getBestOpening(self): totalWeight = 0 choice = None if self.board.variant not in (ASEANCHESS, CAMBODIANCHESS, MAKRUKCHESS, HORDECHESS, PLACEMENTCHESS, SITTUYINCHESS, LOSERSCHESS, SUICIDECHESS, GIVEAWAYCHESS, ATOMICCHESS, KINGOFTHEHILLCHESS, THREECHECKCHESS, RACINGKINGSCHESS): for move, weight, learn in getOpenings(self.board): totalWeight += weight if totalWeight == 0: break if not move or random.randrange(totalWeight) < weight: choice = move if choice is None: self.outOfBook = True return choice
def __getBestOpening (self): totalWeight = 0 choice = None if self.board.variant not in (ASEANCHESS, CAMBODIANCHESS, MAKRUKCHESS, \ SITTUYINCHESS, LOSERSCHESS, SUICIDECHESS,\ ATOMICCHESS, KINGOFTHEHILLCHESS, THREECHECKCHESS): for move, weight, histGames, histScore in getOpenings(self.board): totalWeight += weight if totalWeight == 0: break if not move or random.randrange(totalWeight) < weight: choice = move if choice is None: self.outOfBook = True return choice
def get_book_move(self): openings = getOpenings(self.boards[-1].board) openings.sort(key=lambda t: t[1], reverse=True) if not openings: return None total_weights = 0 for move, weight, learn in openings: total_weights += weight if total_weights < 1: return None choice = random.randint(0, total_weights - 1) current_sum = 0 for move, weight, learn in openings: current_sum += weight if current_sum > choice: return Move(move)
def shownChanged(self, boardview, shown): m = boardview.model if m is None: return if m.isPlayingICSGame(): return b = m.getBoardAtPly(shown, boardview.shown_variation_idx) parent = self.empty_parent() openings = getOpenings(b.board) openings.sort(key=lambda t: t[1], reverse=True) if not openings: return totalWeight = 0.0 # Polyglot-formatted books have space for learning data. # See version ac31dc37ec89 for an attempt to parse it. # In this version, we simply ignore it. (Most books don't have it.) for move, weight, games, score in openings: totalWeight += weight self.opening_names = [] for move, weight, games, score in openings: if totalWeight != 0: weight /= totalWeight goodness = min(float(weight * len(openings)), 1.0) weight = "%0.1f%%" % (100 * weight) opening = get_eco(b.move(Move(move)).board.hash) if opening is None: eco = "" # self.opening_names.append("") else: eco = "%s - %s %s" % (opening[0], opening[1], opening[2]) # self.opening_names.append("%s %s" % (opening[1], opening[2])) self.store.append(parent, [(b, Move(move), None), ( weight, 1, goodness), 0, False, eco, False, False]) tp = Gtk.TreePath(self.path) self.tv.expand_row(tp, False)
def run(self): while True: try: line = raw_input() except EOFError: line = "quit" lines = line.split() try: if not lines: continue log.debug(line, extra={"task": "xboard"}) ########## CECP commands ########## # See http://home.hccnet.nl/h.g.muller/engine-intf.html if lines[0] == "xboard": pass elif lines[0] == "protover": stringPairs = [ "=".join( [k, '"%s"' % v if isinstance(v, str) else str(v)]) for k, v in self.features.items() ] self.print("feature %s" % " ".join(stringPairs)) self.print("feature done=1") elif lines[0] in ("accepted", "rejected"): # We only really care about one case: if tuple(lines) == ("rejected", "debug"): self.debug = False elif lines[0] == "new": self.__stopSearching() self.board = LBoard(NORMALCHESS) self.board.applyFen(FEN_START) self.outOfBook = False self.forced = False self.playingAs = BLACK self.clock[:] = self.basetime, self.basetime self.searchtime = 0 self.sd = MAXPLY if self.analyzing: self.__analyze() elif lines[0] == "variant": if len(lines) > 1: if lines[1] == "fischerandom": self.board.variant = FISCHERRANDOMCHESS elif lines[1] == "crazyhouse": self.board.variant = CRAZYHOUSECHESS self.board.iniHouse() elif lines[1] == "wildcastle": self.board.variant = WILDCASTLESHUFFLECHESS elif lines[1] == "losers": self.board.variant = LOSERSCHESS elif lines[1] == "suicide": self.board.variant = SUICIDECHESS elif lines[1] == "atomic": self.board.variant = ATOMICCHESS self.board.iniAtomic() elif lines[1] == "3check": self.board.variant = THREECHECKCHESS elif lines[1] == "kingofthehill": self.board.variant = KINGOFTHEHILLCHESS self.print("setup (PNBRQKpnbrqk) 8x8+0_fairy %s" % FEN_START) elif lines[1] == "asean": self.board = LBoard(ASEANCHESS) self.board.applyFen(ASEANSTART) elif lines[1] == "makruk": self.board = LBoard(MAKRUKCHESS) self.board.applyFen(MAKRUKSTART) elif lines[1] == "cambodian": self.board = LBoard(CAMBODIANCHESS) self.board.applyFen(KAMBODIANSTART) self.print( "setup (PN.R.M....SKpn.r.m....sk) 8x8+0_makruk %s" % KAMBODIANSTART) self.print("piece K& KiN") self.print("piece M& FifD") elif lines[1] == "sittuyin": self.board = LBoard(SITTUYINCHESS) self.board.applyFen(SITTUYINSTART) self.print( "setup (PN.R.F....SKpn.r.f....sk) 8x8+6_bughouse %s" % SITTUYINSTART) self.print("piece N& Nj@3") self.print("piece S& FfWj@3") self.print("piece F& Fjb@3") self.print("piece R& R@1") self.print("piece K& Kj@3") self.print("piece P& fmWfcFj@3") elif lines[0] == "quit": self.forced = True self.__stopSearching() sys.exit(0) elif lines[0] == "random": leval.random = True elif lines[0] == "force": if not self.forced and not self.analyzing: self.forced = True self.__stopSearching() elif lines[0] == "go": self.playingAs = self.board.color self.forced = False self.__go() elif lines[0] == "playother": self.playingAs = 1 - self.board.color self.forced = False # TODO: start pondering, if possible elif lines[0] in ("black", "white"): newColor = lines[0] == "black" and BLACK or WHITE self.__stopSearching() self.playingAs = 1 - newColor if self.board.color != newColor: self.board.setColor(newColor) self.board.setEnpassant(None) if self.analyzing: self.__analyze() elif lines[0] == "level": self.movestogo = int(lines[1]) inc = int(lines[3]) minutes = lines[2].split(":") # Per protocol spec, strip off any non-numeric suffixes. for i in range(len(minutes)): minutes[i] = re.match(r'\d*', minutes[i]).group() self.basetime = int(minutes[0]) * 60 if len(minutes) > 1 and minutes[1]: self.basetime += int(minutes[1]) self.clock[:] = self.basetime, self.basetime self.increment = inc, inc elif lines[0] == "st": self.searchtime = float(lines[1]) elif lines[0] == "sd": self.sd = int(lines[1]) # Unimplemented: nps elif lines[0] == "time": self.clock[self.playingAs] = float(lines[1]) / 100. elif lines[0] == "otim": self.clock[1 - self.playingAs] = float(lines[1]) / 100. elif lines[0] == "usermove": self.__stopSearching() try: move = parseAny(self.board, lines[1]) except ParsingError as e: self.print("Error (unknown command): %s" % lines[1]) self.print(self.board) continue if not validateMove(self.board, move): self.print("Illegal move: %s" % lines[1]) self.print(self.board) continue self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() elif lines[0] == "?": if not self.forced and not self.analyzing: self.__stopSearching() elif lines[0] == "ping": self.print("pong %s" % lines[1]) elif lines[0] == "draw": if self.__willingToDraw(): self.print("offer draw") elif lines[0] == "result": # We don't really care what the result is at the moment. pass elif lines[0] == "setboard": self.__stopSearching() try: self.board = LBoard(self.board.variant) fen = " ".join(lines[1:]) self.board.applyFen( fen.replace("[", "/").replace("]", "")) except SyntaxError as e: self.print("tellusererror Illegal position: %s" % str(e)) # "edit" is unimplemented. See docs. Exiting edit mode returns to analyze mode. elif lines[0] == "hint": pass # TODO: Respond "Hint: MOVE" if we have an expected reply elif lines[0] == "bk": entries = getOpenings(self.board) if entries: totalWeight = sum(entry[1] for entry in entries) for entry in entries: self.print("\t%s\t%02.2f%%" % (toSAN(self.board, entry[0]), entry[1] * 100.0 / totalWeight)) elif lines[0] == "undo": self.__stopSearching() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] == "remove": self.__stopSearching() self.board.popMove() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] in ("hard", "easy"): self.ponder = (lines[0] == "hard") elif lines[0] in ("post", "nopost"): self.post = (lines[0] == "post") elif lines[0] == "analyze": self.analyzing = True self.__analyze() elif lines[0] in ("name", "rating", "ics", "computer"): pass # We don't care. # Unimplemented: pause, resume elif lines[0] == "memory": # FIXME: this is supposed to control the *total* memory use. if lsearch.searching: self.print("Error (already searching):", line) else: limit = int(lines[1]) if limit < 1: self.print("Error (limit too low):", line) else: pass # TODO implement #lsearch.setHashSize(limit) elif lines[0] == "cores": pass # We aren't SMP-capable. elif lines[0] == "egtpath": if len(lines) >= 3 and lines[1] == "gaviota": conf.set("egtb_path", conf.get("egtb_path", lines[2])) from pychess.Utils.lutils.lsearch import enableEGTB enableEGTB() elif lines[0] == "option" and len(lines) > 1: name, eq, value = lines[1].partition("=") if value: value = int( value ) # CECP spec says option values are *always* numeric if name == "skipPruneChance": if 0 <= value <= 100: self.skipPruneChance = value / 100.0 else: self.print( "Error (argument must be an integer 0..100): %s" % line) ########## CECP analyze mode commands ########## # See http://www.gnu.org/software/xboard/engine-intf.html#11 elif lines[0] == "exit": if self.analyzing: self.__stopSearching() self.analyzing = False # Periodic updates (".") are not implemented. ########## Custom commands ########## elif lines[0] == "moves": self.print(self.board) self.print([ toSAN(self.board, move) for move in genAllMoves(self.board) ]) elif lines[0] == "captures": self.print(self.board) self.print([ toSAN(self.board, move) for move in genCaptures(self.board) ]) elif lines[0] == "evasions": self.print(self.board) self.print([ toSAN(self.board, move) for move in genCheckEvasions(self.board) ]) elif lines[0] == "benchmark": benchmark() elif lines[0] == "profile": if len(lines) > 1: import cProfile cProfile.runctx("benchmark()", locals(), globals(), lines[1]) else: self.print("Usage: profile outputfilename") elif lines[0] == "perft": root = "0" if len(lines) < 3 else lines[2] depth = "1" if len(lines) == 1 else lines[1] if root.isdigit() and depth.isdigit(): perft(self.board, int(depth), int(root)) else: self.print("Error (arguments must be integer") elif len(lines) == 1: # A GUI without usermove support might try to send a move. try: move = parseAny(self.board, line) except: self.print("Error (unknown command): %s" % line) continue if not validateMove(self.board, move): self.print("Illegal move: %s" % lines[0]) self.print(self.board) continue self.__stopSearching() self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() else: self.print("Error (unknown command): %s" % line) except IndexError: self.print("Error (missing argument): %s" % line)
def run (self): while True: try: line = raw_input() except EOFError: line = "quit" lines = line.split() if 1: #try: if not lines: continue ########## CECP commands ########## # See http://www.gnu.org/software/xboard/engine-intf.html#8 elif lines[0] == "xboard": pass elif lines[0] == "protover": stringPairs = ["=".join([k, '"%s"' % v if type(v) is str else str(v)]) for k,v in self.features.iteritems()] print "feature %s" % " ".join(stringPairs) print "feature done=1" elif lines[0] in ("accepted", "rejected"): # We only really care about one case: if tuple(lines) == ("rejected", "debug"): self.debug = False elif lines[0] == "new": self.__stopSearching() self.board = LBoard(NORMALCHESS) self.board.applyFen(FEN_START) self.forced = False self.playingAs = BLACK self.clock[:] = self.basetime, self.basetime self.searchtime = 0 self.sd = MAXPLY if self.analyzing: self.__analyze() elif lines[0] == "variant": if len(lines) > 1: if lines[1] == "fischerandom": self.board.variant = FISCHERRANDOMCHESS elif lines[1] == "crazyhouse": self.board.variant = CRAZYHOUSECHESS self.board.iniHouse() elif lines[1] == "wildcastle": self.board.variant = WILDCASTLESHUFFLECHESS elif lines[1] == "losers": self.board.variant = LOSERSCHESS elif lines[1] == "suicide": self.board.variant = SUICIDECHESS elif lines[1] == "atomic": self.board.variant = ATOMICCHESS self.board.iniAtomic() elif lines[0] == "quit": self.forced = True self.__stopSearching() sys.exit(0) elif lines[0] == "random": leval.random = True elif lines[0] == "force": if not self.forced and not self.analyzing: self.forced = True self.__stopSearching() elif lines[0] == "go": self.playingAs = self.board.color self.forced = False self.__go() elif lines[0] == "playother": self.playingAs = 1-self.board.color self.forced = False # TODO: start pondering, if possible elif lines[0] in ("black", "white"): newColor = lines[0] == "black" and BLACK or WHITE self.__stopSearching() self.playingAs = 1-newColor if self.board.color != newColor: self.board.setColor(newColor) self.board.setEnpassant(None) if self.analyzing: self.__analyze() elif lines[0] == "level": self.movestogo = int(lines[1]) inc = int(lines[3]) minutes = lines[2].split(":") # Per protocol spec, strip off any non-numeric suffixes. for i in xrange(len(minutes)): minutes[i] = re.match(r'\d*', minutes[i]).group() self.basetime = int(minutes[0])*60 if len(minutes) > 1 and minutes[1]: self.basetime += int(minutes[1]) self.clock[:] = self.basetime, self.basetime self.increment = inc, inc elif lines[0] == "st": self.searchtime = float(lines[1]) elif lines[0] == "sd": self.sd = int(lines[1]) # Unimplemented: nps elif lines[0] == "time": self.clock[self.playingAs] = float(lines[1])/100. elif lines[0] == "otim": self.clock[1-self.playingAs] = float(lines[1])/100. elif lines[0] == "usermove": self.__stopSearching() try: move = parseAny (self.board, lines[1]) except ParsingError, e: print "Error (unknown command):", lines[1] print self.board continue if not validateMove(self.board, move): print "Illegal move", lines[1] print self.board continue self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() elif lines[0] == "?": if not self.forced and not self.analyzing: self.__stopSearching() elif lines[0] == "ping": print "pong", lines[1] elif lines[0] == "draw": if self.__willingToDraw(): print "offer draw" elif lines[0] == "result": # We don't really care what the result is at the moment. pass elif lines[0] == "setboard": self.__stopSearching() try: self.board = LBoard(self.board.variant) fen = " ".join(lines[1:]) self.board.applyFen(fen.replace("[", "/").replace("]", "")) except SyntaxError as e: print "tellusererror Illegal position:", str(e) if self.analyzing: self.__analyze() # "edit" is unimplemented. See docs. Exiting edit mode returns to analyze mode. elif lines[0] == "hint": pass # TODO: Respond "Hint: MOVE" if we have an expected reply elif lines[0] == "bk": entries = getOpenings(self.board) if entries: totalWeight = sum(entry[1] for entry in entries) for entry in entries: print "\t%s\t%02.2f%%" % (toSAN(self.board, entry[0]), entry[1] * 100.0 / totalWeight) elif lines[0] == "undo": self.__stopSearching() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] == "remove": self.__stopSearching() self.board.popMove() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] in ("hard", "easy"): self.ponder = (lines[0] == "hard") elif lines[0] in ("post", "nopost"): self.post = (lines[0] == "post") elif lines[0] == "analyze": self.analyzing = True self.__analyze() elif lines[0] in ("name", "rating", "ics", "computer"): pass # We don't care. # Unimplemented: pause, resume elif lines[0] == "memory": # FIXME: this is supposed to control the *total* memory use. if lsearch.searching: print "Error (already searching):", line else: limit = int(lines[1]) if limit < 1: print "Error (limit too low):", line else: pass # TODO implement #lsearch.setHashSize(limit) elif lines[0] == "cores": pass # We aren't SMP-capable. elif lines[0] == "egtpath": # TODO: Accept "egtpath TYPE PATH" commands, at least for Gaviota EGTBs pass elif lines[0] == "option" and len(lines) > 1: name, eq, value = lines[1].partition("=") if value: value = int(value) # CECP spec says option values are *always* numeric if name == "skipPruneChance": if 0 <= value <= 100: self.skipPruneChance = value / 100.0 else: print "Error (argument must be an integer 0..100):", line ########## CECP analyze mode commands ########## # See http://www.gnu.org/software/xboard/engine-intf.html#11 elif lines[0] == "exit": if self.analyzing: self.__stopSearching() self.analyzing = False # Periodic updates (".") are not implemented. ########## Custom commands ########## elif lines[0] == "egtb": enableEGTB() elif lines[0] == "benchmark": benchmark() elif lines[0] == "profile": if len(lines) > 1: import cProfile cProfile.runctx("benchmark()", locals(), globals(), lines[1]) else: print "Usage: profile outputfilename" elif len(lines) == 1: # A GUI without usermove support might try to send a move. try: move = parseAny (self.board, line) except: print "Error (unknown command):", line continue if not validateMove(self.board, move): print "Illegal move", lines[0] print self.board continue self.__stopSearching() self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() else: print "Error (unknown command):", line
def run(self): while True: try: line = get_input() except EOFError: line = "quit" lines = line.split() try: if not lines: continue log.debug(line, extra={"task": "xboard"}) # CECP commands # See http://home.hccnet.nl/h.g.muller/engine-intf.html if lines[0] == "xboard": pass elif lines[0] == "protover": stringPairs = ["=".join([k, '"%s"' % v if isinstance( v, str) else str(v)]) for k, v in self.features.items()] self.print("feature %s" % " ".join(stringPairs)) self.print("feature done=1") elif lines[0] in ("accepted", "rejected"): # We only really care about one case: if tuple(lines) == ("rejected", "debug"): self.debug = False elif lines[0] == "new": self.__stopSearching() self.board = LBoard(NORMALCHESS) self.board.applyFen(FEN_START) self.outOfBook = False self.forced = False self.playingAs = BLACK self.clock[:] = self.basetime, self.basetime self.searchtime = 0 self.sd = MAXPLY if self.analyzing: self.__analyze() elif lines[0] == "variant": if len(lines) > 1: if lines[1] == "fischerandom": self.board.variant = FISCHERRANDOMCHESS elif lines[1] == "crazyhouse": self.board.variant = CRAZYHOUSECHESS self.board.iniHouse() elif lines[1] == "wildcastle": self.board.variant = WILDCASTLESHUFFLECHESS elif lines[1] == "losers": self.board.variant = LOSERSCHESS elif lines[1] == "suicide": self.board.variant = SUICIDECHESS elif lines[1] == "giveaway": self.board.variant = GIVEAWAYCHESS elif lines[1] == "atomic": self.board.variant = ATOMICCHESS self.board.iniAtomic() elif lines[1] == "3check": self.board.variant = THREECHECKCHESS elif lines[1] == "kingofthehill": self.board.variant = KINGOFTHEHILLCHESS self.print("setup (PNBRQKpnbrqk) 8x8+0_fairy %s" % FEN_START) elif lines[1] == "horde": self.board = LBoard(HORDECHESS) self.board.applyFen(HORDESTART) elif lines[1] == "asean": self.board = LBoard(ASEANCHESS) self.board.applyFen(ASEANSTART) elif lines[1] == "makruk": self.board = LBoard(MAKRUKCHESS) self.board.applyFen(MAKRUKSTART) elif lines[1] == "cambodian": self.board = LBoard(CAMBODIANCHESS) self.board.applyFen(KAMBODIANSTART) self.print( "setup (PN.R.M....SKpn.r.m....sk) 8x8+0_makruk %s" % KAMBODIANSTART) self.print("piece K& KiN") self.print("piece M& FifD") elif lines[1] == "sittuyin": self.board = LBoard(SITTUYINCHESS) self.board.applyFen(SITTUYINSTART) self.print( "setup (PN.R.F....SKpn.r.f....sk) 8x8+6_bughouse %s" % SITTUYINSTART) self.print("piece N& Nj@3") self.print("piece S& FfWj@3") self.print("piece F& Fjb@3") self.print("piece R& R@1") self.print("piece K& Kj@3") self.print("piece P& fmWfcFj@3") elif lines[0] == "quit": self.forced = True self.__stopSearching() sys.exit(0) elif lines[0] == "random": leval.random = True elif lines[0] == "force": if not self.forced and not self.analyzing: self.forced = True self.__stopSearching() elif lines[0] == "go": self.playingAs = self.board.color self.forced = False self.__go() elif lines[0] == "playother": self.playingAs = 1 - self.board.color self.forced = False # TODO: start pondering, if possible elif lines[0] in ("black", "white"): newColor = lines[0] == "black" and BLACK or WHITE self.__stopSearching() self.playingAs = 1 - newColor if self.board.color != newColor: self.board.setColor(newColor) self.board.setEnpassant(None) if self.analyzing: self.__analyze() elif lines[0] == "level": self.movestogo = int(lines[1]) inc = int(lines[3]) minutes = lines[2].split(":") # Per protocol spec, strip off any non-numeric suffixes. for i in range(len(minutes)): minutes[i] = re.match(r'\d*', minutes[i]).group() self.basetime = int(minutes[0]) * 60 if len(minutes) > 1 and minutes[1]: self.basetime += int(minutes[1]) self.clock[:] = self.basetime, self.basetime self.increment = inc, inc elif lines[0] == "st": self.searchtime = float(lines[1]) elif lines[0] == "sd": self.sd = int(lines[1]) # Unimplemented: nps elif lines[0] == "time": self.clock[self.playingAs] = float(lines[1]) / 100. elif lines[0] == "otim": self.clock[1 - self.playingAs] = float(lines[1]) / 100. elif lines[0] == "usermove": self.__stopSearching() try: move = parseAny(self.board, lines[1]) except ParsingError as err: self.print("Error (unknown command): %s" % lines[1]) self.print(self.board.prepr(ascii=ASCII)) continue if not validateMove(self.board, move): self.print("Illegal move: %s" % lines[1]) self.print(self.board.prepr(ascii=ASCII)) continue self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() elif lines[0] == "?": if not self.forced and not self.analyzing: self.__stopSearching() elif lines[0] == "ping": self.print("pong %s" % lines[1]) elif lines[0] == "draw": if self.__willingToDraw(): self.print("offer draw") elif lines[0] == "result": # We don't really care what the result is at the moment. pass elif lines[0] == "setboard": self.__stopSearching() try: self.board = LBoard(self.board.variant) fen = " ".join(lines[1:]) self.board.applyFen(fen.replace("[", "/").replace("]", "")) except SyntaxError as err: self.print("tellusererror Illegal position: %s" % str(err)) # "edit" is unimplemented. See docs. Exiting edit mode returns to analyze mode. elif lines[0] == "hint": pass # TODO: Respond "Hint: MOVE" if we have an expected reply elif lines[0] == "bk": entries = getOpenings(self.board) if entries: totalWeight = sum(entry[1] for entry in entries) for entry in entries: self.print("\t%s\t%02.2f%%" % (toSAN(self.board, entry[0]), entry[1] * 100.0 / totalWeight)) elif lines[0] == "undo": self.__stopSearching() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] == "remove": self.__stopSearching() self.board.popMove() self.board.popMove() if self.analyzing: self.__analyze() elif lines[0] in ("hard", "easy"): self.ponder = (lines[0] == "hard") elif lines[0] in ("post", "nopost"): self.post = (lines[0] == "post") elif lines[0] == "analyze": self.analyzing = True self.__analyze() elif lines[0] in ("name", "rating", "ics", "computer"): pass # We don't care. # Unimplemented: pause, resume elif lines[0] == "memory": # FIXME: this is supposed to control the *total* memory use. if lsearch.searching: self.print("Error (already searching):", line) else: limit = int(lines[1]) if limit < 1: self.print("Error (limit too low):", line) else: pass # TODO implement # lsearch.setHashSize(limit) elif lines[0] == "cores": pass # We aren't SMP-capable. elif lines[0] == "egtpath": if len(lines) >= 3 and lines[1] == "gaviota": conf.set("egtb_path", conf.get("egtb_path", lines[2])) from pychess.Utils.lutils.lsearch import enableEGTB enableEGTB() elif lines[0] == "option" and len(lines) > 1: name, eq, value = lines[1].partition("=") if value: value = int( value ) # CECP spec says option values are *always* numeric if name == "skipPruneChance": if 0 <= value <= 100: self.skipPruneChance = value / 100.0 else: self.print( "Error (argument must be an integer 0..100): %s" % line) # CECP analyze mode commands # See http://www.gnu.org/software/xboard/engine-intf.html#11 elif lines[0] == "exit": if self.analyzing: self.__stopSearching() self.analyzing = False # Periodic updates (".") are not implemented. # Custom commands elif lines[0] == "moves": self.print(self.board.prepr(ascii=ASCII)) self.print([toSAN(self.board, move) for move in genAllMoves(self.board)]) elif lines[0] == "captures": self.print(self.board.prepr(ascii=ASCII)) self.print([toSAN(self.board, move) for move in genCaptures(self.board)]) elif lines[0] == "evasions": self.print(self.board.prepr(ascii=ASCII)) self.print([toSAN(self.board, move) for move in genCheckEvasions(self.board)]) elif lines[0] == "benchmark": if len(lines) > 1: benchmark(int(lines[1])) else: benchmark() elif lines[0] == "profile": if len(lines) > 1: import cProfile cProfile.runctx("benchmark()", locals(), globals(), lines[1]) else: self.print("Usage: profile outputfilename") elif lines[0] == "perft": root = "0" if len(lines) < 3 else lines[2] depth = "1" if len(lines) == 1 else lines[1] if root.isdigit() and depth.isdigit(): perft(self.board, int(depth), int(root)) else: self.print("Error (arguments must be integer") elif lines[0] == "stop_unittest": break elif len(lines) == 1: # A GUI without usermove support might try to send a move. try: move = parseAny(self.board, line) except ParsingError: self.print("Error (unknown command): %s" % line) continue if not validateMove(self.board, move): self.print("Illegal move: %s" % lines[0]) self.print(self.board.prepr(ascii=ASCII)) continue self.__stopSearching() self.board.applyMove(move) self.playingAs = self.board.color if not self.forced and not self.analyzing: self.__go() if self.analyzing: self.__analyze() else: self.print("Error (unknown command): %s" % line) except IndexError: self.print("Error (missing argument): %s" % line)