def makeReady(self): signal.signal(signal.SIGINT, Gtk.main_quit) PyChess.makeReady(self) self.connection = FICSMainConnection("freechess.org", self.ports, self.username, self.password) self.connection.connect("connectingMsg", self.__showConnectLog) self.connection._connect() self.connection.glm.connect("addPlayer", self.__onAddPlayer) self.connection.glm.connect("removePlayer", self.__onRemovePlayer) self.connection.cm.connect("privateMessage", self.__onTell) self.connection.alm.connect("logOut", self.__onLogOut) self.connection.bm.connect("playGameCreated", self.__onGameCreated) self.connection.bm.connect("curGameEnded", self.__onGameEnded) self.connection.bm.connect("boardUpdate", self.__onBoardUpdate) self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd) self.connection.om.connect("onOfferAdd", self.__onOfferAdd) self.connection.adm.connect("onAdjournmentsList", self.__onAdjournmentsList) self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove) self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove) self.connection.adm.queryAdjournments() self.connection.lvm.setVariable("autoflag", 1) self.connection.fm.setFingerNote( 1, "PyChess is the chess engine bundled with the PyChess %s " % pychess.VERSION + "chess client. This instance is owned by %s, but acts " % self.owner + "quite autonomously.") self.connection.fm.setFingerNote( 2, "PyChess is 100% Python code and is released under the terms of " + "the GPL. The evalution function is largely equal to the one of" + "GnuChess, but it plays quite differently.") self.connection.fm.setFingerNote( 3, "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 " + "MB DDR2 Ram, but is built to take use of 64bit calculating when " + "accessible, through the gpm library.") self.connection.fm.setFingerNote( 4, "PyChess uses a small 500 KB openingbook based solely on Kasparov " + "games. The engine doesn't have much endgame knowledge, but might " + "in some cases access an online endgamedatabase.") self.connection.fm.setFingerNote( 5, "PyChess will allow any pause/resume and adjourn wishes, but will " + "deny takebacks. Draw, abort and switch offers are accepted, " + "if they are found to be an advance. Flag is auto called, but " + "PyChess never resigns. We don't want you to forget your basic " + "mating skills.")
def onConnectClicked(self, button): self.canceled = False self.widgets["messagePanel"].hide() if self.widgets["logOnAsGuest"].get_active(): username = self.widgets["nameEntry"].get_text() password = "" else: username = self.widgets["nameEntry"].get_text() password = self.widgets["passEntry"].get_text() if port: ports = (port, ) else: ports = self.widgets["portsEntry"].get_text() ports = list(map(int, re.findall("\d+", ports))) if 5000 not in ports: ports.append(5000) if 23 not in ports: ports.append(23) alternate_host = self.widgets["hostEntry"].get_text() timeseal = self.widgets["timesealCheck"].get_active() self.showConnecting() self.host = (host if host is not None else alternate_host if alternate_host else "freechess.org") self.connection = FICSMainConnection(self.host, ports, timeseal, username, password) for signal, callback in ( ("connected", self.onConnected), ("error", self.onConnectionError), ("connectingMsg", self.showMessage), ): self.cids[self.connection].append( self.connection.connect(signal, callback)) self.main_connected_event = asyncio.Event() self.connection_task = create_task(self.connection.start()) # guest users are rather limited on ICC (helper connection is useless) if self.host not in ("localhost", "127.0.0.1", "chessclub.com"): self.helperconn = FICSHelperConnection(self.connection, self.host, ports, timeseal) self.helperconn.connect("error", self.onHelperConnectionError) @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() yield from self.helperconn.start() self.helperconn_task = create_task(coro())
def onConnectClicked(self, button): self.canceled = False self.widgets["messagePanel"].hide() if self.widgets["logOnAsGuest"].get_active(): username = self.widgets["nameEntry"].get_text() password = "" else: username = self.widgets["nameEntry"].get_text() password = self.widgets["passEntry"].get_text() if port: ports = (port, ) else: ports = self.widgets["portsEntry"].get_text() ports = list(map(int, re.findall("\d+", ports))) if 5000 not in ports: ports.append(5000) if 23 not in ports: ports.append(23) alternate_host = self.widgets["hostEntry"].get_text() timeseal = self.widgets["timesealCheck"].get_active() self.showConnecting() self.host = host if host is not None else alternate_host if alternate_host else "freechess.org" self.connection = FICSMainConnection(self.host, ports, timeseal, username, password) for signal, callback in (("connected", self.onConnected), ("error", self.onConnectionError), ("connectingMsg", self.showMessage)): self.cids[self.connection].append(self.connection.connect(signal, callback)) self.main_connected_event = asyncio.Event() self.connection_task = asyncio.async(self.connection.start()) # guest users are rather limited on ICC (helper connection is useless) if self.host not in ("localhost", "127.0.0.1", "chessclub.com"): self.helperconn = FICSHelperConnection(self.connection, self.host, ports, timeseal) self.helperconn.connect("error", self.onHelperConnectionError) @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() yield from self.helperconn.start() self.helperconn_task = asyncio.async(coro())
class ICLogon: def __init__(self): self.connection = None self.helperconn = None self.connection_task = None self.helperconn_task = None self.lounge = None self.canceled = False self.cids = defaultdict(list) self.widgets = uistuff.GladeWidgets("fics_logon.glade") uistuff.keepWindowSize("fics_logon", self.widgets["fics_logon"], defaultPosition=uistuff.POSITION_GOLDEN) self.widgets["fics_logon"].connect( 'key-press-event', lambda w, e: e.keyval == Gdk.KEY_Escape and w.hide()) self.ics = "FICS" self.as_guest = self.widgets["logOnAsGuest"] self.widgets["logOnAsGuest"].connect("toggled", self.on_logOnAsGuest_toggled) def on_username_changed(widget): conf.set("usernameEntry", self.user_name_get_value(widget), section=self.ics) self.widgets["nameEntry"].connect("changed", on_username_changed) def on_password_changed(widget): conf.set("passwordEntry", widget.get_text(), section=self.ics) self.widgets["passEntry"].connect("changed", on_password_changed) def on_host_changed(widget): conf.set("hostEntry", self.host_get_value(widget), section=self.ics) self.widgets["hostEntry"].connect("changed", on_host_changed) self.widgets["timesealCheck"].connect("toggled", self.on_timeseal_toggled) self.infobar = Gtk.InfoBar() self.infobar.set_message_type(Gtk.MessageType.WARNING) # self.widgets["messagePanelHBox"].pack_start(self.infobar, # expand=False, fill=False) self.widgets["messagePanelHBox"].pack_start(self.infobar, False, False, 0) self.widgets["cancelButton"].connect("clicked", self.onCancel, True) self.widgets["stopButton"].connect("clicked", self.onCancel, False) self.widgets["createNewButton"].connect("clicked", self.onCreateNew) self.widgets["connectButton"].connect("clicked", self.onConnectClicked) self.widgets["progressbar"].set_show_text(True) def get_user_names(self, value=None): """ Split and return usernameEntry config item into registered and guest username """ if value is not None: names = value.split("|") else: names = conf.get("usernameEntry", section=self.ics).split("|") if len(names) == 0: names = ["", ""] elif len(names) < 2: names.append(names[0]) return names def user_name_get_value(self, entry): names = self.get_user_names() if self.as_guest.get_active(): text = "%s|%s" % (names[0], entry.get_text()) else: text = "%s|%s" % (entry.get_text(), names[1]) return text def user_name_set_value(self, entry, value): names = self.get_user_names(value=value) if self.as_guest.get_active(): entry.set_text(names[1]) else: entry.set_text(names[0]) # workaround to FICS Password input doesnt handle strings starting with a number # https://github.com/pychess/pychess/issues/1375 def password_set_value(self, entry, value): entry.set_text(str(value)) # workaround to Can't type IP to FICS login dialog # https://github.com/pychess/pychess/issues/1360 def host_get_value(self, entry): return entry.get_text().replace(".", "|") def host_set_value(self, entry, value): entry.set_text(str(value).replace("|", ".")) def on_logOnAsGuest_toggled(self, widget): names = self.get_user_names() self.widgets["nameEntry"].set_text( names[1] if widget.get_active() else names[0]) if self.ics == "ICC": self.widgets["nameLabel"].set_sensitive(not widget.get_active()) self.widgets["nameEntry"].set_sensitive(not widget.get_active()) else: self.widgets["nameLabel"].set_sensitive(True) self.widgets["nameEntry"].set_sensitive(True) self.widgets["passwordLabel"].set_sensitive(not widget.get_active()) self.widgets["passEntry"].set_sensitive(not widget.get_active()) conf.set("asGuestCheck", widget.get_active(), section=self.ics) def on_timeseal_toggled(self, widget): conf.set("timesealCheck", widget.get_active(), section=self.ics) def on_ics_combo_changed(self, combo): tree_iter = combo.get_active_iter() if tree_iter is not None: model = combo.get_model() self.ics = model[tree_iter][0] # print("Selected: %s" % self.ics) self.widgets["logOnAsGuest"].set_active( conf.get("asGuestCheck", section=self.ics)) self.on_logOnAsGuest_toggled(self.widgets["logOnAsGuest"]) self.user_name_set_value( self.widgets["nameEntry"], conf.get("usernameEntry", section=self.ics)) self.password_set_value( self.widgets["passEntry"], conf.get("passwordEntry", section=self.ics)) self.host_set_value(self.widgets["hostEntry"], conf.get("hostEntry", section=self.ics)) self.widgets["timesealCheck"].set_active( conf.get("timesealCheck", section=self.ics)) self.on_timeseal_toggled(self.widgets["timesealCheck"]) def _disconnect(self): for obj in self.cids: for cid in self.cids[obj]: if obj.handler_is_connected(cid): obj.disconnect(cid) self.cids.clear() if self.connection is not None: self.connection.close() if not self.connection_task.cancelled(): self.connection_task.cancel() self.connection = None if self.helperconn is not None: self.helperconn.close() if not self.helperconn_task.cancelled(): self.helperconn_task.cancel() self.helperconn = None self.lounge = None def _cancel(self): if self.connection is not None: self.connection.cancel() if self.helperconn is not None: self.helperconn.cancel() self._disconnect() def show(self): self.widgets["fics_logon"].show() def present(self): self.widgets["fics_logon"].present() def hide(self): self.widgets["fics_logon"].hide() def showConnecting(self): self.widgets["progressbarBox"].show() self.widgets["mainbox"].set_sensitive(False) self.widgets["connectButton"].hide() self.widgets["stopButton"].show() def pulse(): self.widgets["progressbar"].pulse() if self.connection is None: return False else: return not self.connection.isConnected() self.pulser = GLib.timeout_add(30, pulse) def showNormal(self): self.widgets["mainbox"].set_sensitive(True) self.widgets["connectButton"].show() self.widgets["fics_logon"].set_default(self.widgets["connectButton"]) self.widgets["stopButton"].hide() self.widgets["progressbarBox"].hide() self.widgets["progressbar"].set_text("") GObject.source_remove(self.pulser) def showMessage(self, connection, message): self.widgets["progressbar"].set_text(message) def showError(self, connection, error): text = str(error) if isinstance(error, IOError): title = _("Connection Error") elif isinstance(error, LogOnException): title = _("Log on Error") elif isinstance(error, EOFError): title = _("Connection was closed") elif isinstance(error, socket.error): title = _("Connection Error") text = ", ".join(map(str, error.args)) elif isinstance(error, socket.gaierror) or \ isinstance(error, socket.herror): title = _("Address Error") text = ", ".join(map(str, error.args)) elif isinstance(error, AutoLogoutException): title = _("Auto-logout") text = _( "You have been logged out because you were idle more than 60 minutes" ) else: title = str(error.__class__) self.showNormal() content_area = self.infobar.get_content_area() for widget in content_area: content_area.remove(widget) content = Gtk.HBox() image = Gtk.Image() image.set_from_stock(Gtk.STOCK_DIALOG_WARNING, Gtk.IconSize.DIALOG) content.pack_start(image, False, False, 0) vbox = Gtk.VBox() label = Gtk.Label() label.props.xalign = 0 label.props.justify = Gtk.Justification.LEFT label.set_markup("<b><big>%s</big></b>" % title) vbox.pack_start(label, True, False, 0) for line in str(text).split("\n"): label = Gtk.Label() label.set_size_request(476, -1) label.props.selectable = True label.props.wrap = True label.props.xalign = 0 label.props.justify = Gtk.Justification.LEFT label.set_markup(line) vbox.pack_start(label, True, False, 0) content.pack_start(vbox, False, False, 7) content_area.add(content) self.widgets["messagePanel"].show_all() def onCreateNew(self, button): if self.widgets["hostEntry"].get_text() == "chessclub.com": webbrowser.open( "https://store.chessclub.com/customer/account/create/") else: webbrowser.open("http://www.freechess.org/Register/index.html") def onConnectClicked(self, button): self.canceled = False self.widgets["messagePanel"].hide() if self.widgets["logOnAsGuest"].get_active(): username = self.widgets["nameEntry"].get_text() password = "" else: username = self.widgets["nameEntry"].get_text() password = self.widgets["passEntry"].get_text() if port: ports = (port, ) else: ports = self.widgets["portsEntry"].get_text() ports = list(map(int, re.findall(r"\d+", ports))) if 5000 not in ports: ports.append(5000) if 23 not in ports: ports.append(23) alternate_host = self.widgets["hostEntry"].get_text() timeseal = self.widgets["timesealCheck"].get_active() self.showConnecting() self.host = host if host is not None else alternate_host if alternate_host else "freechess.org" self.connection = FICSMainConnection(self.host, ports, timeseal, username, password) for signal, callback in (("connected", self.onConnected), ("error", self.onConnectionError), ("connectingMsg", self.showMessage)): self.cids[self.connection].append( self.connection.connect(signal, callback)) self.main_connected_event = asyncio.Event() self.connection_task = create_task(self.connection.start()) # guest users are rather limited on ICC (helper connection is useless) if self.host not in ("localhost", "127.0.0.1", "chessclub.com"): self.helperconn = FICSHelperConnection(self.connection, self.host, ports, timeseal) self.helperconn.connect("error", self.onHelperConnectionError) @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() yield from self.helperconn.start() self.helperconn_task = create_task(coro()) def onHelperConnectionError(self, connection, error): if self.helperconn is not None: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("Guest logins disabled by FICS server")) text = "PyChess can maintain users status and games list only if it changes\n\ 'open', 'gin' and 'availinfo' user variables.\n\ Do you enable to set these variables on?" dialog.format_secondary_text(text) response = dialog.run() dialog.destroy() self.helperconn.cancel() self.helperconn.close() self.helperconn = None set_user_vars = response == Gtk.ResponseType.YES @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() self.connection.start_helper_manager(set_user_vars) create_task(coro()) def onConnected(self, connection): self.main_connected_event.set() if connection.ICC: self.connection.start_helper_manager(True) self.lounge = perspective_manager.get_perspective("fics") self.lounge.open_lounge(connection, self.helperconn, self.host) self.hide() self.lounge.show() self.lounge.connect("logout", lambda iclounge: self.onLogout(connection)) self.cids[self.lounge].append( self.lounge.connect("autoLogout", lambda lounge: self.onAutologout(connection))) self.showNormal() self.widgets["messagePanel"].hide() def onCancel(self, widget, hide): self.canceled = True if self.connection and self.connection.isConnecting(): self._cancel() self.showNormal() if hide: self.widgets["fics_logon"].hide() def onConnectionError(self, connection, error): self._disconnect() if not self.canceled: self.showError(connection, error) self.present() def onLogout(self, connection): self._disconnect() def onAutologout(self, connection): self._disconnect() self.showError(connection, AutoLogoutException()) self.present()
class ICLogon(object): def __init__(self): self.connection = None self.helperconn = None self.connection_task = None self.helperconn_task = None self.lounge = None self.canceled = False self.cids = defaultdict(list) self.widgets = uistuff.GladeWidgets("fics_logon.glade") uistuff.keepWindowSize("fics_logon", self.widgets["fics_logon"], defaultPosition=uistuff.POSITION_GOLDEN) self.widgets["fics_logon"].connect( 'key-press-event', lambda w, e: e.keyval == Gdk.KEY_Escape and w.hide()) self.ics = "FICS" self.as_guest = self.widgets["logOnAsGuest"] self.widgets["logOnAsGuest"].connect("toggled", self.on_logOnAsGuest_toggled) def on_username_changed(widget): conf.set("usernameEntry", self.user_name_get_value(widget), section=self.ics) self.widgets["nameEntry"].connect("changed", on_username_changed) def on_password_changed(widget): conf.set("passwordEntry", widget.get_text(), section=self.ics) self.widgets["passEntry"].connect("changed", on_password_changed) def on_host_changed(widget): conf.set("hostEntry", self.host_get_value(widget), section=self.ics) self.widgets["hostEntry"].connect("changed", on_host_changed) self.widgets["timesealCheck"].connect("toggled", self.on_timeseal_toggled) self.infobar = Gtk.InfoBar() self.infobar.set_message_type(Gtk.MessageType.WARNING) # self.widgets["messagePanelHBox"].pack_start(self.infobar, # expand=False, fill=False) self.widgets["messagePanelHBox"].pack_start(self.infobar, False, False, 0) self.widgets["cancelButton"].connect("clicked", self.onCancel, True) self.widgets["stopButton"].connect("clicked", self.onCancel, False) self.widgets["createNewButton"].connect("clicked", self.onCreateNew) self.widgets["connectButton"].connect("clicked", self.onConnectClicked) self.widgets["progressbar"].set_show_text(True) def get_user_names(self, value=None): """ Split and return usernameEntry config item into registered and guest username """ if value is not None: names = value.split("|") else: names = conf.get("usernameEntry", "", section=self.ics).split("|") if len(names) == 0: names = ["", ""] elif len(names) < 2: names.append(names[0]) return names def user_name_get_value(self, entry): names = self.get_user_names() if self.as_guest.get_active(): text = "%s|%s" % (names[0], entry.get_text()) else: text = "%s|%s" % (entry.get_text(), names[1]) return text def user_name_set_value(self, entry, value): names = self.get_user_names(value=value) if self.as_guest.get_active(): entry.set_text(names[1]) else: entry.set_text(names[0]) # workaround to FICS Password input doesnt handle strings starting with a number # https://github.com/pychess/pychess/issues/1375 def password_set_value(self, entry, value): entry.set_text(str(value)) # workaround to Can't type IP to FICS login dialog # https://github.com/pychess/pychess/issues/1360 def host_get_value(self, entry): return entry.get_text().replace(".", "|") def host_set_value(self, entry, value): entry.set_text(str(value).replace("|", ".")) def on_logOnAsGuest_toggled(self, widget): names = self.get_user_names() self.widgets["nameEntry"].set_text(names[1] if widget.get_active() else names[0]) if self.ics == "ICC": self.widgets["nameLabel"].set_sensitive(not widget.get_active()) self.widgets["nameEntry"].set_sensitive(not widget.get_active()) else: self.widgets["nameLabel"].set_sensitive(True) self.widgets["nameEntry"].set_sensitive(True) self.widgets["passwordLabel"].set_sensitive(not widget.get_active()) self.widgets["passEntry"].set_sensitive(not widget.get_active()) conf.set("asGuestCheck", widget.get_active(), section=self.ics) def on_timeseal_toggled(self, widget): conf.set("timesealCheck", widget.get_active(), section=self.ics) def on_ics_combo_changed(self, combo): tree_iter = combo.get_active_iter() if tree_iter is not None: model = combo.get_model() self.ics = model[tree_iter][0] # print("Selected: %s" % self.ics) self.widgets["logOnAsGuest"].set_active(conf.get("asGuestCheck", True, section=self.ics)) self.on_logOnAsGuest_toggled(self.widgets["logOnAsGuest"]) self.user_name_set_value(self.widgets["nameEntry"], conf.get("usernameEntry", "", section=self.ics)) self.password_set_value(self.widgets["passEntry"], conf.get("passwordEntry", "", section=self.ics)) default_host = "freechess.org" if self.ics == "FICS" else "chessclub.com" self.host_set_value(self.widgets["hostEntry"], conf.get("hostEntry", default_host, section=self.ics)) self.widgets["timesealCheck"].set_active(conf.get("timesealCheck", True, section=self.ics)) self.on_timeseal_toggled(self.widgets["timesealCheck"]) def _disconnect(self): for obj in self.cids: for cid in self.cids[obj]: if obj.handler_is_connected(cid): obj.disconnect(cid) self.cids.clear() if self.connection is not None: self.connection.close() if not self.connection_task.cancelled(): self.connection_task.cancel() self.connection = None if self.helperconn is not None: self.helperconn.close() if not self.helperconn_task.cancelled(): self.helperconn_task.cancel() self.helperconn = None self.lounge = None def _cancel(self): if self.connection is not None: self.connection.cancel() if self.helperconn is not None: self.helperconn.cancel() self._disconnect() def show(self): self.widgets["fics_logon"].show() def present(self): self.widgets["fics_logon"].present() def hide(self): self.widgets["fics_logon"].hide() def showConnecting(self): self.widgets["progressbarBox"].show() self.widgets["mainbox"].set_sensitive(False) self.widgets["connectButton"].hide() self.widgets["stopButton"].show() def pulse(): self.widgets["progressbar"].pulse() if self.connection is None: return False else: return not self.connection.isConnected() self.pulser = GObject.timeout_add(30, pulse) def showNormal(self): self.widgets["mainbox"].set_sensitive(True) self.widgets["connectButton"].show() self.widgets["fics_logon"].set_default(self.widgets["connectButton"]) self.widgets["stopButton"].hide() self.widgets["progressbarBox"].hide() self.widgets["progressbar"].set_text("") GObject.source_remove(self.pulser) def showMessage(self, connection, message): self.widgets["progressbar"].set_text(message) def showError(self, connection, error): text = str(error) if isinstance(error, IOError): title = _("Connection Error") elif isinstance(error, LogOnException): title = _("Log on Error") elif isinstance(error, EOFError): title = _("Connection was closed") elif isinstance(error, socket.error): title = _("Connection Error") text = ", ".join(map(str, error.args)) elif isinstance(error, socket.gaierror) or \ isinstance(error, socket.herror): title = _("Address Error") text = ", ".join(map(str, error.args)) elif isinstance(error, AutoLogoutException): title = _("Auto-logout") text = _( "You have been logged out because you were idle more than 60 minutes") else: title = str(error.__class__) self.showNormal() content_area = self.infobar.get_content_area() for widget in content_area: content_area.remove(widget) content = Gtk.HBox() image = Gtk.Image() image.set_from_stock(Gtk.STOCK_DIALOG_WARNING, Gtk.IconSize.DIALOG) content.pack_start(image, False, False, 0) vbox = Gtk.VBox() label = Gtk.Label() label.props.xalign = 0 label.props.justify = Gtk.Justification.LEFT label.set_markup("<b><big>%s</big></b>" % title) vbox.pack_start(label, True, False, 0) for line in str(text).split("\n"): label = Gtk.Label() label.set_size_request(476, -1) label.props.selectable = True label.props.wrap = True label.props.xalign = 0 label.props.justify = Gtk.Justification.LEFT label.set_markup(line) vbox.pack_start(label, True, False, 0) content.pack_start(vbox, False, False, 7) content_area.add(content) self.widgets["messagePanel"].show_all() def onCreateNew(self, button): if self.widgets["hostEntry"].get_text() == "chessclub.com": webbrowser.open("https://store.chessclub.com/customer/account/create/") else: webbrowser.open("http://www.freechess.org/Register/index.html") def onConnectClicked(self, button): self.canceled = False self.widgets["messagePanel"].hide() if self.widgets["logOnAsGuest"].get_active(): username = self.widgets["nameEntry"].get_text() password = "" else: username = self.widgets["nameEntry"].get_text() password = self.widgets["passEntry"].get_text() if port: ports = (port, ) else: ports = self.widgets["portsEntry"].get_text() ports = list(map(int, re.findall("\d+", ports))) if 5000 not in ports: ports.append(5000) if 23 not in ports: ports.append(23) alternate_host = self.widgets["hostEntry"].get_text() timeseal = self.widgets["timesealCheck"].get_active() self.showConnecting() self.host = host if host is not None else alternate_host if alternate_host else "freechess.org" self.connection = FICSMainConnection(self.host, ports, timeseal, username, password) for signal, callback in (("connected", self.onConnected), ("error", self.onConnectionError), ("connectingMsg", self.showMessage)): self.cids[self.connection].append(self.connection.connect(signal, callback)) self.main_connected_event = asyncio.Event() self.connection_task = asyncio.async(self.connection.start()) # guest users are rather limited on ICC (helper connection is useless) if self.host not in ("localhost", "127.0.0.1", "chessclub.com"): self.helperconn = FICSHelperConnection(self.connection, self.host, ports, timeseal) self.helperconn.connect("error", self.onHelperConnectionError) @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() yield from self.helperconn.start() self.helperconn_task = asyncio.async(coro()) def onHelperConnectionError(self, connection, error): if self.helperconn is not None: dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("Guest logins disabled by FICS server")) text = "PyChess can maintain users status and games list only if it changes\n\ 'open', 'gin' and 'availinfo' user variables.\n\ Do you enable to set these variables on?" dialog.format_secondary_text(text) response = dialog.run() dialog.destroy() self.helperconn.cancel() self.helperconn.close() self.helperconn = None set_user_vars = response == Gtk.ResponseType.YES @asyncio.coroutine def coro(): yield from self.main_connected_event.wait() self.connection.start_helper_manager(set_user_vars) asyncio.async(coro()) def onConnected(self, connection): self.main_connected_event.set() if connection.ICC: self.connection.start_helper_manager(True) self.lounge = perspective_manager.get_perspective("fics") self.lounge.open_lounge(connection, self.helperconn, self.host) self.hide() self.lounge.show() self.lounge.connect("logout", lambda iclounge: self.onLogout(connection)) self.cids[self.lounge].append(self.lounge.connect( "autoLogout", lambda lounge: self.onAutologout(connection))) self.showNormal() self.widgets["messagePanel"].hide() def onCancel(self, widget, hide): self.canceled = True if self.connection and self.connection.isConnecting(): self._cancel() self.showNormal() if hide: self.widgets["fics_logon"].hide() def onConnectionError(self, connection, error): self._disconnect() if not self.canceled: self.showError(connection, error) self.present() def onLogout(self, connection): self._disconnect() def onAutologout(self, connection): self._disconnect() self.showError(connection, AutoLogoutException()) self.present()
class PyChessFICS(PyChess): def __init__ (self, password, from_address, to_address): PyChess.__init__(self) self.ports = (23, 5000) if not password: self.username = "******" else: self.username = "******" self.owner = "Lobais" self.password = password self.from_address = "The PyChess Bot <%s>" % from_address self.to_address = "Thomas Dybdahl Ahle <%s>" % to_address # Possible start times self.minutes = (1,2,3,4,5,6,7,8,9,10) self.gains = (0,5,10,15,20) # Possible colors. None == random self.colors = (WHITE, BLACK, None) # The amount of random challenges, that PyChess sends with each seek self.challenges = 10 enableEGTB() self.sudos = set() self.ownerOnline = False self.waitingForPassword = None self.log = [] self.acceptedTimesettings = [] self.worker = None repeat_sleep(self.sendChallenges, 60*1) def __triangular(self, low, high, mode): """Triangular distribution. Continuous distribution bounded by given lower and upper limits, and having a given mode value in-between. http://en.wikipedia.org/wiki/Triangular_distribution """ u = random.random() c = (mode - low) / (high - low) if u > c: u = 1 - u c = 1 - c low, high = high, low tri = low + (high - low) * (u * c) ** 0.5 if tri < mode: return int(tri) elif tri > mode: return int(math.ceil(tri)) return int(round(tri)) def sendChallenges(self): if self.connection.bm.isPlaying(): return True statsbased = ((0.39197722779282, 3, 0), (0.59341408108783, 5, 0), (0.77320877377846, 1, 0), (0.8246379941394, 10, 0), (0.87388717406441, 2, 12), (0.91443760169489, 15, 0), (0.9286423058163, 4, 0), (0.93891977227793, 2, 0), (0.94674539138335, 20, 0), (0.95321476842423, 2, 2), (0.9594588808257, 5, 2), (0.96564528079889, 3, 2), (0.97173859621034, 7, 0), (0.97774906636184, 3, 1), (0.98357243654425, 5, 12), (0.98881309737017, 5, 5), (0.99319644938247, 6, 0), (0.99675879556023, 3, 12), (1, 5, 3)) #n = random.random() #for culminativeChance, minute, gain in statsbased: # if n < culminativeChance: # break culminativeChance, minute, gain = random.choice(statsbased) #type = random.choice((TYPE_LIGHTNING, TYPE_BLITZ, TYPE_STANDARD)) #if type == TYPE_LIGHTNING: # minute = self.__triangular(0,2+1,1) # mingain = not minute and 1 or 0 # maxgain = int((3-minute)*3/2) # gain = random.randint(mingain, maxgain) #elif type == TYPE_BLITZ: # minute = self.__triangular(0,14+1,5) # mingain = max(int((3-minute)*3/2+1), 0) # maxgain = int((15-minute)*3/2) # gain = random.randint(mingain, maxgain) #elif type == TYPE_STANDARD: # minute = self.__triangular(0,20+1,12) # mingain = max(int((15-minute)*3/2+1), 0) # maxgain = int((20-minute)*3/2) # gain = self.__triangular(mingain, maxgain, mingain) #color = random.choice(self.colors) self.extendlog(["Seeking %d %d" % (minute, gain)]) self.connection.glm.seek(minute, gain, True) opps = random.sample(self.connection.players.get_online_playernames(), self.challenges) self.extendlog("Challenging %s" % op for op in opps) for player in opps: self.connection.om.challenge(player, minute, gain, True) return True def makeReady(self): signal.signal(signal.SIGINT, Gtk.main_quit) PyChess.makeReady(self) self.connection = FICSMainConnection("freechess.org", self.ports, self.username, self.password) self.connection.connect("connectingMsg", self.__showConnectLog) self.connection._connect() self.connection.glm.connect("addPlayer", self.__onAddPlayer) self.connection.glm.connect("removePlayer", self.__onRemovePlayer) self.connection.cm.connect("privateMessage", self.__onTell) self.connection.alm.connect("logOut", self.__onLogOut) self.connection.bm.connect("playGameCreated", self.__onGameCreated) self.connection.bm.connect("curGameEnded", self.__onGameEnded) self.connection.bm.connect("boardUpdate", self.__onBoardUpdate) self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd) self.connection.om.connect("onOfferAdd", self.__onOfferAdd) self.connection.adm.connect("onAdjournmentsList", self.__onAdjournmentsList) self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove) self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove) self.connection.adm.queryAdjournments() self.connection.lvm.setVariable("autoflag", 1) self.connection.fm.setFingerNote(1, "PyChess is the chess engine bundled with the PyChess %s " % pychess.VERSION + "chess client. This instance is owned by %s, but acts " % self.owner + "quite autonomously.") self.connection.fm.setFingerNote(2, "PyChess is 100% Python code and is released under the terms of " + "the GPL. The evalution function is largely equal to the one of" + "GnuChess, but it plays quite differently.") self.connection.fm.setFingerNote(3, "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 " + "MB DDR2 Ram, but is built to take use of 64bit calculating when " + "accessible, through the gpm library.") self.connection.fm.setFingerNote(4, "PyChess uses a small 500 KB openingbook based solely on Kasparov " + "games. The engine doesn't have much endgame knowledge, but might " + "in some cases access an online endgamedatabase.") self.connection.fm.setFingerNote(5, "PyChess will allow any pause/resume and adjourn wishes, but will " + "deny takebacks. Draw, abort and switch offers are accepted, " + "if they are found to be an advance. Flag is auto called, but " + "PyChess never resigns. We don't want you to forget your basic " + "mating skills.") def main(self): self.connection.run() self.extendlog([str(self.acceptedTimesettings)]) self.phoneHome("Session ended\n"+"\n".join(self.log)) print("Session ended") def run(self): t = Thread(target=self.main, name=fident(self.main)) t.daemon = True t.start() Gdk.threads_init() Gtk.main() #=========================================================================== # General #=========================================================================== def __showConnectLog (self, connection, message): print(message) def __onLogOut (self, autoLogoutManager): self.connection.close() #sys.exit() def __onAddPlayer (self, gameListManager, player): if player["name"] in self.sudos: self.sudos.remove(player["name"]) if player["name"] == self.owner: self.connection.cm.tellPlayer(self.owner, "Greetings") self.ownerOnline = True def __onRemovePlayer (self, gameListManager, playername): if playername == self.owner: self.ownerOnline = False def __onAdjournmentsList (self, adjournManager, adjournments): for adjournment in adjournments: if adjournment["online"]: adjournManager.challenge(adjournment["opponent"]) def __usage (self): return "|| PyChess bot help file || " +\ "# help 'Displays this help file' " +\ "# sudo <password> <command> 'Lets PyChess execute the given command' "+\ "# sendlog 'Makes PyChess send you its current log'" def __onTell (self, chatManager, name, title, isadmin, text): if self.waitingForPassword: if text.strip() == self.password or (not self.password and text == "none"): self.sudos.add(name) self.tellHome("%s gained sudo access" % name) self.connection.client.run_command(self.waitingForPassword) else: chatManager.tellPlayer(name, "Wrong password") self.tellHome("%s failed sudo access" % name) self.waitingForPassword = None return args = text.split() #if args == ["help"]: # chatManager.tellPlayer(name, self.__usage()) if args[0] == "sudo": command = " ".join(args[1:]) if name in self.sudos or name == self.owner: # Notice: This can be used to make nasty loops print(command, file=self.connection.client) else: print(repr(name), self.sudos) chatManager.tellPlayer(name, "Please send me the password") self.waitingForPassword = command elif args == ["sendlog"]: if self.log: # TODO: Consider email chatManager.tellPlayer(name, "\\n".join(self.log)) else: chatManager.tellPlayer(name, "The log is currently empty") else: if self.ownerOnline: self.tellHome("%s told me '%s'" % (name, text)) else: def onlineanswer (message): data = urlopen("http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895", urlencode({"message":message, "botcust2":"x"}).encode("utf-8")).read().decode('utf-8') ss = "<b>DMPGirl:</b>" es = "<br>" answer = data[data.find(ss)+len(ss) : data.find(es,data.find(ss))] chatManager.tellPlayer(name, answer) t = Thread(target=onlineanswer, name=fident(onlineanswer), args=(text,)) t.daemon = True t.start() #chatManager.tellPlayer(name, "Sorry, your request was nonsense.\n"+\ # "Please read my help file for more info") #=========================================================================== # Challenges and other offers #=========================================================================== def __onChallengeAdd (self, offerManager, index, match): #match = {"tp": type, "w": fname, "rt": rating, "color": color, # "r": rated, "t": mins, "i": incr} offerManager.acceptIndex(index) def __onOfferAdd (self, offerManager, offer): if offer.type in (PAUSE_OFFER, RESUME_OFFER, ADJOURN_OFFER): offerManager.accept(offer) elif offer.type in (TAKEBACK_OFFER,): offerManager.decline(offer) elif offer.type in (DRAW_OFFER, ABORT_OFFER, SWITCH_OFFER): if self.__willingToDraw(): offerManager.accept(offer) else: offerManager.decline(offer) #=========================================================================== # Playing #=========================================================================== def __onGameCreated (self, boardManager, ficsgame): base = int(ficsgame.minutes)*60 inc = int(ficsgame.inc) self.clock[:] = base, base self.increment[:] = inc, inc self.gameno = ficsgame.gameno self.lastPly = -1 self.acceptedTimesettings.append((base, inc)) self.tellHome("Starting a game (%s, %s) gameno: %s" % (ficsgame.wplayer.name, ficsgame.bplayer.name, ficsgame.gameno)) if ficsgame.bplayer.name.lower() == self.connection.getUsername().lower(): self.playingAs = BLACK else: self.playingAs = WHITE self.board = LBoard(NORMALCHESS) # Now we wait until we recieve the board. def __go (self): if self.worker: self.worker.cancel() self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker)) self.worker.connect("published", lambda w, msg: self.extendlog(msg)) self.worker.connect("done", self.__onMoveCalculated) self.worker.execute() def __willingToDraw (self): return self.scr <= 0 # FIXME: this misbehaves in all but the simplest use cases def __onGameEnded (self, boardManager, ficsgame): self.tellHome(reprResult_long[ficsgame.result] + " " + reprReason_long[ficsgame.reason]) lsearch.searching = False if self.worker: self.worker.cancel() self.worker = None def __onMoveCalculated (self, worker, sanmove): if worker.isCancelled() or not sanmove: return self.board.applyMove(parseSAN(self.board,sanmove)) self.connection.bm.sendMove(sanmove) self.extendlog(["Move sent %s" % sanmove]) def __onBoardUpdate (self, boardManager, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): self.extendlog(["","I got move %d %s for gameno %s" % (ply, lastmove, gameno)]) if self.gameno != gameno: return self.board.applyFen(fen) self.clock[:] = wms/1000., bms/1000. if curcol == self.playingAs: self.__go() def __onAmbiguousMove (self, errorManager, move): # This is really a fix for fics, but sometimes it is necessary if determineAlgebraicNotation(move) == SAN: self.board.popMove() move_ = parseSAN(self.board, move) lanmove = toLAN(self.board, move_) self.board.applyMove(move_) self.connection.bm.sendMove(lanmove) else: self.connection.cm.tellOpponent( "I'm sorry, I wanted to move %s, but FICS called " % move + "it 'Ambigious'. I can't find another way to express it, " + "so you can win") self.connection.bm.resign() #=========================================================================== # Utils #=========================================================================== def extendlog(self, messages): [log.info(m+"\n") for m in messages] self.log.extend(messages) del self.log[:-10] def tellHome(self, message): print(message) if self.ownerOnline: self.connection.cm.tellPlayer(self.owner, message) def phoneHome(self, message): SENDMAIL = '/usr/sbin/sendmail' SUBJECT = "Besked fra botten" p = subprocess.Popen([SENDMAIL, '-f', email.Utils.parseaddr(self.from_address)[1], email.Utils.parseaddr(self.to_address)[1]], stdin=subprocess.PIPE) print("MIME-Version: 1.0", file=p.stdin) print("Content-Type: text/plain; charset=UTF-8", file=p.stdin) print("Content-Disposition: inline", file=p.stdin) print("From: %s" % self.from_address, file=p.stdin) print("To: %s" % self.to_address, file=p.stdin) print("Subject: %s" % SUBJECT, file=p.stdin) print(file=p.stdin) print(message, file=p.stdin) print("Cheers", file=p.stdin) p.stdin.close() p.wait()
class PyChessFICS(PyChess): def __init__(self, password, from_address, to_address): PyChess.__init__(self) self.ports = (23, 5000) if not password: self.username = "******" else: self.username = "******" self.owner = "Lobais" self.password = password self.from_address = "The PyChess Bot <%s>" % from_address self.to_address = "Thomas Dybdahl Ahle <%s>" % to_address # Possible start times self.minutes = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) self.gains = (0, 5, 10, 15, 20) # Possible colors. None == random self.colors = (WHITE, BLACK, None) # The amount of random challenges, that PyChess sends with each seek self.challenges = 10 enableEGTB() self.sudos = set() self.ownerOnline = False self.waitingForPassword = None self.log = [] self.acceptedTimesettings = [] self.worker = None repeat_sleep(self.sendChallenges, 60 * 1) def __triangular(self, low, high, mode): """Triangular distribution. Continuous distribution bounded by given lower and upper limits, and having a given mode value in-between. http://en.wikipedia.org/wiki/Triangular_distribution """ u = random.random() c = (mode - low) / (high - low) if u > c: u = 1 - u c = 1 - c low, high = high, low tri = low + (high - low) * (u * c)**0.5 if tri < mode: return int(tri) elif tri > mode: return int(math.ceil(tri)) return int(round(tri)) def sendChallenges(self): if self.connection.bm.isPlaying(): return True statsbased = ((0.39197722779282, 3, 0), (0.59341408108783, 5, 0), (0.77320877377846, 1, 0), (0.8246379941394, 10, 0), (0.87388717406441, 2, 12), (0.91443760169489, 15, 0), (0.9286423058163, 4, 0), (0.93891977227793, 2, 0), (0.94674539138335, 20, 0), (0.95321476842423, 2, 2), (0.9594588808257, 5, 2), (0.96564528079889, 3, 2), (0.97173859621034, 7, 0), (0.97774906636184, 3, 1), (0.98357243654425, 5, 12), (0.98881309737017, 5, 5), (0.99319644938247, 6, 0), (0.99675879556023, 3, 12), (1, 5, 3)) #n = random.random() #for culminativeChance, minute, gain in statsbased: # if n < culminativeChance: # break culminativeChance, minute, gain = random.choice(statsbased) #type = random.choice((TYPE_LIGHTNING, TYPE_BLITZ, TYPE_STANDARD)) #if type == TYPE_LIGHTNING: # minute = self.__triangular(0,2+1,1) # mingain = not minute and 1 or 0 # maxgain = int((3-minute)*3/2) # gain = random.randint(mingain, maxgain) #elif type == TYPE_BLITZ: # minute = self.__triangular(0,14+1,5) # mingain = max(int((3-minute)*3/2+1), 0) # maxgain = int((15-minute)*3/2) # gain = random.randint(mingain, maxgain) #elif type == TYPE_STANDARD: # minute = self.__triangular(0,20+1,12) # mingain = max(int((15-minute)*3/2+1), 0) # maxgain = int((20-minute)*3/2) # gain = self.__triangular(mingain, maxgain, mingain) #color = random.choice(self.colors) self.extendlog(["Seeking %d %d" % (minute, gain)]) self.connection.glm.seek(minute, gain, True) opps = random.sample(self.connection.players.get_online_playernames(), self.challenges) self.extendlog("Challenging %s" % op for op in opps) for player in opps: self.connection.om.challenge(player, minute, gain, True) return True def makeReady(self): signal.signal(signal.SIGINT, Gtk.main_quit) PyChess.makeReady(self) self.connection = FICSMainConnection("freechess.org", self.ports, self.username, self.password) self.connection.connect("connectingMsg", self.__showConnectLog) self.connection._connect() self.connection.glm.connect("addPlayer", self.__onAddPlayer) self.connection.glm.connect("removePlayer", self.__onRemovePlayer) self.connection.cm.connect("privateMessage", self.__onTell) self.connection.alm.connect("logOut", self.__onLogOut) self.connection.bm.connect("playGameCreated", self.__onGameCreated) self.connection.bm.connect("curGameEnded", self.__onGameEnded) self.connection.bm.connect("boardUpdate", self.__onBoardUpdate) self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd) self.connection.om.connect("onOfferAdd", self.__onOfferAdd) self.connection.adm.connect("onAdjournmentsList", self.__onAdjournmentsList) self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove) self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove) self.connection.adm.queryAdjournments() self.connection.lvm.setVariable("autoflag", 1) self.connection.fm.setFingerNote( 1, "PyChess is the chess engine bundled with the PyChess %s " % pychess.VERSION + "chess client. This instance is owned by %s, but acts " % self.owner + "quite autonomously.") self.connection.fm.setFingerNote( 2, "PyChess is 100% Python code and is released under the terms of " + "the GPL. The evalution function is largely equal to the one of" + "GnuChess, but it plays quite differently.") self.connection.fm.setFingerNote( 3, "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 " + "MB DDR2 Ram, but is built to take use of 64bit calculating when " + "accessible, through the gpm library.") self.connection.fm.setFingerNote( 4, "PyChess uses a small 500 KB openingbook based solely on Kasparov " + "games. The engine doesn't have much endgame knowledge, but might " + "in some cases access an online endgamedatabase.") self.connection.fm.setFingerNote( 5, "PyChess will allow any pause/resume and adjourn wishes, but will " + "deny takebacks. Draw, abort and switch offers are accepted, " + "if they are found to be an advance. Flag is auto called, but " + "PyChess never resigns. We don't want you to forget your basic " + "mating skills.") def main(self): self.connection.run() self.extendlog([str(self.acceptedTimesettings)]) self.phoneHome("Session ended\n" + "\n".join(self.log)) print("Session ended") def run(self): t = Thread(target=self.main, name=fident(self.main)) t.daemon = True t.start() Gdk.threads_init() Gtk.main() #=========================================================================== # General #=========================================================================== def __showConnectLog(self, connection, message): print(message) def __onLogOut(self, autoLogoutManager): self.connection.close() #sys.exit() def __onAddPlayer(self, gameListManager, player): if player["name"] in self.sudos: self.sudos.remove(player["name"]) if player["name"] == self.owner: self.connection.cm.tellPlayer(self.owner, "Greetings") self.ownerOnline = True def __onRemovePlayer(self, gameListManager, playername): if playername == self.owner: self.ownerOnline = False def __onAdjournmentsList(self, adjournManager, adjournments): for adjournment in adjournments: if adjournment["online"]: adjournManager.challenge(adjournment["opponent"]) def __usage(self): return "|| PyChess bot help file || " +\ "# help 'Displays this help file' " +\ "# sudo <password> <command> 'Lets PyChess execute the given command' "+\ "# sendlog 'Makes PyChess send you its current log'" def __onTell(self, chatManager, name, title, isadmin, text): if self.waitingForPassword: if text.strip() == self.password or (not self.password and text == "none"): self.sudos.add(name) self.tellHome("%s gained sudo access" % name) self.connection.client.run_command(self.waitingForPassword) else: chatManager.tellPlayer(name, "Wrong password") self.tellHome("%s failed sudo access" % name) self.waitingForPassword = None return args = text.split() #if args == ["help"]: # chatManager.tellPlayer(name, self.__usage()) if args[0] == "sudo": command = " ".join(args[1:]) if name in self.sudos or name == self.owner: # Notice: This can be used to make nasty loops print(command, file=self.connection.client) else: print(repr(name), self.sudos) chatManager.tellPlayer(name, "Please send me the password") self.waitingForPassword = command elif args == ["sendlog"]: if self.log: # TODO: Consider email chatManager.tellPlayer(name, "\\n".join(self.log)) else: chatManager.tellPlayer(name, "The log is currently empty") else: if self.ownerOnline: self.tellHome("%s told me '%s'" % (name, text)) else: def onlineanswer(message): data = urlopen( "http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895", urlencode({ "message": message, "botcust2": "x" }).encode("utf-8")).read().decode('utf-8') ss = "<b>DMPGirl:</b>" es = "<br>" answer = data[data.find(ss) + len(ss):data.find(es, data.find(ss))] chatManager.tellPlayer(name, answer) t = Thread(target=onlineanswer, name=fident(onlineanswer), args=(text, )) t.daemon = True t.start() #chatManager.tellPlayer(name, "Sorry, your request was nonsense.\n"+\ # "Please read my help file for more info") #=========================================================================== # Challenges and other offers #=========================================================================== def __onChallengeAdd(self, offerManager, index, match): #match = {"tp": type, "w": fname, "rt": rating, "color": color, # "r": rated, "t": mins, "i": incr} offerManager.acceptIndex(index) def __onOfferAdd(self, offerManager, offer): if offer.type in (PAUSE_OFFER, RESUME_OFFER, ADJOURN_OFFER): offerManager.accept(offer) elif offer.type in (TAKEBACK_OFFER, ): offerManager.decline(offer) elif offer.type in (DRAW_OFFER, ABORT_OFFER, SWITCH_OFFER): if self.__willingToDraw(): offerManager.accept(offer) else: offerManager.decline(offer) #=========================================================================== # Playing #=========================================================================== def __onGameCreated(self, boardManager, ficsgame): base = int(ficsgame.minutes) * 60 inc = int(ficsgame.inc) self.clock[:] = base, base self.increment[:] = inc, inc self.gameno = ficsgame.gameno self.lastPly = -1 self.acceptedTimesettings.append((base, inc)) self.tellHome( "Starting a game (%s, %s) gameno: %s" % (ficsgame.wplayer.name, ficsgame.bplayer.name, ficsgame.gameno)) if ficsgame.bplayer.name.lower() == self.connection.getUsername( ).lower(): self.playingAs = BLACK else: self.playingAs = WHITE self.board = LBoard(NORMALCHESS) # Now we wait until we recieve the board. def __go(self): if self.worker: self.worker.cancel() self.worker = GtkWorker( lambda worker: PyChess._PyChess__go(self, worker)) self.worker.connect("published", lambda w, msg: self.extendlog(msg)) self.worker.connect("done", self.__onMoveCalculated) self.worker.execute() def __willingToDraw(self): return self.scr <= 0 # FIXME: this misbehaves in all but the simplest use cases def __onGameEnded(self, boardManager, ficsgame): self.tellHome(reprResult_long[ficsgame.result] + " " + reprReason_long[ficsgame.reason]) lsearch.searching = False if self.worker: self.worker.cancel() self.worker = None def __onMoveCalculated(self, worker, sanmove): if worker.isCancelled() or not sanmove: return self.board.applyMove(parseSAN(self.board, sanmove)) self.connection.bm.sendMove(sanmove) self.extendlog(["Move sent %s" % sanmove]) def __onBoardUpdate(self, boardManager, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): self.extendlog( ["", "I got move %d %s for gameno %s" % (ply, lastmove, gameno)]) if self.gameno != gameno: return self.board.applyFen(fen) self.clock[:] = wms / 1000., bms / 1000. if curcol == self.playingAs: self.__go() def __onAmbiguousMove(self, errorManager, move): # This is really a fix for fics, but sometimes it is necessary if determineAlgebraicNotation(move) == SAN: self.board.popMove() move_ = parseSAN(self.board, move) lanmove = toLAN(self.board, move_) self.board.applyMove(move_) self.connection.bm.sendMove(lanmove) else: self.connection.cm.tellOpponent( "I'm sorry, I wanted to move %s, but FICS called " % move + "it 'Ambigious'. I can't find another way to express it, " + "so you can win") self.connection.bm.resign() #=========================================================================== # Utils #=========================================================================== def extendlog(self, messages): [log.info(m + "\n") for m in messages] self.log.extend(messages) del self.log[:-10] def tellHome(self, message): print(message) if self.ownerOnline: self.connection.cm.tellPlayer(self.owner, message) def phoneHome(self, message): SENDMAIL = '/usr/sbin/sendmail' SUBJECT = "Besked fra botten" p = subprocess.Popen([ SENDMAIL, '-f', email.Utils.parseaddr(self.from_address)[1], email.Utils.parseaddr(self.to_address)[1] ], stdin=subprocess.PIPE) print("MIME-Version: 1.0", file=p.stdin) print("Content-Type: text/plain; charset=UTF-8", file=p.stdin) print("Content-Disposition: inline", file=p.stdin) print("From: %s" % self.from_address, file=p.stdin) print("To: %s" % self.to_address, file=p.stdin) print("Subject: %s" % SUBJECT, file=p.stdin) print(file=p.stdin) print(message, file=p.stdin) print("Cheers", file=p.stdin) p.stdin.close() p.wait()