Compare commits

..

15 Commits

Author SHA1 Message Date
SpudGunMan
5ecc563e96 newChunker 2025-10-19 20:18:08 -07:00
SpudGunMan
eeeb43cacc Update lemonade.py 2025-10-19 20:12:28 -07:00
SpudGunMan
9fdcea56fc Update lemonade.py 2025-10-19 20:10:26 -07:00
SpudGunMan
24a33fe882 Update lemonade.py 2025-10-19 20:08:34 -07:00
SpudGunMan
5710cebf39 Update mmind.py 2025-10-19 20:04:05 -07:00
SpudGunMan
b66487863d Update mmind.py 2025-10-19 19:35:41 -07:00
SpudGunMan
b3c4d208b7 Update mmind.py 2025-10-19 19:29:34 -07:00
SpudGunMan
f41ff2d5f7 Update mmind.py 2025-10-19 19:21:48 -07:00
SpudGunMan
48366bc595 Update mmind.py 2025-10-19 19:15:31 -07:00
SpudGunMan
02dd64382d Update mesh_bot.py 2025-10-19 19:05:23 -07:00
SpudGunMan
731b48ad65 Update mesh_bot.py 2025-10-19 19:04:34 -07:00
SpudGunMan
69a7082669 Update README.md 2025-10-19 18:57:56 -07:00
SpudGunMan
fafa7d8a51 Update config.template 2025-10-19 18:57:27 -07:00
Kelly
6e69b5f014 Merge pull request #219 from pdxlocations/allow-port-numbers
Enhance TCP interface initialization to support host:port format
2025-10-19 18:54:54 -07:00
pdxlocations
df9f3806a3 Enhance TCP interface initialization to support host:port format 2025-10-19 16:00:45 -07:00
8 changed files with 114 additions and 132 deletions

View File

@@ -229,7 +229,7 @@ meshtastic --ble-scan
# config.ini
# type can be serial, tcp, or ble.
# port is the serial port to use; commented out will try to auto-detect
# hostname is the IP address of the device to connect to for TCP type
# hostname is the IP/DNS and port for tcp type default is host:4403
# mac is the MAC address of the device to connect to for BLE type
[interface]

View File

@@ -1,7 +1,7 @@
#config.ini
# type can be serial, tcp, or ble
# port is the serial port to use, commented out will try to auto-detect
# hostname is the IP address of the device to connect to for tcp type
# hostname is the IP/DNS and port for tcp type default is host:4403
# mac is the MAC address of the device to connect to for ble type
[interface]

View File

@@ -883,7 +883,7 @@ def handleGolf(message, nodeID, deviceID):
# create new player
msg = f"Welcome to 🏌GolfSim⛳\n"
msg += f"Clubs: (D)river, (L)ow Iron, (M)id Iron, (H)igh Iron, (G)ap Wedge, Lob (W)edge\n"
msg += f"Clubs: (D)river, (L)ow Iron, (M)id Iron, (H)igh Iron, (G)ap Wedge, Lob (W)edge (C)addie\n"
msg += playGolf(nodeID=nodeID, message=message, last_cmd=last_cmd)
return msg

View File

@@ -326,8 +326,8 @@ def playGolf(nodeID, message, finishedHole=False, last_cmd=''):
else:
last_cmd = 'stroking'
else:
msg += "\nYou have " + str(distance_remaining) + "yd. ⛳️"
msg += "\nClub?[D, L, M, H, G, W]🏌️"
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
@@ -371,7 +371,7 @@ def playGolf(nodeID, message, finishedHole=False, last_cmd=''):
if hole not in [1, 10]:
# Show player total scoring info for the round, except hole 1 and 10
msg += "\nYou've hit a total of " + str(total_strokes) + " strokes today, for"
msg += f"\nYou've hit a total of " + str(total_strokes) + " strokes today, for"
msg += getScorecardGolf(total_to_par)
# Move to next hole
@@ -410,6 +410,6 @@ def playGolf(nodeID, message, finishedHole=False, last_cmd=''):
else:
# Show player the next hole
msg += playGolf(nodeID, '', True, last_cmd='new')
msg += "\n🏌️[D, L, M, H, G, W, End]🏌️"
msg += f"\n🏌️[D, L, M, H, G, W, End]🏌️"
return msg

View File

