Source code for maverick.players.archetypes.grinder

from typing import TYPE_CHECKING

from ...player import Player
from ...enums import ActionType
from ...playeraction import PlayerAction
from ...utils import estimate_holding_strength

if TYPE_CHECKING:  # pragma: no cover
    from ...game import Game

__all__ = ["GrinderBot"]


[docs] class GrinderBot(Player): """A volume-oriented bot focused on steady expected value. Uses hand strength evaluation to make disciplined, long-term EV decisions. Calculates pot odds precisely and makes mathematically sound plays based on hand equity. Consistent bet sizing and no fancy play syndrome. - **Key Traits:** Multitabling, consistent lines, bankroll discipline, uses hand equity for EV calculations. - **Strengths:** Reliable long-term profits, disciplined decision making. - **Weaknesses:** Predictability, limited creativity. - **Common At:** Online cash games. """ cls_uid = "eae4e67da03d4aed8b90ef4f9d232df1"
[docs] def decide_action( self, *, game: "Game", valid_actions: list[ActionType], min_raise_amount: int, call_amount: int, min_bet_amount: int, ) -> PlayerAction: """Play solid, consistent poker focused on long-term EV using hand strength.""" # Evaluate hand strength private_cards = self.state.holding.cards community_cards = game.state.community_cards # Get hand equity if community_cards: hand_equity = estimate_holding_strength( private_cards, community_cards=community_cards, n_private=game.rules.showdown.hole_cards_required, n_simulations=600, n_players=len(game.state.get_players_in_hand()), ) else: # Pre-flop estimation hand_equity = estimate_holding_strength( private_cards, n_private=game.rules.showdown.hole_cards_required, n_simulations=250, n_players=len(game.state.get_players_in_hand()), ) # Grinder thresholds - focused on +EV plays value_hand = hand_equity > 0.60 profitable_hand = hand_equity > 0.45 # Standard raises for value if ActionType.RAISE in valid_actions and value_hand: raise_amount = min(min_raise_amount, self.state.stack) return PlayerAction( player_uid=self.uid, action_type=ActionType.RAISE, amount=raise_amount ) # Bet for value with standard sizing if ActionType.BET in valid_actions and value_hand: bet_amount = min(min_bet_amount * 2, self.state.stack) return PlayerAction( player_uid=self.uid, action_type=ActionType.BET, amount=bet_amount ) # Call with good pot odds and profitable hands if ActionType.CALL in valid_actions and profitable_hand: # Basic pot odds calculation - call if getting 2:1 or better if call_amount <= self.state.stack and call_amount <= game.state.pot * 0.5: return PlayerAction(player_uid=self.uid, action_type=ActionType.CALL) # Check when free if ActionType.CHECK in valid_actions: return PlayerAction(player_uid=self.uid, action_type=ActionType.CHECK) # Fold marginal situations return PlayerAction(player_uid=self.uid, action_type=ActionType.FOLD)