def prepareNewGame(self): """returns a new game object""" names = list(x.name for x in self.users) # the server and all databases save the english name but we # want to make sure a translation exists for the client GUI robotNames = [ m18ncE('kajongg, name of robot player, to be translated', 'Robot 1'), m18ncE('kajongg, name of robot player, to be translated', 'Robot 2'), m18ncE('kajongg, name of robot player, to be translated', 'Robot 3')] while len(names) < 4: names.append(robotNames[3 - len(names)]) result = RemoteGame(names, self.ruleset, client=Client(), playOpen=self.playOpen, autoPlay=self.autoPlay, wantedGame=self.wantedGame, shouldSave=True) return result
def loadSuspendedTables(self, user): """loads all yet unloaded suspended tables where this user is participating. We do not unload them if the user logs out, there are filters anyway returning only the suspended games for a certain user. Never load old autoplay games.""" query = Query("select distinct g.id, g.starttime, " \ "g.seed, " \ "ruleset, s.scoretime " \ "from game g, player p0, score s," \ "player p1, player p2, player p3 " \ "where autoplay=0 " \ " and p0.id=g.p0 and p1.id=g.p1 " \ " and p2.id=g.p2 and p3.id=g.p3 " \ " and (p0.name=? or p1.name=? or p2.name=? or p3.name=?) " \ " and s.game=g.id" \ " and g.endtime is null" \ " and exists(select 1 from score where game=g.id)" \ " and s.scoretime = (select max(scoretime) from score where game=g.id) limit 10", list([user.name, user.name, user.name, user.name])) for gameid, starttime, seed, ruleset, suspendTime in query.records: playOpen = False # do not continue playing resumed games with open tiles, # playOpen is for testing purposes only anyway if gameid not in self.suspendedTables and starttime: # why do we get a record with empty fields when the query should return nothing? if gameid not in (x.game.gameid if x.game else None for x in self.tables.values()): table = Table(self, None, Ruleset.cached(ruleset, used=True), playOpen, autoPlay=False, wantedGame=str(seed)) table.tableid = 1000 + gameid table.status = m18ncE('table status', 'Suspended') + suspendTime table.preparedGame = RemoteGame.loadFromDB(gameid, None, cacheRuleset=True) self.suspendedTables[gameid] = table
def startGame(self, requests): """if all players said ready, start the game""" mayStart = True for msg in requests: if msg.answer == Message.NO or len(requests) < 4: # this player answered "I am not ready", exclude her from table # a player might already have logged of from the table. So if we # are not 4 anymore, all players must leave the table self.server.leaveTable(msg.player.remote, self.tableid) # TODO: the other players are still asked for game start - table should be reset instead self.preparedGame = None mayStart = False if not mayStart: return self.game = self.preparedGame elementIter = iter(elements.all(self.game.ruleset)) for tile in self.game.wall.tiles: tile.element = elementIter.next() tile.element = tile.upper() assert isinstance(self.game, RemoteGame), self.game self.status = m18ncE('table status', 'Running') self.preparedGame = None # if the players on this table also reserved seats on other tables, # clear them for user in self.users: for tableid in self.server.tables.keys()[:]: if tableid != self.tableid: self.server.leaveTable(user, tableid) # tell other users not involved in this table that it is now running for user in self.server.users: if user not in self.users: self.server.callRemote(user, 'replaceTable', self.msg()) self.sendVoiceIds()
def __init__(self, server, owner, rulesetStr, playOpen, autoPlay, wantedGame): self.server = server self.owner = owner if isinstance(rulesetStr, Ruleset): self.ruleset = rulesetStr else: self.ruleset = Ruleset.fromList(rulesetStr) self.playOpen = playOpen self.autoPlay = autoPlay self.wantedGame = wantedGame self.tableid = None self.users = [owner] if owner else [] self.preparedGame = None self.game = None self.status = m18ncE('table status','New')
class Query(object): """a more pythonic interface to QSqlQuery. We could instead use the python sqlite3 module but then we would either have to do more programming for the model/view tables, or we would have two connections to the same database. For selecting queries we fill a list with ALL records. Every record is a list of all fields. q.records[0][1] is record 0, field 1. For select, we also convert to python data types - as far as we need them""" localServerName = m18ncE('kajongg name for local game server', 'Local Game') def __init__(self, cmdList, args=None, dbHandle=None, silent=False, mayFail=False): """we take a list of sql statements. Only the last one is allowed to be a select statement. Do prepared queries by passing a single query statement in cmdList and the parameters in args. If args is a list of lists, execute the prepared query for every sublist. If dbHandle is passed, use that for db access. Else if the default dbHandle (DBHandle.default) is defined, use it.""" # pylint: disable=R0912 # pylint says too many branches silent |= not Debug.sql self.dbHandle = dbHandle or DBHandle.default preparedQuery = not isinstance(cmdList, list) and bool(args) self.query = QSqlQuery(self.dbHandle) self.msg = None self.records = [] if not isinstance(cmdList, list): cmdList = list([cmdList]) self.cmdList = cmdList for cmd in cmdList: retryCount = 0 while retryCount < 100: self.lastError = None if preparedQuery: self.query.prepare(cmd) if not isinstance(args[0], list): args = list([args]) for dataSet in args: if not silent: _, utf8Args = xToUtf8(u'', dataSet) logDebug("{cmd} [{args}]".format( cmd=cmd, args=", ".join(utf8Args))) for value in dataSet: self.query.addBindValue(QVariant(value)) self.success = self.query.exec_() if not self.success: break else: if not silent: logDebug('%s %s' % (self.dbHandle.name, cmd)) self.success = self.query.exec_(cmd) if self.success or self.query.lastError().number() not in (5, 6): # 5: database locked, 6: table locked. Where can we get symbols for this? break time.sleep(0.1) retryCount += 1 if not self.success: self.lastError = unicode(self.query.lastError().text()) self.msg = 'ERROR in %s: %s' % (self.dbHandle.databaseName(), self.lastError) if mayFail: if not silent: logDebug(self.msg) else: logException(self.msg) return self.records = None self.fields = None if self.query.isSelect(): self.retrieveRecords() def rowcount(self): """how many rows were affected?""" return self.query.numRowsAffected() def retrieveRecords(self): """get all records from SQL into a python list""" record = self.query.record() self.fields = [record.field(x) for x in range(record.count())] self.records = [] while self.query.next(): self.records.append( [self.__convertField(x) for x in range(record.count())]) def __convertField(self, idx): """convert a QSqlQuery field into a python value""" result = self.query.value(idx).toPyObject() if isinstance(result, QString): result = unicode(result) if isinstance(result, long) and -sys.maxint - 1 <= result <= sys.maxint: result = int(result) return result
def __init__(self): ClientMessage.__init__(self, name=m18ncE('kajongg','OK'), shortcut=m18ncE('kajongg game dialog:Key for OK', 'O'))
def __init__(self): NotifyAtOnceMessage.__init__(self, name=m18ncE('kajongg','No Claim'), shortcut=m18ncE('kajongg game dialog:Key for No claim', 'N'))
def __init__(self): ServerMessage.__init__(self, name=m18ncE('kajongg', 'Dangerous Game'))
def __init__(self): ServerMessage.__init__(self, name=m18ncE('kajongg', 'No Choice')) self.move = None
def __init__(self): ServerMessage.__init__(self, name=m18ncE('kajongg', 'Violates Original Call'))
def __init__(self): ClientMessage.__init__(self, name=m18ncE('kajongg','Discard'), shortcut=m18ncE('kajongg game dialog:Key for Discard', 'D'))
def __init__(self): NotifyAtOnceMessage.__init__(self, name=m18ncE('kajongg','Original Call'), shortcut=m18ncE('kajongg game dialog:Key for Original Call', 'O'))
def __init__(self): NotifyAtOnceMessage.__init__(self, name=m18ncE('kajongg','Mah Jongg'), shortcut=m18ncE('kajongg game dialog:Key for Mah Jongg', 'M'))
def __init__(self): PungChowMessage.__init__(self, name=m18ncE('kajongg','Chow'), shortcut=m18ncE('kajongg game dialog:Key for Chow', 'C'))