@@ -259,7 +259,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
buffer += ". " + \
formatted + temperature.units + " " + \
forecastd[list(forecastd)[temperature.forecast]][2] + \
" " + glyph
" " + glyph + f"\n"
# Calculate the potential sales as a percentage of the maximum value
# (lower temperature = fewer sales, severe weather = fewer sales)
@@ -288,23 +288,23 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
# Calculate the unit cost and display the estimated sales from the forecast potential
unit = max(0.01, min(cups.unit + lemons.unit + sugar.unit, 4.0)) # limit the unit cost between $0.01 and $4.00
buffer += " SupplyCost" + locale.currency(round(unit, 2), grouping=True) + " a cup."
buffer += " Sales Potential:" + str(potential) + " cups."
buffer += f"\nSupplyCost" + locale.currency(round(unit, 2), grouping=True) + " a cup."
buffer += f"\nSales Potential:" + str(potential) + " cups."
# Display the current inventory
buffer += " Inventory:"
buffer += f"\nInventory:"
buffer += "🥤:" + str(inventory.cups)
buffer += "🍋:" + str(inventory.lemons)
buffer += "🍚:" + str(inventory.sugar)
# Display the updated item prices
buffer += f"\nPrices: "
buffer += "🥤:" + locale.currency(round(cups.cost, 2), grouping=True) + " 📦 of " + str(cups.count) + "."
buffer += " 🍋:" + locale.currency(round(lemons.cost, 2), grouping=True) + " 🧺 of " + str(lemons.count) + "."
buffer += " 🍚:" + locale.currency(round(sugar.cost, 2), grouping=True) + " bag for " + str(sugar.count) + "🥤."
buffer += f"\nPrices:\n"
buffer += f"\n🥤:" + locale.currency(round(cups.cost, 2), grouping=True) + " 📦 of " + str(cups.count) + "."
buffer += f"\n🍋:" + locale.currency(round(lemons.cost, 2), grouping=True) + " 🧺 of " + str(lemons.count) + "."
buffer += f"\n🍚:" + locale.currency(round(sugar.cost, 2), grouping=True) + " bag for " + str(sugar.count) + "🥤."
# Display the current cash
gainloss = inventory.cash - inventory.start
buffer += " 💵:" + locale.currency(round(inventory.cash, 2), grouping=True)
buffer += f"\n💵:" + locale.currency(round(inventory.cash, 2), grouping=True)
# if the player is in the red
@@ -315,7 +315,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
else:
buffer += "📊P&L📈" + pnl
buffer += f"\n🥤 to buy? Have {inventory.cups} Cost {locale.currency(cups.cost, grouping=True)} a 📦 of {str(cups.count)}"
buffer += f"\n🥤 to buy?\nHave {inventory.cups} Cost {locale.currency(cups.cost, grouping=True)} a 📦 of {str(cups.count)}"
saveValues(nodeID, inventory, cups, lemons, sugar, weeks, score)
return buffer
@@ -339,7 +339,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
except Exception as e:
return "invalid input, enter the number of 🥤 to purchase or (N)one"
msg += f"\n 🍋 to buy? Have {inventory.lemons}🥤 of 🍋 Cost {locale.currency(lemons.cost, grouping=True)} a 🧺 for {str(lemons.count)}🥤"
msg += f"\n 🍋 to buy?\nHave {inventory.lemons}🥤 of 🍋 Cost {locale.currency(lemons.cost, grouping=True)} a 🧺 for {str(lemons.count)}🥤"
# set the last command to lemons in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
@@ -369,7 +369,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
newlemons = -1
return "invalid input, enter the number of 🍋 to purchase"
msg += f"\n 🍚 to buy? You have {inventory.sugar}🥤 of 🍚, Cost {locale.currency(sugar.cost, grouping=True)} a bag for {str(sugar.count)}🥤"
msg += f"\n 🍚 to buy?\nYou have {inventory.sugar}🥤 of 🍚, Cost {locale.currency(sugar.cost, grouping=True)} a bag for {str(sugar.count)}🥤"
# set the last command to sugar in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:
@@ -415,7 +415,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
lemonadeTracker[i]['cmd'] = "sales"
if "g" in message.lower():
lemonadeTracker[i]['cmd'] = "cups"
msg = f"#of🥤 to buy? Have {inventory.cups} Cost {locale.currency(cups.cost, grouping=True)} a 📦 of {str(cups.count)}"
msg = f"#of🥤\nto buy? Have {inventory.cups} Cost {locale.currency(cups.cost, grouping=True)} a 📦 of {str(cups.count)}"
return msg
else:
lemonsLastCmd = "sales"
@@ -468,7 +468,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
msg += " N.Profit:" + locale.currency(net, grouping=True)
# Display the updated inventory levels
msg += "\nRemaining"
msg += f"\nRemaining"
msg += " 🥤:" + str(inventory.cups)
msg += " 🍋:" + str(inventory.lemons)
msg += " 🍚:" + str(inventory.sugar)
@@ -485,7 +485,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
pad_week = len(str(weeks.total))
pad_sale = len(str(weeks.sales))
total = 0
msg += "\nWeekly📊"
msg += f"\nWeekly📊"
for i in range(len(weeks.summary)):
msg += "#" + str(weeks.current).rjust(pad_week) + ". " + str(weeks.summary[i]['sales']).rjust(pad_sale) + \
" sold x " + locale.currency(weeks.summary[i]['price'], grouping=True) + "ea. "
@@ -525,7 +525,7 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
if (inventory.sugar <= 0):
msg += " You ran out of sugar.🍚"
else:
msg += "\nCongratulations 🍋🍋 your sales were perfect!🎉"
msg += f"\nCongratulations 🍋🍋 your sales were perfect!🎉"
# Increment the score counters
score.value = score.value + minnet
@@ -536,27 +536,26 @@ def playLemonstand(nodeID, message, celsius=False, newgame=False):
if (weeks.current == weeks.total):
# end of the game
success = round((score.value / score.total) * 100)
msg += "\nYou've made " + locale.currency(score.value, grouping=True) + " out of a possible " + \
msg += f"\nYou've made " + locale.currency(score.value, grouping=True) + " out of a possible " + \
locale.currency(score.total, grouping=True) + " for a score of " + str(success) + "% "
msg += "You've sold " + str(weeks.total_sales) + " total 🥤🍋"
msg += f"\nYou've sold " + str(weeks.total_sales) + " total 🥤🍋"
# check for high score
high_score = getHighScoreLemon()
if (inventory.cash > int(high_score['cash'])):
msg += "\nCongratulations! You've set a new high score!🎉💰🍋"
msg += f"\nCongratulations! You've set a new high score!🎉💰🍋"
high_score['cash'] = inventory.cash
high_score['success'] = success
high_score['userID'] = nodeID
with open('data/lemonstand.pkl', 'wb') as file:
pickle.dump(high_score, file)
endGame(nodeID)
else:
# keep playing
weeks.current = weeks.current + 1
msg += f"Play another week🥤? or (E)nd Game"
msg += f"\nPlay another week🥤? or (E)nd Game"
# set the last command to new in the inventory db
for i in range(len(lemonadeTracker)):
if lemonadeTracker[i]['nodeID'] == nodeID:

