comparison plugins/plugin_misc_tarot.py @ 99:63c9067a1499

Tarot game: invalid cards management - tarot plugin: card validity check, new signal tarotGameInvalidCards - wix: when an invalid cards signal is received, the cards are back in the hand, and the state change so the player as to play again.
author Goffi <goffi@goffi.org>
date Fri, 18 Jun 2010 15:19:32 +0800
parents dd556233a1b1
children 783e9d6980ec
comparison
equal deleted inserted replaced
98:dd556233a1b1 99:63c9067a1499
130 host.bridge.addSignal("tarotGameChooseContrat", ".communication", signature='sss') #args: room_jid, xml_data, profile 130 host.bridge.addSignal("tarotGameChooseContrat", ".communication", signature='sss') #args: room_jid, xml_data, profile
131 host.bridge.addSignal("tarotGameShowCards", ".communication", signature='ssa(ss)a{ss}s') #args: room_jid, type ["chien", "poignée",...], cards, data[dict], profile 131 host.bridge.addSignal("tarotGameShowCards", ".communication", signature='ssa(ss)a{ss}s') #args: room_jid, type ["chien", "poignée",...], cards, data[dict], profile
132 host.bridge.addSignal("tarotGameCardsPlayed", ".communication", signature='ssa(ss)s') #args: room_jid, player, type ["chien", "poignée",...], cards, data[dict], profile 132 host.bridge.addSignal("tarotGameCardsPlayed", ".communication", signature='ssa(ss)s') #args: room_jid, player, type ["chien", "poignée",...], cards, data[dict], profile
133 host.bridge.addSignal("tarotGameYourTurn", ".communication", signature='ss') #args: room_jid, profile 133 host.bridge.addSignal("tarotGameYourTurn", ".communication", signature='ss') #args: room_jid, profile
134 host.bridge.addSignal("tarotGameScore", ".communication", signature='ssasass') #args: room_jid, xml_data, winners (list of nicks), loosers (list of nicks), profile 134 host.bridge.addSignal("tarotGameScore", ".communication", signature='ssasass') #args: room_jid, xml_data, winners (list of nicks), loosers (list of nicks), profile
135 host.bridge.addSignal("tarotGameInvalidCards", ".communication", signature='ssa(ss)a(ss)s') #args: room_jid, game phase, played_cards, invalid_cards, profile
135 self.deck_ordered = [] 136 self.deck_ordered = []
136 for value in ['excuse']+map(str,range(1,22)): 137 for value in ['excuse']+map(str,range(1,22)):
137 self.deck_ordered.append(Card(("atout",value))) 138 self.deck_ordered.append(Card(("atout",value)))
138 for suit in ["pique", "coeur", "carreau", "trefle"]: 139 for suit in ["pique", "coeur", "carreau", "trefle"]:
139 for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]: 140 for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]:
205 looser_elt = domish.Element(('','looser')) 206 looser_elt = domish.Element(('','looser'))
206 looser_elt.addContent(looser) 207 looser_elt.addContent(looser)
207 score_elt.addChild(looser_elt) 208 score_elt.addChild(looser_elt)
208 return score_elt 209 return score_elt
209 210
211 def __invalid_cards_elt(self, played_cards, invalid_cards, game_phase):
212 """Create a element for invalid_cards error
213 @param list_cards: list of Card
214 @param game_phase: phase of the game ['ecart', 'play']"""
215 error_elt = domish.Element(('','error'))
216 played_elt = self.__card_list_to_xml(played_cards, 'played')
217 invalid_elt = self.__card_list_to_xml(invalid_cards, 'invalid')
218 error_elt['type'] = 'invalid_cards'
219 error_elt['phase'] = game_phase
220 error_elt.addChild(played_elt)
221 error_elt.addChild(invalid_elt)
222 return error_elt
223
210 def __next_player(self, game_data, next_pl = None): 224 def __next_player(self, game_data, next_pl = None):
211 """Increment player number & return player name 225 """Increment player number & return player name
212 @param next_pl: if given, then next_player is forced to this one 226 @param next_pl: if given, then next_player is forced to this one
213 """ 227 """
214 if next_pl: 228 if next_pl:
323 for card in players_data[defenseur]['levees']: 337 for card in players_data[defenseur]['levees']:
324 check_score+=card.points 338 check_score+=card.points
325 if game_data['contrat'] == "Garde Contre": 339 if game_data['contrat'] == "Garde Contre":
326 for card in game_data['chien']: 340 for card in game_data['chien']:
327 check_score+=card.points 341 check_score+=card.points
328 if ( score + check_score != 91 ):
329 pdb.set_trace()
330 assert (score + check_score == 91) 342 assert (score + check_score == 91)
331 343
332 point_limit = None 344 point_limit = None
333 if nb_bouts == 3: 345 if nb_bouts == 3:
334 point_limit = 36 346 point_limit = 36
370 for player in game_data['players']: 382 for player in game_data['players']:
371 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']} 383 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']}
372 debug(scores_str) 384 debug(scores_str)
373 385
374 return (scores_str, winners, loosers) 386 return (scores_str, winners, loosers)
387
388 def __invalid_cards(self, game_data, cards):
389 """Checks that the player has the right to play what he wants to
390 @param game_data: Game data
391 @param cards: cards the player want to play
392 @return forbidden_cards cards or empty list if cards are ok"""
393 forbidden_cards = []
394 if game_data['stage'] == 'ecart':
395 for card in cards:
396 if card.bout or card.value=="roi":
397 forbidden_cards.append(card)
398 #TODO: manage case where atouts (trumps) are in the dog
399 elif game_data['stage'] == 'play':
400 biggest_atout = None
401 suit_asked = None
402 players = game_data['players']
403 players_data = game_data['players_data']
404 idx = players.index(game_data['first_player'])
405 current_idx = game_data['current_player']
406 current_player = players[current_idx]
407 if idx == current_idx:
408 #the player is the first to play, he can play what he wants
409 return forbidden_cards
410 while (idx != current_idx):
411 player = players[idx]
412 played_card = players_data[player]['played']
413 if not suit_asked and played_card.value != "excuse":
414 suit_asked = played_card.suit
415 if played_card.suit == "atout" and played_card > biggest_atout:
416 biggest_atout = played_card
417 idx = (idx + 1) % len(players)
418 has_suit = False #True if there is one card of the asked suit in the hand of the player
419 has_atout = False
420 biggest_hand_atout = None
421
422 for hand_card in game_data['hand'][current_player]:
423 if hand_card.suit == suit_asked:
424 has_suit = True
425 if hand_card.suit == "atout":
426 has_atout = True
427 if hand_card.suit == "atout" and hand_card > biggest_hand_atout:
428 biggest_hand_atout = hand_card
429
430 assert len(cards) == 1
431 card = cards[0]
432 if card.suit != suit_asked and has_suit and card.value != "excuse":
433 forbidden_cards.append(card)
434 return forbidden_cards
435 if card.suit != suit_asked and card.suit != "atout" and has_atout:
436 forbidden_cards.append(card)
437 return forbidden_cards
438 if card.suit == "atout" and card < biggest_atout and biggest_hand_atout > biggest_atout and card.value != "excuse":
439 forbidden_cards.append(card)
440 else:
441 error(_('Internal error: unmanaged game stage'))
442 return forbidden_cards
443
375 444
376 def __start_play(self, room_jid, game_data, profile): 445 def __start_play(self, room_jid, game_data, profile):
377 """Start the game (tell to the first player after dealer to play""" 446 """Start the game (tell to the first player after dealer to play"""
378 game_data['stage'] = "play" 447 game_data['stage'] = "play"
379 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) #the player after the dealer start 448 next_player_idx = game_data['current_player'] = (game_data['init_player'] + 1) % len(game_data['players']) #the player after the dealer start
582 game_data['attaquant'] = elt['attaquant'] 651 game_data['attaquant'] = elt['attaquant']
583 self.host.bridge.tarotGameShowCards(room_jid.userhost(), "chien", self.__xml_to_list(elt), data, profile) 652 self.host.bridge.tarotGameShowCards(room_jid.userhost(), "chien", self.__xml_to_list(elt), data, profile)
584 653
585 elif elt.name == 'cards_played': 654 elif elt.name == 'cards_played':
586 if game_data['stage'] == "ecart": 655 if game_data['stage'] == "ecart":
587 #TODO: check validity of écart (no king, no oulder, cards must be in player hand)
588 #TODO: show atouts (trumps) if player put some in écart 656 #TODO: show atouts (trumps) if player put some in écart
589 assert (game_data['attaquant'] == elt['player']) #TODO: throw an xml error here 657 assert (game_data['attaquant'] == elt['player']) #TODO: throw an xml error here
590 list_cards = Card.from_tuples(self.__xml_to_list(elt)) 658 list_cards = Card.from_tuples(self.__xml_to_list(elt))
659 #we now check validity of card
660 invalid_cards = self.__invalid_cards(game_data, list_cards)
661 if invalid_cards:
662 mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+elt['player']))
663 mess.firstChildElement().addChild(self.__invalid_cards_elt(list_cards, invalid_cards, game_data['stage']))
664 self.host.profiles[profile].xmlstream.send(mess)
665 return
666
591 #FIXME: gof: manage Garde Sans & Garde Contre cases 667 #FIXME: gof: manage Garde Sans & Garde Contre cases
592 players_data[elt['player']]['levees'].extend(list_cards) #we add the chien to attaquant's levées 668 players_data[elt['player']]['levees'].extend(list_cards) #we add the chien to attaquant's levées
593 for card in list_cards: 669 for card in list_cards:
594 game_data['hand'][elt['player']].remove(card) 670 game_data['hand'][elt['player']].remove(card)
595 671
600 cards = Card.from_tuples(self.__xml_to_list(elt)) 676 cards = Card.from_tuples(self.__xml_to_list(elt))
601 677
602 if mess_elt['type'] == 'groupchat': 678 if mess_elt['type'] == 'groupchat':
603 self.host.bridge.tarotGameCardsPlayed(room_jid.userhost(), elt['player'], self.__xml_to_list(elt), profile) 679 self.host.bridge.tarotGameCardsPlayed(room_jid.userhost(), elt['player'], self.__xml_to_list(elt), profile)
604 else: 680 else:
605 #TODO: check card validity and send error mess if necessary 681 #we first check validity of card
682 invalid_cards = self.__invalid_cards(game_data, cards)
683 if invalid_cards:
684 mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+current_player))
685 mess.firstChildElement().addChild(self.__invalid_cards_elt(cards, invalid_cards, game_data['stage']))
686 self.host.profiles[profile].xmlstream.send(mess)
687 return
606 #the card played is ok, we forward it to everybody 688 #the card played is ok, we forward it to everybody
607 #first we remove it from the hand and put in on the table 689 #first we remove it from the hand and put in on the table
608 game_data['hand'][current_player].remove(cards[0]) 690 game_data['hand'][current_player].remove(cards[0])
609 players_data[current_player]['played'] = cards[0] 691 players_data[current_player]['played'] = cards[0]
610 692
655 for looser in elt.elements(name='looser', uri=''): 737 for looser in elt.elements(name='looser', uri=''):
656 loosers.append(unicode(looser)) 738 loosers.append(unicode(looser))
657 form = data_form.Form.fromElement(form_elt) 739 form = data_form.Form.fromElement(form_elt)
658 xml_data = XMLTools.dataForm2xml(form) 740 xml_data = XMLTools.dataForm2xml(form)
659 self.host.bridge.tarotGameScore(room_jid.userhost(), xml_data, winners, loosers, profile) 741 self.host.bridge.tarotGameScore(room_jid.userhost(), xml_data, winners, loosers, profile)
742 elif elt.name == 'error':
743 if elt['type'] == 'invalid_cards':
744 played_cards = self.__xml_to_list(elt.elements(name='played',uri='').next())
745 invalid_cards = self.__xml_to_list(elt.elements(name='invalid',uri='').next())
746 self.host.bridge.tarotGameInvalidCards(room_jid.userhost(), elt['phase'], played_cards, invalid_cards, profile)
747 else:
748 error (_('Unmanaged error type: %s') % elt['type'])
749 else:
750 error (_('Unmanaged card game element: %s') % elt.name)
660 751
661 def getHandler(self, profile): 752 def getHandler(self, profile):
662 return CardGameHandler(self) 753 return CardGameHandler(self)
663 754
664 class CardGameHandler (XMPPHandler): 755 class CardGameHandler (XMPPHandler):