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
This commit is contained in:
Goffi 2010-06-02 15:57:23 +09:30
commit 1a9f7e8396
4 changed files with 139 additions and 20 deletions

View file

@ -53,6 +53,7 @@ class QuickApp():
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 @@ class QuickApp():
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

View file

@ -174,7 +174,20 @@ class CardPanel(wx.Panel):
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:

View file

@ -131,6 +131,7 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
point_limit = 51
else:
point_limit = 56
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()
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)
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
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 @@ class Tarot():
#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 @@ class Tarot():
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 @@ class Tarot():
#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 @@ class Tarot():
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 @@ class Tarot():
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)

View file

@ -46,7 +46,9 @@ class XMLTools:
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 @@ class XMLTools:
__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: