Coverage for Mucked.py: 0%

218 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-15 19:33 +0000

1#!/usr/bin/env python 

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

3"""Mucked.py 

4 

5Mucked cards display for FreePokerTools HUD. 

6""" 

7 

8from __future__ import print_function 

9from __future__ import division 

10# Copyright 2008-2012, Ray E. Barker 

11# 

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

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

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

15# (at your option) any later version. 

16# 

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

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

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

20# GNU General Public License for more details. 

21# 

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

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

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

25 

26######################################################################## 

27 

28 

29from past.utils import old_div 

30# import L10n 

31# _ = L10n.init_translation() 

32 

33# Standard Library modules 

34import logging 

35 

36 

37from PyQt5.QtCore import QObject 

38from PyQt5.QtGui import QPainter, QPixmap, QStandardItem, QStandardItemModel 

39from PyQt5.QtWidgets import QGridLayout, QLabel, QTableView, QVBoxLayout, QWidget 

40 

41# FreePokerTools modules 

42import Card 

43import Aux_Base 

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

45 

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

47log = logging.getLogger("hud") 

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 self.hud = hud # hud object that this aux window supports 

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

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

59 

60 try: 

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

62 self.hero = site_params["screen_name"] 

63 except Exception: 

64 self.hero = "" 

65 

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

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

68 self.mucked_list.mucked_cards = self.mucked_cards 

69 

70 def create(self): 

71 self.container = QWidget() 

72 self.vbox = QVBoxLayout() 

73 self.container.setLayout(self.vbox) 

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

75 

76 self.mucked_list.create(self.vbox) 

77 self.mucked_cards.create(self.vbox) 

78 self.container.show() 

79 

80 def update_data(self, new_hand_id, db_connection): 

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

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

83 self.mucked_list.update_data(new_hand_id, db_connection) 

84 

85 def update_gui(self, new_hand_id): 

86 self.mucked_cards.update_gui(new_hand_id) 

87 self.mucked_list.update_gui(new_hand_id) 

88 

89 

90class Stud_list(object): 

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

92 self.parent = parent 

93 self.params = params 

94 self.config = config 

95 self.hero = hero 

96 

97 def create(self, container): 

98 self.container = container 

99 self.treeview = QTableView() 

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

101 self.treeview.setModel(self.liststore) 

102 self.liststore.setHorizontalHeaderLabels(["HandID", "Cards", "Net", "Winner"]) 

103 self.treeview.verticalHeader().hide() 

104 self.container.addWidget(self.treeview) 

105 

106 def update_data(self, new_hand_id, db_connection): 

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

108 

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

110 self.winners = db_connection.get_winners_from_hand(new_hand_id) 

111 pot = 0 

112 winners = "" 

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

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

115 if winners != "": 

116 winners = f"{winners}, " 

117 winners = winners + player 

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

119 

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

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

122 

123 def get_hero_cards(self, hero): 

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

125 if hero == "": 

126 return "xxxxxx" 

127 return next( 

128 ( 

129 Card.valueSuitFromCard(self.parent.hud.cards[stat["seat"]][0]) 

130 + Card.valueSuitFromCard(self.parent.hud.cards[stat["seat"]][1]) 

131 + Card.valueSuitFromCard(self.parent.hud.cards[stat["seat"]][2]) 

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

133 if stat["screen_name"] == hero 

134 ), 

135 "xxxxxx", 

136 ) 

137 

138 def update_gui(self, new_hand_id): 

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

140 self.treeview.resizeColumnsToContents() 

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

142 

143 

144class Stud_cards(object): 

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

146 self.parent = parent 

147 self.params = params 

148 self.config = config 

149 

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

151 self.grid_contents = {} 

152 self.eb = {} 

153 

154 self.rows = 8 

155 self.cols = 7 

156 

157 def create(self, container): 

158 self.container = container 

159 self.grid = QGridLayout() 

160 

161 for r in range(self.rows): 

162 for c in range(self.cols): 

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

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

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

166 

167 # set up the contents for the cells 

168 for r in range(self.rows): 

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

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

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

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

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

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

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

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

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

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

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

180 

181 # add the cell contents to the table 

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

