mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-03-28 17:32:36 +01:00
449 lines
14 KiB
Python
449 lines
14 KiB
Python
# 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
|