Files
meshing-around/modules/games/golfsim.py
SpudGunMan 757d6d30b8 fix
2025-12-27 19:38:06 -08:00

417 lines
16 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# https://github.com/danfriedman30/pythongame
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
import random
import time
import pickle
from modules.log import logger
from modules.settings import golfTracker
# Clubs setup
driver_distances = list(range(230, 280, 5))
low_distances = list(range(185, 215, 5))
mid_distances = list(range(130, 185, 5))
high_distances = list(range(90, 135, 5))
gap_wedge_distances = list(range(50, 85, 5))
lob_wedge_distances = list(range(10, 50, 5))
putt_outcomes = [1, 2, 3]
# Hole/Course Setup
full_hole_range = list(range(130, 520, 5))
par3_range = list(range(130, 255, 5))
par4_range = list(range(255, 445, 5))
par5_range = list(range(445, 520, 5))
par3_4_range = par3_range + par4_range
par3_5_range = par3_range + par5_range
par4_5_range = par4_range + par5_range
# Player setup
playingHole = False
from modules.settings import golfTracker
# Club functions
def hit_driver():
club_distance = random.choice(driver_distances)
return club_distance
def hit_low_iron():
club_distance = random.choice(low_distances)
return club_distance
def hit_mid_iron():
club_distance = random.choice(mid_distances)
return club_distance
def hit_high_iron():
club_distance = random.choice(high_distances)
return club_distance
def hit_gap_wedge():
club_distance = random.choice(gap_wedge_distances)
return club_distance
def hit_lob_wedge():
club_distance = random.choice(lob_wedge_distances)
return club_distance
def finish_hole():
finish = random.choice(putt_outcomes)
return finish
def endGameGolf(nodeID):
# pop player from tracker
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker.pop(i)
logger.debug("System: GolfSim: Player " + str(nodeID) + " has ended their round.")
def getScorecardGolf(scorecard):
# Scorecard messages, convert score to message comment
msg = ""
if scorecard == 8:
# Quadruple bogey
msg += " +Quad Bogey☃ "
elif scorecard == 7:
# Triple bogey
msg += " +Triple Bogey "
elif scorecard == 6:
# Double bogey
msg += " +Double Bogey "
elif scorecard == 5:
# Bogey
msg += " +Bogey "
elif scorecard > 0:
# Over par
msg += f" +Par {str(scorecard)} "
elif scorecard == 0:
# Even par
msg += " Even Par💪 "
elif scorecard == -1:
# Birdie
msg += " -Birdie🐦 "
elif scorecard == -2:
# Eagle
msg += " -Eagle🦅 "
elif scorecard == -3:
# Albatross
msg += " -Albatross🦅🦅 "
else:
# Under par
msg += f" -Par {str(abs(scorecard))} "
return msg
def getHighScoreGolf(nodeID, strokes, par):
# check if player is in high score list
try:
with open('data/golfsim_hs.pkl', 'rb') as f:
golfHighScore = pickle.load(f)
except:
logger.debug("System: GolfSim: High Score file not found.")
golfHighScore = [{'nodeID': nodeID, 'strokes': strokes, 'par': par}]
with open('data/golfsim_hs.pkl', 'wb') as f:
pickle.dump(golfHighScore, f)
if strokes < golfHighScore[0]['strokes']:
# player got new low score which is high score
golfHighScore[0]['nodeID'] = nodeID
golfHighScore[0]['strokes'] = strokes
golfHighScore[0]['par'] = par
with open('data/golfsim_hs.pkl', 'wb') as f:
pickle.dump(golfHighScore, f)
return golfHighScore
return 0
# Main game loop
def playGolf(nodeID, message, finishedHole=False, last_cmd=''):
msg = ''
# Course setup
par3_count = 0
par4_count = 0
par5_count = 0
# Scorecard setup
total_strokes = 0
total_to_par = 0
par = 0
hole = 1
# get player's last command from tracker if not new player
last_cmd = ""
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
last_cmd = golfTracker[i]['cmd']
hole = golfTracker[i]['hole']
distance_remaining = golfTracker[i]['distance_remaining']
hole_shots = golfTracker[i]['hole_shots']
par = golfTracker[i]['par']
total_strokes = golfTracker[i]['total_strokes']
total_to_par = golfTracker[i]['total_to_par']
#update last played time
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker[i]['last_played'] = time.time()
if last_cmd == "new":
# Start a new hole
if hole <= 9:
# Set up hole count restrictions on par
if par3_count < 2 and par4_count < 5 and par5_count < 2:
hole_length = random.choice(full_hole_range)
if par3_count >= 2 and par4_count < 5 and par5_count < 2:
hole_length = random.choice(par4_5_range)
if par3_count >= 2 and par4_count < 5 and par5_count >= 2:
hole_length = random.choice(par4_range)
if par3_count < 2 and par4_count < 5 and par5_count >= 2:
hole_length = random.choice(par3_4_range)
if par3_count < 2 and par4_count >= 5 and par5_count >= 2:
hole_length = random.choice(par3_range)
if par3_count >= 2 and par4_count >= 5 and par5_count < 2:
hole_length = random.choice(par5_range)
if par3_count < 2 and par4_count >= 5 and par5_count < 2:
hole_length = random.choice(par3_5_range)
# Set up par for the hole
if hole_length <= 250:
par = 3
par3_count += 1
elif hole_length > 250 and hole_length <= 440:
par = 4
par4_count += 1
elif hole_length > 440:
par = 5
par5_count += 1
# roll for chance of hazard
hazard_chance = random.randint(1, 100)
weather_chance = random.randint(1, 100)
# have low chances of hazards and weather
hasHazard = False
hazard = ""
if hazard_chance < 25:
# Further reduce chance of hazards with weather
if weather_chance < 15:
# randomly calculate a hazard for the hole sand, 🌊, 🌲, 🏘️, etc
hazard = random.choice(["🏖️", "🌊", "🌲", "🏘️"])
hasHazard = True
# Set initial parameters before starting a hole
distance_remaining = hole_length
hole_shots = 0
last_cmd = 'stroking'
# save player's current game state
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker[i]['cmd'] = last_cmd
golfTracker[i]['hole'] = hole
golfTracker[i]['distance_remaining'] = distance_remaining
golfTracker[i]['cmd'] = 'stroking'
golfTracker[i]['par'] = par
golfTracker[i]['total_strokes'] = total_strokes
golfTracker[i]['total_to_par'] = total_to_par
golfTracker[i]['hazard'] = hazard
golfTracker[i]['last_played'] = time.time()
golfTracker[i]['hole_shots'] = hole_shots
# Show player the hole information
msg += "⛳️#" + str(hole) + " is a " + str(hole_length) + "-yard Par " + str(par) + "."
if hasHazard:
msg += "⚠️" + hazard + "."
else:
# add weather conditions with random choice from list, this is fluff
msg += random.choice(["☀️", "💨", "☀️", "☀️", "⛅️", "☁️", "☀️"])
if not finishedHole:
msg += f"\nChoose your club."
return msg
if last_cmd == 'stroking':
# Get player's current game state
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
distance_remaining = golfTracker[i]['distance_remaining']
hole = golfTracker[i]['hole']
hole_shots = golfTracker[i]['hole_shots']
par = golfTracker[i]['par']
total_strokes = golfTracker[i]['total_strokes']
total_to_par = golfTracker[i]['total_to_par']
hazard = golfTracker[i]['hazard']
# Start loop to be able to choose clubs while at least 20 yards away
if distance_remaining >= 20:
msg = ""
club = message.lower()
shot_distance = 0
pin_distance = distance_remaining
if club == "driver" or club.startswith("d"):
shot_distance = hit_driver()
msg += "🏌Hit D " + str(shot_distance) + "yd. "
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif "low" in club or club.startswith("l"):
shot_distance = hit_low_iron()
msg += "🏌Hit L Iron " + str(shot_distance) + "yd. "
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif "mid" in club or club.startswith("m"):
shot_distance = hit_mid_iron()
msg += "🏌Hit M Iron " + str(shot_distance) + "yd. "
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif "high" in club or club.startswith("h"):
shot_distance = hit_high_iron()
msg += "🏌Hit H Iron " + str(shot_distance) + "yd. "
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif "gap" in club or club.startswith("g"):
shot_distance = hit_gap_wedge()
msg += "🏌Hit G Wedge " + str(shot_distance) + "yd ."
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif "wedge" in club or club.startswith("w"):
shot_distance = hit_lob_wedge()
msg += "🏌Hit L Wedge " + str(shot_distance) + "yd. "
distance_remaining = abs(distance_remaining - shot_distance)
hole_shots += 1
elif club == "caddy" or club.startswith("c"):
# Show player the club distances
msg += f"Caddy Guess:\nD:{hit_driver()} L:{hit_low_iron()} M:{hit_mid_iron()} H:{hit_high_iron()} G:{hit_gap_wedge()} W:{hit_lob_wedge()}"
else:
msg += f"Didnt get your club 🥪♣️🪩 choice, you have {distance_remaining}yds. to ⛳️"
return msg
if distance_remaining - pin_distance > pin_distance or shot_distance > pin_distance:
# Check for over-shooting the hole
if distance_remaining > 20:
# did it go off the "green"?
msg += "Overshot the green!🚀"
if distance_remaining == 0:
msg += "🎯Perfect shot! "
last_cmd = 'putt'
elif distance_remaining < 20:
# Roll Dice
hole_in_one_chance = random.randint(1, 100)
wind_factor = random.randint(1, 10)
skill_factor = random.randint(1, 10)
critter_factor = random.randint(1, 50)
# Check for hole in one
if hole_in_one_chance <= 5 and wind_factor > 7 and skill_factor > 8:
distance_remaining = 0
# Check for critters
if skill_factor > 8 and critter_factor < 40 and wind_factor > 2 and hole_in_one_chance > 5:
msg += random.choice(["A 🐿️ steals your ball!😡 ","You Hit a 🦅 soring past ", "🐊 need we say more? ", "hit a 🪟 of a 🏡 "])
distance_remaining = -1
# Handle hazard
if hazard == "🌊" and skill_factor < 7:
msg += "In the water!🌊"
distance_remaining = -1
if hazard == "🏖️" and skill_factor < 5:
msg += "In the sand!🏖️"
distance_remaining = random.randint(5, 10)
if hazard == "🌲" and skill_factor < 3:
msg += "In the trees!🌲"
distance_remaining += random.randint(5, 20)
if hazard == "🏘️" and skill_factor < 2:
msg += "In the parking lot!🚗"
distance_remaining += random.randint(10, 30)
# Check we didnt go off the green or into a hazard
if distance_remaining < 20:
last_cmd = 'putt'
else:
last_cmd = 'stroking'
else:
msg += f"\nYou have " + str(distance_remaining) + "yd. ⛳️"
msg += f"\nClub?[D, L, M, H, G, W]🏌️"
# save player's current game state, keep stroking
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker[i]['distance_remaining'] = distance_remaining
golfTracker[i]['hole_shots'] = hole_shots
golfTracker[i]['total_strokes'] = total_strokes
golfTracker[i]['cmd'] = 'stroking'
return msg
if last_cmd == 'putt':
# Finish the hole by putting
critter = False
if distance_remaining < 20:
if distance_remaining == 0:
putts = 0
elif distance_remaining == -1:
putts = 0
critter = True
else:
putts = finish_hole()
# Calculate hole and round scores
hole_strokes = hole_shots + putts
hole_to_par = hole_strokes - par
total_strokes += hole_strokes
total_to_par += hole_to_par
if not critter:
# Show player hole/round scoring info
if putts == 0 and hole_strokes == 1:
msg += "🎯Hole in one!⛳️"
elif putts == 0:
msg += "You're in the hole at " + str(hole_strokes) + " strokes!"
else:
msg += "You're on the green! After " + str(putts) + " putt(s), you're in for " + str(hole_strokes) + " strokes."
msg += getScorecardGolf(hole_to_par)
if hole not in [1, 10]:
# Show player total scoring info for the round, except hole 1 and 10
msg += f"\nYou've hit a total of " + str(total_strokes) + " strokes today, for"
msg += getScorecardGolf(total_to_par)
# Move to next hole
hole += 1
else:
msg += f"Got a new ball at Pro-Shop, marshal put you @" # flow into same hole haha
# Scorecard reset
hole_to_par = 0
hole_strokes = 0
hole_shots = 0
# Save player's current game state
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker[i]['hole_strokes'] = hole_strokes
golfTracker[i]['hole_to_par'] = hole_to_par
golfTracker[i]['total_strokes'] = total_strokes
golfTracker[i]['total_to_par'] = total_to_par
golfTracker[i]['hole'] = hole
golfTracker[i]['cmd'] = 'new'
golfTracker[i]['last_played'] = time.time()
if hole >= 9:
# Final score messages & exit prompt
msg += f"🎉Finished 9-hole round⛳"
#HighScore Display
highscore = getHighScoreGolf(nodeID, total_strokes, total_to_par)
if highscore != 0:
msg += " 🏆New Club Record🏆"
# pop player from tracker
for i in range(len(golfTracker)):
if golfTracker[i]['nodeID'] == nodeID:
golfTracker.pop(i)
logger.debug("System: GolfSim: Player " + str(nodeID) + " has finished their round.")
else:
# Show player the next hole
msg += playGolf(nodeID, '', True, last_cmd='new')
msg += f"\n🏌️[D, L, M, H, G, W, End]🏌️"
return msg