mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-08-06 17:03:04 +02:00
VideoPoker
This commit is contained in:
@@ -57,6 +57,7 @@ SyslogToFile = False
|
||||
dopeWars = True
|
||||
lemonade = True
|
||||
blackjack = True
|
||||
videopoker = True
|
||||
|
||||
[sentry]
|
||||
# detect anyone close to the bot
|
||||
|
||||
+57
@@ -29,6 +29,7 @@ def auto_response(message, snr, rssi, hop, message_from_id, channel_number, devi
|
||||
"dopewars": lambda: handleDopeWars(message_from_id, message, deviceID),
|
||||
"lemonstand": lambda: handleLemonade(message_from_id, message),
|
||||
"blackjack": lambda: handleBlackJack(message_from_id, message),
|
||||
"videopoker": lambda: handleVideoPoker(message_from_id, message),
|
||||
"ask:": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
|
||||
"askai": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
|
||||
"joke": tell_joke,
|
||||
@@ -280,6 +281,45 @@ def handleBlackJack(nodeID, message):
|
||||
|
||||
return msg
|
||||
|
||||
from modules.videopoker import *
|
||||
def handleVideoPoker(nodeID, message):
|
||||
global vpTracker
|
||||
msg = ""
|
||||
|
||||
# if player sends a L for leave table
|
||||
if message.lower().startswith("l"):
|
||||
logger.debug(f"System: VideoPoker: {nodeID} is leaving the table")
|
||||
# add 16 hours to the player time to leave the table, this will be detected by bot logic as player leaving
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['leaveTime'] = time.time() + 57600
|
||||
vpTracker[i]['cmd'] = "new"
|
||||
else:
|
||||
# Play Video Poker
|
||||
msg = playVideoPoker(nodeID=nodeID, message=message)
|
||||
|
||||
# get player's last command from tracker
|
||||
last_cmd = ""
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
last_cmd = vpTracker[i]['cmd']
|
||||
|
||||
# find higest dollar amount in tracker for high score
|
||||
if last_cmd == "new":
|
||||
high_score = 0
|
||||
user = 0
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['highScore'] > high_score:
|
||||
high_score = vpTracker[i]['highScore']
|
||||
user = vpTracker[i]['nodeID']
|
||||
if user != 0:
|
||||
msg += f"\nHigh Score: {high_score} by {get_name_from_number(user)}"
|
||||
|
||||
if last_cmd != "":
|
||||
logger.debug(f"System: VideoPoker: {nodeID} last command: {last_cmd}")
|
||||
|
||||
return msg
|
||||
|
||||
def handle_wxc(message_from_id, deviceID, cmd):
|
||||
location = get_node_location(message_from_id, deviceID)
|
||||
if use_meteo_wxApi and not "wxc" in cmd and not use_metric:
|
||||
@@ -563,6 +603,23 @@ def onReceive(packet, interface):
|
||||
# play the game
|
||||
send_message(handleLemonade(message_from_id, message_string), channel_number, message_from_id, rxNode)
|
||||
|
||||
for i in range(0, len(vpTracker)):
|
||||
if vpTracker[i].get('nodeID') == message_from_id:
|
||||
# check if the player has played in the last 8 hours
|
||||
if vpTracker[i].get('time') > (time.time() - 28800):
|
||||
playingGame = True
|
||||
game = "VideoPoker"
|
||||
if llm_enabled:
|
||||
logger.debug(f"System: LLM Disabled for {message_from_id} for duration of game")
|
||||
|
||||
#if time exceeds 8 hours reset the player
|
||||
if vpTracker[i].get('time') < (time.time() - 28800):
|
||||
logger.debug(f"System: VideoPoker: Resetting player {message_from_id}")
|
||||
vpTracker.pop(i)
|
||||
|
||||
# play the game
|
||||
send_message(handleVideoPoker(message_from_id, message_string), channel_number, message_from_id, rxNode)
|
||||
|
||||
for i in range(0, len(jackTracker)):
|
||||
if jackTracker[i].get('nodeID') == message_from_id:
|
||||
# check if the player has played in the last 8 hours
|
||||
|
||||
@@ -41,7 +41,7 @@ VALUES = {
|
||||
"A": 11,
|
||||
}
|
||||
|
||||
class Card:
|
||||
class jackCard:
|
||||
def __init__(self, suit, rank):
|
||||
self.suit = suit
|
||||
self.rank = rank
|
||||
@@ -49,7 +49,7 @@ class Card:
|
||||
def __str__(self):
|
||||
return self.rank + " of " + self.suit
|
||||
|
||||
class Deck:
|
||||
class jackDeck:
|
||||
""" Creating a Deck of cards and Deal two cards to both player and dealer. """
|
||||
|
||||
def __init__(self):
|
||||
@@ -78,7 +78,7 @@ class Deck:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
class Hand:
|
||||
class jackHand:
|
||||
""" Adding the values of player/dealer cards and change the values of Aces acc. to situation. """
|
||||
def __init__(self):
|
||||
self.cards = []
|
||||
@@ -98,7 +98,7 @@ class Hand:
|
||||
self.value -= 10
|
||||
self.aces -= 1
|
||||
|
||||
class Chips:
|
||||
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
|
||||
@@ -220,13 +220,13 @@ def playBlackJack(nodeID, message):
|
||||
# Initalize the Game
|
||||
msg, last_cmd = '', None
|
||||
p_win, d_win, draw = 0, 0, 0
|
||||
p_chips = Chips()
|
||||
p_hand = Hand()
|
||||
d_hand = Hand()
|
||||
p_chips = jackChips()
|
||||
p_hand = jackHand()
|
||||
d_hand = jackHand()
|
||||
p_cards, d_cards = [], []
|
||||
bet_money = 0
|
||||
# Initalize the Cards
|
||||
cards_deck = Deck()
|
||||
cards_deck = jackDeck()
|
||||
cards_deck.shuffle()
|
||||
p_cards, d_cards = cards_deck.deal_cards()
|
||||
# Deal the cards to player and dealer
|
||||
|
||||
@@ -145,6 +145,7 @@ try:
|
||||
dopewars_enabled = config['games'].getboolean('dopeWars', True)
|
||||
lemonade_enabled = config['games'].getboolean('lemonade', True)
|
||||
blackjack_enabled = config['games'].getboolean('blackjack', True)
|
||||
videoPoker_enabled = config['games'].getboolean('videoPoker', True)
|
||||
|
||||
except KeyError as e:
|
||||
print(f"System: Error reading config file: {e}")
|
||||
|
||||
@@ -94,6 +94,12 @@ if blackjack_enabled:
|
||||
from modules.blackjack import * # from the spudgunman/meshing-around repo
|
||||
trap_list = trap_list + ("blackjack",)
|
||||
games_enabled = True
|
||||
|
||||
# Video Poker Configuration
|
||||
if videoPoker_enabled:
|
||||
from modules.videopoker import * # from the spudgunman/meshing-around repo
|
||||
trap_list = trap_list + ("videopoker",)
|
||||
games_enabled = True
|
||||
|
||||
# Games Configuration
|
||||
if games_enabled is True:
|
||||
@@ -106,6 +112,8 @@ if games_enabled is True:
|
||||
gamesCmdList += "LemonStand, "
|
||||
if blackjack_enabled:
|
||||
gamesCmdList += "BlackJack, "
|
||||
if videoPoker_enabled:
|
||||
gamesCmdList += "VideoPoker, "
|
||||
gamesCmdList = gamesCmdList[:-2] # remove the last comma
|
||||
|
||||
# Scheduled Broadcast Configuration
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
# Port of https://github.com/devtronvarma/Video-Poker-Terminal-Game
|
||||
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
|
||||
import random
|
||||
import time
|
||||
from modules.log import *
|
||||
|
||||
vpStartingCash = 20
|
||||
vpTracker= [{'nodeID': 0, 'cmd': 'new', 'time': time.time(), 'cash': vpStartingCash, 'player': None, 'deck': None, 'highScore': 0, 'drawCount': 0}]
|
||||
|
||||
# Define the Card class
|
||||
class CardVP:
|
||||
|
||||
card_values = { # value of the ace is high until it needs to be low
|
||||
2: 2,
|
||||
3: 3,
|
||||
4: 4,
|
||||
5: 5,
|
||||
6: 6,
|
||||
7: 7,
|
||||
8: 8,
|
||||
9: 9,
|
||||
10: 10,
|
||||
'Jack': 11,
|
||||
'Queen': 12,
|
||||
'King': 13,
|
||||
'Ace': 14
|
||||
}
|
||||
|
||||
def __init__(self, suit, rank):
|
||||
"""
|
||||
:param suit: The face of the card, e.g. Spade or Diamond
|
||||
:param rank: The value of the card, e.g 3 or King
|
||||
"""
|
||||
self.suit = suit.capitalize()
|
||||
self.rank = rank
|
||||
self.points = self.card_values[rank]
|
||||
|
||||
# Function to output ascii version of the cards in a hand in the terminal
|
||||
def drawCards(*cards, return_string=True):
|
||||
"""
|
||||
Instead of a boring text version of the card we render an ASCII image of the card.
|
||||
:param cards: One or more card objects
|
||||
:param return_string: By default we return the string version of the card, but the dealer hide the 1st card and we
|
||||
keep it as a list so that the dealer can add a hidden card in front of the list
|
||||
"""
|
||||
# we will use this to prints the appropriate icons for each card
|
||||
suits_name = ['Spades', 'Diamonds', 'Hearts', 'Clubs']
|
||||
suits_symbols = ['♠', '♦', '♥', '♣']
|
||||
|
||||
# create an empty list of list, each sublist is a line 2 lines for the card
|
||||
lines = [[] for i in range(1)]
|
||||
|
||||
for index, card in enumerate(cards):
|
||||
# "King" should be "K" and "10" should still be "10"
|
||||
if card.rank == 10: # ten is the only one who's rank is 2 char long
|
||||
rank = str(card.rank)
|
||||
space = '' # if we write "10" on the card that line will be 1 char to long
|
||||
else:
|
||||
rank = str(card.rank)[0] # some have a rank of 'King' this changes that to a simple 'K' ("King" doesn't fit)
|
||||
space = ' ' # no "10", we use a blank space to will the void
|
||||
# get the cards suit in two steps
|
||||
suit = suits_name.index(card.suit)
|
||||
suit = suits_symbols[suit]
|
||||
|
||||
# add the individual card on a line by line basis
|
||||
lines[0].append('{}{} '.format(rank, suit))
|
||||
|
||||
result = []
|
||||
result.append('1 2 3 4 5') # add the index for the cards to top row
|
||||
for index, line in enumerate(lines):
|
||||
result.append(''.join(lines[index]))
|
||||
|
||||
# hidden cards do not use string
|
||||
if return_string:
|
||||
return '\n'.join(result)
|
||||
else:
|
||||
return result
|
||||
|
||||
# Define Deck class
|
||||
class DeckVP:
|
||||
|
||||
def __init__(self):
|
||||
self.cards = []
|
||||
self.build()
|
||||
|
||||
# method for building the deck
|
||||
def build(self):
|
||||
for s in ['Spades', 'Diamonds', 'Hearts', 'Clubs']:
|
||||
for v in range(2, 11):
|
||||
self.cards.append(CardVP(s,v))
|
||||
for c in ["Jack", "Queen", "King", "Ace"]:
|
||||
self.cards.append(CardVP(s,c))
|
||||
|
||||
# method to show cards in deck
|
||||
def display(self):
|
||||
for c in self.cards:
|
||||
print(drawCards(c))
|
||||
|
||||
# method to shuffle cards in deck
|
||||
def shuffle(self):
|
||||
for i in range(len(self.cards) - 1, 0, -1):
|
||||
r = random.randint(0, i)
|
||||
self.cards[i], self.cards[r] = self.cards[r], self.cards[i]
|
||||
|
||||
# method to draw card from the deck
|
||||
def draw_card(self):
|
||||
return self.cards.pop()
|
||||
|
||||
# Define Player Class
|
||||
class PlayerVP:
|
||||
def __init__(self):
|
||||
self.hand = []
|
||||
self.bankroll = 20
|
||||
|
||||
# Method for initial five-card draw
|
||||
def draw_cards(self, deck):
|
||||
for i in range(5):
|
||||
self.hand.append(deck.draw_card())
|
||||
return self
|
||||
|
||||
# Method for displaying player's hand
|
||||
def show_hand(self):
|
||||
msg = (drawCards(
|
||||
self.hand[0],
|
||||
self.hand[1],
|
||||
self.hand[2],
|
||||
self.hand[3],
|
||||
self.hand[4]))
|
||||
return msg
|
||||
|
||||
# Method for placing a bet
|
||||
def bet(self, ammount=0):
|
||||
try:
|
||||
bet = int(ammount)
|
||||
except ValueError:
|
||||
bet = 1
|
||||
|
||||
if bet > self.bankroll:
|
||||
return "You can only bet the money you have. No strip poker here..."
|
||||
self.bet_size = self.bankroll
|
||||
elif bet > 5:
|
||||
return "You can only bet 5 coins at most."
|
||||
self.bet_size = 5
|
||||
else:
|
||||
self.bet_size = bet
|
||||
self.bankroll -= self.bet_size
|
||||
|
||||
# Method for selecting cards to redraw
|
||||
def redraw(self, deck, message):
|
||||
# if message has single digit, then it is the card to redraw, else it is the list of cards to redraw with a comma
|
||||
if len(message) == 1:
|
||||
redraw_index = int(message) - 1
|
||||
self.hand[redraw_index] = deck.draw_card()
|
||||
else:
|
||||
redraw_list = [int(x) - 1 for x in message.split(',')]
|
||||
for i in redraw_list:
|
||||
self.hand[i] = deck.draw_card()
|
||||
|
||||
|
||||
return self.show_hand()
|
||||
|
||||
# Method for scoring hand, calculating winnings, and outputting message
|
||||
def score_hand(self):
|
||||
points = sorted([self.hand[i].points for i in range(5)])
|
||||
suits = [self.hand[i].suit for i in range(5)]
|
||||
points_repeat = [points.count(i) for i in points]
|
||||
suits_repeat = [suits.count(i) for i in suits]
|
||||
diff = max(points) - min(points)
|
||||
hand_name = ""
|
||||
payoff = {
|
||||
"Royal Flush": 10,
|
||||
"Straight Flush": 9,
|
||||
"Flush": 8,
|
||||
"Full House": 7,
|
||||
"Four of a Kind": 6,
|
||||
"Three of a Kind": 5,
|
||||
"Two Pair": 4,
|
||||
"Straight": 3,
|
||||
"Pair": 2,
|
||||
"Bad Hand": -1,
|
||||
}
|
||||
|
||||
if 5 in suits_repeat:
|
||||
if points == [10, 11, 12, 13, 14]: #find royal flush
|
||||
hand_name = "Royal Flush"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif diff == 4 and max(points_repeat) == 1: # find straight flush w/o ace low
|
||||
hand_name = "Straight Flush"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif diff == 12 and points[4] == 14: # find straight flush w/ace low
|
||||
check = 0
|
||||
for i in range(1, 4):
|
||||
check += points[i] - points[i - 1]
|
||||
if check == 3:
|
||||
hand_name = "Straight Flush"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
else:
|
||||
hand_name = "Flush"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
else:
|
||||
hand_name = "Flush"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif sorted(points_repeat) == [2,2,3,3,3]: # find full house
|
||||
hand_name = "Full House"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif 4 in points_repeat: # find four of a kind
|
||||
hand_name = "Four of a Kind"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif 3 in points_repeat: # find three of a kind
|
||||
hand_name = "Three of a Kind"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif points_repeat.count(2) == 4: # find two-pair
|
||||
hand_name = "Two Pair"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif 2 in points_repeat: # find pair
|
||||
hand_name = "Pair"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif diff == 4 and max(points_repeat) == 1: # find straight w/o ace low
|
||||
hand_name = "Straight"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
elif diff == 12 and points[4] == 14: # find straight w/ace low
|
||||
check = 0
|
||||
for i in range(1, 4):
|
||||
check += points[i] - points[i - 1]
|
||||
if check == 3:
|
||||
hand_name = "Straight"
|
||||
self.bankroll += self.bet_size * payoff[hand_name] + self.bet_size
|
||||
else:
|
||||
hand_name = "Bad Hand"
|
||||
self.bankroll += self.bet_size * payoff[hand_name]
|
||||
else: # for everything else
|
||||
hand_name = "Bad Hand"
|
||||
self.bankroll += self.bet_size * payoff[hand_name]
|
||||
|
||||
msg = "You have a {}. Your bankroll is now {} coins.".format(hand_name, self.bankroll)
|
||||
self.hand = []
|
||||
return msg
|
||||
|
||||
|
||||
def getLastCmdVp(nodeID):
|
||||
last_cmd = ""
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
last_cmd = vpTracker[i]['cmd']
|
||||
return last_cmd
|
||||
|
||||
def setLastCmdVp(nodeID, cmd):
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['cmd'] = cmd
|
||||
|
||||
def playVideoPoker(nodeID, message):
|
||||
msg = ""
|
||||
|
||||
# Initialize the player
|
||||
if getLastCmdVp(nodeID) is None or getLastCmdVp(nodeID=nodeID) == "":
|
||||
# create new player if not in tracker
|
||||
logger.debug(f"System: VideoPoker: New Player {nodeID}")
|
||||
vpTracker.append({'nodeID': nodeID, 'cmd': 'new', 'time': time.time(), 'cash': vpStartingCash, 'player': None, 'deck': None, 'highScore': 0, 'drawCount': 0})
|
||||
return f"Welcome to VideoPoker! you have {vpStartingCash} coins, Whats your bet?"
|
||||
elif getLastCmdVp(nodeID) == "gameOver" or getLastCmdVp(nodeID) == "new":
|
||||
# load the player bankroll from tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
cash = vpTracker[i]['cash']
|
||||
return f"Welcome back to VideoPoker! you have {cash} coins, Whats your bet?"
|
||||
|
||||
# Gather the player's bet
|
||||
if getLastCmdVp(nodeID) == "new" or getLastCmdVp(nodeID) == "gameOver":
|
||||
# Initialize shuffled Deck and Player
|
||||
player = PlayerVP()
|
||||
deck = DeckVP()
|
||||
deck.shuffle()
|
||||
drawCount = 0
|
||||
|
||||
# save player and deck to tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['player'] = player
|
||||
vpTracker[i]['deck'] = deck
|
||||
|
||||
msg = player.bet(str(message))
|
||||
if msg != None:
|
||||
print(msg)
|
||||
else:
|
||||
setLastCmdVp(nodeID, "playing")
|
||||
|
||||
# Play the game
|
||||
if getLastCmdVp(nodeID) == "playing":
|
||||
msg = ''
|
||||
|
||||
player.draw_cards(deck)
|
||||
msg += player.show_hand()
|
||||
setLastCmdVp(nodeID, "redraw")
|
||||
|
||||
# save player and deck to tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['player'] = player
|
||||
vpTracker[i]['deck'] = deck
|
||||
vpTracker[i]['drawCount'] = drawCount
|
||||
|
||||
msg += f"\nDeal any cards? List them by number separated by commas"
|
||||
return msg
|
||||
|
||||
if getLastCmdVp(nodeID) == "redraw":
|
||||
# load the player and deck from tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
player = vpTracker[i]['player']
|
||||
deck = vpTracker[i]['deck']
|
||||
drawCount = vpTracker[i]['drawCount']
|
||||
|
||||
# if player wants to redraw cards, and not done so twice total
|
||||
if message.lower().startswith("n"):
|
||||
setLastCmdVp(nodeID, "endGame")
|
||||
else:
|
||||
if drawCount < 2:
|
||||
msg = player.redraw(deck, message)
|
||||
drawCount += 1
|
||||
setLastCmdVp(nodeID, "endGame")
|
||||
# save player and deck to tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['player'] = player
|
||||
vpTracker[i]['deck'] = deck
|
||||
vpTracker[i]['drawCount'] = drawCount
|
||||
return msg
|
||||
else:
|
||||
setLastCmdVp(nodeID, "endGame")
|
||||
|
||||
if getLastCmdVp(nodeID) == "endGame":
|
||||
msg = ''
|
||||
# load the player and deck from tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
player = vpTracker[i]['player']
|
||||
deck = vpTracker[i]['deck']
|
||||
|
||||
msg += player.score_hand()
|
||||
|
||||
if player.bankroll < 1:
|
||||
player.bankroll = vpStartingCash
|
||||
return "Looks like you're out of money. Better luck next time!"
|
||||
|
||||
# check if player has new high score
|
||||
if player.bankroll > vpTracker[i]['highScore']:
|
||||
vpTracker[i]['highScore'] = player.bankroll
|
||||
msg += " You have a new personal high score of {} coins.".format(player.bankroll)
|
||||
else:
|
||||
msg += " Your personal high score is {} coins.".format(vpTracker[i]['highScore'])
|
||||
|
||||
msg += "Place your Bet, 'L' to leave the game."
|
||||
|
||||
setLastCmdVp(nodeID, "gameOver")
|
||||
# reset player and deck in tracker
|
||||
for i in range(len(vpTracker)):
|
||||
if vpTracker[i]['nodeID'] == nodeID:
|
||||
vpTracker[i]['player'] = None
|
||||
vpTracker[i]['deck'] = None
|
||||
vpTracker[i]['drawCount'] = 0
|
||||
|
||||
return msg
|
||||
|
||||
Reference in New Issue
Block a user