Coverage for Mucked.py: 0%

217 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-28 16:41 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3"""Mucked.py 

4 

5Mucked cards display for FreePokerTools HUD. 

6""" 

7from __future__ import print_function 

8from __future__ import division 

9# Copyright 2008-2012, Ray E. Barker 

10#  

11# This program is free software; you can redistribute it and/or modify 

12# it under the terms of the GNU General Public License as published by 

13# the Free Software Foundation; either version 2 of the License, or 

14# (at your option) any later version. 

15#  

16# This program is distributed in the hope that it will be useful, 

17# but WITHOUT ANY WARRANTY; without even the implied warranty of 

18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19# GNU General Public License for more details. 

20#  

21# You should have received a copy of the GNU General Public License 

22# along with this program; if not, write to the Free Software 

23# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

24 

25######################################################################## 

26 

27 

28 

29 

30from past.utils import old_div 

31#import L10n 

32#_ = L10n.init_translation() 

33 

34# Standard Library modules 

35import logging 

36# logging has been set up in fpdb.py or HUD_main.py, use their settings: 

37log = logging.getLogger("hud") 

38 

39from PyQt5.QtCore import QObject 

40from PyQt5.QtGui import (QPainter, QPixmap, QStandardItem, QStandardItemModel) 

41from PyQt5.QtWidgets import (QGridLayout, QLabel, QTableView, 

42 QVBoxLayout, QWidget) 

43 

44# FreePokerTools modules 

45import Card 

46import Aux_Base 

47# Utility routine to get the number of valid cards in the card tuple 

48 

49 

50def valid_cards(ct): 

51 return sum(c != 0 for c in ct) 

52 

53 

54class Stud_mucked(Aux_Base.Aux_Window): 

55 def __init__(self, hud, config, params): 

56 

57 self.hud = hud # hud object that this aux window supports 

58 self.config = config # configuration object for this aux window to use 

59 self.params = params # hash aux params from config 

60 

61 try: 

62 site_params = self.config.get_site_parameters(self.hud.site) 

63 self.hero = site_params['screen_name'] 

64 except Exception: 

65 self.hero = '' 

66 

67 self.mucked_list = Stud_list(self, params, config, self.hero) 

68 self.mucked_cards = Stud_cards(self, params, config) 

69 self.mucked_list.mucked_cards = self.mucked_cards 

70 

71 def create(self): 

72 self.container = QWidget() 

73 self.vbox = QVBoxLayout() 

74 self.container.setLayout(self.vbox) 

75 self.container.setWindowTitle(self.hud.table.name) 

76 

77 self.mucked_list.create(self.vbox) 

78 self.mucked_cards.create(self.vbox) 

79 self.container.show() 

80 

81 def update_data(self, new_hand_id, db_connection): 

82 # uncomment next line when action is available in the db 

83 # self.mucked_cards.update_data(new_hand_id, db_connection) 

84 self.mucked_list.update_data(new_hand_id, db_connection) 

85 

86 def update_gui(self, new_hand_id): 

87 self.mucked_cards.update_gui(new_hand_id) 

88 self.mucked_list.update_gui(new_hand_id) 

89 

90 

91class Stud_list(object): 

92 def __init__(self, parent, params, config, hero): 

93 

94 self.parent = parent 

95 self.params = params 

96 self.config = config 

97 self.hero = hero 

98 

99 def create(self, container): 

100 self.container = container 

101 self.treeview = QTableView() 

102 self.liststore = QStandardItemModel(0, 4, self.treeview) 

103 self.treeview.setModel(self.liststore) 

104 self.liststore.setHorizontalHeaderLabels(['HandID', 'Cards', 'Net', 'Winner']) 

105 self.treeview.verticalHeader().hide() 

106 self.container.addWidget(self.treeview) 

107 

108 def update_data(self, new_hand_id, db_connection): 

109 """Updates the data needed for the list box.""" 

110 

111# db_connection = Database.Database(self.config, 'fpdb', '') 

112 self.winners = db_connection.get_winners_from_hand(new_hand_id) 

113 pot = 0 

114 winners = '' 

115 for player in list(self.winners.keys()): 

116 pot = pot + int(self.winners[player]) 

117 if winners != '': 

118 winners = f"{winners}, " 

119 winners = winners + player 

120 pot_dec = "%.2f" % (old_div(float(pot), 100)) 

121 

122 hero_cards = self.get_hero_cards(self.parent.hero) 

123 self.info_row = ((new_hand_id, hero_cards, pot_dec, winners), ) 

124 

125 def get_hero_cards(self, hero): 

126 """Formats the hero cards for inclusion in the table.""" 

127 if hero == '': 

128 return "xxxxxx" 

129 return next( 

130 ( 

131 Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][0]) 

132 + Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][1]) 

133 + Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][2]) 

134 for stat in list(self.parent.hud.stat_dict.values()) 

135 if stat['screen_name'] == hero 

136 ), 

137 "xxxxxx", 

138 ) 

139 

140 def update_gui(self, new_hand_id): 

141 self.liststore.appendRow(list(map(QStandardItem, self.info_row[0]))) 

