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
|
2024-05-01 14:46:15 +02:00
|
|
|
import os
|
2024-04-28 18:56:21 +02:00
|
|
|
import random
|
2024-05-01 14:46:15 +02:00
|
|
|
import jsonpickle
|
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"
|
|
|
|
remaining = {"blue": wagonsPerColors, "green": wagonsPerColors, "black": wagonsPerColors, "red": wagonsPerColors, "yellow": wagonsPerColors}
|
|
|
|
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
|
|
|
|
|
2024-05-06 10:02:08 +02:00
|
|
|
def enable(self):
|
2024-05-06 10:50:49 +02:00
|
|
|
if self.state == 0:
|
|
|
|
print("Circus is not or no longer in game.")
|
|
|
|
return False
|
2024-05-06 10:02:08 +02:00
|
|
|
self.state = 1
|
|
|
|
|
|
|
|
def getNextColor(self):
|
|
|
|
return self.wagons[self.state - 1]
|
|
|
|
|
2024-05-06 10:07:22 +02:00
|
|
|
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.")
|
2024-05-06 10:02:08 +02:00
|
|
|
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
|
|
|
|
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-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)
|
2024-05-06 10:02:08 +02:00
|
|
|
self.taken = set()
|
|
|
|
|
|
|
|
def getRemainingPepites(self):
|
|
|
|
return {1, 2, 3, 4, 5, 6, 7} - self.taken
|
2024-05-05 16:51:06 +02:00
|
|
|
|
2024-05-06 10:07:22 +02:00
|
|
|
def takeReward(self, choice):
|
2024-05-05 16:51:06 +02:00
|
|
|
if choice in self.taken:
|
|
|
|
print(str(choice) + " has already been obtained.")
|
|
|
|
return False
|
2024-05-06 10:02:08 +02:00
|
|
|
self.taken.add(choice)
|
2024-05-19 11:34:14 +02:00
|
|
|
print("Congrats! You obtained $" + str(self.nuggets[choice]))
|
2024-05-05 16:51:06 +02:00
|
|
|
|
|
|
|
class Player:
|
2024-05-06 10:07:22 +02:00
|
|
|
|
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
|
|
|
|
2024-05-01 14:46:15 +02:00
|
|
|
class Game:
|
2024-04-28 18:56:21 +02:00
|
|
|
|
2024-05-01 14:46:15 +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
|
2024-05-06 10:02:08 +02:00
|
|
|
self.concession = False
|
2024-05-05 16:51:06 +02:00
|
|
|
|
|
|
|
# General data to generate
|
|
|
|
self.circus = Circus(playersNb)
|
2024-05-01 14:46:15 +02:00
|
|
|
# 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):
|
2024-05-06 10:02:08 +02:00
|
|
|
color = input("Enter player " + str(n + 1) + "'s color: ")
|
2024-05-05 16:51:06 +02:00
|
|
|
self.players.append(Player(color))
|
|
|
|
|
2024-05-06 10:02:08 +02:00
|
|
|
def printStatus(self):
|
2024-05-19 11:34:14 +02:00
|
|
|
print("")
|
2024-05-06 10:02:08 +02:00
|
|
|
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]))
|
2024-05-06 10:02:08 +02:00
|
|
|
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()))
|
2024-05-06 10:02:08 +02:00
|
|
|
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-01 14:46:15 +02:00
|
|
|
def saveData(self):
|
|
|
|
savefile = open('./savefile.json', '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:
|
2024-05-01 14:46:15 +02:00
|
|
|
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)
|
|
|
|
myGame.printStatus()
|
|
|
|
|
2024-05-05 16:51:06 +02:00
|
|
|
# TESTS
|
|
|
|
|
|
|
|
# Test of data generation
|
2024-05-01 14:46:15 +02:00
|
|
|
# myGame = Game()
|
2024-05-19 22:12:30 +02:00
|
|
|
# myGame.initGame()
|
2024-05-01 14:46:15 +02:00
|
|
|
# myGame.saveData()
|
2024-05-05 16:51:06 +02:00
|
|
|
|
|
|
|
# Test of data loading
|
2024-05-19 22:12:30 +02:00
|
|
|
# myGame = loadData('savefile.json')
|
2024-05-19 21:47:24 +02:00
|
|
|
# myGame.printStatus()
|
2024-05-05 16:51:06 +02:00
|
|
|
|
|
|
|
# Test of ConcessionCard
|
2024-05-06 10:02:08 +02:00
|
|
|
# cc = ConcessionCard()
|
|
|
|
# userChoice = 3
|
2024-05-19 11:34:14 +02:00
|
|
|
# print(cc.nuggets)
|
2024-05-06 10:07:22 +02:00
|
|
|
# cc.takeReward(userChoice - 1)
|
2024-05-19 11:34:14 +02:00
|
|
|
# print(cc.nuggets)
|
2024-05-06 10:02:08 +02:00
|
|
|
# print(cc.taken)
|
|
|
|
# print("Remaining: " + str(cc.getRemainingPepites()))
|
2024-05-06 10:07:22 +02:00
|
|
|
# cc.takeReward(userChoice - 1)
|
2024-05-19 11:34:14 +02:00
|
|
|
# print(cc.nuggets)
|
2024-05-06 10:02:08 +02:00
|
|
|
# print(cc.taken)
|
|
|
|
# print("Remaining: " + str(cc.getRemainingPepites()))
|
2024-05-05 16:51:06 +02:00
|
|
|
|
|
|
|
# Test of Player
|
2024-05-19 22:12:30 +02:00
|
|
|
# myGame = Game()
|
|
|
|
# myGame.initGame()
|
|
|
|
# myGame.printStatus()
|
|
|
|
# myGame.treasure.enable()
|
|
|
|
# myGame.printStatus()
|
|
|
|
# myGame.treasure.takeTreasure()
|
|
|
|
# myGame.treasure.takeTreasure()
|
|
|
|
# myGame.treasure.takeTreasure()
|
|
|
|
# myGame.treasure.takeTreasure()
|
|
|
|
# myGame.printStatus()
|
|
|
|
# myGame.treasure.takeTreasure()
|
|
|
|
# myGame.printStatus()
|