# Port of https://github.com/Himan10/BlackJack # Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024 from random import choices, shuffle from modules.log import * import time jack_starting_cash = 100 # Replace 100 with your desired starting cash value jackTracker= [{'nodeID': 0, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\ 'bet': 0, 'gameStats': {'p_win': 0, 'd_win': 0, 'draw': 0}, 'p_cards':[], 'd_cards':[], 'p_hand':[], 'd_hand':[], 'next_card':[]}] SUITS = ("♥️", "♦️", "♠️", "♣️") RANKS = ( "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", ) VALUES = { "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "10": 10, "J": 10, "Q": 10, "K": 10, "A": 11, } class jackCard: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return self.rank + " of " + self.suit class jackDeck: """ Creating a Deck of cards and Deal two cards to both player and dealer. """ def __init__(self): self.deck = [] self.player = [] self.dealer = [] for suit in SUITS: for rank in RANKS: self.deck.append((suit, rank)) def shuffle(self): shuffle(self.deck) def deal_cards(self): self.player = choices(self.deck, k=2) self.delete_cards(self.player) self.dealer = choices(self.deck, k=2) self.delete_cards(self.dealer) # Delete Drawn Cards return self.player, self.dealer def delete_cards(self, total_drawn): """ Delete Drawn cards from the Decks """ try: for i in total_drawn: self.deck.remove(i) except ValueError: pass class jackHand: """ Adding the values of player/dealer cards and change the values of Aces acc. to situation. """ def __init__(self): self.cards = [] self.value = 0 self.aces = 0 def add_cards(self, card): self.cards.extend(card) for count, ele in enumerate(card, 0): if ele[1] == "A": self.aces += 1 self.value += VALUES[ele[1]] self.adjust_for_ace() def adjust_for_ace(self): while self.aces > 0 and self.value > 21: self.value -= 10 self.aces -= 1 class jackChips: """ Player/dealer chips for making bets and Adding/Deducting amount in/from Player's total. """ def __init__(self): self.total = jack_starting_cash self.bet = 0 self.winnings = 0 def win_bet(self): self.total += self.bet self.winnings += 1 def loss_bet(self): self.total -= self.bet self.winnings -= 1 def take_bet(bet_amount, player_money): try: if bet_amount >= player_money or bet_amount <= 0: return f"Enter a bet amount between 1 and {player_money}" return bet_amount except TypeError: return "Invalid bet amount" def success_rate(card, obj_h): """ Calculate Success rate of 'HIT' new cards """ msg = "" rate = 0 diff = 21 - obj_h.value if diff != 0: rate = (VALUES[card[0][1]] / diff) * 100 if rate < 100: msg += f"If Hit, chance {int(rate)}% failure, {100-int(rate)}% success." elif rate > 100: l_rate = int(rate - (rate - 99)) # Round to 99 if card[0][1] == "A": l_rate -= 99 msg += f"If Hit, chance {100-l_rate}% failure, and {l_rate}% success" else: msg += f"If Hit, a low chance of success." return msg def hits(obj_de): new_card = [obj_de.deal_cards()[0][0]] # obj_h.add_cards(new_card) return new_card def display_hand(hand): # Display the cards in the hand nicely d = "" # display for card in hand: d += f"{card[1]}{card[0]}" if card != hand[-1]: d += ", " return d def show_some(player_cards, dealer_cards, obj_h): msg = f"Player[{obj_h.value}] {display_hand(player_cards)} " msg += f"Dealer[{VALUES[dealer_cards[1][1]]}] {dealer_cards[1][1]}{dealer_cards[1][0]} " return msg def show_all(player_cards, dealer_cards, obj_h, obj_d): msg = f"Player[{obj_h.value}] {display_hand(player_cards)} " msg += f"Dealer[{obj_d.value}] {display_hand(dealer_cards)}" return msg def player_bust(obj_h, obj_c): if obj_h.value > 21: obj_c.loss_bet() return True return False def player_wins(obj_h, obj_d, obj_c): if any((obj_h.value == 21, obj_h.value > obj_d.value and obj_h.value < 21)): obj_c.win_bet() return True return False def dealer_bust(obj_d, obj_h, obj_c): if obj_d.value > 21: if obj_h.value < 21: obj_c.win_bet() return True return False def dealer_wins(obj_h, obj_d, obj_c): if any((obj_d.value == 21, obj_d.value > obj_h.value and obj_d.value < 21)): obj_c.loss_bet() return True return False def push(obj_h, obj_d): if obj_h.value == obj_d.value: return True return False def player_surrender(obj_c): obj_c.loss_bet() return True def gameStats(p_count, d_count, draw_c): msg = f"\n📊🏆P:{p_count},D:{d_count},T:{draw_c}" return msg def getLastCmdJack(nodeID): for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: return jackTracker[i]['cmd'] return None def setLastCmdJack(nodeID, cmd): for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: jackTracker[i]['cmd'] = cmd return True return False def playBlackJack(nodeID, message): # Initalize the Game msg, last_cmd = '', None p_win, d_win, draw = 0, 0, 0 p_chips = jackChips() p_hand = jackHand() d_hand = jackHand() p_cards, d_cards = [], [] bet_money = 0 # Initalize the Cards cards_deck = jackDeck() cards_deck.shuffle() p_cards, d_cards = cards_deck.deal_cards() # Deal the cards to player and dealer p_hand.add_cards(p_cards) d_hand.add_cards(d_cards) next_card = hits(cards_deck) # Check if player, use tracking for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: last_cmd = jackTracker[i]['cmd'] p_chips.total = jackTracker[i]['cash'] p_win = jackTracker[i]['gameStats']['p_win'] d_win = jackTracker[i]['gameStats']['d_win'] draw = jackTracker[i]['gameStats']['draw'] bet_money = jackTracker[i]['bet'] p_chips.bet = bet_money if last_cmd == "playing": p_cards = jackTracker[i]['p_cards'] d_cards = jackTracker[i]['d_cards'] p_hand = jackTracker[i]['p_hand'] d_hand = jackTracker[i]['d_hand'] next_card = jackTracker[i]['next_card'] if last_cmd is None: # create new player if not in tracker logger.debug(f"System: BlackJack: New Player {nodeID}") jackTracker.append({'nodeID': nodeID, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\ 'bet': 0, 'gameStats': {'p_win': p_win, 'd_win': d_win, 'draw': draw}, 'p_cards':p_cards, 'd_cards':d_cards, 'p_hand':p_hand.cards, 'd_hand':d_hand.cards, 'next_card':next_card}) return f"Welcome to BlackJack!♠️♥️♣️♦️ you have {p_chips.total} chips, Whats your bet?" if getLastCmdJack(nodeID) == "new": # Place Bet try: # handle B letter if message == "b": if bet_money == 0: bet_money = 5 else: bet_money = bet_money # handle # message if bet_money != 0: bet_money = int(bet_money) else: bet_money = int(message) if bet_money <= p_chips.total or bet_money <= 1: p_chips.bet = take_bet(bet_money, p_chips.total) else: return f"Invalid Bet, the maximum bet you can place is {p_chips.total}" except ValueError: return f"Invalid Bet, the maximum bet you can place is {p_chips.total}" # Show the cards msg += show_some(p_cards, d_cards, p_hand) # check for blackjack 21 and only two cards if p_hand.value == 21 and len(p_hand.cards) == 2: msg += "Player 🎰 BLAAAACKJACKKKK 💰" p_chips.total += round(p_chips.bet * 1.5) setLastCmdJack(nodeID, "dealerTurn") # Save the game state for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: jackTracker[i]['cash'] = p_chips.total break else: # Display the statistics stats = success_rate(next_card, p_hand) msg += stats setLastCmdJack(nodeID, "betPlaced") if getLastCmdJack(nodeID) == "betPlaced": setLastCmdJack(nodeID, "playing") msg += "(H)it,(S)tand,(F)orfit,(D)ouble" # save the game state for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: jackTracker[i]['cash'] = p_chips.total jackTracker[i]['bet'] = p_chips.bet jackTracker[i]['p_cards'] = p_cards jackTracker[i]['d_cards'] = d_cards jackTracker[i]['p_hand'] = p_hand jackTracker[i]['d_hand'] = d_hand jackTracker[i]['next_card'] = next_card return msg while getLastCmdJack(nodeID) == "playing": # Recall var. from hit and stand function next_card = hits(cards_deck) # Get the statistics stats = success_rate(next_card, p_hand) # Player's Turn choice = message.lower() if choice == "hit" or choice == "h": # hits(obj_de, p_hand) p_hand.add_cards(next_card) msg += show_some(p_hand.cards, d_cards, p_hand) elif choice == "stand" or choice == "s": setLastCmdJack(nodeID, "dealerTurn") elif choice == "forfit" or choice == "f": p_chips.bet = p_chips.bet / 2 setLastCmdJack(nodeID, "dealerTurn") p_hand.value += 21 elif choice == "double" or choice == "d": if p_chips.bet * 2 <= p_chips.total: p_chips.bet *= 2 next_d_card = hits(cards_deck) p_hand.add_cards(next_d_card) setLastCmdJack(nodeID, "dealerTurn") else: return "You can't Double Down, dont have enough chips" else: return "Invalid Choice" # Check if player bust if player_bust(p_hand, p_chips): d_win += 1 msg += "Player:BUST💥" setLastCmdJack(nodeID, "dealerTurn") if getLastCmdJack(nodeID) == "playing": msg += stats msg += "[H,S,F,D,L]" # Save the game state for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: jackTracker[i]['cash'] = p_chips.total jackTracker[i]['bet'] = p_chips.bet jackTracker[i]['gameStats']['p_win'] = p_win jackTracker[i]['gameStats']['d_win'] = d_win jackTracker[i]['gameStats']['draw'] = draw jackTracker[i]['p_cards'] = p_cards jackTracker[i]['d_cards'] = d_cards jackTracker[i]['p_hand'] = p_hand jackTracker[i]['d_hand'] = d_hand break # Exit player's turn if getLastCmdJack(nodeID) == "dealerTurn": break return msg if getLastCmdJack(nodeID) == "dealerTurn": # recall the game state for i in range(len(jackTracker)): if jackTracker[i]['nodeID'] == nodeID: p_chips.total = jackTracker[i]['cash'] p_chips.bet = jackTracker[i]['bet'] p_win = jackTracker[i]['gameStats']['p_win'] d_win = jackTracker[i]['gameStats']['d_win'] draw = jackTracker[i]['gameStats']['draw'] p_cards = jackTracker[i]['p_cards'] d_cards = jackTracker[i]['d_cards'] p_hand = jackTracker[i]['p_hand'] d_hand = jackTracker[i]['d_hand'] next_card = jackTracker[i]['next_card'] break if p_hand.value <= 21: # Dealer's Turn while d_hand.value < 17: d_card = hits(cards_deck) d_hand.add_cards(d_card) if dealer_bust(d_hand, p_hand, p_chips): p_win += 1 msg += "Dealer:BUST💥" break # Show all cards msg += show_all(p_hand.cards, d_hand.cards, p_hand, d_hand) # Check who wins if push(p_hand, d_hand): draw += 1 msg += f"👌PUSH" elif player_wins(p_hand, d_hand, p_chips): p_win += 1 msg += f"🎉PLAYER WINS🎰" elif dealer_wins(p_hand, d_hand, p_chips): d_win += 1 msg += f"👎DEALER WINS" else: msg += f"👎DEALER WINS" # Display the Game Stats msg += gameStats(str(p_win), str(d_win), str(draw)) # Display the chips left if p_chips.total < 1: if p_chips.total > 0: msg += f"🪙Keep the change you filthy animal!" else: msg += "💸NO MORE MONEY! Game Over!" p_chips.total = jack_starting_cash else: msg += f"💰You have {p_chips.total} chips left" msg += "(B)et or (L)eave table." # Reset the game setLastCmdJack(nodeID, "new") jackTracker[i]['cash'] = p_chips.total jackTracker[i]['gameStats']['p_win'] = p_win jackTracker[i]['gameStats']['d_win'] = d_win jackTracker[i]['gameStats']['draw'] = draw jackTracker[i]['p_cards'] = [] jackTracker[i]['d_cards'] = [] jackTracker[i]['p_hand'] = [] jackTracker[i]['d_hand'] = [] jackTracker[i]['time'] = time.time() return msg