142 self.treeview.resizeColumnsToContents() 

143 self.treeview.horizontalHeader().setStretchLastSection(True) 

144 

145 

146class Stud_cards(object): 

147 def __init__(self, parent, params, config): 

148 

149 self.parent = parent 

150 self.params = params 

151 self.config = config 

152 

153 self.card_images = self.parent.hud.parent.deck.get_all_card_images() 

154 self.grid_contents = {} 

155 self.eb = {} 

156 

157 self.rows = 8 

158 self.cols = 7 

159 

160 def create(self, container): 

161 self.container = container 

162 self.grid = QGridLayout() 

163 

164 for r in range(self.rows): 

165 for c in range(self.cols): 

166 # Start by creating a box of nothing but card backs 

167 self.eb[(c, r)]= QLabel() 

168 self.eb[(c, r)].setPixmap(self.card_images[0]) 

169 

170# set up the contents for the cells 

171 for r in range(self.rows): 

172 self.grid_contents[(0, r)] = QLabel("%d" % (r + 1)) 

173 self.grid_contents[(1, r)] = QLabel("player %d" % (r + 1)) 

174 self.grid_contents[(4, r)] = QLabel("-") 

175 self.grid_contents[(9, r)] = QLabel("-") 

176 self.grid_contents[(2, r)] = self.eb[(0, r)] 

177 self.grid_contents[(3, r)] = self.eb[(1, r)] 

178 self.grid_contents[(5, r)] = self.eb[(2, r)] 

179 self.grid_contents[(6, r)] = self.eb[(3, r)] 

180 self.grid_contents[(7, r)] = self.eb[(4, r)] 

181 self.grid_contents[(8, r)] = self.eb[(5, r)] 

182 self.grid_contents[(10, r)] = self.eb[(6, r)] 

183 

184# add the cell contents to the table 

185 for c in range(self.cols + 4): 

186 for r in range(self.rows): 

187 self.grid.addWidget(self.grid_contents[(c, r)], r, c) 

188 

189 self.container.addLayout(self.grid) 

190 

191 def update_data(self, new_hand_id, db_connection): 

192 self.tips = [] 

193 action = db_connection.get_action_from_hand(new_hand_id) 

194 print(action) 

195 for street in action: 

196 temp = '' 

197 for act in street: 

198 temp = temp + act[0] + " " + act[1] + "s " 

199 if act[2] > 0: 

200 if act[2] % 100 > 0: 

201 temp = temp + "%4.2f\n" % (old_div(float(act[2]), 100)) 

202 else: 

203 temp = temp + "%d\n" % (old_div(act[2], 100)) 

204 else: 

205 temp = temp + "\n" 

206 self.tips.append(temp) 

207 

208 def update_gui(self, new_hand_id): 

209 self.clear() 

210 for c, cards in list(self.parent.hud.cards.items()): 

211 if c == 'common': continue 

212 self.grid_contents[(1, c - 1)].setText(self.get_screen_name(c)) 

213 for i in ((0, cards[0]), (1, cards[1]), (2, cards[2]), (3, cards[3]), 

214 (4, cards[4]), (5, cards[5]), (6, cards[6])): 

215 if i[1] != 0: 

216 # Pixmaps are stored in dict with rank+suit keys 

217 (_rank, _suit) = Card.valueSuitFromCard(i[1]) 

218 _rank = Card.card_map[_rank] 

219 self.eb[(i[0], c - 1)].setPixmap(self.card_images[_suit][_rank]) 

220# action in tools tips for later streets 

221 round_to_col = (0, 3, 4, 5, 6) 

222 # for round in range(1, len(self.tips)): 

223 # for r in range(0, self.rows): 

224 # self.eb[(round_to_col[round], r)].set_tooltip_text(self.tips[round]) 

225 

226 def get_screen_name(self, seat_no): 

227 """Gets and returns the screen name from stat_dict, given seat number.""" 

228 return next( 

229 ( 

230 self.parent.hud.stat_dict[k]['screen_name'] 

231 for k in list(self.parent.hud.stat_dict.keys()) 

232 if self.parent.hud.stat_dict[k]['seat'] == seat_no 

233 ), 

234 "No Name", 

235 ) 

236 

237 def clear(self): 

238 for r in range(0, self.rows): 

239 self.grid_contents[(1, r)].setText(" ") 

240 for c in range(0, 7): 

241 # Start by creating a box of nothing but card backs 

242 self.eb[(c, r)].setPixmap(self.card_images[0]) 

243 

244 

245class Flop_Mucked(Aux_Base.Aux_Seats, QObject): 

246 """Aux_Window class for displaying mucked cards for flop games.""" 

247 

248 def __init__(self, hud, config, params): 

249 super(Flop_Mucked, self).__init__(hud, config, params) 

250 QObject.__init__(self) 

251 self.card_images = self.hud.parent.deck.get_all_card_images() 

252 self.card_height = self.hud.parent.hud_params["card_ht"] 

253 self.card_width = self.hud.parent.hud_params["card_wd"] 

254 self.uses_timer = True # this Aux_seats object uses a timer to control hiding 