View File

@@ -60,98 +60,63 @@ def makeCodeMMind(diff):
return secret_code
#get guess from user
def getGuessMMind(diff, guess):
msg = ''
if diff == "n":
valid_colorsMMind = "RYGB"
elif diff == "h":
valid_colorsMMind = "RYGBOP"
elif diff == "x":
valid_colorsMMind = "RYGBOPWK"
user_guess = guess.upper()
valid_guess = True
if len(user_guess) != 4:
valid_guess = False
for i in range(len(user_guess)):
if user_guess[i] not in valid_colorsMMind:
valid_guess = False
if valid_guess == False:
user_guess = "XXXX"
def getGuessMMind(diff, guess, nodeID):
valid_colors = {
"n": "RYGB",
"h": "RYGBOP",
"x": "RYGBOPWK"
}
user_guess = guess.strip().upper()
if len(user_guess) != 4 or any(c not in valid_colors.get(diff, "RYGB") for c in user_guess):
return "XXXX"
#increase the turn count and store in tracker
for i in range(len(mindTracker)):
if mindTracker[i]['nodeID'] == nodeID:
mindTracker[i]['turns'] += 1
mindTracker[i]['last_played'] = time.time()
mindTracker[i]['diff'] = diff
return user_guess
def getHighScoreMMind(nodeID, turns, diff):
# check if player is in high score list and pick the lowest score
try:
with open('mmind_hs.pkl', 'rb') as f:
mindHighScore = pickle.load(f)
except:
logger.debug("System: MasterMind: High Score file not found.")
mindHighScore = [{'nodeID': nodeID, 'turns': turns, 'diff': diff}]
with open('mmind_hs.pkl', 'wb') as f:
pickle.dump(mindHighScore, f)
import os
hs_file = 'data/mmind_hs.pkl'
# Try to load existing high scores
if os.path.exists(hs_file):
try:
with open(hs_file, 'rb') as f:
mindHighScore = pickle.load(f)
except Exception as e:
logger.debug(f"System: MasterMind: Error loading high score file: {e}")
mindHighScore = []
else:
mindHighScore = []
# If nodeID==0, just return 0
if nodeID == 0:
# just return the high score
mindHighScore = [{'nodeID': 0, 'turns': 0, 'diff': 'n'}]
return mindHighScore
# calculate lowest score
lowest_score = mindHighScore[0]['turns']
# If no high score, add this one
if not mindHighScore:
mindHighScore = [{'nodeID': nodeID, 'turns': turns, 'diff': diff}]
with open(hs_file, 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
if mindHighScore[0]['diff'] == "n" and diff == "n":
if lowest_score > turns:
# update the high score for normal if new score is lower
mindHighScore[0]['nodeID'] = nodeID
mindHighScore[0]['turns'] = turns
mindHighScore[0]['diff'] = diff
# write new high score to file
with open('mmind_hs.pkl', 'wb') as f:
# If the diff matches, compare and update if better
if mindHighScore[0]['diff'] == diff:
if turns < mindHighScore[0]['turns']:
mindHighScore[0] = {'nodeID': nodeID, 'turns': turns, 'diff': diff}
with open(hs_file, 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
elif mindHighScore[0]['diff'] == "n" and diff == "h":
# update the high score for hard if normal is the only high score
mindHighScore[0]['nodeID'] = nodeID
mindHighScore[0]['turns'] = turns
mindHighScore[0]['diff'] = diff
# write new high score to file
with open('mmind_hs.pkl', 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
elif mindHighScore[0]['diff'] == "h" and diff == "h":
if lowest_score > turns:
# update the high score for hard if new score is lower
mindHighScore[0]['nodeID'] = nodeID
mindHighScore[0]['turns'] = turns
mindHighScore[0]['diff'] = diff
# write new high score to file
with open('mmind_hs.pkl', 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
elif mindHighScore[0]['diff'] == "n" or mindHighScore[0]['diff'] == "h" and diff == "x":
# update the high score for expert if normal or high is the only high score
mindHighScore[0]['nodeID'] = nodeID
mindHighScore[0]['turns'] = turns
mindHighScore[0]['diff'] = diff
# write new high score to file
with open('mmind_hs.pkl', 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
elif mindHighScore[0]['diff'] == "x" and diff == "x":
if lowest_score > turns:
# update the high score for expert if new score is lower
mindHighScore[0]['nodeID'] = nodeID
mindHighScore[0]['turns'] = turns
mindHighScore[0]['diff'] = diff
# write new high score to file
with open('mmind_hs.pkl', 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
return 0
# If the diff is different, replace with new high score for new diff
mindHighScore[0] = {'nodeID': nodeID, 'turns': turns, 'diff': diff}
with open(hs_file, 'wb') as f:
pickle.dump(mindHighScore, f)
return mindHighScore
def getEmojiMMind(secret_code):
@@ -180,7 +145,7 @@ def getEmojiMMind(secret_code):
return secret_code_emoji
#compare userGuess with secret code and provide feedback
def compareCodeMMind(secret_code, user_guess):
def compareCodeMMind(secret_code, user_guess, nodeID):
game_won = False
perfect_pins = 0
wrong_position = 0
@@ -208,9 +173,26 @@ def compareCodeMMind(secret_code, user_guess):
temp_code.remove(guess) # Remove the first occurrence of the matched color
# display feedback
if game_won:
msg += f"Correct{getEmojiMMind(user_guess)}\n"
msg += f"\n🏆Correct{getEmojiMMind(user_guess)}\nYou are the master mind!🤯"
# get turn count from tracker
for i in range(len(mindTracker)):
if mindTracker[i]['nodeID'] == nodeID:
turns = mindTracker[i]['turns'] - 2 # subtract 2 to account for increment after last guess and starting at 1
diff = mindTracker[i]['diff']
# get high score
high_score = getHighScoreMMind(nodeID, turns, diff)
if high_score[0]['turns'] != 0:
msg += f"\n🏆 High Score:{turns} turns, Difficulty:{diff}"
# reset turn count in tracker
msg += f"\nWould you like to play again? (N)ormal, (H)ard, or e(X)pert?"
# reset turn count in tracker
for i in range(len(mindTracker)):
if mindTracker[i]['nodeID'] == nodeID:
mindTracker[i]['turns'] = 0
mindTracker[i]['secret_code'] = ''
mindTracker[i]['cmd'] = 'new'
else:
msg += f"Guess{getEmojiMMind(user_guess)}\n"
msg += f"\nGuess{getEmojiMMind(user_guess)}\n"
if perfect_pins > 0 and game_won == False:
msg += "✅ color ✅ position: {}".format(perfect_pins)
@@ -229,11 +211,11 @@ def playGameMMind(diff, secret_code, turn_count, nodeID, message):
msg = ''
won = False
if turn_count <= 10:
user_guess = getGuessMMind(diff, message)
user_guess = getGuessMMind(diff, message, nodeID)
if user_guess == "XXXX":
msg += f"Invalid guess. Please enter 4 valid colors letters.\n🔴🟢🔵🔴 is RGBR"
return msg
check_guess = compareCodeMMind(secret_code, user_guess)
check_guess = compareCodeMMind(secret_code, user_guess, nodeID)
# display turn count and feedback
msg += "Turn {}:".format(turn_count)
@@ -243,18 +225,6 @@ def playGameMMind(diff, secret_code, turn_count, nodeID, message):
if won == True:
msg += f"\n🎉🧠 you win 🥷🤯"
# get high score
high_score = getHighScoreMMind(nodeID, turn_count, diff)
if high_score != 0:
msg += f"\n🏆 High Score:{high_score[0]['turns']} turns, Difficulty:{high_score[0]['diff'].upper()}"
msg += "\nWould you like to play again?\n(N)ormal, (H)ard, e(X)pert (E)nd?"
# reset turn count in tracker
for i in range(len(mindTracker)):
if mindTracker[i]['nodeID'] == nodeID:
mindTracker[i]['turns'] = 1
mindTracker[i]['secret_code'] = ''
mindTracker[i]['cmd'] = 'new'
else:
# increment turn count and keep playing
turn_count += 1
@@ -264,12 +234,12 @@ def playGameMMind(diff, secret_code, turn_count, nodeID, message):
mindTracker[i]['turns'] = turn_count
elif won == False:
msg += f"🙉Game Over🙈\nThe code was: {getEmojiMMind(secret_code)}"
msg += "\nYou have run out of turns.😿"
msg += "\nWould you like to play again? (N)ormal, (H)ard, or e(X)pert?"
msg += f"\nYou have run out of turns.😿"
msg += f"\nWould you like to play again? (N)ormal, (H)ard, or e(X)pert?"
# reset turn count in tracker
for i in range(len(mindTracker)):
if mindTracker[i]['nodeID'] == nodeID:
mindTracker[i]['turns'] = 1
mindTracker[i]['turns'] = 0
mindTracker[i]['secret_code'] = ''
mindTracker[i]['cmd'] = 'new'

View File

@@ -425,7 +425,7 @@ def playVideoPoker(nodeID, message):
if player.bankroll < 1:
player.bankroll = vpStartingCash
msg += "\nLooks 💸 like you're out of money. 💳 resetting ballance 🏧"
msg += f"\nLooks 💸 like you're out of money. 💳 resetting ballance 🏧"
elif player.bankroll > vpTracker[i]['highScore']:
vpTracker[i]['highScore'] = player.bankroll
msg += " 🎉HighScore!"

View File

@@ -331,7 +331,20 @@ for i in range(1, 10):
if interface_type == 'serial':
globals()[f'interface{i}'] = meshtastic.serial_interface.SerialInterface(globals().get(f'port{i}'))
elif interface_type == 'tcp':
globals()[f'interface{i}'] = meshtastic.tcp_interface.TCPInterface(globals().get(f'hostname{i}'))
host = globals().get(f'hostname{i}', '127.0.0.1')
port = 4403
# Allow host:port format
if isinstance(host, str) and ':' in host:
maybe_host, maybe_port = host.rsplit(':', 1)
if maybe_port.isdigit():
host = maybe_host
try:
port = int(maybe_port)
except ValueError:
port = 4403
globals()[f'interface{i}'] = meshtastic.tcp_interface.TCPInterface(hostname=host, portNumber=port)
elif interface_type == 'ble':
globals()[f'interface{i}'] = meshtastic.ble_interface.BLEInterface(globals().get(f'mac{i}'))
else: