Coverage for Stats.py: 0%
784 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-15 19:33 +0000
« 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 -*-
4"""Manage collecting and formatting of stats and tooltips."""
5# Copyright 2008-2011, Ray E. Barker
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 2 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, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22########################################################################
24# How to write a new stat:
25# 0 Do not use a name like "xyz_2". Names ending in _ and a single digit are
26# used to indicate the number of decimal places the user wants to see in the Hud.
27# 1 You can see a listing of all the raw stats (e.g., from the HudCache table)
28# by running Database.py as a stand along program. You need to combine
29# those raw stats to get stats to present to the HUD. If you need more
30# information than is in the HudCache table, then you have to write SQL.
31# 2 The raw stats seen when you run Database.py are available in the Stats.py
32# in the stat_dict dict. For example the number of vpips would be
33# stat_dict[player]['vpip']. So the % vpip is
34# float(stat_dict[player]['vpip'])/float(stat_dict[player]['n']). You can see how the
35# keys of stat_dict relate to the column names in HudCache by inspecting
36# the proper section of the SQL.py module.
37# The stat_dict keys should be in lower case, i.e. vpip not VPIP, since
38# postgres returns the column names in lower case.
39# 3 You have to write a small function for each stat you want to add. See
40# the vpip() function for example. This function has to be protected from
41# exceptions, using something like the try:/except: paragraphs in vpip.
42# 4 The name of the function has to be the same as the of the stat used
43# in the config file.
44# 5 The stat functions have a peculiar return value, which is outlined in
45# the do_stat function. This format is useful for tool tips and maybe
46# other stuff.
47# 6 All stats receive two params (stat_dict and player) - if these parameters contain
48# "None", the stat must return its description in tuple [5] and must not traceback
49# 7 Stats needing values from the hand instance can find these in _global_hand_instance.foo
50# attribute
52import L10n
55# Standard Library modules
56import sys
59import re
61# FreePokerTools modules
62import Configuration
63import Database
65# import Charset
66import Card
67import Hand
69# String manipulation
70import codecs
73import logging
75if __name__ == "__main__":
76 Configuration.set_logfile("fpdb-log.txt")
77# logging has been set up in fpdb.py or HUD_main.py, use their settings:
78log = logging.getLogger("db")
80re_Places = re.compile("_[0-9]$")
82encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
83_ = L10n.get_translation()
86# Since tuples are immutable, we have to create a new one when
87# overriding any decimal placements. Copy old ones and recreate the
88# second value in tuple to specified format-
89def __stat_override(decimals, stat_vals):
90 """
91 Returns a tuple with the first element of `stat_vals` as a float, the second element as a string
92 with `decimals` number of decimal places, and the remaining elements of `stat_vals`.
94 Parameters:
95 - decimals (int): The number of decimal places to round the first element of `stat_vals`.
96 - stat_vals (tuple): A tuple of values.
98 Returns:
99 - tuple: A tuple with the first element of `stat_vals` as a float, the second element as a string
100 with `decimals` number of decimal places, and the remaining elements of `stat_vals`.
101 """
102 s = "%.*f" % (decimals, 100.0 * stat_vals[0])
103 return stat_vals[0], s, stat_vals[2], stat_vals[3], stat_vals[4], stat_vals[5]
106def do_tip(widget, tip):
107 """
108 Sets the tooltip of the given widget to the UTF-8 encoded version of the tip.
110 Parameters:
111 - widget: The widget to set the tooltip for.
112 - tip: The tip to encode and set as the tooltip.
114 Returns:
115 - None
116 """
117 _tip = str(tip)
118 widget.setToolTip(_tip)
121def do_stat(stat_dict, player=24, stat="vpip", hand_instance=None):
122 """
123 Calculates a specific statistic for a given player in a hand.
125 Args:
126 stat_dict (dict): A dictionary containing statistics for all players in the hand.
127 player (int, optional): The player for whom to calculate the statistic. Defaults to 24.
128 stat (str, optional): The statistic to calculate. Defaults to 'vpip'.
129 hand_instance (object, optional): An instance of the hand. Defaults to None.
131 Returns:
132 The calculated statistic for the player, or None if the statistic is not in the list of available statistics.
134 Note:
135 The hand instance is not needed for many stat functions, so it is stored in a global variable to avoid having to conditionally pass the extra value.
136 If the statistic name ends with an underscore followed by a number, it is overridden with the specified number of decimal places.
137 The decimal place override assumes the raw result is a fraction (x/100), and manual decimal places only make sense for percentage values.
138 The profit/100 hands (bb/BB) already default to three decimal places anyhow, so they are unlikely override candidates.
139 """
140 # hand instance is not needed for many stat functions
141 # so this optional parameter will be stored in a global
142 # to avoid having to conditionally pass the extra value
143 global _global_hand_instance
144 _global_hand_instance = hand_instance
146 statname = stat
147 match = re_Places.search(stat)
148 if match: # override if necessary
149 statname = stat[0:-2]
151 if statname not in STATLIST:
152 return None
154 result = eval("%(stat)s(stat_dict, %(player)d)" % {"stat": statname, "player": player})
156 # If decimal places have been defined, override result[1]
157 # NOTE: decimal place override ALWAYS assumes the raw result is a
158 # fraction (x/100); manual decimal places really only make sense for
159 # percentage values. Also, profit/100 hands (bb/BB) already default
160 # to three decimal places anyhow, so they are unlikely override
161 # candidates.
162 if match:
163 places = int(stat[-1:])
164 result = __stat_override(places, result)
165 return result
168# OK, for reference the tuple returned by the stat is:
169# 0 - The stat, raw, no formating, eg 0.33333333
170# 1 - formatted stat with appropriate precision, eg. 33; shown in HUD
171# 2 - formatted stat with appropriate precision, punctuation and a hint, eg v=33%
172# 3 - same as #2 except name of stat instead of hint, eg vpip=33%
173# 4 - the calculation that got the stat, eg 9/27
174# 5 - the name of the stat, useful for a tooltip, eg vpip
176###########################################
177# functions that return individual stats
180def totalprofit(stat_dict, player):
181 """
182 Calculates the total profit for a given player.
184 Args:
185 stat_dict (dict): A dictionary containing player statistics.
186 player (int): The player for whom to calculate the total profit.
188 Returns:
189 tuple: A tuple containing the following values:
190 - stat (float): The total profit divided by 100.
191 - formatted_stat (str): The formatted total profit with two decimal places.
192 - tp_formatted_stat (str): The formatted total profit with two decimal places and a hint.
193 - tot_prof_formatted_stat (str): The formatted total profit with two decimal places and a hint.
194 - str_stat (str): The total profit as a string.
195 - stat_name (str): The name of the statistic.
197 If the 'net' key is not present in the stat_dict for the given player, or if the value cannot be converted to a float,
198 the function returns a tuple with default values:
199 - ('0', '$0.00', 'tp=0', 'totalprofit=0', '0', 'Total Profit')
200 """
201 try:
202 stat = float(stat_dict[player]["net"]) / 100
203 return (stat / 100.0, "$%.2f" % stat, "tp=$%.2f" % stat, "tot_prof=$%.2f" % stat, str(stat), "Total Profit")
204 except (KeyError, ValueError, TypeError):
205 return ("0", "$0.00", "tp=0", "totalprofit=0", "0", "Total Profit")
208def playername(stat_dict, player):
209 """
210 Retrieves the player's screen name from the stat dictionary.
212 Args:
213 stat_dict (dict): A dictionary containing player statistics.
214 player (int): The player for whom to retrieve the screen name.
216 Returns:
217 tuple: A tuple containing the player's screen name repeated five times and a constant 'Player name' at the end. If the player's screen name is not found, it returns an empty string five times followed by 'Player name'.
218 """
219 try:
220 return (
221 stat_dict[player]["screen_name"],
222 stat_dict[player]["screen_name"],
223 stat_dict[player]["screen_name"],
224 stat_dict[player]["screen_name"],
225 stat_dict[player]["screen_name"],
226 "Player name",
227 )
228 except (KeyError, ValueError, TypeError):
229 return ("", "", "", "", "", "Player name")
232def _calculate_end_stack(stat_dict, player, hand_instance):
233 """
234 Calculate the end stack size for a given player in a hand instance.
236 Args:
237 stat_dict (dict): A dictionary containing player statistics.
238 player (int): The player for whom to calculate the end stack size.
239 hand_instance (Hand): An instance of the Hand class representing the current hand.
241 Returns:
242 float: The end stack size for the given player.
244 Note:
245 This function is currently located in Stats.py but it should be moved to Hands.py since it belongs there.
247 Todo:
248 - Find a better way to calculate the end stack size from the hand_instance.
249 - Add a hand_instance "end_of_hand_stack" attribute.
250 """
251 # fixme - move this code into Hands.py - it really belongs there
253 # To reflect the end-of-hand position, we need a end-stack calculation
254 # fixme, is there an easier way to do this from the hand_instance???
255 # can't seem to find a hand_instance "end_of_hand_stack" attribute
257 # First, find player stack size at the start of the hand
258 stack = 0.0
259 for item in hand_instance.players:
260 if item[1] == stat_dict[player]["screen_name"]:
261 stack = float(item[2])
263 # Next, deduct all action from this player
264 for street in hand_instance.bets:
265 for item in hand_instance.bets[street]:
266 if item == stat_dict[player]["screen_name"]:
267 for amount in hand_instance.bets[street][stat_dict[player]["screen_name"]]:
268 stack -= float(amount)
270 # Next, add back any money returned
271 for p in hand_instance.pot.returned:
272 if p == stat_dict[player]["screen_name"]:
273 stack += float(hand_instance.pot.returned[p])
275 # Finally, add back any winnings
276 for item in hand_instance.collectees:
277 if item == stat_dict[player]["screen_name"]:
278 stack += float(hand_instance.collectees[item])
279 return stack
282def m_ratio(stat_dict, player):
283 """
284 Calculate the M-ratio for a player in a tournament.
286 Args:
287 stat_dict (dict): A dictionary containing player statistics.
288 player (int): The player for whom to calculate the M-ratio.
290 Returns:
291 tuple: A tuple containing the M-ratio value and formatted strings.
293 Note:
294 This function calculates the M-ratio using the end-of-hand stack count versus the hand's antes/blinds.
295 """
296 # Tournament M-ratio calculation
297 # Using the end-of-hand stack count vs. that hand's antes/blinds
299 # sum all blinds/antes
300 stat = 0.0
301 compulsory_bets = 0.0
302 hand_instance = _global_hand_instance
304 if not hand_instance:
305 return (
306 (stat / 100.0),
307 "%d" % (int(stat)),
308 "M=%d" % (int(stat)),
309 "M=%d" % (int(stat)),
310 "(%d)" % (int(stat)),
311 "M ratio",
312 )
314 for p in hand_instance.bets["BLINDSANTES"]:
315 for i in hand_instance.bets["BLINDSANTES"][p]:
316 compulsory_bets += float(i)
317 compulsory_bets += float(hand_instance.gametype.get("sb", 0)) # Ensure "sb" key exists
318 compulsory_bets += float(hand_instance.gametype.get("bb", 0)) # Ensure "bb" key exists
320 stack = _calculate_end_stack(stat_dict, player, hand_instance)
322 if compulsory_bets != 0: # Check if compulsory_bets is non-zero to avoid division by zero
323 stat = stack / compulsory_bets
324 else:
325 stat = 0 # Default to 0 if compulsory_bets is zero
327 return (
328 (int(stat)),
329 "%d" % (int(stat)),
330 "M=%d" % (int(stat)),
331 "M=%d" % (int(stat)),
332 "(%d)" % (int(stat)),
333 "M ratio",
334 )
337def bbstack(stat_dict, player):
338 """
339 Calculate the tournament stack size in Big Blinds.
341 Args:
342 stat_dict (dict): A dictionary containing player statistics.
343 player (int): The player for whom to calculate the stack size.
345 Returns:
346 tuple: A tuple containing the stack size in Big Blinds and related information.
348 Note:
349 This function calculates the stack size in Big Blinds based on the end of hand stack count and the current Big Blind limit.
350 """
351 # Tournament Stack calculation in Big Blinds
352 # Result is end of hand stack count / Current Big Blind limit
353 stat = 0.0
354 hand_instance = _global_hand_instance
355 if not (hand_instance):
356 return (stat, "NA", "v=NA", "vpip=NA", "(0/0)", "bb stack")
358 # current big blind limit
360 current_bigblindlimit = 0
361 current_bigblindlimit += float(hand_instance.gametype["bb"])
363 stack = _calculate_end_stack(stat_dict, player, hand_instance)
365 if current_bigblindlimit != 0:
366 stat = stack / current_bigblindlimit
367 else:
368 stat = 0
370 return (
371 (stat / 100.0),
372 "%d" % (int(stat)),
373 "bb's=%d" % (int(stat)),
374 "#bb's=%d" % (int(stat)),
375 "(%d)" % (int(stat)),
376 "bb stack",
377 )
380def playershort(stat_dict, player):
381 """
382 Retrieves the shortened screen name of a player from the given stat_dict.
384 Args:
385 stat_dict (dict): A dictionary containing player statistics.
386 player (int): The player for whom to retrieve the shortened screen name.
388 Returns:
389 tuple: A tuple containing the shortened screen name and related information.
391 Raises:
392 KeyError: If the player's screen name is not found in the stat_dict.
394 Note:
395 If the length of the screen name is greater than 6, it is truncated to 5 characters and a dot is appended.
396 The returned tuple contains the shortened screen name repeated 5 times and the player's full screen name.
397 """
398 try:
399 r = stat_dict[player]["screen_name"]
400 except (KeyError, ValueError, TypeError):
401 return ("", "", "", "", "", ("Player Name") + " 1-5")
403 if len(r) > 6:
404 r = r[:5] + "."
405 return (r, r, r, r, stat_dict[player]["screen_name"], ("Player Name") + " 1-5")
408def vpip(stat_dict, player):
409 """
410 A function to calculate and return VPIP (Voluntarily Put In Pot) percentage.
412 Args:
413 stat_dict (dict): A dictionary containing player statistics.
414 player (str): The player for whom to calculate the VPIP.
416 Returns:
417 tuple: A tuple containing:
418 - VPIP percentage (float)
419 - VPIP percentage formatted as a string
420 - 'v=' followed by VPIP percentage formatted as a percentage string
421 - 'vpip=' followed by VPIP percentage formatted as a percentage string
422 - '(x/y)' where x is the VPIP and y is VPIP opportunities
423 - 'Voluntarily put in preflop/3rd street %'
425 If an error occurs, returns:
426 - 0.0
427 - 'NA'
428 - 'v=NA'
429 - 'vpip=NA'
430 - '(0/0)'
431 - 'Voluntarily put in preflop/3rd street %'
432 """
433 stat = 0.0
434 try:
435 vpip_opp = float(stat_dict[player].get("vpip_opp", 0)) # Ensure key exists
436 if vpip_opp != 0: # Check if vpip_opp is non-zero to avoid division by zero
437 stat = float(stat_dict[player]["vpip"]) / vpip_opp
438 else:
439 stat = 0 # Default to 0 if vpip_opp is zero
441 return (
442 stat,
443 "%3.1f" % (100.0 * stat),
444 "v=%3.1f%%" % (100.0 * stat),
445 "vpip=%3.1f%%" % (100.0 * stat),
446 "(%d/%d)" % (stat_dict[player]["vpip"], vpip_opp),
447 "Voluntarily put in preflop/3rd street %",
448 )
449 except (KeyError, ValueError, TypeError):
450 return (stat, "NA", "v=NA", "vpip=NA", "(0/0)", "Voluntarily put in preflop/3rd street %")
453def pfr(stat_dict, player):
454 """
455 Calculate and return the preflop raise percentage (pfr) for a player.
457 Args:
458 stat_dict (dict): A dictionary containing player statistics.
459 player (int): The player for whom the pfr is calculated.
461 Returns:
462 tuple: A tuple containing the pfr value, formatted pfr percentages, and related information.
463 """
464 stat = 0.0
465 try:
466 pfr_opp = float(stat_dict[player].get("pfr_opp", 0)) # Ensure key exists
467 if pfr_opp != 0: # Check if pfr_opp is non-zero to avoid division by zero
468 stat = float(stat_dict[player]["pfr"]) / pfr_opp
469 else:
470 stat = 0 # Default to 0 if pfr_opp is zero
472 return (
473 stat,
474 "%3.1f" % (100.0 * stat),
475 "p=%3.1f%%" % (100.0 * stat),
476 "pfr=%3.1f%%" % (100.0 * stat),
477 "(%d/%d)" % (stat_dict[player]["pfr"], pfr_opp),
478 "Preflop/3rd street raise %",
479 )
480 except (KeyError, ValueError, TypeError):
481 return (stat, "NA", "p=NA", "pfr=NA", "(0/0)", "Preflop/3rd street raise %")
484def wtsd(stat_dict, player):
485 """
486 Calculate and return the percentage of hands where a player went to showdown when seen flop/4th street.
488 Args:
489 stat_dict (dict): A dictionary containing player statistics.
490 player (int): The player for whom the percentage is calculated.
492 Returns:
493 tuple: A tuple containing the percentage value, formatted percentage percentages, and related information.
494 """
495 stat = 0.0
496 try:
497 saw_f = float(stat_dict[player].get("saw_f", 0)) # Ensure key exists
498 if saw_f != 0: # Check if saw_f is non-zero to avoid division by zero
499 stat = float(stat_dict[player]["sd"]) / saw_f
500 else:
501 stat = 0 # Default to 0 if saw_f is zero
503 return (
504 stat,
505 "%3.1f" % (100.0 * stat),
506 "w=%3.1f%%" % (100.0 * stat),
507 "wtsd=%3.1f%%" % (100.0 * stat),
508 "(%d/%d)" % (stat_dict[player]["sd"], saw_f),
509 "% went to showdown when seen flop/4th street",
510 )
511 except (KeyError, ValueError, TypeError):
512 return (stat, "NA", "w=NA", "wtsd=NA", "(0/0)", "% went to showdown when seen flop/4th street")
515def wmsd(stat_dict, player):
516 """
517 Calculate and return the win money at showdown (wmsd) statistics for a player.
519 Args:
520 stat_dict (dict): A dictionary containing player statistics.
521 player (int): The player for whom the wmsd is calculated.
523 Returns:
524 tuple: A tuple containing the wmsd value, formatted wmsd percentages, and related information.
525 """
526 stat = 0.0
527 try:
528 sd = float(stat_dict[player].get("sd", 0)) # Ensure key exists
529 if sd != 0: # Check if sd is non-zero to avoid division by zero
530 stat = float(stat_dict[player]["wmsd"]) / sd
531 else:
532 stat = 0 # Default to 0 if sd is zero
534 return (
535 stat,
536 "%3.1f" % (100.0 * stat),
537 "w=%3.1f%%" % (100.0 * stat),
538 "wmsd=%3.1f%%" % (100.0 * stat),
539 "(%5.1f/%d)" % (float(stat_dict[player]["wmsd"]), sd),
540 "% won some money at showdown",
541 )
542 except (KeyError, ValueError, TypeError):
543 return (stat, "NA", "w=NA", "wmsd=NA", "(0/0)", "% won some money at showdown")
546# Money is stored as pennies, so there is an implicit 100-multiplier
547# already in place
548def profit100(stat_dict, player):
549 """
550 Calculate the profit per 100 hands for a given player.
552 Args:
553 stat_dict (dict): A dictionary containing player statistics.
554 player (int): The player for whom the profit per 100 hands is calculated.
556 Returns:
557 tuple: A tuple containing the profit per 100 hands value, formatted profit percentages, and related information.
559 Notes:
560 - The profit per 100 hands is calculated by dividing the net winnings by the number of hands played.
561 - If an exception occurs during the calculation, the function returns a tuple with default values.
562 """
563 stat = 0.0
564 try:
565 n = float(stat_dict[player].get("n", 0)) # Ensure key exists
566 if n != 0: # Check if 'n' (number of hands) is non-zero
567 stat = float(stat_dict[player]["net"]) / n
568 else:
569 stat = 0 # Default to 0 if 'n' is zero
571 return (
572 stat / 100.0,
573 "%.2f" % (stat),
574 "p=%.2f" % (stat),
575 "p/100=%.2f" % (stat),
576 "%d/%d" % (stat_dict[player]["net"], n),
577 "Profit per 100 hands",
578 )
580 except (KeyError, ValueError, TypeError):
581 if stat_dict:
582 log.error(
583 "exception calculating profit100: 100 * %d / %d" % (stat_dict[player]["net"], stat_dict[player]["n"])
584 )
585 return (stat, "NA", "p=NA", "p/100=NA", "(0/0)", "Profit per 100 hands")
588def bbper100(stat_dict, player):
589 """
590 Calculate the number of big blinds won per 100 hands for a given player.
592 Args:
593 stat_dict (dict): A dictionary containing player statistics.
594 player (int): The player for whom the number of big blinds won per 100 hands is calculated.
596 Returns:
597 tuple: A tuple containing the number of big blinds won per 100 hands value, formatted values, and related information.
598 """
599 stat = 0.0
600 try:
601 bigblind = float(stat_dict[player].get("bigblind", 0)) # Ensure key exists
602 if bigblind != 0: # Check if 'bigblind' is non-zero
603 stat = 100.0 * float(stat_dict[player]["net"]) / bigblind
604 else:
605 stat = 0 # Default to 0 if 'bigblind' is zero
607 return (
608 stat / 100.0,
609 "%5.3f" % (stat),
610 "bb100=%5.3f" % (stat),
611 "bb100=%5.3f" % (stat),
612 "(%d,%d)" % (100 * stat_dict[player]["net"], bigblind),
613 "Big blinds won per 100 hands",
614 )
616 except (KeyError, ValueError, TypeError):
617 if stat_dict:
618 log.info(
619 "exception calculating bbper100: 100 * %d / %d"
620 % (stat_dict[player]["net"], stat_dict[player]["bigblind"])
621 )
622 return (stat, "NA", "bb100=NA", "bb100=NA", "(--)", "Big blinds won per 100 hands")
625def BBper100(stat_dict, player):
626 """
627 Calculate the number of big bets won per 100 hands for a given player.
629 Args:
630 stat_dict (dict): A dictionary containing player statistics.
631 player (int): The player for whom the number of big bets won per 100 hands is calculated.
633 Returns:
634 tuple: A tuple containing the number of big bets won per 100 hands value, formatted values, and related information.
636 Notes:
637 - The number of big bets won per 100 hands is calculated by dividing the net winnings by the big blind value, multiplied by 50.
638 - If an exception occurs during the calculation, the function returns a tuple with default values.
639 """
640 stat = 0.0
641 try:
642 bigblind = float(stat_dict[player].get("bigblind", 0)) # Ensure key exists
643 if bigblind != 0: # Check if 'bigblind' is non-zero
644 stat = 50 * float(stat_dict[player]["net"]) / bigblind
645 else:
646 stat = 0 # Default to 0 if 'bigblind' is zero
648 return (
649 stat / 100.0,
650 "%5.3f" % (stat),
651 "BB100=%5.3f" % (stat),
652 "BB100=%5.3f" % (stat),
653 "(%d,%d)" % (100 * stat_dict[player]["net"], 2 * bigblind),
654 "Big bets won per 100 hands",
655 )
657 except (KeyError, ValueError, TypeError):
658 if stat_dict:
659 log.info("exception calculating BBper100: " + str(stat_dict[player]))
660 return (stat, "NA", "BB100=NA", "BB100=NA", "(--)", "Big bets won per 100 hands")
663def saw_f(stat_dict, player):
664 """Calculate the saw flop percentage for a given player.
666 Args:
667 stat_dict (dict): A dictionary containing player statistics.
668 player (int): The player for whom the saw flop percentage is calculated.
670 Returns:
671 tuple: A tuple containing the saw flop percentage in various formats.
672 - The saw flop percentage as a float.
673 - The saw flop percentage formatted to one decimal place.
674 - The saw flop percentage with a label.
675 - The saw flop percentage with a different label.
676 - The count of times saw flop divided by total count.
677 - A description of the statistic.
679 If an error occurs during calculation, default values are returned.
680 """
681 try:
682 num = float(stat_dict[player]["saw_f"])
683 den = float(stat_dict[player]["n"])
684 stat = num / den
685 return (
686 stat,
687 "%3.1f" % (100.0 * stat),
688 "sf=%3.1f%%" % (100.0 * stat),
689 "saw_f=%3.1f%%" % (100.0 * stat),
690 "(%d/%d)" % (stat_dict[player]["saw_f"], stat_dict[player]["n"]),
691 "Flop/4th street seen %",
692 )
694 except (KeyError, ValueError, TypeError):
695 stat = 0.0
696 return (stat, "NA", "sf=NA", "saw_f=NA", "(0/0)", "Flop/4th street seen %")
699def n(stat_dict, player):
700 """
701 Calculate and format the number of hands seen for a player.
703 Args:
704 stat_dict (dict): A dictionary containing player statistics.
705 player (int): The player for whom the number of hands seen is calculated.
707 Returns:
708 tuple: A tuple containing formatted strings representing the number of hands seen in different ways.
709 """
710 try:
711 # If sample is large enough, use X.Yk notation instead
712 _n = stat_dict[player]["n"]
713 fmt = "%d" % _n
714 if _n >= 10000:
715 k = _n / 1000
716 c = _n % 1000
717 _c = float(c) / 100.0
718 d = int(round(_c))
719 if d == 10:
720 k += 1
721 d = 0
722 fmt = "%d.%dk" % (k, d)
723 return (
724 stat_dict[player]["n"],
725 "%s" % fmt,
726 "n=%d" % (stat_dict[player]["n"]),
727 "n=%d" % (stat_dict[player]["n"]),
728 "(%d)" % (stat_dict[player]["n"]),
729 "Number of hands seen",
730 )
732 except (KeyError, ValueError, TypeError):
733 # Number of hands shouldn't ever be "NA"; zeroes are better here
734 return (0, "%d" % (0), "n=%d" % (0), "n=%d" % (0), "(%d)" % (0), "Number of hands seen")
737def steal(stat_dict, player):
738 """
739 Calculate and format the steal percentage for a player.
741 Args:
742 stat_dict (dict): A dictionary containing player statistics.
743 player (int): The player for whom the steal percentage is calculated.
745 Returns:
746 tuple: A tuple containing formatted strings representing the steal percentage in different ways.
747 - stat (float): The steal percentage.
748 - '%3.1f' (str): The steal percentage formatted as a string with 3 decimal places.
749 - 'st=%3.1f%%' (str): The steal percentage formatted as a string with 3 decimal places and a percentage sign.
750 - 'steal=%3.1f%%' (str): The steal percentage formatted as a string with 3 decimal places and a percentage sign.
751 - '(%d/%d)' (str): The steal count and steal opponent count formatted as a string.
752 - '% steal attempted' (str): The description of the steal percentage.
754 Raises:
755 None
757 Notes:
758 - The steal percentage is calculated by dividing the steal count by the steal opponent count.
759 - If any of the required statistics are missing, the function returns default values.
760 """
761 stat = 0.0
762 try:
763 steal_opp = float(stat_dict[player].get("steal_opp", 0)) # Ensure key exists
764 if steal_opp != 0: # Check if steal_opp is non-zero to avoid division by zero
765 stat = float(stat_dict[player]["steal"]) / steal_opp
766 else:
767 stat = 0 # Default to 0 if steal_opp is zero
769 return (
770 stat,
771 "%3.1f" % (100.0 * stat),
772 "st=%3.1f%%" % (100.0 * stat),
773 "steal=%3.1f%%" % (100.0 * stat),
774 "(%d/%d)" % (stat_dict[player]["steal"], steal_opp),
775 "% steal attempted",
776 )
778 except (KeyError, ValueError, TypeError):
779 return (stat, "NA", "st=NA", "steal=NA", "(0/0)", "% steal attempted")
782def s_steal(stat_dict, player):
783 """
784 Calculate and format the steal success percentage for a player.
786 Args:
787 stat_dict (dict): A dictionary containing player statistics.
788 player (int): The player for whom the steal success percentage is calculated.
790 Returns:
791 tuple: A tuple containing formatted strings representing the steal success percentage in different ways.
792 - stat (float): The steal success percentage.
793 - '%3.1f' (str): The steal success percentage formatted as a string with 3 decimal places.
794 - 's_st=%3.1f%%' (str): The steal success percentage formatted with a specific label.
795 - 's_steal=%3.1f%%' (str): The steal success percentage formatted with a specific label.
796 - '(%d/%d)' (str): The steal success count and total steal count formatted as a string.
797 - '% steal success' (str): The description of the steal success percentage.
799 Raises:
800 None
801 """
802 stat = 0.0
803 try:
804 if float(stat_dict[player]["steal"]) != 0:
805 stat = float(stat_dict[player]["suc_st"]) / float(stat_dict[player]["steal"])
806 return (
807 stat,
808 "%3.1f" % (100.0 * stat),
809 "s_st=%3.1f%%" % (100.0 * stat),
810 "s_steal=%3.1f%%" % (100.0 * stat),
811 "(%d/%d)" % (stat_dict[player]["suc_st"], stat_dict[player]["steal"]),
812 "% steal success",
813 )
815 except (KeyError, ValueError, TypeError):
816 return (stat, "NA", "s_st=NA", "s_steal=NA", "(0/0)", "% steal success")
819def f_SB_steal(stat_dict, player):
820 """
821 Calculate the folded Small Blind (SB) to steal statistics for a player.
823 Args:
824 stat_dict (dict): A dictionary containing player statistics.
825 player (int): The player for whom the statistics are calculated.
827 Returns:
828 tuple: A tuple containing the folded SB to steal statistics.
829 - stat (float): The folded SB to steal percentage.
830 - '%3.1f' (str): The folded SB to steal percentage formatted as a string with 3 decimal places.
831 - 'fSB=%3.1f%%' (str): The folded SB to steal percentage formatted with a specific label.
832 - 'fSB_s=%3.1f%%' (str): The folded SB to steal percentage formatted with a specific label.
833 - '(%d/%d)' (str): The number of folded SB to steal and the total number of folded SB formatted as a string.
834 - '% folded SB to steal' (str): The description of the folded SB to steal percentage.
836 Raises:
837 None
838 """
839 stat = 0.0
840 try:
841 if float(stat_dict[player]["sbstolen"]) != 0:
842 stat = float(stat_dict[player]["sbnotdef"]) / float(stat_dict[player]["sbstolen"])
843 return (
844 stat,
845 "%3.1f" % (100.0 * stat),
846 "fSB=%3.1f%%" % (100.0 * stat),
847 "fSB_s=%3.1f%%" % (100.0 * stat),
848 "(%d/%d)" % (stat_dict[player]["sbnotdef"], stat_dict[player]["sbstolen"]),
849 "% folded SB to steal",
850 )
851 except (KeyError, ValueError, TypeError):
852 return (stat, "NA", "fSB=NA", "fSB_s=NA", "(0/0)", "% folded SB to steal")
855def f_BB_steal(stat_dict, player):
856 """Calculate the folded Big Blind (BB) to steal statistics for a player.
858 Args:
859 stat_dict (dict): A dictionary containing player statistics.
860 player (int): The player for whom the statistics are calculated.
862 Returns:
863 tuple: A tuple containing the calculated statistics in different formats:
864 - Float: The calculated statistic.
865 - String: The statistic formatted as a percentage with one decimal place.
866 - String: A formatted string representing the statistic.
867 - String: A formatted string representing the statistic with a suffix.
868 - String: A formatted string showing the count of BB not defended and BB stolen.
869 - String: A description of the statistic.
871 If an exception occurs during the calculation, returns default values for the statistics.
872 """
873 stat = 0.0
874 try:
875 if float(stat_dict[player]["bbstolen"]) != 0:
876 stat = float(stat_dict[player]["bbnotdef"]) / float(stat_dict[player]["bbstolen"])
877 return (
878 stat,
879 "%3.1f" % (100.0 * stat),
880 "fBB=%3.1f%%" % (100.0 * stat),
881 "fBB_s=%3.1f%%" % (100.0 * stat),
882 "(%d/%d)" % (stat_dict[player]["bbnotdef"], stat_dict[player]["bbstolen"]),
883 "% folded BB to steal",
884 )
885 except (KeyError, ValueError, TypeError):
886 return (stat, "NA", "fBB=NA", "fBB_s=NA", "(0/0)", "% folded BB to steal")
889def f_steal(stat_dict, player):
890 """
891 Calculate the folded blind to steal statistics for a player.
893 Args:
894 stat_dict (dict): A dictionary containing player statistics.
895 player (int): The player for whom the statistics are calculated.
897 Returns:
898 tuple: A tuple containing the calculated statistics in different formats:
899 - Float: The calculated statistic.
900 - String: The statistic formatted as a percentage with one decimal place.
901 - String: A formatted string representing the statistic.
902 - String: A formatted string representing the statistic with a suffix.
903 - String: A formatted string showing the count of folded blind not defended and blind stolen.
904 - String: A description of the statistic.
906 If an exception occurs during the calculation, returns default values for the statistics.
907 """
908 stat = 0.0
909 try:
910 folded_blind = stat_dict[player].get("sbnotdef", 0) + stat_dict[player].get("bbnotdef", 0)
911 blind_stolen = stat_dict[player].get("sbstolen", 0) + stat_dict[player].get("bbstolen", 0)
913 if blind_stolen != 0: # Check if blind_stolen is non-zero to avoid division by zero
914 stat = float(folded_blind) / float(blind_stolen)
916 return (
917 stat,
918 "%3.1f" % (100.0 * stat),
919 "fB=%3.1f%%" % (100.0 * stat),
920 "fB_s=%3.1f%%" % (100.0 * stat),
921 "(%d/%d)" % (folded_blind, blind_stolen),
922 "% folded blind to steal",
923 )
924 except (KeyError, ValueError, TypeError):
925 return (stat, "NA", "fB=NA", "fB_s=NA", "(0/0)", "% folded blind to steal")
928def three_B(stat_dict, player):
929 """
930 Calculate the three bet statistics for a player.
932 Args:
933 stat_dict (dict): A dictionary containing player statistics.
934 player (int): The player for whom the statistics are calculated.
936 Returns:
937 tuple: A tuple containing the calculated statistics in different formats:
938 - Float: The calculated statistic.
939 - String: The statistic formatted as a percentage with one decimal place.
940 - String: A formatted string representing the statistic.
941 - String: A formatted string representing the statistic with a suffix.
942 - String: A formatted string showing the count of three bets made and opponent's three bets.
943 - String: A description of the statistic.
945 If an exception occurs during the calculation, returns default values for the statistics.
946 """
947 stat = 0.0
948 try:
949 tb_opp_0 = float(stat_dict[player].get("tb_opp_0", 0)) # Ensure key exists
950 if tb_opp_0 != 0: # Check if tb_opp_0 is non-zero to avoid division by zero
951 stat = float(stat_dict[player]["tb_0"]) / tb_opp_0
952 else:
953 stat = 0 # Default to 0 if tb_opp_0 is zero
955 return (
956 stat,
957 "%3.1f" % (100.0 * stat),
958 "3B=%3.1f%%" % (100.0 * stat),
959 "3B_pf=%3.1f%%" % (100.0 * stat),
960 "(%d/%d)" % (stat_dict[player]["tb_0"], tb_opp_0),
961 "% 3 bet preflop/3rd street",
962 )
963 except (KeyError, ValueError, TypeError):
964 return (stat, "NA", "3B=NA", "3B_pf=NA", "(0/0)", "% 3 bet preflop/3rd street")
967def four_B(stat_dict, player):
968 """
969 Calculate the four bet statistics for a player.
971 Args:
972 stat_dict (dict): A dictionary containing player statistics.
973 player (int): The player for whom the statistics are calculated.
975 Returns:
976 tuple: A tuple containing the calculated statistics in different formats:
977 - Float: The calculated statistic.
978 - String: The statistic formatted as a percentage with one decimal place.
979 - String: A formatted string representing the statistic.
980 - String: A formatted string representing the statistic with a suffix.
981 - String: A formatted string showing the count of four bets made and opponent's four bets.
982 - String: A description of the statistic.
984 If an exception occurs during the calculation, returns default values for the statistics.
985 """
986 stat = 0.0
987 try:
988 fb_opp_0 = float(stat_dict[player].get("fb_opp_0", 0)) # Ensure key exists
989 if fb_opp_0 != 0: # Check if fb_opp_0 is non-zero to avoid division by zero
990 stat = float(stat_dict[player]["fb_0"]) / fb_opp_0
991 else:
992 stat = 0 # Default to 0 if fb_opp_0 is zero
994 return (
995 stat,
996 "%3.1f" % (100.0 * stat),
997 "4B=%3.1f%%" % (100.0 * stat),
998 "4B=%3.1f%%" % (100.0 * stat),
999 "(%d/%d)" % (stat_dict[player]["fb_0"], fb_opp_0),
1000 "% 4 bet preflop/3rd street",
1001 )
1002 except (KeyError, ValueError, TypeError):
1003 return (stat, "NA", "4B=NA", "4B=NA", "(0/0)", "% 4 bet preflop/3rd street")
1006def cfour_B(stat_dict, player):
1007 """
1008 Calculate the cold 4 bet statistics for a player.
1010 Args:
1011 stat_dict (dict): A dictionary containing player statistics.
1012 player (int): The player for whom the statistics are calculated.
1014 Returns:
1015 tuple: A tuple containing the calculated statistics in different formats:
1016 - Float: The calculated statistic.
1017 - String: The statistic formatted as a percentage with one decimal place.
1018 - String: A formatted string representing the statistic.
1019 - String: A formatted string representing the statistic with a suffix.
1020 - String: A formatted string showing the count of cold 4 bets made and opponent's cold 4 bets.
1021 - String: A description of the statistic.
1023 If an exception occurs during the calculation, returns default values for the statistics.
1024 """
1025 stat = 0.0
1026 try:
1027 if float(stat_dict[player]["cfb_opp_0"]) != 0:
1028 stat = float(stat_dict[player]["cfb_0"]) / float(stat_dict[player]["cfb_opp_0"])
1029 return (
1030 stat,
1031 "%3.1f" % (100.0 * stat),
1032 "C4B=%3.1f%%" % (100.0 * stat),
1033 "C4B_pf=%3.1f%%" % (100.0 * stat),
1034 "(%d/%d)" % (stat_dict[player]["cfb_0"], stat_dict[player]["cfb_opp_0"]),
1035 "% cold 4 bet preflop/3rd street",
1036 )
1037 except (KeyError, ValueError, TypeError):
1038 return (stat, "NA", "C4B=NA", "C4B_pf=NA", "(0/0)", "% cold 4 bet preflop/3rd street")
1041# Four Bet Range
1042def fbr(stat_dict, player):
1043 """
1044 A function to calculate the four bet range statistics for a player.
1046 Args:
1047 stat_dict (dict): A dictionary containing player statistics.
1048 player (int): The player for whom the statistics are calculated.
1050 Returns:
1051 tuple: A tuple containing the calculated statistics in different formats:
1052 - Float: The calculated statistic.
1053 - String: The statistic formatted as a percentage with one decimal place.
1054 - String: A formatted string representing the statistic.
1055 - String: A formatted string representing the statistic with a suffix.
1056 - String: A formatted string showing the product of 'pfr' and 'four_B'.
1057 - String: A description of the statistic.
1059 If an exception occurs during the calculation, returns default values for the statistics.
1060 """
1061 stat = 0.0
1062 try:
1063 fb_opp_0 = float(stat_dict[player].get("fb_opp_0", 0)) # Ensure key exists
1064 pfr_opp = float(stat_dict[player].get("n", 0)) # Ensure key exists
1066 if fb_opp_0 != 0 and pfr_opp != 0: # Check both values to avoid division by zero
1067 stat = (float(stat_dict[player]["fb_0"]) / fb_opp_0) * (float(stat_dict[player]["pfr"]) / pfr_opp)
1068 else:
1069 stat = 0 # Default to 0 if any of the values is zero
1071 return (
1072 stat,
1073 "%3.1f" % (100.0 * stat),
1074 "fbr=%3.1f%%" % (100.0 * stat),
1075 "4Brange=%3.1f%%" % (100.0 * stat),
1076 "(pfr*four_B)",
1077 "4 bet range",
1078 )
1079 except (KeyError, ValueError, TypeError):
1080 return (stat, "NA", "fbr=NA", "fbr=NA", "(pfr*four_B)", "4 bet range")
1083# Call 3 Bet
1084def ctb(stat_dict, player):
1085 """
1086 A function to calculate the call three bet statistics for a player.
1088 Args:
1089 stat_dict (dict): A dictionary containing player statistics.
1090 player (int): The player for whom the statistics are calculated.
1092 Returns:
1093 tuple: A tuple containing the calculated statistics in different formats:
1094 - Float: The calculated statistic.
1095 - String: The statistic formatted as a percentage with one decimal place.
1096 - String: A formatted string representing the statistic.
1097 - String: A formatted string representing the statistic with a suffix.
1098 - String: A formatted string showing the product of 'f3b_opp_0', 'f3b_0', and 'fb_0'.
1099 - String: A description of the statistic.
1101 If an exception occurs during the calculation, returns default values for the statistics.
1102 """
1103 stat = 0.0
1104 try:
1105 f3b_opp_0 = float(stat_dict[player].get("f3b_opp_0", 0)) # Ensure key exists
1107 if f3b_opp_0 != 0: # Check if f3b_opp_0 is non-zero to avoid division by zero
1108 stat = (
1109 float(stat_dict[player]["f3b_opp_0"])
1110 - float(stat_dict[player]["f3b_0"])
1111 - float(stat_dict[player]["fb_0"])
1112 ) / f3b_opp_0
1113 else:
1114 stat = 0 # Default to 0 if f3b_opp_0 is zero
1116 return (
1117 stat,
1118 "%3.1f" % (100.0 * stat),
1119 "ctb=%3.1f%%" % (100.0 * stat),
1120 "call3B=%3.1f%%" % (100.0 * stat),
1121 "(%d/%d)"
1122 % (
1123 float(stat_dict[player]["f3b_opp_0"]) - stat_dict[player]["fb_0"] - stat_dict[player]["f3b_0"],
1124 stat_dict[player]["fb_opp_0"],
1125 ),
1126 "% call 3 bet",
1127 )
1128 except (KeyError, ValueError, TypeError):
1129 return (stat, "NA", "ctb=NA", "ctb=NA", "(0/0)", "% call 3 bet")
1132def dbr1(stat_dict, player):
1133 """Calculate and return the Donk Bet and Raise statistic for a given player on flop/4th street.
1135 Args:
1136 stat_dict (dict): A dictionary containing player statistics.
1137 player (int): The player for whom the statistic is calculated.
1139 Returns:
1140 tuple: A tuple containing the calculated statistic, percentage representation, formatted strings, and additional information.
1142 Example:
1143 dbr1(stat_dict, player)
1144 """
1145 stat = 0.0
1146 try:
1147 aggr_1 = float(stat_dict[player].get("aggr_1", 0))
1148 cb_1 = float(stat_dict[player].get("cb_1", 0))
1149 saw_f = float(stat_dict[player].get("saw_f", 0))
1150 cb_opp_1 = float(stat_dict[player].get("cb_opp_1", 0))
1152 if (saw_f - cb_opp_1) != 0: # Check to avoid division by zero
1153 stat = (aggr_1 - cb_1) / (saw_f - cb_opp_1)
1154 else:
1155 stat = 0 # Default to 0 if the denominator is zero
1157 return (
1158 stat,
1159 "%3.1f" % (100.0 * stat),
1160 "dbr1=%3.1f%%" % (100.0 * stat),
1161 "dbr1=%3.1f%%" % (100.0 * stat),
1162 "(%d/%d)"
1163 % (
1164 aggr_1 - cb_1,
1165 saw_f - cb_opp_1,
1166 ),
1167 "% DonkBetAndRaise flop/4th street",
1168 )
1169 except (KeyError, ValueError, TypeError):
1170 return (stat, "NA", "dbr1=NA", "dbr1=NA", "(0/0)", "% DonkBetAndRaise flop/4th street")
1173def dbr2(stat_dict, player):
1174 """Calculate and return the Donk Bet and Raise statistic for a given player on turn/5th street.
1176 Args:
1177 stat_dict (dict): A dictionary containing player statistics.
1178 player (int): The player for whom the statistic is calculated.
1180 Returns:
1181 tuple: A tuple containing the calculated statistic, percentage representation, formatted strings, and additional information.
1183 Example:
1184 dbr2(stat_dict, player)
1185 """
1186 stat = 0.0
1187 try:
1188 aggr_2 = float(stat_dict[player].get("aggr_2", 0))
1189 cb_2 = float(stat_dict[player].get("cb_2", 0))
1190 saw_2 = float(stat_dict[player].get("saw_2", 0))
1191 cb_opp_2 = float(stat_dict[player].get("cb_opp_2", 0))
1193 if (saw_2 - cb_opp_2) != 0: # Check to avoid division by zero
1194 stat = (aggr_2 - cb_2) / (saw_2 - cb_opp_2)
1195 else:
1196 stat = 0 # Default to 0 if the denominator is zero
1198 return (
1199 stat,
1200 "%3.1f" % (100.0 * stat),
1201 "dbr2=%3.1f%%" % (100.0 * stat),
1202 "dbr2=%3.1f%%" % (100.0 * stat),
1203 "(%d/%d)"
1204 % (
1205 aggr_2 - cb_2,
1206 saw_2 - cb_opp_2,
1207 ),
1208 "% DonkBetAndRaise turn/5th street",
1209 )
1210 except (KeyError, ValueError, TypeError):
1211 return (stat, "NA", "dbr2=NA", "dbr2=NA", "(0/0)", "% DonkBetAndRaise turn/5th street")
1214def dbr3(stat_dict, player):
1215 """Calculate and return the Donk Bet and Raise statistic for a given player on river/6th street.
1217 Args:
1218 stat_dict (dict): A dictionary containing player statistics.
1219 player (int): The player for whom the statistic is calculated.
1221 Returns:
1222 tuple: A tuple containing the calculated statistic, percentage representation, formatted strings, and additional information.
1224 Example:
1225 dbr3(stat_dict, player)
1226 """
1227 stat = 0.0
1228 try:
1229 aggr_3 = float(stat_dict[player].get("aggr_3", 0))
1230 cb_3 = float(stat_dict[player].get("cb_3", 0))
1231 saw_3 = float(stat_dict[player].get("saw_3", 0))
1232 cb_opp_3 = float(stat_dict[player].get("cb_opp_3", 0))
1234 if (saw_3 - cb_opp_3) != 0: # Check to avoid division by zero
1235 stat = (aggr_3 - cb_3) / (saw_3 - cb_opp_3)
1236 else:
1237 stat = 0 # Default to 0 if the denominator is zero
1239 return (
1240 stat,
1241 "%3.1f" % (100.0 * stat),
1242 "dbr3=%3.1f%%" % (100.0 * stat),
1243 "dbr3=%3.1f%%" % (100.0 * stat),
1244 "(%d/%d)"
1245 % (
1246 aggr_3 - cb_3,
1247 saw_3 - cb_opp_3,
1248 ),
1249 "% DonkBetAndRaise river/6th street",
1250 )
1251 except (KeyError, ValueError, TypeError):
1252 return (stat, "NA", "dbr3=NA", "dbr3=NA", "(0/0)", "% DonkBetAndRaise river/6th street")
1255def f_dbr1(stat_dict, player):
1256 """Calculate and return the fold to DonkBetAndRaise statistic for a given player on flop/4th street.
1258 Args:
1259 stat_dict (dict): A dictionary containing player statistics.
1260 player (int): The player for whom the statistic is calculated.
1262 Returns:
1263 tuple: A tuple containing the calculated statistic, formatted strings, and additional information.
1265 Example:
1266 f_dbr1(stat_dict, player)
1268 Note:
1269 If an exception occurs during calculation, 'NA' values are returned.
1270 """
1271 stat = 0.0
1272 try:
1273 f_freq_1 = float(stat_dict[player].get("f_freq_1", 0))
1274 f_cb_1 = float(stat_dict[player].get("f_cb_1", 0))
1275 was_raised_1 = float(stat_dict[player].get("was_raised_1", 0))
1276 f_cb_opp_1 = float(stat_dict[player].get("f_cb_opp_1", 0))
1278 if (was_raised_1 - f_cb_opp_1) != 0: # Check to avoid division by zero
1279 stat = (f_freq_1 - f_cb_1) / (was_raised_1 - f_cb_opp_1)
1280 else:
1281 stat = 0 # Default to 0 if the denominator is zero
1283 return (
1284 stat,
1285 "%3.1f" % (100.0 * stat),
1286 "f_dbr1=%3.1f%%" % (100.0 * stat),
1287 "f_dbr1=%3.1f%%" % (100.0 * stat),
1288 "(%d/%d)"
1289 % (
1290 f_freq_1 - f_cb_1,
1291 was_raised_1 - f_cb_opp_1,
1292 ),
1293 "% Fold to DonkBetAndRaise flop/4th street",
1294 )
1295 except (KeyError, ValueError, TypeError):
1296 return (stat, "NA", "f_dbr1=NA", "f_dbr1=NA", "(0/0)", "% Fold DonkBetAndRaise flop/4th street")
1299def f_dbr2(stat_dict, player):
1300 """Calculate and return the fold to DonkBetAndRaise statistic for a given player on turn/5th street.
1302 Args:
1303 stat_dict (dict): A dictionary containing player statistics.
1304 player (int): The player for whom the statistic is calculated.
1306 Returns:
1307 tuple: A tuple containing the calculated statistic, formatted strings, and additional information.
1309 Example:
1310 f_dbr2(stat_dict, player)
1312 Note:
1313 If an exception occurs during calculation, 'NA' values are returned.
1314 """
1315 stat = 0.0
1316 try:
1317 f_freq_2 = float(stat_dict[player].get("f_freq_2", 0))
1318 f_cb_2 = float(stat_dict[player].get("f_cb_2", 0))
1319 was_raised_2 = float(stat_dict[player].get("was_raised_2", 0))
1320 f_cb_opp_2 = float(stat_dict[player].get("f_cb_opp_2", 0))
1322 if (was_raised_2 - f_cb_opp_2) != 0: # Check to avoid division by zero
1323 stat = (f_freq_2 - f_cb_2) / (was_raised_2 - f_cb_opp_2)
1324 else:
1325 stat = 0 # Default to 0 if the denominator is zero
1327 return (
1328 stat,
1329 "%3.1f" % (100.0 * stat),
1330 "f_dbr2=%3.1f%%" % (100.0 * stat),
1331 "f_dbr2=%3.1f%%" % (100.0 * stat),
1332 "(%d/%d)"
1333 % (
1334 f_freq_2 - f_cb_2,
1335 was_raised_2 - f_cb_opp_2,
1336 ),
1337 "% Fold to DonkBetAndRaise turn",
1338 )
1339 except (KeyError, ValueError, TypeError):
1340 return (stat, "NA", "f_dbr2=NA", "f_dbr2=NA", "(0/0)", "% Fold DonkBetAndRaise turn")
1343def f_dbr3(stat_dict, player):
1344 """Calculate and return the fold to DonkBetAndRaise statistic for a given player on river/6th street.
1346 Args:
1347 stat_dict (dict): A dictionary containing player statistics.
1348 player (int): The player for whom the statistic is calculated.
1350 Returns:
1351 tuple: A tuple containing the calculated statistic, formatted strings, and additional information.
1353 Example:
1354 f_dbr3(stat_dict, player)
1356 Note:
1357 If an exception occurs during calculation, 'NA' values are returned.
1358 """
1359 stat = 0.0
1360 try:
1361 f_freq_3 = float(stat_dict[player].get("f_freq_3", 0))
1362 f_cb_3 = float(stat_dict[player].get("f_cb_3", 0))
1363 was_raised_3 = float(stat_dict[player].get("was_raised_3", 0))
1364 f_cb_opp_3 = float(stat_dict[player].get("f_cb_opp_3", 0))
1366 if (was_raised_3 - f_cb_opp_3) != 0: # Check to avoid division by zero
1367 stat = (f_freq_3 - f_cb_3) / (was_raised_3 - f_cb_opp_3)
1368 else:
1369 stat = 0 # Default to 0 if the denominator is zero
1371 return (
1372 stat,
1373 "%3.1f" % (100.0 * stat),
1374 "f_dbr3=%3.1f%%" % (100.0 * stat),
1375 "f_dbr3=%3.1f%%" % (100.0 * stat),
1376 "(%d/%d)"
1377 % (
1378 f_freq_3 - f_cb_3,
1379 was_raised_3 - f_cb_opp_3,
1380 ),
1381 "% Fold to DonkBetAndRaise river",
1382 )
1383 except (KeyError, ValueError, TypeError):
1384 return (stat, "NA", "f_dbr3=NA", "f_dbr3=NA", "(0/0)", "% Fold DonkBetAndRaise river")
1387def squeeze(stat_dict, player):
1388 """
1389 Calculate the squeeze statistic for a player.
1391 Args:
1392 stat_dict (dict): A dictionary containing player statistics.
1393 player (int): The player for whom the statistic is calculated.
1395 Returns:
1396 tuple: A tuple containing the calculated statistic, percentage values, and formatted strings.
1397 """
1398 stat = 0.0
1399 try:
1400 sqz_opp_0 = float(stat_dict[player].get("sqz_opp_0", 0)) # Ensure key exists and default to 0
1401 if sqz_opp_0 != 0: # Check to avoid division by zero
1402 stat = float(stat_dict[player]["sqz_0"]) / sqz_opp_0
1403 else:
1404 stat = 0 # Default to 0 if sqz_opp_0 is zero
1406 return (
1407 stat,
1408 "%3.1f" % (100.0 * stat),
1409 "SQZ=%3.1f%%" % (100.0 * stat),
1410 "SQZ_pf=%3.1f%%" % (100.0 * stat),
1411 "(%d/%d)" % (stat_dict[player]["sqz_0"], sqz_opp_0),
1412 "% squeeze preflop",
1413 )
1414 except (KeyError, ValueError, TypeError):
1415 return (stat, "NA", "SQZ=NA", "SQZ_pf=NA", "(0/0)", "% squeeze preflop")
1418def raiseToSteal(stat_dict, player):
1419 """Calculate the raise to steal stat for a player.
1421 Args:
1422 stat_dict (dict): A dictionary containing stats for each player.
1423 player (int): The player for whom the stat is calculated.
1425 Returns:
1426 tuple: A tuple containing the raise to steal stat, formatted percentages, and additional information.
1427 """
1428 stat = 0.0
1429 try:
1430 rts_opp = float(stat_dict[player].get("rts_opp", 0)) # Ensure key exists and default to 0
1431 if rts_opp != 0: # Check to avoid division by zero
1432 stat = float(stat_dict[player]["rts"]) / rts_opp
1433 else:
1434 stat = 0 # Default to 0 if rts_opp is zero
1436 return (
1437 stat,
1438 "%3.1f" % (100.0 * stat),
1439 "RST=%3.1f%%" % (100.0 * stat),
1440 "RST_pf=%3.1f%%" % (100.0 * stat),
1441 "(%d/%d)" % (stat_dict[player]["rts"], rts_opp),
1442 "% raise to steal",
1443 )
1444 except (KeyError, ValueError, TypeError):
1445 return (stat, "NA", "RST=NA", "RST_pf=NA", "(0/0)", "% raise to steal")
1448def car0(stat_dict, player):
1449 """Calculate the percentage of called a raise preflop stat for a player based on the provided stat dictionary.
1451 Args:
1452 stat_dict (dict): A dictionary containing stats for each player.
1453 player (int): The player for whom the CAR0 stat is calculated.
1455 Returns:
1456 tuple: A tuple containing various formatted strings representing the CAR0 stat.
1457 If an exception occurs during calculation, returns default 'NA' values.
1458 """
1459 stat = 0.0
1460 try:
1461 car_opp_0 = float(stat_dict[player].get("car_opp_0", 0)) # Ensure key exists and default to 0
1462 if car_opp_0 != 0: # Check to avoid division by zero
1463 stat = float(stat_dict[player]["car_0"]) / car_opp_0
1464 else:
1465 stat = 0 # Default to 0 if car_opp_0 is zero
1467 return (
1468 stat,
1469 "%3.1f" % (100.0 * stat),
1470 "CAR0=%3.1f%%" % (100.0 * stat),
1471 "CAR_pf=%3.1f%%" % (100.0 * stat),
1472 "(%d/%d)" % (stat_dict[player]["car_0"], car_opp_0),
1473 "% called a raise preflop",
1474 )
1475 except (KeyError, ValueError, TypeError):
1476 return (stat, "NA", "CAR0=NA", "CAR_pf=NA", "(0/0)", "% called a raise preflop")
1479def f_3bet(stat_dict, player):
1480 """Calculate the Fold to 3-Bet statistic for a player.
1482 Args:
1483 stat_dict (dict): A dictionary containing player statistics.
1484 player (int): The player for whom the statistic is calculated.
1486 Returns:
1487 tuple: A tuple containing various representations of the Fold to 3-Bet statistic.
1488 The tuple includes the statistic value, percentage, labels, and counts.
1489 If an error occurs during calculation, returns 'NA' values.
1490 """
1491 stat = 0.0
1492 try:
1493 f3b_opp_0 = float(stat_dict[player].get("f3b_opp_0", 0)) # Ensure key exists and default to 0
1494 if f3b_opp_0 != 0: # Check to avoid division by zero
1495 stat = float(stat_dict[player]["f3b_0"]) / f3b_opp_0
1496 else:
1497 stat = 0 # Default to 0 if f3b_opp_0 is zero
1499 return (
1500 stat,
1501 "%3.1f" % (100.0 * stat),
1502 "F3B=%3.1f%%" % (100.0 * stat),
1503 "F3B_pf=%3.1f%%" % (100.0 * stat),
1504 "(%d/%d)" % (stat_dict[player]["f3b_0"], f3b_opp_0),
1505 "% fold to 3 bet preflop/3rd street",
1506 )
1507 except (KeyError, ValueError, TypeError):
1508 return (stat, "NA", "F3B=NA", "F3B_pf=NA", "(0/0)", "% fold to 3 bet preflop/3rd street")
1511def f_4bet(stat_dict, player):
1512 """
1513 Calculate and return fold to 4-bet statistics for a player.
1515 Args:
1516 stat_dict (dict): Dictionary containing player statistics.
1517 player (int): Player identifier.
1519 Returns:
1520 tuple: Tuple containing various statistics related to fold to 4-bet.
1521 """
1522 stat = 0.0
1523 try:
1524 f4b_opp_0 = float(stat_dict[player].get("f4b_opp_0", 0)) # Ensure key exists and default to 0
1525 if f4b_opp_0 != 0: # Check to avoid division by zero
1526 stat = float(stat_dict[player]["f4b_0"]) / f4b_opp_0
1527 else:
1528 stat = 0 # Default to 0 if f4b_opp_0 is zero
1530 return (
1531 stat,
1532 "%3.1f" % (100.0 * stat),
1533 "F4B=%3.1f%%" % (100.0 * stat),
1534 "F4B_pf=%3.1f%%" % (100.0 * stat),
1535 "(%d/%d)" % (stat_dict[player]["f4b_0"], f4b_opp_0),
1536 "% fold to 4 bet preflop/3rd street",
1537 )
1538 except (KeyError, ValueError, TypeError):
1539 return (stat, "NA", "F4B=NA", "F4B_pf=NA", "(0/0)", "% fold to 4 bet preflop/3rd street")
1542def WMsF(stat_dict, player):
1543 """Calculate the win money percentage when seeing the flop or 4th street.
1545 Args:
1546 stat_dict (dict): A dictionary containing player statistics.
1547 player (int): The player for whom the statistics are calculated.
1549 Returns:
1550 tuple: A tuple containing various win money percentage statistics and descriptions.
1551 """
1552 stat = 0.0
1553 try:
1554 saw_1 = float(stat_dict[player].get("saw_1", 0)) # Ensure key exists and default to 0
1555 if saw_1 != 0: # Check to avoid division by zero
1556 stat = float(stat_dict[player]["w_w_s_1"]) / saw_1
1557 else:
1558 stat = 0 # Default to 0 if saw_1 is zero
1560 return (
1561 stat,
1562 "%3.1f" % (100.0 * stat),
1563 "wf=%3.1f%%" % (100.0 * stat),
1564 "w_w_f=%3.1f%%" % (100.0 * stat),
1565 "(%d/%d)" % (stat_dict[player]["w_w_s_1"], stat_dict[player]["saw_f"]),
1566 "% won money when seen flop/4th street",
1567 )
1568 except (KeyError, ValueError, TypeError):
1569 return (stat, "NA", "wf=NA", "w_w_f=NA", "(0/0)", "% won money when seen flop/4th street")
1572def a_freq1(stat_dict, player):
1573 """Calculate aggression frequency for a specific player based on their stats on flop/4th street.
1575 Args:
1576 stat_dict (dict): A dictionary containing player statistics.
1577 player (int): The player for whom the aggression frequency is calculated.
1579 Returns:
1580 tuple: A tuple containing the calculated aggression frequency, formatted strings, and related information.
1581 """
1582 stat = 0.0
1583 try:
1584 saw_f = float(stat_dict[player].get("saw_f", 0)) # Ensure key exists and default to 0
1585 if saw_f != 0: # Check to avoid division by zero
1586 stat = float(stat_dict[player]["aggr_1"]) / saw_f
1587 else:
1588 stat = 0 # Default to 0 if saw_f is zero
1590 return (
1591 stat,
1592 "%3.1f" % (100.0 * stat),
1593 "a1=%3.1f%%" % (100.0 * stat),
1594 "a_fq_1=%3.1f%%" % (100.0 * stat),
1595 "(%d/%d)" % (stat_dict[player]["aggr_1"], saw_f),
1596 "Aggression frequency flop/4th street",
1597 )
1598 except (KeyError, ValueError, TypeError):
1599 return (stat, "NA", "a1=NA", "a_fq_1=NA", "(0/0)", "Aggression frequency flop/4th street")
1602def a_freq2(stat_dict, player):
1603 """Calculate aggression frequency for a specific player based on their stats on turn/5th street.
1605 Args:
1606 stat_dict (dict): A dictionary containing player statistics.
1607 player (int): The player for whom the aggression frequency is calculated.
1609 Returns:
1610 tuple: A tuple containing the calculated aggression frequency, formatted strings, and related information.
1611 """
1612 stat = 0.0
1613 try:
1614 saw_2 = float(stat_dict[player].get("saw_2", 0)) # Ensure key exists and default to 0
1615 if saw_2 != 0: # Check to avoid division by zero
1616 stat = float(stat_dict[player]["aggr_2"]) / saw_2
1617 else:
1618 stat = 0 # Default to 0 if saw_2 is zero
1620 return (
1621 stat,
1622 "%3.1f" % (100.0 * stat),
1623 "a2=%3.1f%%" % (100.0 * stat),
1624 "a_fq_2=%3.1f%%" % (100.0 * stat),
1625 "(%d/%d)" % (stat_dict[player]["aggr_2"], saw_2),
1626 "Aggression frequency turn/5th street",
1627 )
1628 except (KeyError, ValueError, TypeError):
1629 return (stat, "NA", "a2=NA", "a_fq_2=NA", "(0/0)", "Aggression frequency turn/5th street")
1632def a_freq3(stat_dict, player):
1633 """Calculate aggression frequency for a specific player based on their stats on river/6th street.
1635 Args:
1636 stat_dict (dict): A dictionary containing player statistics.
1637 player (int): The player for whom the aggression frequency is calculated.
1639 Returns:
1640 tuple: A tuple containing the calculated aggression frequency, formatted strings, and related information.
1641 """
1642 stat = 0.0
1643 try:
1644 saw_3 = float(stat_dict[player].get("saw_3", 0)) # Ensure key exists and default to 0
1645 if saw_3 != 0: # Check to avoid division by zero
1646 stat = float(stat_dict[player]["aggr_3"]) / saw_3
1647 else:
1648 stat = 0 # Default to 0 if saw_3 is zero
1650 return (
1651 stat,
1652 "%3.1f" % (100.0 * stat),
1653 "a3=%3.1f%%" % (100.0 * stat),
1654 "a_fq_3=%3.1f%%" % (100.0 * stat),
1655 "(%d/%d)" % (stat_dict[player]["aggr_3"], saw_3),
1656 "Aggression frequency river/6th street",
1657 )
1658 except (KeyError, ValueError, TypeError):
1659 return (stat, "NA", "a3=NA", "a_fq_3=NA", "(0/0)", "Aggression frequency river/6th street")
1662def a_freq4(stat_dict, player):
1663 """Calculate aggression frequency for a specific player based on their stats on 7th street.
1665 Args:
1666 stat_dict (dict): A dictionary containing player statistics.
1667 player (int): The player for whom the aggression frequency is calculated.
1669 Returns:
1670 tuple: A tuple containing the calculated aggression frequency, formatted strings, and related information.
1671 """
1672 stat = 0.0
1673 try:
1674 if float(stat_dict[player]["saw_4"]) != 0:
1675 stat = float(stat_dict[player]["aggr_4"]) / float(stat_dict[player]["saw_4"])
1676 return (
1677 stat,
1678 "%3.1f" % (100.0 * stat),
1679 "a4=%3.1f%%" % (100.0 * stat),
1680 "a_fq_4=%3.1f%%" % (100.0 * stat),
1681 "(%d/%d)" % (stat_dict[player]["aggr_4"], stat_dict[player]["saw_4"]),
1682 "Aggression frequency 7th street",
1683 )
1684 except (KeyError, ValueError, TypeError):
1685 return (stat, "NA", "a4=NA", "a_fq_4=NA", "(0/0)", "Aggression frequency 7th street")
1688def a_freq_123(stat_dict, player):
1689 """Calculate aggression frequency for a specific player based on their stats post-flop.
1691 Args:
1692 stat_dict (dict): A dictionary containing player statistics.
1693 player (int): The player for whom the aggression frequency is calculated.
1695 Returns:
1696 tuple: A tuple containing the calculated aggression frequency, formatted strings, and related information.
1697 """
1698 stat = 0.0
1699 try:
1700 # Sum up aggression and seen stats
1701 total_aggr = (
1702 stat_dict[player].get("aggr_1", 0) + stat_dict[player].get("aggr_2", 0) + stat_dict[player].get("aggr_3", 0)
1703 )
1704 total_saw = (
1705 stat_dict[player].get("saw_1", 0) + stat_dict[player].get("saw_2", 0) + stat_dict[player].get("saw_3", 0)
1706 )
1708 # Check to avoid division by zero
1709 if total_saw != 0:
1710 stat = float(total_aggr) / float(total_saw)
1711 else:
1712 stat = 0 # Default to 0 if total_saw is zero
1714 return (
1715 stat,
1716 "%3.1f" % (100.0 * stat),
1717 "afq=%3.1f%%" % (100.0 * stat),
1718 "post_a_fq=%3.1f%%" % (100.0 * stat),
1719 "(%d/%d)" % (total_aggr, total_saw),
1720 "Post-flop aggression frequency",
1721 )
1722 except (KeyError, ValueError, TypeError):
1723 return (stat, "NA", "afq=NA", "post_a_fq=NA", "(0/0)", "Post-flop aggression frequency")
1726def agg_fact(stat_dict, player):
1727 """Calculate the aggression factor based on the given player's statistics.
1729 Args:
1730 stat_dict (dict): A dictionary containing the player's statistics.
1731 player (str): The player for whom the aggression factor is calculated.
1733 Returns:
1734 tuple: A tuple containing the calculated aggression factor in different formats.
1735 The formats include percentage, float, and string representations.
1736 If an exception occurs during calculation, default values are returned.
1737 """
1738 stat = 0.0
1739 try:
1740 # Sum of all bet/raise and call actions
1741 bet_raise = (
1742 stat_dict[player].get("aggr_1", 0)
1743 + stat_dict[player].get("aggr_2", 0)
1744 + stat_dict[player].get("aggr_3", 0)
1745 + stat_dict[player].get("aggr_4", 0)
1746 )
1747 post_call = (
1748 stat_dict[player].get("call_1", 0)
1749 + stat_dict[player].get("call_2", 0)
1750 + stat_dict[player].get("call_3", 0)
1751 + stat_dict[player].get("call_4", 0)
1752 )
1754 # Check to avoid division by zero
1755 if post_call > 0:
1756 stat = float(bet_raise) / float(post_call)
1757 else:
1758 stat = float(bet_raise)
1760 return (
1761 stat / 100.0,
1762 "%2.2f" % (stat),
1763 "afa=%2.2f" % (stat),
1764 "agg_fa=%2.2f" % (stat),
1765 "(%d/%d)" % (bet_raise, post_call),
1766 "Aggression factor",
1767 )
1768 except (KeyError, ValueError, TypeError):
1769 return (stat, "NA", "afa=NA", "agg_fa=NA", "(0/0)", "Aggression factor")
1772def agg_fact_pct(stat_dict, player):
1773 """Calculate the aggression factor percentage based on the given player's stats.
1775 Args:
1776 stat_dict (dict): A dictionary containing the player's statistics.
1777 player (int): The player for whom the aggression factor percentage is calculated.
1779 Returns:
1780 tuple: A tuple containing the aggression factor percentage, formatted strings, and related information.
1782 Raises:
1783 Exception: If an error occurs during the calculation, returns default values.
1784 """
1785 stat = 0.0
1786 try:
1787 # Safely retrieve the values, defaulting to 0 if the keys are missing
1788 bet_raise = (
1789 stat_dict[player].get("aggr_1", 0)
1790 + stat_dict[player].get("aggr_2", 0)
1791 + stat_dict[player].get("aggr_3", 0)
1792 + stat_dict[player].get("aggr_4", 0)
1793 )
1794 post_call = (
1795 stat_dict[player].get("call_1", 0)
1796 + stat_dict[player].get("call_2", 0)
1797 + stat_dict[player].get("call_3", 0)
1798 + stat_dict[player].get("call_4", 0)
1799 )
1801 # Check to avoid division by zero
1802 if float(post_call + bet_raise) > 0.0:
1803 stat = float(bet_raise) / float(post_call + bet_raise)
1805 return (
1806 stat / 100.0,
1807 "%2.2f" % (stat),
1808 "afap=%2.2f" % (stat),
1809 "agg_fa_pct=%2.2f" % (stat),
1810 "(%d/%d)" % (bet_raise, post_call),
1811 "Aggression factor pct",
1812 )
1813 except (KeyError, ValueError, TypeError):
1814 return (stat, "NA", "afap=NA", "agg_fa_pct=NA", "(0/0)", "Aggression factor pct")
1817def cbet(stat_dict, player):
1818 """Calculate the continuation bet (cbet) percentage for a player.
1820 Args:
1821 stat_dict (dict): A dictionary containing statistics for the player.
1822 player (int): The player for whom the cbet percentage is calculated.
1824 Returns:
1825 tuple: A tuple containing the cbet percentage, formatted strings, and stats.
1827 Raises:
1828 Exception: If there is an issue with calculating the cbet percentage.
1829 """
1830 stat = 0.0
1831 try:
1832 # Safely retrieve cbet and opportunity values, defaulting to 0 if keys don't exist
1833 cbets = (
1834 stat_dict[player].get("cb_1", 0)
1835 + stat_dict[player].get("cb_2", 0)
1836 + stat_dict[player].get("cb_3", 0)
1837 + stat_dict[player].get("cb_4", 0)
1838 )
1839 oppt = (
1840 stat_dict[player].get("cb_opp_1", 0)
1841 + stat_dict[player].get("cb_opp_2", 0)
1842 + stat_dict[player].get("cb_opp_3", 0)
1843 + stat_dict[player].get("cb_opp_4", 0)
1844 )
1846 # Check to avoid division by zero
1847 if oppt != 0:
1848 stat = float(cbets) / float(oppt)
1849 else:
1850 stat = 0 # Default to 0 if oppt is zero
1852 return (
1853 stat,
1854 "%3.1f" % (100.0 * stat),
1855 "cbet=%3.1f%%" % (100.0 * stat),
1856 "cbet=%3.1f%%" % (100.0 * stat),
1857 "(%d/%d)" % (cbets, oppt),
1858 "% continuation bet",
1859 )
1860 except (KeyError, ValueError, TypeError):
1861 return (stat, "NA", "cbet=NA", "cbet=NA", "(0/0)", "% continuation bet")
1864def cb1(stat_dict, player):
1865 """Calculate the continuation bet statistic for a given player on flop/4th street.
1867 Args:
1868 stat_dict (dict): A dictionary containing player statistics.
1869 player (int): The player for whom the statistic is calculated.
1871 Returns:
1872 tuple: A tuple containing various formatted strings representing the continuation bet statistic.
1873 """
1874 stat = 0.0
1875 try:
1876 if float(stat_dict[player]["cb_opp_1"]) != 0:
1877 stat = float(stat_dict[player]["cb_1"]) / float(stat_dict[player]["cb_opp_1"])
1878 return (
1879 stat,
1880 "%3.1f" % (100.0 * stat),
1881 "cb1=%3.1f%%" % (100.0 * stat),
1882 "cb_1=%3.1f%%" % (100.0 * stat),
1883 "(%d/%d)" % (stat_dict[player]["cb_1"], stat_dict[player]["cb_opp_1"]),
1884 "% continuation bet flop/4th street",
1885 )
1886 except (KeyError, ValueError, TypeError):
1887 return (stat, "NA", "cb1=NA", "cb_1=NA", "(0/0)", "% continuation bet flop/4th street")
1890def cb2(stat_dict, player):
1891 """Calculate the continuation bet statistic for a given player on turn/5th street.
1893 Args:
1894 stat_dict (dict): A dictionary containing player statistics.
1895 player (int): The player for whom the statistic is calculated.
1897 Returns:
1898 tuple: A tuple containing various formatted strings representing the continuation bet statistic.
1899 """
1900 stat = 0.0
1901 try:
1902 cb_opp_2 = float(stat_dict[player].get("cb_opp_2", 0)) # Ensure key exists and default to 0
1903 if cb_opp_2 != 0: # Check to avoid division by zero
1904 stat = float(stat_dict[player]["cb_2"]) / cb_opp_2
1905 else:
1906 stat = 0 # Default to 0 if cb_opp_2 is zero
1908 return (
1909 stat,
1910 "%3.1f" % (100.0 * stat),
1911 "cb2=%3.1f%%" % (100.0 * stat),
1912 "cb_2=%3.1f%%" % (100.0 * stat),
1913 "(%d/%d)" % (stat_dict[player]["cb_2"], cb_opp_2),
1914 "% continuation bet turn/5th street",
1915 )
1916 except (KeyError, ValueError, TypeError):
1917 return (stat, "NA", "cb2=NA", "cb_2=NA", "(0/0)", "% continuation bet turn/5th street")
1920def cb3(stat_dict, player):
1921 """Calculate the continuation bet statistic for a given player on river/6th street.
1923 Args:
1924 stat_dict (dict): A dictionary containing player statistics.
1925 player (int): The player for whom the statistic is calculated.
1927 Returns:
1928 tuple: A tuple containing various formatted strings representing the continuation bet statistic.
1929 """
1930 stat = 0.0
1931 try:
1932 cb_opp_3 = float(stat_dict[player].get("cb_opp_3", 0)) # Ensure key exists and default to 0
1933 if cb_opp_3 != 0: # Check to avoid division by zero
1934 stat = float(stat_dict[player]["cb_3"]) / cb_opp_3
1935 else:
1936 stat = 0 # Default to 0 if cb_opp_3 is zero
1938 return (
1939 stat,
1940 "%3.1f" % (100.0 * stat),
1941 "cb3=%3.1f%%" % (100.0 * stat),
1942 "cb_3=%3.1f%%" % (100.0 * stat),
1943 "(%d/%d)" % (stat_dict[player]["cb_3"], cb_opp_3),
1944 "% continuation bet river/6th street",
1945 )
1946 except (KeyError, ValueError, TypeError):
1947 return (stat, "NA", "cb3=NA", "cb_3=NA", "(0/0)", "% continuation bet river/6th street")
1950def cb4(stat_dict, player):
1951 """Calculate the continuation bet statistic for a given player on 7th street.
1953 Args:
1954 stat_dict (dict): A dictionary containing player statistics.
1955 player (int): The player for whom the statistic is calculated.
1957 Returns:
1958 tuple: A tuple containing various formatted strings representing the continuation bet statistic.
1959 """
1960 stat = 0.0
1961 try:
1962 if float(stat_dict[player]["cb_opp_4"]) != 0:
1963 stat = float(stat_dict[player]["cb_4"]) / float(stat_dict[player]["cb_opp_4"])
1964 return (
1965 stat,
1966 "%3.1f" % (100.0 * stat),
1967 "cb4=%3.1f%%" % (100.0 * stat),
1968 "cb_4=%3.1f%%" % (100.0 * stat),
1969 "(%d/%d)" % (stat_dict[player]["cb_4"], stat_dict[player]["cb_opp_4"]),
1970 "% continuation bet 7th street",
1971 )
1972 except (KeyError, ValueError, TypeError):
1973 return (stat, "NA", "cb4=NA", "cb_4=NA", "(0/0)", "% continuation bet 7th street")
1976def ffreq1(stat_dict, player):
1977 """
1978 Calculate the fold frequency statistic for a given player on the flop/4th street.
1980 Args:
1981 stat_dict (dict): A dictionary containing player statistics.
1982 player (int): The player for whom the statistic is calculated.
1984 Returns:
1985 tuple: A tuple containing various formatted strings representing the fold frequency statistic.
1986 """
1987 stat = 0.0
1988 try:
1989 was_raised_1 = float(stat_dict[player].get("was_raised_1", 0)) # Ensure key exists and default to 0
1990 if was_raised_1 != 0: # Check to avoid division by zero
1991 stat = float(stat_dict[player]["f_freq_1"]) / was_raised_1
1992 else:
1993 stat = 0 # Default to 0 if was_raised_1 is zero
1995 return (
1996 stat,
1997 "%3.1f" % (100.0 * stat),
1998 "ff1=%3.1f%%" % (100.0 * stat),
1999 "ff_1=%3.1f%%" % (100.0 * stat),
2000 "(%d/%d)" % (stat_dict[player]["f_freq_1"], was_raised_1),
2001 "% fold frequency flop/4th street",
2002 )
2003 except (KeyError, ValueError, TypeError):
2004 return (stat, "NA", "ff1=NA", "ff_1=NA", "(0/0)", "% fold frequency flop/4th street")
2007def ffreq2(stat_dict, player):
2008 """
2009 Calculate the fold frequency statistic for a given player on the turn/5th street.
2011 Args:
2012 stat_dict (dict): A dictionary containing player statistics.
2013 player (int): The player for whom the statistic is calculated.
2015 Returns:
2016 tuple: A tuple containing various formatted strings representing the fold frequency statistic.
2017 """
2018 stat = 0.0
2019 try:
2020 was_raised_2 = float(stat_dict[player].get("was_raised_2", 0)) # Ensure key exists and default to 0
2021 if was_raised_2 != 0: # Check to avoid division by zero
2022 stat = float(stat_dict[player]["f_freq_2"]) / was_raised_2
2023 else:
2024 stat = 0 # Default to 0 if was_raised_2 is zero
2026 return (
2027 stat,
2028 "%3.1f" % (100.0 * stat),
2029 "ff2=%3.1f%%" % (100.0 * stat),
2030 "ff_2=%3.1f%%" % (100.0 * stat),
2031 "(%d/%d)" % (stat_dict[player]["f_freq_2"], was_raised_2),
2032 "% fold frequency turn/5th street",
2033 )
2034 except (KeyError, ValueError, TypeError):
2035 return (stat, "NA", "ff2=NA", "ff_2=NA", "(0/0)", "% fold frequency turn/5th street")
2038def ffreq3(stat_dict, player):
2039 """
2040 Calculate the fold frequency statistic for a given player on the river/6th street.
2042 Args:
2043 stat_dict (dict): A dictionary containing player statistics.
2044 player (int): The player for whom the statistic is calculated.
2046 Returns:
2047 tuple: A tuple containing various formatted strings representing the fold frequency statistic.
2048 """
2049 stat = 0.0
2050 try:
2051 was_raised_3 = float(stat_dict[player].get("was_raised_3", 0)) # Ensure key exists and default to 0
2052 if was_raised_3 != 0: # Check to avoid division by zero
2053 stat = float(stat_dict[player]["f_freq_3"]) / was_raised_3
2054 else:
2055 stat = 0 # Default to 0 if was_raised_3 is zero
2057 return (
2058 stat,
2059 "%3.1f" % (100.0 * stat),
2060 "ff3=%3.1f%%" % (100.0 * stat),
2061 "ff_3=%3.1f%%" % (100.0 * stat),
2062 "(%d/%d)" % (stat_dict[player]["f_freq_3"], was_raised_3),
2063 "% fold frequency river/6th street",
2064 )
2065 except (KeyError, ValueError, TypeError):
2066 return (stat, "NA", "ff3=NA", "ff_3=NA", "(0/0)", "% fold frequency river/6th street")
2069def ffreq4(stat_dict, player):
2070 """
2071 Calculate the fold frequency statistic for a given player on the 7th street.
2073 Args:
2074 stat_dict (dict): A dictionary containing player statistics.
2075 player (int): The player for whom the statistic is calculated.
2077 Returns:
2078 tuple: A tuple containing various formatted strings representing the fold frequency statistic.
2079 """
2080 stat = 0.0
2081 try:
2082 if float(stat_dict[player]["was_raised_4"]) != 0:
2083 stat = float(stat_dict[player]["f_freq_4"]) / float(stat_dict[player]["was_raised_4"])
2084 return (
2085 stat,
2086 "%3.1f" % (100.0 * stat),
2087 "ff4=%3.1f%%" % (100.0 * stat),
2088 "ff_4=%3.1f%%" % (100.0 * stat),
2089 "(%d/%d)" % (stat_dict[player]["f_freq_4"], stat_dict[player]["was_raised_4"]),
2090 "% fold frequency 7th street",
2091 )
2092 except (KeyError, ValueError, TypeError):
2093 return (stat, "NA", "ff4=NA", "ff_4=NA", "(0/0)", "% fold frequency 7th street")
2096def f_cb1(stat_dict, player):
2097 """
2098 Calculate the fold to continuation bet statistic for a given player on the flop/4th street.
2100 Args:
2101 stat_dict (dict): A dictionary containing player statistics.
2102 player (int): The player for whom the statistic is calculated.
2104 Returns:
2105 tuple: A tuple containing various formatted strings representing the fold to continuation bet statistic.
2106 The tuple contains the following elements:
2107 - stat (float): The calculated statistic value.
2108 - percent (str): The calculated statistic value formatted as a percentage.
2109 - f_cb1 (str): The calculated statistic value formatted as a percentage with a specific format.
2110 - f_cb_1 (str): The calculated statistic value formatted as a percentage with a specific format.
2111 - count (str): The count of occurrences divided by the count of opponent's continuation bets.
2112 - description (str): A description of the statistic.
2113 """
2114 stat = 0.0
2115 try:
2116 f_cb_opp_1 = float(stat_dict[player].get("f_cb_opp_1", 0)) # Ensure key exists and default to 0
2117 if f_cb_opp_1 != 0: # Check to avoid division by zero
2118 stat = float(stat_dict[player]["f_cb_1"]) / f_cb_opp_1
2119 else:
2120 stat = 0 # Default to 0 if f_cb_opp_1 is zero
2122 return (
2123 stat,
2124 "%3.1f" % (100.0 * stat),
2125 "f_cb1=%3.1f%%" % (100.0 * stat),
2126 "f_cb_1=%3.1f%%" % (100.0 * stat),
2127 "(%d/%d)" % (stat_dict[player]["f_cb_1"], f_cb_opp_1),
2128 "% fold to continuation bet flop/4th street",
2129 )
2130 except (KeyError, ValueError, TypeError):
2131 return (stat, "NA", "f_cb1=NA", "f_cb_1=NA", "(0/0)", "% fold to continuation bet flop/4th street")
2134def f_cb2(stat_dict, player):
2135 """
2136 Calculate the fold to continuation bet statistic for a given player on the turn/5th street.
2138 Args:
2139 stat_dict (dict): A dictionary containing player statistics.
2140 player (int): The player for whom the statistic is calculated.
2142 Returns:
2143 tuple: A tuple containing various formatted strings representing the fold to continuation bet statistic.
2144 The tuple contains the following elements:
2145 - stat (float): The calculated statistic value.
2146 - percent (str): The calculated statistic value formatted as a percentage.
2147 - f_cb2 (str): The calculated statistic value formatted as a percentage with a specific format.
2148 - f_cb_2 (str): The calculated statistic value formatted as a percentage with a specific format.
2149 - count (str): The count of occurrences divided by the count of opponent's continuation bets.
2150 - description (str): A description of the statistic.
2151 """
2152 stat = 0.0
2153 try:
2154 if float(stat_dict[player]["f_cb_opp_2"]) != 0:
2155 stat = float(stat_dict[player]["f_cb_2"]) / float(stat_dict[player]["f_cb_opp_2"])
2156 return (
2157 stat,
2158 "%3.1f" % (100.0 * stat),
2159 "f_cb2=%3.1f%%" % (100.0 * stat),
2160 "f_cb_2=%3.1f%%" % (100.0 * stat),
2161 "(%d/%d)" % (stat_dict[player]["f_cb_2"], stat_dict[player]["f_cb_opp_2"]),
2162 "% fold to continuation bet turn/5th street",
2163 )
2164 except (KeyError, ValueError, TypeError):
2165 return (stat, "NA", "f_cb2=NA", "f_cb_2=NA", "(0/0)", "% fold to continuation bet turn/5th street")
2168def f_cb3(stat_dict, player):
2169 """
2170 Calculate the fold to continuation bet statistic for a given player on the river/6th street.
2172 Args:
2173 stat_dict (dict): A dictionary containing player statistics.
2174 player (int): The player for whom the statistic is calculated.
2176 Returns:
2177 tuple: A tuple containing various formatted strings representing the fold to continuation bet statistic.
2178 The tuple contains the following elements:
2179 - stat (float): The calculated statistic value.
2180 - percent (str): The calculated statistic value formatted as a percentage.
2181 - f_cb3 (str): The calculated statistic value formatted as a percentage with a specific format.
2182 - f_cb_3 (str): The calculated statistic value formatted as a percentage with a specific format.
2183 - count (str): The count of occurrences divided by the count of opponent's continuation bets.
2184 - description (str): A description of the statistic.
2185 """
2186 stat = 0.0
2187 try:
2188 if float(stat_dict[player]["f_cb_opp_3"]) != 0:
2189 stat = float(stat_dict[player]["f_cb_3"]) / float(stat_dict[player]["f_cb_opp_3"])
2190 return (
2191 stat,
2192 "%3.1f" % (100.0 * stat),
2193 "f_cb3=%3.1f%%" % (100.0 * stat),
2194 "f_cb_3=%3.1f%%" % (100.0 * stat),
2195 "(%d/%d)" % (stat_dict[player]["f_cb_3"], stat_dict[player]["f_cb_opp_3"]),
2196 "% fold to continuation bet river/6th street",
2197 )
2198 except (KeyError, ValueError, TypeError):
2199 return (stat, "NA", "f_cb3=NA", "f_cb_3=NA", "(0/0)", "% fold to continuation bet river/6th street")
2202def f_cb4(stat_dict, player):
2203 """
2204 Calculate the fold to continuation bet statistic for a given player on the 7th street.
2206 Args:
2207 stat_dict (dict): A dictionary containing player statistics.
2208 player (int): The player for whom the statistic is calculated.
2210 Returns:
2211 tuple: A tuple containing various formatted strings representing the fold to continuation bet statistic.
2212 The tuple contains the following elements:
2213 - stat (float): The calculated statistic value.
2214 - percent (str): The calculated statistic value formatted as a percentage.
2215 - f_cb4 (str): The calculated statistic value formatted as a percentage with a specific format.
2216 - f_cb_4 (str): The calculated statistic value formatted as a percentage with a specific format.
2217 - count (str): The count of occurrences divided by the count of opponent's continuation bets.
2218 - description (str): A description of the statistic.
2220 Raises:
2221 None
2222 """
2223 stat = 0.0
2224 try:
2225 if float(stat_dict[player]["f_cb_opp_4"]) != 0:
2226 stat = float(stat_dict[player]["f_cb_4"]) / float(stat_dict[player]["f_cb_opp_4"])
2227 return (
2228 stat,
2229 "%3.1f" % (100.0 * stat),
2230 "f_cb4=%3.1f%%" % (100.0 * stat),
2231 "f_cb_4=%3.1f%%" % (100.0 * stat),
2232 "(%d/%d)" % (stat_dict[player]["f_cb_4"], stat_dict[player]["f_cb_opp_4"]),
2233 "% fold to continuation bet 7th street",
2234 )
2235 except (KeyError, ValueError, TypeError):
2236 return (stat, "NA", "f_cb4=NA", "f_cb_4=NA", "(0/0)", "% fold to continuation bet 7th street")
2239def cr1(stat_dict, player):
2240 """
2241 Calculate the check-raise flop/4th street statistic for a given player.
2243 Args:
2244 stat_dict (dict): A dictionary containing player statistics.
2245 player (int): The player for whom the statistic is calculated.
2247 Returns:
2248 tuple: A tuple containing various formatted strings representing the check-raise flop/4th street statistic.
2249 The tuple contains the following elements:
2250 - stat (float): The calculated statistic value.
2251 - percent (str): The calculated statistic value formatted as a percentage.
2252 - cr1 (str): The calculated statistic value formatted with a specific format.
2253 - cr_1 (str): The calculated statistic value formatted with a specific format.
2254 - count (str): The count of occurrences divided by the count of opponent's check-raises.
2255 - description (str): A description of the statistic.
2257 Raises:
2258 None
2259 """
2260 stat = 0.0
2261 try:
2262 ccr_opp_1 = float(stat_dict[player].get("ccr_opp_1", 0)) # Ensure key exists and default to 0
2263 if ccr_opp_1 != 0: # Check to avoid division by zero
2264 stat = float(stat_dict[player]["cr_1"]) / ccr_opp_1
2265 else:
2266 stat = 0 # Default to 0 if ccr_opp_1 is zero
2268 return (
2269 stat,
2270 "%3.1f" % (100.0 * stat),
2271 "cr1=%3.1f%%" % (100.0 * stat),
2272 "cr_1=%3.1f%%" % (100.0 * stat),
2273 "(%d/%d)" % (stat_dict[player]["cr_1"], ccr_opp_1),
2274 "% check-raise flop/4th street",
2275 )
2276 except (KeyError, ValueError, TypeError):
2277 return (stat, "NA", "cr1=NA", "cr_1=NA", "(0/0)", "% check-raise flop/4th street")
2280def cr2(stat_dict, player):
2281 """
2282 Calculates the check-raise turn/5th street for a given player.
2284 Args:
2285 stat_dict (dict): A dictionary containing player statistics.
2286 player (int): The player for whom the statistic is calculated.
2288 Returns:
2289 tuple: A tuple containing various formatted strings representing the check-raise to fold ratio.
2290 The tuple contains the following elements:
2291 - stat (float): The calculated statistic value.
2292 - percent (str): The calculated statistic value formatted as a percentage.
2293 - cr2 (str): The calculated statistic value formatted with a specific format.
2294 - cr_2 (str): The calculated statistic value formatted with a specific format.
2295 - count (str): The count of occurrences divided by the count of opponent's check-raises.
2296 - description (str): A description of the statistic.
2297 """
2298 stat = 0.0
2299 try:
2300 ccr_opp_2 = float(stat_dict[player].get("ccr_opp_2", 0)) # Ensure key exists and default to 0
2301 if ccr_opp_2 != 0: # Check to avoid division by zero
2302 stat = float(stat_dict[player]["cr_2"]) / ccr_opp_2
2303 return (
2304 stat,
2305 "%3.1f" % (100.0 * stat),
2306 "cr2=%3.1f%%" % (100.0 * stat),
2307 "cr_2=%3.1f%%" % (100.0 * stat),
2308 "(%d/%d)" % (stat_dict[player]["cr_2"], ccr_opp_2),
2309 "% check-raise turn/5th street",
2310 )
2311 except (KeyError, ValueError, TypeError):
2312 return (stat, "NA", "cr2=NA", "cr_2=NA", "(0/0)", "% check-raise turn/5th street")
2315def cr3(stat_dict, player):
2316 """
2317 Calculate the river/6th street check-raise statistic for a given player.
2319 Args:
2320 stat_dict (dict): A dictionary containing player statistics.
2321 player (int): The player for whom the statistic is calculated.
2323 Returns:
2324 tuple: A tuple containing various formatted strings representing the check-raise to fold ratio.
2325 The tuple contains the following elements:
2326 - stat (float): The calculated statistic value.
2327 - percent (str): The calculated statistic value formatted as a percentage.
2328 - cr3 (str): The calculated statistic value formatted with a specific format.
2329 - cr_3 (str): The calculated statistic value formatted with a specific format.
2330 - count (str): The count of occurrences divided by the count of opponent's check-raises.
2331 - description (str): A description of the statistic.
2333 Raises:
2334 None
2335 """
2336 stat = 0.0
2337 try:
2338 ccr_opp_3 = float(stat_dict[player].get("ccr_opp_3", 0)) # Ensure key exists and default to 0
2339 if ccr_opp_3 != 0: # Check to avoid division by zero
2340 stat = float(stat_dict[player]["cr_3"]) / ccr_opp_3
2341 return (
2342 stat,
2343 "%3.1f" % (100.0 * stat),
2344 "cr3=%3.1f%%" % (100.0 * stat),
2345 "cr_3=%3.1f%%" % (100.0 * stat),
2346 "(%d/%d)" % (stat_dict[player]["cr_3"], ccr_opp_3),
2347 "% check-raise river/6th street",
2348 )
2349 except (KeyError, ValueError, TypeError):
2350 return (stat, "NA", "cr3=NA", "cr_3=NA", "(0/0)", "% check-raise river/6th street")
2353def cr4(stat_dict, player):
2354 """
2355 Calculate the 7th street check-raise statistics for a given player on the 7th street.
2357 Args:
2358 stat_dict (dict): A dictionary containing player statistics.
2359 player (int): The player for whom the statistic is calculated.
2361 Returns:
2362 tuple: A tuple containing various formatted strings representing the check-raise to fold ratio.
2363 The tuple contains the following elements:
2364 - stat (float): The calculated statistic value.
2365 - percent (str): The calculated statistic value formatted as a percentage.
2366 - cr4 (str): The calculated statistic value formatted with a specific format.
2367 - cr_4 (str): The calculated statistic value formatted with a specific format.
2368 - count (str): The count of occurrences divided by the count of opponent's check-raises.
2369 - description (str): A description of the statistic.
2371 Raises:
2372 None
2373 """
2374 stat = 0.0
2375 try:
2376 ccr_opp_4 = float(stat_dict[player].get("ccr_opp_4", 0)) # Ensure key exists and default to 0
2377 if ccr_opp_4 != 0: # Check to avoid division by zero
2378 stat = float(stat_dict[player]["cr_4"]) / ccr_opp_4
2379 return (
2380 stat,
2381 "%3.1f" % (100.0 * stat),
2382 "cr4=%3.1f%%" % (100.0 * stat),
2383 "cr_4=%3.1f%%" % (100.0 * stat),
2384 "(%d/%d)" % (stat_dict[player]["cr_4"], ccr_opp_4),
2385 "% check-raise 7th street",
2386 )
2387 except (KeyError, ValueError, TypeError):
2388 return (stat, "NA", "cr4=NA", "cr_4=NA", "(0/0)", "% check-raise 7th street")
2391def game_abbr(stat_dict, player):
2392 """
2393 Function to retrieve the abbreviation for a specific poker game based on the game category and limit type.
2395 Parameters:
2396 - stat_dict: Dictionary containing statistics related to the game.
2397 - player: Integer representing the player number.
2399 Returns:
2400 - Tuple containing various representations of the game abbreviation.
2401 """
2402 hand_instance = _global_hand_instance
2403 stat = ""
2404 try:
2405 if hand_instance is None or "gametype" not in hand_instance:
2406 # If hand_instance is None, return default empty values
2407 return ("NA", "NA", "game=NA", "game_abbr=NA", "(NA)", "Game abbreviation")
2409 cat_plus_limit = hand_instance.gametype["category"] + "." + hand_instance.gametype["limitType"]
2410 stat = {
2411 # ftp's 10-game with official abbreviations
2412 "holdem.fl": "H",
2413 "studhilo.fl": "E",
2414 "omahahi.pl": "P",
2415 "27_3draw.fl": "T",
2416 "razz.fl": "R",
2417 "holdem.nl": "N",
2418 "omahahilo.fl": "O",
2419 "studhi.fl": "S",
2420 "27_1draw.nl": "K",
2421 "badugi.fl": "B",
2422 # other common games with dubious abbreviations
2423 "fivedraw.fl": "F",
2424 "fivedraw.pl": "Fp",
2425 "fivedraw.nl": "Fn",
2426 "27_3draw.pl": "Tp",
2427 "27_3draw.nl": "Tn",
2428 "badugi.pl": "Bp",
2429 "badugi.hp": "Bh",
2430 "omahahilo.pl": "Op",
2431 "omahahilo.nl": "On",
2432 "holdem.pl": "Hp",
2433 "studhi.nl": "Sn",
2434 }.get(cat_plus_limit, "Unknown") # Default to "Unknown" if not found
2435 return (stat, "%s" % stat, "game=%s" % stat, "game_abbr=%s" % stat, "(%s)" % stat, "Game abbreviation")
2436 except (KeyError, ValueError, TypeError):
2437 return ("NA", "NA", "game=NA", "game_abbr=NA", "(NA)", "Game abbreviation")
2440def blank(stat_dict, player):
2441 # blank space on the grid
2442 # stat = " "
2443 return ("", "", "", "", "", "<blank>")
2446################################################################################################
2447# NEW STATS
2450def vpip_pfr_ratio(stat_dict, player):
2451 """
2452 Calculate the VPIP/PFR ratio for a player.
2454 This statistic represents the ratio between a player's VPIP (Voluntarily Put money In Pot)
2455 and PFR (Pre-Flop Raise) percentages, which gives an indication of the player's preflop aggression.
2457 Args:
2458 stat_dict (dict): A dictionary containing player statistics.
2459 player (int): The player for whom the statistic is calculated.
2461 Returns:
2462 tuple: A tuple containing the calculated statistic, formatted strings, and related information.
2463 """
2464 try:
2465 vpip_opp = float(stat_dict[player].get("vpip_opp", 0))
2466 pfr_opp = float(stat_dict[player].get("pfr_opp", 0))
2468 # Ensure vpip_opp and pfr_opp are not zero to avoid division by zero
2469 vpip = float(stat_dict[player]["vpip"]) / vpip_opp if vpip_opp != 0 else 0
2470 pfr = float(stat_dict[player]["pfr"]) / pfr_opp if pfr_opp != 0 else 0
2472 if pfr > 0:
2473 stat = vpip / pfr
2474 else:
2475 stat = float("inf") # Avoid division by zero for PFR
2477 return (
2478 stat,
2479 "%2.2f" % (stat),
2480 "v/p=%2.2f" % (stat),
2481 "vpip/pfr=%2.2f" % (stat),
2482 "(%d/%d)/(%d/%d)"
2483 % (
2484 stat_dict[player]["vpip"],
2485 stat_dict[player]["vpip_opp"],
2486 stat_dict[player]["pfr"],
2487 stat_dict[player]["pfr_opp"],
2488 ),
2489 "VPIP/PFR ratio",
2490 )
2491 except (KeyError, ValueError, TypeError):
2492 return (float("inf"), "NA", "v/p=NA", "vpip/pfr=NA", "(0/0)/(0/0)", "VPIP/PFR ratio")
2495def three_bet_range(stat_dict, player):
2496 try:
2497 # Retrieve and check for division by zero in PFR
2498 pfr_opp = float(stat_dict[player].get("pfr_opp", 0))
2499 if pfr_opp != 0:
2500 pfr = float(stat_dict[player]["pfr"]) / pfr_opp
2501 else:
2502 pfr = 0 # Avoid division by zero for PFR
2504 # Retrieve and check for division by zero in 3-Bet
2505 tb_opp_0 = float(stat_dict[player].get("tb_opp_0", 0))
2506 if tb_opp_0 != 0:
2507 three_bet = float(stat_dict[player]["tb_0"]) / tb_opp_0
2508 else:
2509 three_bet = 0 # Avoid division by zero for 3-Bet
2511 # Calculate the 3-Bet Range
2512 stat = pfr * three_bet
2513 return (
2514 stat,
2515 "%3.1f" % (100.0 * stat),
2516 "3BR=%3.1f%%" % (100.0 * stat),
2517 "3BetRange=%3.1f%%" % (100.0 * stat),
2518 "(%d/%d)*(%d/%d)"
2519 % (
2520 stat_dict[player]["pfr"],
2521 stat_dict[player]["pfr_opp"],
2522 stat_dict[player]["tb_0"],
2523 stat_dict[player]["tb_opp_0"],
2524 ),
2525 "3-Bet Range",
2526 )
2527 except (KeyError, ValueError, TypeError):
2528 return (0, "NA", "3BR=NA", "3BetRange=NA", "(0/0)*(0/0)", "3-Bet Range")
2531def check_raise_frequency(stat_dict, player):
2532 try:
2533 # Sum the total check-raises and opportunities
2534 total_cr = (
2535 stat_dict[player].get("cr_1", 0) + stat_dict[player].get("cr_2", 0) + stat_dict[player].get("cr_3", 0)
2536 )
2537 total_opp = (
2538 stat_dict[player].get("ccr_opp_1", 0)
2539 + stat_dict[player].get("ccr_opp_2", 0)
2540 + stat_dict[player].get("ccr_opp_3", 0)
2541 )
2543 # Check to avoid division by zero
2544 if total_opp != 0:
2545 stat = float(total_cr) / float(total_opp)
2546 else:
2547 stat = 0 # Avoid division by zero
2549 return (
2550 stat,
2551 "%3.1f" % (100.0 * stat),
2552 "CRF=%3.1f%%" % (100.0 * stat),
2553 "CheckRaiseFreq=%3.1f%%" % (100.0 * stat),
2554 "(%d/%d)" % (total_cr, total_opp),
2555 "Check-Raise Frequency",
2556 )
2557 except (KeyError, ValueError, TypeError):
2558 return (0, "NA", "CRF=NA", "CheckRaiseFreq=NA", "(0/0)", "Check-Raise Frequency")
2561def river_call_efficiency(stat_dict, player):
2562 try:
2563 river_calls = stat_dict[player].get("call_3", 0) # Safely get river calls, defaulting to 0
2564 showdowns_won = stat_dict[player].get("wmsd", 0) # Safely get showdowns won, defaulting to 0
2566 # Calculate the efficiency, ensuring no division by zero
2567 stat = float(showdowns_won) / float(river_calls) if river_calls > 0 else 0
2569 return (
2570 stat,
2571 "%3.1f" % (100.0 * stat),
2572 "RCE=%3.1f%%" % (100.0 * stat),
2573 "RiverCallEff=%3.1f%%" % (100.0 * stat),
2574 "(%d/%d)" % (showdowns_won, river_calls),
2575 "River Call Efficiency",
2576 )
2577 except (KeyError, ValueError, TypeError):
2578 return (0, "NA", "RCE=NA", "RiverCallEff=NA", "(0/0)", "River Call Efficiency")
2581#
2582#
2583#
2584#################################################################################################
2587def starthands(stat_dict, player):
2588 """
2589 Retrieves the starting hands and their positions for a specific player in a hand.
2591 Args:
2592 stat_dict (dict): A dictionary containing the statistics.
2593 player (int): The ID of the player.
2595 Returns:
2596 tuple: A tuple containing the following:
2597 - A string representing the starting hands and their positions.
2598 - A string representing the starting hands and their positions.
2599 - A string representing the starting hands and their positions.
2600 - A string representing the starting hands and their positions.
2601 - A string representing the starting hands and their positions.
2602 - A string representing the title of the statistic.
2604 Raises:
2605 None.
2607 Notes:
2608 - This function retrieves the starting hands and their positions for a specific player in a hand.
2609 - The starting hands and their positions are displayed in a specific format.
2610 - The function uses a global variable `_global_hand_instance` to get the hand instance.
2611 - The function executes a SQL query to retrieve the starting hands and their positions from the database.
2612 - The function formats the retrieved data and returns it as a tuple.
2614 """
2616 hand_instance = _global_hand_instance
2617 if not hand_instance:
2618 return ("", "", "", "", "", "Hands seen at this table")
2620 # summary of known starting hands+position
2621 # data volumes could get crazy here,so info is limited to hands
2622 # in the current HH file only
2624 # this info is NOT read from the cache, so does not obey aggregation
2625 # parameters for other stats
2627 # display shows 5 categories
2628 # PFcall - limp or coldcall preflop
2629 # PFaggr - raise preflop
2630 # PFdefend - defended in BB
2631 # PFcar
2633 # hand is shown, followed by position indicator
2634 # (b=SB/BB. l=Button/cutoff m=previous 3 seats to that, e=remainder)
2636 # due to screen space required for this stat, it should only
2637 # be used in the popup section i.e.
2638 # <pu_stat pu_stat_name="starthands"> </pu_stat>
2639 handid = int(hand_instance.handid_selected)
2640 PFlimp = "Limped:"
2641 PFaggr = "Raised:"
2642 PFcar = "Called raise:"
2643 PFdefendBB = "Defend BB:"
2644 count_pfl = count_pfa = count_pfc = count_pfd = 5
2646 c = Configuration.Config()
2647 db_connection = Database.Database(c)
2648 sc = db_connection.get_cursor()
2650 query = (
2651 "SELECT distinct startCards, street0Aggr, street0CalledRaiseDone, "
2652 + "case when HandsPlayers.position = 'B' then 'b' "
2653 + "when HandsPlayers.position = 'S' then 'b' "
2654 + "when HandsPlayers.position = '0' then 'l' "
2655 + "when HandsPlayers.position = '1' then 'l' "
2656 + "when HandsPlayers.position = '2' then 'm' "
2657 + "when HandsPlayers.position = '3' then 'm' "
2658 + "when HandsPlayers.position = '4' then 'm' "
2659 + "when HandsPlayers.position = '5' then 'e' "
2660 + "when HandsPlayers.position = '6' then 'e' "
2661 + "when HandsPlayers.position = '7' then 'e' "
2662 + "when HandsPlayers.position = '8' then 'e' "
2663 + "when HandsPlayers.position = '9' then 'e' "
2664 + "else 'X' end "
2665 + "FROM Hands, HandsPlayers, Gametypes "
2666 + "WHERE HandsPlayers.handId = Hands.id "
2667 + " AND Gametypes.id = Hands.gametypeid "
2668 + " AND Gametypes.type = "
2669 + " (SELECT Gametypes.type FROM Gametypes, Hands "
2670 + " WHERE Hands.gametypeid = Gametypes.id and Hands.id = %d) "
2671 + " AND Gametypes.Limittype = "
2672 + " (SELECT Gametypes.limitType FROM Gametypes, Hands "
2673 + " WHERE Hands.gametypeid = Gametypes.id and Hands.id = %d) "
2674 + "AND Gametypes.category = 'holdem' "
2675 + "AND fileId = (SELECT fileId FROM Hands "
2676 + " WHERE Hands.id = %d) "
2677 + "AND HandsPlayers.playerId = %d "
2678 + "AND street0VPI "
2679 + "AND startCards > 0 AND startCards <> 170 "
2680 + "ORDER BY startCards DESC "
2681 + ";"
2682 ) % (int(handid), int(handid), int(handid), int(player))
2684 # print query
2685 sc.execute(query)
2686 for qstartcards, qstreet0Aggr, qstreet0CalledRaiseDone, qposition in sc.fetchall():
2687 humancards = Card.decodeStartHandValue("holdem", qstartcards)
2688 # print humancards, qstreet0Aggr, qstreet0CalledRaiseDone, qposition
2689 if qposition == "b" and qstreet0CalledRaiseDone:
2690 PFdefendBB = PFdefendBB + "/" + humancards
2691 count_pfd += 1
2692 if count_pfd / 8.0 == int(count_pfd / 8.0):
2693 PFdefendBB = PFdefendBB + "\n"
2694 elif qstreet0Aggr is True:
2695 PFaggr = PFaggr + "/" + humancards + "." + qposition
2696 count_pfa += 1
2697 if count_pfa / 8.0 == int(count_pfa / 8.0):
2698 PFaggr = PFaggr + "\n"
2699 elif qstreet0CalledRaiseDone:
2700 PFcar = PFcar + "/" + humancards + "." + qposition
2701 count_pfc += 1
2702 if count_pfc / 8.0 == int(count_pfc / 8.0):
2703 PFcar = PFcar + "\n"
2704 else:
2705 PFlimp = PFlimp + "/" + humancards + "." + qposition
2706 count_pfl += 1
2707 if count_pfl / 8.0 == int(count_pfl / 8.0):
2708 PFlimp = PFlimp + "\n"
2709 sc.close()
2711 returnstring = PFlimp + "\n" + PFaggr + "\n" + PFcar + "\n" + PFdefendBB # + "\n" + str(handid)
2713 return (
2714 (returnstring),
2715 (returnstring),
2716 (returnstring),
2717 (returnstring),
2718 (returnstring),
2719 "Hands seen at this table\n",
2720 )
2723def get_valid_stats():
2724 """
2725 Function to retrieve valid stats descriptions.
2727 Returns:
2728 dict: A dictionary containing descriptions of valid stats.
2729 """
2730 global _global_hand_instance
2731 _global_hand_instance = None
2733 stat_descriptions = {}
2734 for function in STATLIST:
2735 function_instance = getattr(__import__(__name__), function)
2736 res = function_instance(None, None)
2737 stat_descriptions[function] = res[5]
2739 return stat_descriptions
2742STATLIST = sorted(dir())
2743misslist = [
2744 "Configuration",
2745 "Database",
2746 "Charset",
2747 "codecs",
2748 "encoder",
2749 "GInitiallyUnowned",
2750 "gtk",
2751 "pygtk",
2752 "Card",
2753 "L10n",
2754 "log",
2755 "logging",
2756 "Decimal",
2757 "GFileDescriptorBased",
2758 "GPollableInputStream",
2759 "GPollableOutputStream",
2760 "re",
2761 "re_Places",
2762 "Hand",
2763]
2764STATLIST = [x for x in STATLIST if x not in ("do_stat", "do_tip", "get_valid_stats")]
2765STATLIST = [x for x in STATLIST if not x.startswith("_")]
2766STATLIST = [x for x in STATLIST if x not in dir(sys)]
2767STATLIST = [x for x in STATLIST if x not in dir(codecs)]
2768STATLIST = [x for x in STATLIST if x not in misslist]
2769# print "STATLIST is", STATLIST
2771if __name__ == "__main__":
2772 c = Configuration.Config()
2773 db_connection = Database.Database(c)
2774 h = db_connection.get_last_hand()
2775 stat_dict = db_connection.get_stats_from_hand(h, "ring")
2776 hand_instance = Hand.hand_factory(h, c, db_connection)
2778 for player in stat_dict.keys():
2779 print(f"Example stats. Player = {player}, Hand = {h}:")
2780 for attr in STATLIST:
2781 print(attr, " : ", do_stat(stat_dict, player=player, stat=attr, hand_instance=hand_instance))
2782 break
2784 print()
2785 print("Legal stats:")
2786 print("(add _0 to name to display with 0 decimal places, _1 to display with 1, etc)")
2787 stat_descriptions = get_valid_stats()
2788 for stat in STATLIST:
2789 print(stat, " : ", stat_descriptions[stat])