255 

256 def create_common(self, x, y): 

257 """Create the window for the board cards and do the initial population.""" 

258 w = self.aw_class_window(self, "common") 

259 self.positions["common"] = self.create_scale_position(x, y) 

260 w.move(self.positions["common"][0] + self.hud.table.x, 

261 self.positions["common"][1] + self.hud.table.y) 

262 if 'opacity' in self.params: 

263 w.setWindowOpacity(float(self.params['opacity'])) 

264 return w 

265 

266 def create_contents(self, container, i): 

267 """Create the widgets for showing the contents of the Aux_seats window.""" 

268 container.seen_cards = QLabel() 

269 container.seen_cards.setPixmap(self.card_images[0]) 

270 container.setLayout(QVBoxLayout()) 

271 container.layout().setContentsMargins(0, 0, 0, 0) 

272 container.layout().addWidget(container.seen_cards) 

273 

274 # NOTE: self.hud.cards is a dictionary of: 

275 # { seat_num: (card, card, [...]) } 

276 # 

277 # Thus the individual hands (cards for seat) are tuples 

278 def update_contents(self, container, i): 

279 hist_seat = self.hud.layout.hh_seats[i] if type(i) is int else i 

280 if hist_seat not in self.hud.cards: 

281 return 

282 

283 cards = self.hud.cards[hist_seat] 

284 # Here we want to know how many cards the given seat showed; 

285 # board is considered a seat, and has the id 'common' 

286 # 'cards' on the other hand is a tuple. The format is: 

287 # (card_num, card_num, ...) 

288 n_cards = valid_cards(cards) 

289 if n_cards > 1: 

290 # scratch is a working pixmap, used to assemble the image 

291 scratch = QPixmap(int(self.card_width) * n_cards, 

292 int(self.card_height)) 

293 painter = QPainter(scratch) 

294 x = 0 # x coord where the next card starts in scratch 

295 for card in cards: 

296 # concatenate each card image to scratch 

297 # flop game never(?) has unknown cards. 

298 # FIXME: if "show one and fold" ever becomes an option, 

299 # this needs to be changed 

300 if card is None or card == 0: 

301 break 

302 

303 # This gives us the card symbol again 

304 (_rank, _suit) = Card.valueSuitFromCard(card) 

305 _rank = Card.card_map[_rank] 

306 px = self.card_images[_suit][_rank] 

307 painter.drawPixmap(x, 0, px) 

308 x += px.width() 

309 

310 painter.end() 

311 if container is not None: 

312 container.seen_cards.setPixmap(scratch) 

313 container.resize(1, 1) 

314 container.move(self.positions[i][0] + self.hud.table.x, 

315 self.positions[i][1] + self.hud.table.y) # here is where I move back 

316 container.show() 

317 

318 self.displayed = True 

319 if i != "common" and self.get_id_from_seat(i) is not None: 

320 self.m_windows[i].setToolTip(self.hud.stat_dict[self.get_id_from_seat(i)]['screen_name']) 

321 

322 def save_layout(self, *args): 

323 """Save new common position back to the layout element in the config file.""" 

324 new_locs = { 

325 i: ((pos[0]), (pos[1])) 

326 for i, pos in list(self.positions.items()) 

327 if i == 'common' 

328 } 

329 self.config.save_layout_set(self.hud.layout_set, self.hud.max, new_locs, width=None, height=None) 

330 

331 def update_gui(self, new_hand_id): 

332 """Prepare and show the mucked cards.""" 

333 if self.displayed: 

334 self.hide() 

335# See how many players showed a hand. Skip if only 1 shows (= hero) 

336 n_sd = self.count_seats_with_cards(self.hud.cards) 

337 if n_sd < 2: 

338 return 

339 

340 super(Flop_Mucked, self).update_gui(new_hand_id) 

341 

342 if self.displayed and float(self.params['timeout']) > 0: 

343 self.timer_on = True 

344 self.startTimer(int(1000*float(self.params['timeout']))) 

345 

346 def timerEvent(self, event): 

347 self.killTimer(event.timerId()) 

348 if self.timer_on: 

349 self.hide() 

350 

351 def button_press_cb(self, widget, event, i, *args): 

352 """Handle button clicks in the event boxes.""" 

353 

354 if event.button == 2: # middle button event, hold display (do not timeout) 

355 if self.timer_on: 

356 self.timer_on = False 

357 else: 

358 self.timer_on = False; self.hide() 

359 elif event.button == 1 and i == "common": # left button event (move) 

360 # firstly, cancel timer, otherwise block becomes locked if move event 

361 # is happening when timer eventually times-out 

362 if self.timer_on: 

363 self.timer_on = False 

364 # only allow move on "common" element - seat block positions are 

365 # determined by aux_hud, not mucked card display 

366 window = widget.get_parent() 

367 window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) 

368 

369 def expose_all(self): 

370 for i in self.hud.cards: 

371 self.m_windows[i].show() 

372 self.m_windows[i].move(self.positions[i][0] + self.hud.table.x, 

373 self.positions[i][1] + self.hud.table.y) 

374 self.displayed = True 

375