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.
This commit is contained in:
Goffi 2010-06-18 15:19:32 +08:00
commit e337d590e3
3 changed files with 126 additions and 4 deletions

View file

@ -55,6 +55,7 @@ class QuickApp():
self.bridge.register("tarotGameYourTurn", self.tarotMyTurn)
self.bridge.register("tarotGameScore", self.tarotScore)
self.bridge.register("tarotGameCardsPlayed", self.tarotCardsPlayed)
self.bridge.register("tarotGameInvalidCards", self.tarotInvalidCards)
self.bridge.register("subscribe", self.subscribe)
self.bridge.register("paramUpdate", self.paramUpdate)
self.bridge.register("contactDeleted", self.contactDeleted)
@ -324,6 +325,13 @@ class QuickApp():
if self.chat_wins.has_key(room_jid):
self.chat_wins[room_jid].getGame("Tarot").cardsPlayed(player, cards)
def tarotInvalidCards(self, room_jid, phase, played_cards, invalid_cards, profile):
if not self.__check_profile(profile):
return
debug (_("Cards played are not valid: %s") % invalid_cards)
if self.chat_wins.has_key(room_jid):
self.chat_wins[room_jid].getGame("Tarot").invalidCards(phase, played_cards, invalid_cards)
def subscribe(self, type, raw_jid, profile):
"""Called when a subsciption management signal is received"""
if not self.__check_profile(profile):

View file

@ -193,6 +193,29 @@ class CardPanel(wx.Panel):
self.played[player] = pl_cards[0]
self.Refresh()
def invalidCards(self, phase, played_cards, invalid_cards):
"""Invalid cards have been played
@param phase: phase of the game
@param played_cards: all the cards played
@param invalid_cards: cards which are invalid"""
if phase == "play":
self.state = "play"
elif phase == "ecart":
self.state = "ecart"
else:
error ('INTERNAL ERROR: unmanaged game phase')
for suit, value in played_cards:
self.hand.append(self.cards[suit, value])
self._recalc_ori()
self.Refresh()
self.hand.sort()
wx.MessageDialog(self, _("Cards played are invalid !"), _("Error"), wx.OK | wx.ICON_ERROR).ShowModal()
def _is_on_hand(self, pos_x, pos_y):
"""Return True if the coordinate are on the hand cards"""

View file

@ -132,6 +132,7 @@ class Tarot():
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
host.bridge.addSignal("tarotGameInvalidCards", ".communication", signature='ssa(ss)a(ss)s') #args: room_jid, game phase, played_cards, invalid_cards, profile
self.deck_ordered = []
for value in ['excuse']+map(str,range(1,22)):
self.deck_ordered.append(Card(("atout",value)))
@ -207,6 +208,19 @@ class Tarot():
score_elt.addChild(looser_elt)
return score_elt
def __invalid_cards_elt(self, played_cards, invalid_cards, game_phase):
"""Create a element for invalid_cards error
@param list_cards: list of Card
@param game_phase: phase of the game ['ecart', 'play']"""
error_elt = domish.Element(('','error'))
played_elt = self.__card_list_to_xml(played_cards, 'played')
invalid_elt = self.__card_list_to_xml(invalid_cards, 'invalid')
error_elt['type'] = 'invalid_cards'
error_elt['phase'] = game_phase
error_elt.addChild(played_elt)
error_elt.addChild(invalid_elt)
return error_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
@ -325,8 +339,6 @@ class Tarot():
if game_data['contrat'] == "Garde Contre":
for card in game_data['chien']:
check_score+=card.points
if ( score + check_score != 91 ):
pdb.set_trace()
assert (score + check_score == 91)
point_limit = None
@ -373,6 +385,63 @@ class Tarot():
return (scores_str, winners, loosers)
def __invalid_cards(self, game_data, cards):
"""Checks that the player has the right to play what he wants to
@param game_data: Game data
@param cards: cards the player want to play
@return forbidden_cards cards or empty list if cards are ok"""
forbidden_cards = []
if game_data['stage'] == 'ecart':
for card in cards:
if card.bout or card.value=="roi":
forbidden_cards.append(card)
#TODO: manage case where atouts (trumps) are in the dog
elif game_data['stage'] == 'play':
biggest_atout = None
suit_asked = None
players = game_data['players']
players_data = game_data['players_data']
idx = players.index(game_data['first_player'])
current_idx = game_data['current_player']
current_player = players[current_idx]
if idx == current_idx:
#the player is the first to play, he can play what he wants
return forbidden_cards
while (idx != current_idx):
player = players[idx]
played_card = players_data[player]['played']
if not suit_asked and played_card.value != "excuse":
suit_asked = played_card.suit
if played_card.suit == "atout" and played_card > biggest_atout:
biggest_atout = played_card
idx = (idx + 1) % len(players)
has_suit = False #True if there is one card of the asked suit in the hand of the player
has_atout = False
biggest_hand_atout = None
for hand_card in game_data['hand'][current_player]:
if hand_card.suit == suit_asked:
has_suit = True
if hand_card.suit == "atout":
has_atout = True
if hand_card.suit == "atout" and hand_card > biggest_hand_atout:
biggest_hand_atout = hand_card
assert len(cards) == 1
card = cards[0]
if card.suit != suit_asked and has_suit and card.value != "excuse":
forbidden_cards.append(card)
return forbidden_cards
if card.suit != suit_asked and card.suit != "atout" and has_atout:
forbidden_cards.append(card)
return forbidden_cards
if card.suit == "atout" and card < biggest_atout and biggest_hand_atout > biggest_atout and card.value != "excuse":
forbidden_cards.append(card)
else:
error(_('Internal error: unmanaged game stage'))
return forbidden_cards
def __start_play(self, room_jid, game_data, profile):
"""Start the game (tell to the first player after dealer to play"""
game_data['stage'] = "play"
@ -584,10 +653,17 @@ class Tarot():
elif elt.name == 'cards_played':
if game_data['stage'] == "ecart":
#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
list_cards = Card.from_tuples(self.__xml_to_list(elt))
#we now check validity of card
invalid_cards = self.__invalid_cards(game_data, list_cards)
if invalid_cards:
mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+elt['player']))
mess.firstChildElement().addChild(self.__invalid_cards_elt(list_cards, invalid_cards, game_data['stage']))
self.host.profiles[profile].xmlstream.send(mess)
return
#FIXME: gof: manage Garde Sans & Garde Contre cases
players_data[elt['player']]['levees'].extend(list_cards) #we add the chien to attaquant's levées
for card in list_cards:
@ -602,7 +678,13 @@ class Tarot():
if mess_elt['type'] == 'groupchat':
self.host.bridge.tarotGameCardsPlayed(room_jid.userhost(), elt['player'], self.__xml_to_list(elt), profile)
else:
#TODO: check card validity and send error mess if necessary
#we first check validity of card
invalid_cards = self.__invalid_cards(game_data, cards)
if invalid_cards:
mess = self.createGameElt(jid.JID(room_jid.userhost()+'/'+current_player))
mess.firstChildElement().addChild(self.__invalid_cards_elt(cards, invalid_cards, game_data['stage']))
self.host.profiles[profile].xmlstream.send(mess)
return
#the card played is ok, we forward it to everybody
#first we remove it from the hand and put in on the table
game_data['hand'][current_player].remove(cards[0])
@ -657,6 +739,15 @@ class Tarot():
form = data_form.Form.fromElement(form_elt)
xml_data = XMLTools.dataForm2xml(form)
self.host.bridge.tarotGameScore(room_jid.userhost(), xml_data, winners, loosers, profile)
elif elt.name == 'error':
if elt['type'] == 'invalid_cards':
played_cards = self.__xml_to_list(elt.elements(name='played',uri='').next())
invalid_cards = self.__xml_to_list(elt.elements(name='invalid',uri='').next())
self.host.bridge.tarotGameInvalidCards(room_jid.userhost(), elt['phase'], played_cards, invalid_cards, profile)
else:
error (_('Unmanaged error type: %s') % elt['type'])
else:
error (_('Unmanaged card game element: %s') % elt.name)
def getHandler(self, profile):
return CardGameHandler(self)