# HG changeset patch # User Goffi # Date 1275460043 -34200 # Node ID be206a3d1a9b82e9a4d0a888ecbddda33aec3440 # Parent 1eb5ccead43c899af451534b897829c300d54238 Tarot game: score calculation - plugin tarot: score validity is now checked (some of attackers and defender must equal 91) - plugin tarot: new signal tarotGameScore to give the scores and winners/loosers - wix: score are now displayed at the end of the game - xml_tools: 'fixed' type is now managed in dataForm2xml diff -r 1eb5ccead43c -r be206a3d1a9b frontends/quick_frontend/quick_app.py --- a/frontends/quick_frontend/quick_app.py Tue Jun 01 18:16:15 2010 +0930 +++ b/frontends/quick_frontend/quick_app.py Wed Jun 02 15:57:23 2010 +0930 @@ -53,6 +53,7 @@ self.bridge.register("tarotGameChooseContrat", self.tarotChooseContrat) self.bridge.register("tarotGameShowCards", self.tarotShowCards) self.bridge.register("tarotGameYourTurn", self.tarotMyTurn) + self.bridge.register("tarotGameScore", self.tarotScore) self.bridge.register("tarotGameCardsPlayed", self.tarotCardsPlayed) self.bridge.register("subscribe", self.subscribe) self.bridge.register("paramUpdate", self.paramUpdate) @@ -308,6 +309,14 @@ if self.chat_wins.has_key(room_jid): self.chat_wins[room_jid].getGame("Tarot").MyTurn() + def tarotScore(self, room_jid, xml_data, winners, loosers, profile): + """Called when the game is finished and the score are updated""" + if not self.__check_profile(profile): + return + debug (_("Tarot: score received")) + if self.chat_wins.has_key(room_jid): + self.chat_wins[room_jid].getGame("Tarot").showScores(xml_data, winners, loosers) + def tarotCardsPlayed(self, room_jid, player, cards, profile): if not self.__check_profile(profile): return diff -r 1eb5ccead43c -r be206a3d1a9b frontends/wix/card_game.py --- a/frontends/wix/card_game.py Tue Jun 01 18:16:15 2010 +0930 +++ b/frontends/wix/card_game.py Wed Jun 02 15:57:23 2010 +0930 @@ -174,7 +174,20 @@ if self.state == "chien": self.to_show = [] self.state = "play" + + #tmp gof: FIXME + card = self.hand[-1] + self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], profile_key = self.parent.host.profile) + del self.hand[-1] + self.state = "wait" + self._recalc_ori() + self.Refresh() + def showScores(self, xml_data, winners, loosers): + """Called when the player as to select hist contrat + @param xml_data: SàT xml representation of the form""" + form = Form(self.parent.host, xml_data, title = _('You win \o/') if self.player_nick in winners else _('You loose :('), options = ['NO_CANCEL']) + def cardsPlayed(self, player, cards): """A card has been played by player""" if self.to_show: diff -r 1eb5ccead43c -r be206a3d1a9b plugins/plugin_misc_tarot.py --- a/plugins/plugin_misc_tarot.py Tue Jun 01 18:16:15 2010 +0930 +++ b/plugins/plugin_misc_tarot.py Wed Jun 02 15:57:23 2010 +0930 @@ -131,6 +131,7 @@ host.bridge.addSignal("tarotGameShowCards", ".communication", signature='ssa(ss)a{ss}s') #args: room_jid, type ["chien", "poignée",...], cards, data[dict], profile host.bridge.addSignal("tarotGameCardsPlayed", ".communication", signature='ssa(ss)s') #args: room_jid, player, type ["chien", "poignée",...], cards, data[dict], profile host.bridge.addSignal("tarotGameYourTurn", ".communication", signature='ss') #args: room_jid, profile + host.bridge.addSignal("tarotGameScore", ".communication", signature='ssasass') #args: room_jid, xml_data, winners (list of nicks), loosers (list of nicks), profile self.deck_ordered = [] for value in ['excuse']+map(str,range(1,22)): self.deck_ordered.append(("atout",value)) @@ -184,6 +185,28 @@ contrat_elt.addChild(form.toElement()) return contrat_elt + def __give_scores(self, scores, winners, loosers): + """Create an element to give scores + @param scores: unicode (can contain line feed) + @param winners: list of unicode nicks of winners + @param loosers: list of unicode nicks of loosers""" + + score_elt = domish.Element(('','score')) + form = data_form.Form('form', title=_('scores')) + for line in scores.split('\n'): + field = data_form.Field('fixed', value = line) + form.addField(field) + score_elt.addChild(form.toElement()) + for winner in winners: + winner_elt = domish.Element(('','winner')) + winner_elt.addContent(winner) + score_elt.addChild(winner_elt) + for looser in loosers: + looser_elt = domish.Element(('','looser')) + looser_elt.addContent(looser) + score_elt.addChild(looser_elt) + return score_elt + def __next_player(self, game_data, next_pl = None): """Increment player number & return player name @param next_pl: if given, then next_player is forced to this one @@ -213,15 +236,21 @@ if (card.suit == suit_asked or card.suit == "atout") and card > strongest: strongest = card winner = player - assert (winner) + assert winner return winner def __excuse_hack(self, game_data, played, winner): - """give a low card to other team and keep excuse if trick is lost""" + """give a low card to other team and keep excuse if trick is lost + @param game_data: data of the game + @param played: cards currently on the table + @param winner: nick of the trick winner""" #TODO: manage the case where excuse is played on the last trick (and lost) #TODO: gof: manage excuse (fool) players_data = game_data['players_data'] excuse = Card(("atout","excuse")) + + #we first check if the Excuse was already player + #and if somebody is waiting for a card for player in game_data['players']: if players_data[player]['wait_for_low']: #the excuse owner has to give a card to somebody @@ -233,13 +262,14 @@ played.remove(card) players_data[pl_waiting]['levees'].append(card) debug (_('Player %(excuse_owner)s give %(card_waited)s to %(player_waiting)s for Excuse compensation') % {"excuse_owner":player, "card_waited": card, "player_waiting":pl_waiting}) - break + return return if not excuse in played: + #the Excuse is not on the table, nothing to do return - excuse_player = None + excuse_player = None #Who has played the Excuse ? for player in game_data['players']: if players_data[player]['played'] == excuse: excuse_player = player @@ -255,6 +285,8 @@ owner_levees.append(excuse) #finally we give a low card to the trick winner low_card = None + #We look backward in cards won by the Excuse owner to + #find a low value card for card_idx in range(len(owner_levees)-1, -1, -1): if owner_levees[card_idx].points == 0.5: low_card = owner_levees[card_idx] @@ -269,15 +301,29 @@ def __calculate_scores(self, game_data): - """The game is finished, time to know who won :)""" + """The game is finished, time to know who won :) + @param game_data: data of the game + @return: tuple with (string victory message, list of winners, list of loosers)""" players_data = game_data['players_data'] levees = players_data[game_data['attaquant']]['levees'] score = 0 nb_bouts = 0 + bouts = [] for card in levees: if card.bout: nb_bouts +=1 + bouts.append(card.value) score += card.points + + #We now check if there is no bug in score calculation + check_score = 0 + defenseurs = game_data['players'][:] + defenseurs.remove(game_data['attaquant']) + for defenseur in defenseurs: + for card in players_data[defenseur]['levees']: + check_score+=card.points + assert (score + check_score == 91) + point_limit = None if nb_bouts == 3: point_limit = 36 @@ -287,10 +333,41 @@ point_limit = 51 else: point_limit = 56 + if game_data['contrat'] == 'Petite': + contrat_mult = 1 + elif game_data['contrat'] == 'Garde': + contrat_mult = 2 + elif game_data['contrat'] == 'Garde Sans': + contrat_mult = 4 + elif game_data['contrat'] == 'Garde Contre': + contrat_mult = 6 + else: + error(_('Internal error: contrat not managed (mispelled ?)')) + victory = (score >= point_limit) - debug (_('The attacker make %(points)i and need to make %(point_limit)i (%(nb_bouts)s oulder%(plural)s): he %(victory)s') % {'points':score, 'point_limit':point_limit, 'nb_bouts': nb_bouts, 'plural': 's' if nb_bouts>1 else '', 'victory': 'won' if victory else 'lost'}) - #pdb.set_trace() + margin = score - point_limit + pdb.set_trace() + points_defenseur = (-margin + 25) * contrat_mult + winners = [] + loosers = [] + player_score = {} + for player in game_data['players']: + #TODO: adjust this for 3 and 5 players variants + #TODO: manage bonuses (petit au bout, poignée, chelem) + player_score[player] = points_defenseur if player != game_data['attaquant'] else points_defenseur * -3 + players_data[player]['score'] += player_score[player] #we add score of this game to the global score + if player_score[player] > 0: + winners.append(player) + else: + loosers.append(player) + scores_str = _('The attacker (%(attaquant)s) makes %(points)i and needs to make %(point_limit)i (%(nb_bouts)s oulder%(plural)s: %(bouts)s): he %(victory)s') % {'attaquant':game_data['attaquant'], 'points':score, 'point_limit':point_limit, 'nb_bouts': nb_bouts, 'plural': 's' if nb_bouts>1 else '', 'bouts':','.join(map(str,bouts)), 'victory': 'win' if victory else 'loose'} + scores_str+='\n' + for player in game_data['players']: + scores_str+=_("\n--\n%(player)s:\nscore for this game ==> %(score_game)i\ntotal score ==> %(total_score)i") % {'player':player, 'score_game':player_score[player], 'total_score': players_data[player]['score']} + debug(scores_str) + + return (scores_str, winners, loosers) def createGame(self, room_jid_param, players, profile_key='@DEFAULT@'): @@ -312,9 +389,9 @@ status = {} players_data = {} for player in players: - players_data[player] = {} + players_data[player] = {'score':0} status[player] = "init" - self.games[room_jid.userhost()] = {'referee':referee, 'players':players, 'status':status, 'players_data':players_data, 'hand_size':18, 'init_player':0, 'current_player': None, 'stage': None} + self.games[room_jid.userhost()] = {'referee':referee, 'players':players, 'status':status, 'players_data':players_data, 'hand_size':18, 'init_player':0, 'current_player': None, 'contrat': None, 'stage': None} for player in players: mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+player)) mess.firstChildElement().addChild(self.__create_started_elt(players)) @@ -377,6 +454,7 @@ current_player = game_data['current_player'] game_data['stage'] = "init" game_data['first_player'] = None #first player for the current trick + game_data['contrat'] = None hand = game_data['hand'] = {} hand_size = game_data['hand_size'] chien = game_data['chien'] = [] @@ -461,6 +539,7 @@ best_contrat[0] = player best_contrat[1] = contrat debug (_("%(player)s win the bid with %(contrat)s") % {'player':best_contrat[0],'contrat':best_contrat[1]}) + game_data['contrat'] = best_contrat[1] #Time to show the chien to everybody to_jid = jid.JID(room_jid.userhost()) #FIXME: gof: mess = self.createGameElt(to_jid) @@ -484,7 +563,11 @@ #TODO: check validity of écart (no king, no oulder, cards must be in player hand) #TODO: show atouts (trumps) if player put some in écart assert (game_data['attaquant'] == elt['player']) #TODO: throw an xml error here - players_data[elt['player']]['levees'].extend(Card.from_tuples(self.__xml_to_list(elt))) + list_cards = self.__xml_to_list(elt) + #FIXME: gof: manage Garde Sans & Garde Contre cases + players_data[elt['player']]['levees'].extend(Card.from_tuples(list_cards)) #we add the chien to attaquant's levées + for card in list_cards: + game_data['hand'][elt['player']].remove(card) game_data['stage'] = "play" next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) #the player after the dealer start game_data['first_player'] = next_player = game_data['players'][next_player_idx] @@ -494,7 +577,6 @@ self.host.profiles[profile].xmlstream.send(mess) elif game_data['stage'] == "play": current_player = game_data['players'][game_data['current_player']] - #assert (elt['player'] == current_player) #TODO: throw xml error here cards = self.__xml_to_list(elt) if mess_elt['type'] == 'groupchat': @@ -513,8 +595,8 @@ #Did everybody played ? played = [players_data[player]['played'] for player in game_data['players']] - if not played.count(None): - #everybody played + if all(played): + #everybody has played winner = self.__winner(game_data) debug (_('The winner of this trick is %s') % winner) #the winner win the trick @@ -525,7 +607,10 @@ players_data[player]['played'] = None if len(game_data['hand'][current_player]) == 0: #no card lef: the game is finished - self.__calculate_scores(game_data) + to_jid = jid.JID(room_jid.userhost()) #FIXME: gof: + mess = self.createGameElt(to_jid) + chien_elt = mess.firstChildElement().addChild(self.__give_scores(*self.__calculate_scores(game_data))) + self.host.profiles[profile].xmlstream.send(mess) return #next player is the winner next_player = game_data['first_player'] = self.__next_player(game_data, winner) @@ -541,11 +626,20 @@ elif elt.name == 'your_turn': self.host.bridge.tarotGameYourTurn(room_jid.userhost(), profile) - + elif elt.name == 'score': + form_elt = elt.elements(name='x',uri='jabber:x:data').next() + winners = [] + loosers = [] + for winner in elt.elements(name='winner', uri=''): + winners.append(unicode(winner)) + for looser in elt.elements(name='looser', uri=''): + loosers.append(unicode(looser)) + form = data_form.Form.fromElement(form_elt) + xml_data = XMLTools.dataForm2xml(form) + self.host.bridge.tarotGameScore(room_jid.userhost(), xml_data, winners, loosers, profile) + def getHandler(self, profile): return CardGameHandler(self) - - class CardGameHandler (XMPPHandler): implements(iwokkel.IDisco) diff -r 1eb5ccead43c -r be206a3d1a9b tools/xml_tools.py --- a/tools/xml_tools.py Tue Jun 01 18:16:15 2010 +0930 +++ b/tools/xml_tools.py Wed Jun 02 15:57:23 2010 +0930 @@ -46,7 +46,9 @@ elem.appendChild(text) top_element.appendChild(elem) for field in form.fieldList: - if field.fieldType == 'text-single': + if field.fieldType == 'fixed': + __field_type = 'text' + elif field.fieldType == 'text-single': __field_type = "string" elif field.fieldType == 'text-private': __field_type = "password" @@ -57,7 +59,8 @@ __field_type = "string" elem = doc.createElement('elem') - elem.setAttribute('name', field.var) + if field.var: + elem.setAttribute('name', field.var) elem.setAttribute('type', __field_type) elem.setAttribute('label', field.label or "") if field.value: