comparison frontends/src/primitivus/card_game.py @ 223:86d249b6d9b7

Files reorganisation
author Goffi <goffi@goffi.org>
date Wed, 29 Dec 2010 01:06:29 +0100
parents frontends/primitivus/card_game.py@3198bfd66daa
children fd9b7834d98a
comparison
equal deleted inserted replaced
222:3198bfd66daa 223:86d249b6d9b7
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 """
5 Primitivus: a SAT frontend
6 Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """
21
22 import urwid
23 from tools.games import TarotCard
24 from quick_frontend.quick_card_game import QuickCardGame
25 from xmlui import XMLUI
26 from urwid_satext import sat_widgets
27
28 class CardDisplayer(urwid.Text):
29 """Show a card"""
30 signals = ['click']
31
32 def __init__(self, card):
33 self.__selected = False
34 self.card = card
35 urwid.Text.__init__(self, card.getAttrText())
36
37 def selectable(self):
38 return True
39
40 def keypress(self, size, key):
41 if key == ' ':
42 self.select(not self.__selected)
43 self._emit('click')
44 return key
45
46 def mouse_event(self, size, event, button, x, y, focus):
47 if urwid.is_mouse_press(event) and button == 1:
48 self.select(not self.__selected)
49 self._emit('click')
50 return True
51
52 return False
53
54 def select(self, state=True):
55 self.__selected = state
56 attr,txt = self.card.getAttrText()
57 if self.__selected:
58 attr+='_selected'
59 self.set_text((attr,txt))
60 self._invalidate()
61
62 def isSelected(self):
63 return self.__selected
64
65 def getCard(self):
66 return self.card
67
68 def render(self, size, focus=False):
69 canvas = urwid.CompositeCanvas(urwid.Text.render(self, size, focus))
70 if focus:
71 canvas.set_cursor((0,0))
72 return canvas
73
74 class Hand(urwid.WidgetWrap):
75 """Used to display several cards, and manage a hand"""
76 signals = ['click']
77
78 def __init__(self, hand=[], selectable = False, on_click=None, user_data=None):
79 """@param hand: list of Card"""
80 self.__selectable = selectable
81 self.columns = urwid.Columns([],dividechars=1)
82 if on_click:
83 urwid.connect_signal(self, 'click', on_click, user_data)
84 if hand:
85 self.update(hand)
86 urwid.WidgetWrap.__init__(self, self.columns)
87
88 def selectable(self):
89 return self.__selectable
90
91 def keypress(self, size, key):
92
93 if CardDisplayer in [wid.__class__ for wid in self.columns.widget_list]:
94 return self.columns.keypress(size,key)
95 else:
96 #No card displayed, we still have to manage the clicks
97 if key == ' ':
98 self._emit('click', None)
99 return key
100
101 def getSelected(self):
102 """Return a list of selected cards"""
103 _selected = []
104 for wid in self.columns.widget_list:
105 if isinstance(wid, CardDisplayer) and wid.isSelected():
106 _selected.append(wid.getCard())
107 return _selected
108
109 def update(self, hand):
110 """Update the hand displayed in this widget
111 @param hand: list of Card"""
112 del self.columns.widget_list[:]
113 del self.columns.column_types[:]
114 self.columns.widget_list.append(urwid.Text(''))
115 self.columns.column_types.append(('weight',1))
116 for card in hand:
117 widget = CardDisplayer(card)
118 self.columns.widget_list.append(widget)
119 self.columns.column_types.append(('fixed',3))
120 urwid.connect_signal(widget, 'click', self.__onClick)
121 self.columns.widget_list.append(urwid.Text(''))
122 self.columns.column_types.append(('weight',1))
123 self.columns.set_focus(1)
124
125 def __onClick(self,card_wid):
126 self._emit('click', card_wid)
127
128 class Card(TarotCard):
129 """This class is used to represent a card, logically
130 and give a text representation with attributes"""
131 SIZE = 3 #size of a displayed card
132
133 def __init__(self, suit, value):
134 """@param file: path of the PNG file"""
135 TarotCard.__init__(self, (suit, value))
136
137 def getAttrText(self):
138 """return text representation of the card with attributes"""
139 try:
140 value = "%02i" % int(self.value)
141 except ValueError:
142 value = self.value[0].upper()+self.value[1]
143 if self.suit == "atout":
144 if self.value == "excuse":
145 suit = 'c'
146 else:
147 suit = 'A'
148 color = 'neutral'
149 elif self.suit == "pique":
150 suit = u'♠'
151 color = 'black'
152 elif self.suit == "trefle":
153 suit = u'♣'
154 color = 'black'
155 elif self.suit == "coeur":
156 suit = u'♥'
157 color = 'red'
158 elif self.suit == "carreau":
159 suit = u'♦'
160 color = 'red'
161 if self.bout:
162 color = 'special'
163 return ('card_%s' % color,u"%s%s" % (value,suit))
164
165 def getWidget(self):
166 """Return a widget representing the card"""
167 return CardDisplayer(self)
168
169 class Table(urwid.FlowWidget):
170 """Represent the cards currently on the table"""
171
172 def __init__(self):
173 self.top = self.left = self.bottom = self.right = None
174
175 def putCard(self, location, card):
176 """Put a card on the table
177 @param location: where to put the card (top, left, bottom or right)
178 @param card: Card to play or None"""
179 assert location in ['top','left','bottom','right']
180 assert isinstance(card,Card) or card == None
181 if [getattr(self, place) for place in ['top','left','bottom','right']].count(None) == 0:
182 #If the table is full of card, we remove them
183 self.top = self.left = self.bottom = self.right = None
184 setattr(self, location, card)
185 self._invalidate()
186
187 def rows(self,size,focus=False):
188 return self.display_widget(size, focus).rows(size, focus)
189
190 def render(self, size, focus=False):
191 return self.display_widget(size, focus).render(size, focus)
192
193 def display_widget(self, size, focus):
194 cards={}
195 max_col, = size
196 separator = " - "
197 margin = max((max_col-Card.SIZE)/2,0) * ' '
198 margin_center = max((max_col-Card.SIZE*2-len(separator))/2,0) * ' '
199 for location in ['top', 'left', 'bottom', 'right']:
200 card = getattr(self,location)
201 cards[location] = card.getAttrText() if card else Card.SIZE * ' '
202 render_wid = [urwid.Text([margin,cards['top']]),
203 urwid.Text([margin_center,cards['left'],separator,cards['right']]),
204 urwid.Text([margin,cards['bottom']])]
205 return urwid.Pile(render_wid)
206
207
208 class CardGame(QuickCardGame,urwid.WidgetWrap):
209 """Widget for card games"""
210
211 def __init__(self, parent, referee, players, player_nick):
212 QuickCardGame.__init__(self, parent, referee, players, player_nick)
213 self.loadCards()
214 self.top = urwid.Pile([urwid.Padding(urwid.Text(self.top_nick), 'center')])
215 #self.parent.host.debug()
216 self.table = Table()
217 self.center = urwid.Columns([('fixed',len(self.left_nick),urwid.Filler(urwid.Text(self.left_nick))),
218 urwid.Filler(self.table),
219 ('fixed',len(self.right_nick),urwid.Filler(urwid.Text(self.right_nick)))
220 ])
221 """urwid.Pile([urwid.Padding(self.top_card_wid,'center'),
222 urwid.Columns([('fixed',len(self.left_nick),urwid.Text(self.left_nick)),
223 urwid.Padding(self.center_cards_wid,'center'),
224 ('fixed',len(self.right_nick),urwid.Text(self.right_nick))
225 ]),
226 urwid.Padding(self.bottom_card_wid,'center')
227 ])"""
228 self.hand_wid = Hand(selectable = True, on_click = self.onClick)
229 self.main_frame = urwid.Frame(self.center,header=self.top, footer=self.hand_wid, focus_part='footer')
230 urwid.WidgetWrap.__init__(self,self.main_frame)
231 self.parent.host.bridge.tarotGameReady(player_nick, referee, profile_key = self.parent.host.profile)
232
233 def loadCards(self):
234 """Load all the cards in memory"""
235 QuickCardGame.loadCards(self)
236 for value in map(str,range(1,22))+['excuse']:
237 card = Card('atout',value)
238 self.cards[card.suit, card.value]=card
239 self.deck.append(card)
240 for suit in ["pique", "coeur", "carreau", "trefle"]:
241 for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]:
242 card = Card(suit,value)
243 self.cards[card.suit, card.value]=card
244 self.deck.append(card)
245
246 def newGame(self, hand):
247 """Start a new game, with given hand"""
248 QuickCardGame.newGame(self, hand)
249 self.hand_wid.update(self.hand)
250 self.parent.host.redraw()
251
252 def contratSelected(self, data):
253 """Called when the contrat has been choosed
254 @param data: form result"""
255 contrat = data[0][1]
256 QuickCardGame.contratSelected(self, contrat)
257
258 def chooseContrat(self, xml_data):
259 """Called when the player as to select his contrat
260 @param xml_data: SàT xml representation of the form"""
261 misc = {'callback': self.contratSelected}
262 form = XMLUI(self.parent.host, xml_data, title = _('Please choose your contrat'), options = ['NO_CANCEL'], misc = misc)
263 form.show()
264
265 def showCards(self, game_stage, cards, data):
266 """Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
267 QuickCardGame.showCards(self, game_stage, cards, data)
268 self.center.widget_list[1] = urwid.Filler(Hand(self.to_show))
269 self.parent.host.redraw()
270
271 def myTurn(self):
272 QuickCardGame.myTurn(self)
273
274 def showScores(self, xml_data, winners, loosers):
275 """Called when the player as to select hist contrat
276 @param xml_data: SàT xml representation of the form"""
277 form = XMLUI(self.parent.host, xml_data, title = _('You win \o/') if self.player_nick in winners else _('You loose :('), options = ['NO_CANCEL'])
278 form.show()
279
280 def invalidCards(self, phase, played_cards, invalid_cards):
281 """Invalid cards have been played
282 @param phase: phase of the game
283 @param played_cards: all the cards played
284 @param invalid_cards: cards which are invalid"""
285 QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards)
286 self.hand_wid.update(self.hand)
287 if self._autoplay==None: #No dialog if there is autoplay
288 self.parent.host.notify(_('Cards played are invalid !'))
289 self.parent.host.redraw()
290
291 def cardsPlayed(self, player, cards):
292 """A card has been played by player"""
293 QuickCardGame.cardsPlayed(self, player, cards)
294 self.table.putCard(self.getPlayerLocation(player),self.played[player])
295 self.parent.host.redraw()
296
297 ##EVENTS##
298 def onClick(self, hand, card_wid):
299 """Called when user do an action on the hand"""
300 if not self.state in ['play','ecart','wait_for_ecart']:
301 #it's not our turn, we ignore the click
302 card_wid.select(False)
303 return
304 if isinstance(self.center.widget_list[1].original_widget, Hand): #if we have a hand displayed
305 self.center.widget_list[1] = urwid.Filler(self.table) #we show again the table
306 if self.state == "chien":
307 self.to_show = []
308 self.state = "wait"
309 elif self.state == "wait_for_ecart":
310 self.state = "ecart"
311 self.hand.extend(self.to_show)
312 self.hand.sort()
313 self.to_show = []
314 self.hand_wid.update(self.hand)
315 if self.state == "ecart":
316 if len(self.hand_wid.getSelected()) == 6:
317 pop_up_widget = sat_widgets.ConfirmDialog(_("Do you put these cards in chien ?"), yes_cb=self.onEcartDone, no_cb=self.parent.host.removePopUp)
318 self.parent.host.showPopUp(pop_up_widget)
319 elif self.state == "play":
320 card = card_wid.getCard()
321 self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, [(card.suit, card.value)], profile_key = self.parent.host.profile)
322 self.hand.remove(card)
323 self.hand_wid.update(self.hand)
324 self.state = "wait"
325
326 def onEcartDone(self,button):
327 """Called when player has finished is écart"""
328 ecart = []
329 for card in self.hand_wid.getSelected():
330 ecart.append((card.suit, card.value))
331 self.hand.remove(card)
332 self.hand_wid.update(self.hand)
333 self.parent.host.bridge.tarotGamePlayCards(self.player_nick, self.referee, ecart, profile_key = self.parent.host.profile)
334 self.state = "wait"
335 self.parent.host.removePopUp()