183 for r in range(self.rows): 

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

185 

186 self.container.addLayout(self.grid) 

187 

188 def update_data(self, new_hand_id, db_connection): 

189 self.tips = [] 

190 action = db_connection.get_action_from_hand(new_hand_id) 

191 print(action) 

192 for street in action: 

193 temp = "" 

194 for act in street: 

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

196 if act[2] > 0: 

197 if act[2] % 100 > 0: 

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

199 else: 

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

201 else: 

202 temp = temp + "\n" 

203 self.tips.append(temp) 

204 

205 def update_gui(self, new_hand_id): 

206 self.clear() 

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

208 if c == "common": 

209 continue 

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

211 for i in ( 

212 (0, cards[0]), 

213 (1, cards[1]), 

214 (2, cards[2]), 

215 (3, cards[3]), 

216 (4, cards[4]), 

217 (5, cards[5]), 

218 (6, cards[6]), 

219 ): 

220 if i[1] != 0: 

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

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

223 _rank = Card.card_map[_rank] 

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

225 # action in tools tips for later streets 

226 # round_to_col = (0, 3, 4, 5, 6) 

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

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

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

230 

231 def get_screen_name(self, seat_no): 

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

233 return next( 

234 ( 

235 self.parent.hud.stat_dict[k]["screen_name"] 

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

237 if self.parent.hud.stat_dict[k]["seat"] == seat_no 

238 ), 

239 "No Name", 

240 ) 

241 

242 def clear(self): 

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

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

245 for c in range(0, 7): 

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

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

248 

249 

250class Flop_Mucked(Aux_Base.Aux_Seats, QObject): 

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

252 

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

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

255 QObject.__init__(self) 

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

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

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

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

260 

261 def create_common(self, x, y): 

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

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

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

265 w.move(self.positions["common"][0] + self.hud.table.x, self.positions["common"][1] + self.hud.table.y) 

266 if "opacity" in self.params: 

267 w.setWindowOpacity(float(self.params["opacity"])) 

268 return w 

269 

270 def create_contents(self, container, i): 

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

272 container.seen_cards = QLabel() 

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

274 container.setLayout(QVBoxLayout()) 

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

276 container.layout().addWidget(container.seen_cards) 

277 

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

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

280 # 

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

282 def update_contents(self, container, i): 

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

284 if hist_seat not in self.hud.cards: 

285 return 

286 

287 cards = self.hud.cards[hist_seat] 

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

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

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

291 # (card_num, card_num, ...) 

292 n_cards = valid_cards(cards) 

293 if n_cards > 1: 

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

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

296 painter = QPainter(scratch) 

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

298 for card in cards: 

299 # concatenate each card image to scratch 

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

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

302 # this needs to be changed 

303 if card is None or card == 0: 

304 break 

305 

306 # This gives us the card symbol again 

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

308 _rank = Card.card_map[_rank] 

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

310 painter.drawPixmap(x, 0, px) 

311 x += px.width() 

312 

313 painter.end() 

314 if container is not None: 

315 container.seen_cards.setPixmap(scratch) 

316 container.resize(1, 1) 

317 container.move( 

318 self.positions[i][0] + self.hud.table.x, self.positions[i][1] + self.hud.table.y 

319 ) # here is where I move back 

320 container.show() 

321 

322 self.displayed = True 

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

324 self.m_windows[i].setToolTip(self.hud.stat_dict[self.get_id_from_seat(i)]["screen_name"]) 

325 

326 def save_layout(self, *args): 

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

328 new_locs = {i: ((pos[0]), (pos[1])) for i, pos in list(self.positions.items()) if i == "common"} 

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 

359 self.hide() 

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

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

362 # is happening when timer eventually times-out 

363 if self.timer_on: 

364 self.timer_on = False 

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

366 # determined by aux_hud, not mucked card display 

367 window = widget.get_parent() 

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

369 

370 def expose_all(self): 

371 for i in self.hud.cards: 

372 self.m_windows[i].show() 

373 self.m_windows[i].move(self.positions[i][0] + self.hud.table.x, self.positions[i][1] + self.hud.table.y) 

374 self.displayed = True