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:
parent
d663da0526
commit
1a9f7e8396
4 changed files with 139 additions and 20 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue