mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-03-28 17:32:36 +01:00
474 lines
16 KiB
Python
474 lines
16 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
|
||
import pickle
|
||
|
||
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 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."
|
||
else:
|
||
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"
|
||
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 saveHSJack(nodeID, highScore):
|
||
# Save the game state to pickle
|
||
highScore = {'nodeID': nodeID, 'highScore': highScore}
|
||
try:
|
||
with open('data/blackjack_hs.pkl', 'wb') as file:
|
||
pickle.dump(highScore, file)
|
||
except FileNotFoundError:
|
||
logger.debug("System: BlackJack: Creating new data/blackjack_hs.pkl file")
|
||
with open('data/blackjack_hs.pkl', 'wb') as file:
|
||
pickle.dump(highScore, file)
|
||
|
||
def loadHSJack():
|
||
try:
|
||
with open('data/blackjack_hs.pkl', 'rb') as file:
|
||
highScore = pickle.load(file)
|
||
return highScore
|
||
except FileNotFoundError:
|
||
logger.debug("System: BlackJack: Creating new data/blackjack_hs.pkl file")
|
||
highScore = {'nodeID': 0, 'highScore': 0}
|
||
with open('data/blackjack_hs.pkl', 'wb') as file:
|
||
pickle.dump(highScore, file)
|
||
return 0
|
||
|
||
def playBlackJack(nodeID, message):
|
||
# Initalize the Game
|
||
msg, last_cmd = '', None
|
||
blackJack = False
|
||
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']
|
||
if last_cmd == "playing":
|
||
p_chips.bet = bet_money
|
||
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.lower() == "b":
|
||
if bet_money == 0:
|
||
bet_money = 5
|
||
elif message.lower() == "r":
|
||
#resend the hand
|
||
msg += show_some(p_cards, d_cards, p_hand)
|
||
return msg
|
||
else:
|
||
try:
|
||
bet_money = int(message)
|
||
except ValueError:
|
||
return "Invalid Bet, please enter a valid number."
|
||
|
||
if bet_money <= p_chips.total and bet_money >= 1:
|
||
p_chips.bet = bet_money
|
||
else:
|
||
return f"Invalid Bet, the maximum bet you can place is {p_chips.total} and the minimum bet is 1."
|
||
except ValueError:
|
||
return f"Invalid Bet, the maximum bet, {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")
|
||
blackJack = True
|
||
# Save the game state
|
||
for i in range(len(jackTracker)):
|
||
if jackTracker[i]['nodeID'] == nodeID:
|
||
jackTracker[i]['cash'] = int(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,(R)esend,(L)eave table"
|
||
|
||
# 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"
|
||
elif choice == "resend" or choice == "r":
|
||
msg += show_some(p_hand.cards, d_cards, p_hand)
|
||
else:
|
||
return "(H)it,(S)tand,(F)orfit,(D)ouble,(R)esend,(L)eave table"
|
||
|
||
# Check if player bust
|
||
if player_bust(p_hand, p_chips):
|
||
d_win += 1
|
||
msg += "💥PlayerBUST💥"
|
||
setLastCmdJack(nodeID, "dealerTurn")
|
||
|
||
if getLastCmdJack(nodeID) == "playing":
|
||
msg += stats
|
||
msg += "[H,S,F,D]"
|
||
|
||
# Save the game state
|
||
for i in range(len(jackTracker)):
|
||
if jackTracker[i]['nodeID'] == nodeID:
|
||
jackTracker[i]['cash'] = int(p_chips.total)
|
||
jackTracker[i]['bet'] = int(p_chips.bet)
|
||
jackTracker[i]['gameStats']['p_win'] = int(p_win)
|
||
jackTracker[i]['gameStats']['d_win'] = int(d_win)
|
||
jackTracker[i]['gameStats']['draw'] = int(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":
|
||
# Dealers Turn
|
||
if not blackJack:
|
||
# 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 += "💰DealerBUST💥"
|
||
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 += "👌PUSH"
|
||
elif player_wins(p_hand, d_hand, p_chips):
|
||
p_win += 1
|
||
msg += "🎉PLAYER WINS🎰"
|
||
elif dealer_wins(p_hand, d_hand, p_chips):
|
||
d_win += 1
|
||
msg += "👎DEALER WINS"
|
||
else:
|
||
msg += "👎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 += "🪙Keep the change you filthy animal!"
|
||
else:
|
||
msg += "💸NO MORE CHIPS!🏧💳"
|
||
p_chips.total = jack_starting_cash
|
||
else:
|
||
# check high score
|
||
highScore = loadHSJack()
|
||
if highScore != 0 and p_chips.total > highScore['highScore']:
|
||
msg += f"💰HighScore💰{p_chips.total} "
|
||
saveHSJack(nodeID, p_chips.total)
|
||
else:
|
||
msg += f"💰You have {p_chips.total} chips "
|
||
|
||
msg += " Bet or Leave?"
|
||
|
||
# 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
|