ticket-to-campaign/main.py

254 lines
8.1 KiB
Python
Raw Normal View History

2024-05-19 21:47:24 +02:00
# Generation of data for a campaign of Ticket to Ride Legacy: Legends of the West
2024-04-28 18:56:21 +02:00
# Imports
import os
2024-04-28 18:56:21 +02:00
import random
import jsonpickle
2024-05-19 23:09:08 +02:00
import time
2024-04-28 18:56:21 +02:00
class Circus:
# There are:
# 4 wagons of each colors (until 2 players' stop)
# 2 wagons of each colors (until 3 players' stop)
# 2 wagons of each colors (until 4 players' stop)
# 2 wagons of each colors (until 5 players' stop)
# NOTE: In the original distribution, the same color never appears twice in a row
# We chose to remove this constraint, for the sake of simplicity
def __init__(self, playersNb):
wagonsPerColors = 2 * playersNb
colors = "blue", "green", "black", "red", "yellow"
2024-05-19 23:09:08 +02:00
remaining = {"blue": wagonsPerColors, "green": wagonsPerColors, "black": wagonsPerColors, "red": wagonsPerColors,\
"yellow": wagonsPerColors}
2024-04-28 18:56:21 +02:00
self.wagons = []
for n in range(0, 5 * wagonsPerColors):
color = colors[random.randint(0, 4)]
while remaining[color] == 0:
color = colors[random.randint(0, 4)]
self.wagons.append(color)
remaining[color] = remaining[color] - 1
2024-05-05 16:51:06 +02:00
self.state = 0 # 0 means Circus is not used in game yet, 1 means next wagon in list is #1, and so on
def enable(self):
2024-05-23 20:44:07 +02:00
if self.state > 0:
print("Circus is already in game.")
2024-05-06 10:50:49 +02:00
return False
self.state = 1
def getNextColor(self):
return self.wagons[self.state - 1]
def takeWagon(self):
2024-05-05 16:51:06 +02:00
if self.state == 0:
print("Circus is not or no longer in game.")
return False
2024-05-06 10:15:22 +02:00
print("Player obtained a " + self.wagons[self.state - 1] + " circus sticker!")
2024-05-05 16:51:06 +02:00
self.state = self.state + 1
2024-05-06 10:15:22 +02:00
if self.state > len(self.wagons):
2024-05-05 16:51:06 +02:00
print("Circus stickers are now depleted.")
self.state = 0 # effectively disable circus
2024-05-05 16:51:06 +02:00
2024-05-06 10:50:49 +02:00
class TreasureCard:
def __init__(self):
self.treasures = [36, 33, 29, 27, 24]
self.state = -1 # disabled
def enable(self):
self.state = 0 # 0 means 0 treasures have been found
def getFoundNumber(self):
if self.state == -1:
print("Treasure hunt has not started yet or is completed.")
return False
return self.state
def takeTreasure(self):
if self.state == -1:
print("Treasure hunt has not started yet or is completed.")
return False
2024-05-23 20:44:07 +02:00
print("Congrats! You obtained $" + str(self.treasures[self.state]))
2024-05-06 10:50:49 +02:00
self.state = self.state + 1
if self.state == 5:
print("All treasures have been found.")
self.state = -1 # effectively disable treasure card
2024-05-05 16:51:06 +02:00
2024-05-19 11:34:14 +02:00
class ConcessionCard:
2024-05-05 16:51:06 +02:00
# Each card contains:
# 6 cities to connect to the player's concession. There is no need to implement those.
2024-05-19 11:34:14 +02:00
# 7 gold nuggets, as rewards when the player succefully connects a city to their concession. The player can choose
# which nugget to earn, and then discovers the associated reward (between 11 and 17 coins).
# A ConcessionCard is then composed of 7 nuggets, with the rewards randomly distributed.
2024-05-23 20:44:07 +02:00
2024-05-05 16:51:06 +02:00
def __init__(self):
availableValues = [11, 12, 13, 14, 15, 16, 17]
2024-05-19 11:34:14 +02:00
nuggetsNb = len(availableValues) - 1
self.nuggets = []
2024-05-05 16:51:06 +02:00
for n in range(0, 7):
2024-05-19 11:34:14 +02:00
choice = random.randint(0, nuggetsNb - n)
self.nuggets.append(availableValues[choice])
2024-05-05 16:51:06 +02:00
availableValues.pop(choice)
self.taken = set()
def getRemainingPepites(self):
return {1, 2, 3, 4, 5, 6, 7} - self.taken
2024-05-05 16:51:06 +02:00
def takeReward(self, choice):
2024-05-23 20:44:07 +02:00
if not choice.isdigit():
print("Please choose a number.")
return False
choice = int(choice)
if choice not in range(1, 8):
print("This is not a valid number")
return False
2024-05-05 16:51:06 +02:00
if choice in self.taken:
print(str(choice) + " has already been obtained.")
return False
self.taken.add(choice)
2024-05-23 20:44:07 +02:00
print("Congrats! You obtained $" + str(self.nuggets[choice - 1]))
2024-05-05 16:51:06 +02:00
class Player:
2024-05-05 16:51:06 +02:00
def __init__(self, color):
self.color = color
self.concession = ConcessionCard()
2024-04-28 18:56:21 +02:00
class Game:
2024-04-28 18:56:21 +02:00
# initGame() is used to generate all data for a campaign and initialize status variables
2024-05-19 22:12:30 +02:00
def initGame(self):
2024-05-19 21:47:24 +02:00
self.years = 1865, 1868, 1871, 1874, 1877, 1880, 1883, 1886, 1889, 1892, 1895, 1898
2024-05-19 22:12:30 +02:00
playersNb = input("Enter the number of players (2-5): ")
while not playersNb.isdigit() or int(playersNb) not in range(2, 6):
playersNb = input("OUT OF RANGE! Enter the number of players (2-5): ")
playersNb = int(playersNb)
2024-05-05 16:51:06 +02:00
# Game status
2024-05-19 21:47:24 +02:00
self.yearId = 0
self.concession = False
2024-05-05 16:51:06 +02:00
# General data to generate
self.circus = Circus(playersNb)
# Mama O'Connell
2024-05-06 10:50:49 +02:00
self.treasure = TreasureCard()
2024-05-05 16:51:06 +02:00
# Players
self.players = []
for n in range(0, playersNb):
color = input("Enter player " + str(n + 1) + "'s color: ")
2024-05-05 16:51:06 +02:00
self.players.append(Player(color))
2024-05-23 20:44:07 +02:00
def getPlayerByColor(self, color):
for player in self.players:
if player.color.lower() == color.lower():
return player
print("ERROR: player '" + color + "' is not defined")
return False
def enableConcession(self):
self.concession = True
def disableConcession(self):
self.concession = False
def printStatus(self):
2024-05-23 20:44:07 +02:00
print("")
print("---------------------------------------------------------------------")
2024-05-19 11:34:14 +02:00
print("")
print("Ticket to Ride Legacy: Legends of the West")
print("")
2024-05-19 21:47:24 +02:00
print("Campaign - Year: " + str(self.years[self.yearId]))
print("")
print("Players:")
for player in self.players:
print(" " + player.color)
if self.concession:
2024-05-19 11:34:14 +02:00
print(" Concession card remaining nuggets: " + str(player.concession.getRemainingPepites()))
print("")
if self.circus.state > 0:
print("Circus next sticker color: " + self.circus.getNextColor())
2024-05-06 10:50:49 +02:00
if self.treasure.state > -1:
print(f"Treasures found: {self.treasure.getFoundNumber()}")
2024-04-28 18:56:21 +02:00
2024-05-19 23:09:08 +02:00
def saveData(self, path):
savefile = open('./' + path, 'w+')
savefile.write(jsonpickle.encode(self))
savefile.close()
2024-05-19 22:12:30 +02:00
def loadData(path):
with open('./' + path, 'r') as savefile:
content = savefile.read()
data = jsonpickle.decode(content)
return data
2024-05-05 16:51:06 +02:00
2024-05-19 22:12:30 +02:00
print("")
print("Ticket to Ride Legacy: Legends of the West")
print("")
choice = input("What do you want to do (new/load)? ")
while choice not in ("new", "load"):
choice = input("UNDEFINED! What do you want to do (new/load)? ")
if choice == "new":
myGame = Game()
myGame.initGame()
elif choice == "load":
path = input("Path to save file (defaults to savefile.json)? ")
if path == "":
path = "savefile.json"
myGame = loadData(path)
2024-05-19 23:09:08 +02:00
while True:
myGame.printStatus()
command = input("==> ")
2024-05-23 20:44:07 +02:00
while command not in ('load', 'save', 'next year', 'exit', 'enable circus', 'take circus', 'enable concession',\
'take concession', 'disable concession', 'enable treasure', 'take treasure'):
2024-05-19 23:09:08 +02:00
print("")
print("Available commands:")
print(" Main: 'load', 'save', 'next year', 'exit'")
print(" Circus: 'enable circus', 'take circus'")
print(" Treasure: 'enable treasure', 'take treasure'")
2024-05-23 20:44:07 +02:00
print(" Concessions: 'enable concession', 'take concession', 'disable concession'")
2024-05-19 23:09:08 +02:00
command = input("==> ")
2024-05-23 20:44:07 +02:00
print("")
2024-05-19 23:09:08 +02:00
match command:
case 'load':
choice = input("WARNING! If you load, you will loose all unsaved changes. Are you sure? (type YES if you are) ")
if choice == "YES":
path = input("Path to save file (defaults to savefile.json)? ")
if path == "":
path = "savefile.json"
myGame = loadData(path)
case 'save':
path = input("Path to save file (defaults to savefile.json)? ")
if path == "":
path = "savefile.json"
myGame.saveData(path)
print("Game saved!")
case 'next year':
myGame.yearId = myGame.yearId + 1
case 'exit':
exit()
2024-05-23 20:44:07 +02:00
case 'enable circus':
myGame.circus.enable()
case 'take circus':
myGame.circus.takeWagon()
case 'enable treasure':
myGame.treasure.enable()
case 'take treasure':
myGame.treasure.takeTreasure()
case 'enable concession':
myGame.enableConcession()
case 'take concession':
choice = input("Player? ==> ")
player = myGame.getPlayerByColor(choice)
if player == False:
print("Not a valid player.")
else:
choice = input("Which nugget? ==> ")
print("")
player.concession.takeReward(choice)
case 'disable concession':
myGame.disableConcession()