mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-05 20:40:25 -08:00
448 lines
15 KiB
Python
448 lines
15 KiB
Python
"""
|
|
KING
|
|
|
|
A strategy game where the player is the king.
|
|
|
|
Ported to Python by Martin Thoma in 2022
|
|
"""
|
|
|
|
import sys
|
|
from dataclasses import dataclass
|
|
from random import randint, random
|
|
|
|
FOREST_LAND = 1000
|
|
INITIAL_LAND = FOREST_LAND + 1000
|
|
COST_OF_LIVING = 100
|
|
COST_OF_FUNERAL = 9
|
|
YEARS_IN_TERM = 8
|
|
POLLUTION_CONTROL_FACTOR = 25
|
|
|
|
|
|
def ask_int(prompt) -> int:
|
|
while True:
|
|
try:
|
|
return int(input(prompt))
|
|
except ValueError:
|
|
continue
|
|
|
|
|
|
@dataclass
|
|
class GameState:
|
|
rallods: int = -1
|
|
countrymen: int = -1
|
|
land: int = INITIAL_LAND
|
|
foreign_workers: int = 0
|
|
years_in_office: int = 0
|
|
|
|
# previous year stats
|
|
crop_loss_last_year: int = 0
|
|
|
|
# current year stats
|
|
died_contrymen: int = 0
|
|
pollution_deaths: int = 0
|
|
population_change: int = 0
|
|
|
|
# current year - market situation (in rallods per square mile)
|
|
planting_cost: int = -1
|
|
land_buy_price: int = -1
|
|
|
|
tourism_earnings: int = 0
|
|
|
|
def set_market_conditions(self) -> None:
|
|
self.land_buy_price = randint(95, 105)
|
|
self.planting_cost = randint(10, 15)
|
|
|
|
@property
|
|
def farmland(self) -> int:
|
|
return self.land - FOREST_LAND
|
|
|
|
@property
|
|
def settled_people(self) -> int:
|
|
return self.countrymen - self.population_change
|
|
|
|
def sell_land(self, amount: int) -> None:
|
|
assert amount <= self.farmland
|
|
self.land -= amount
|
|
self.rallods += self.land_buy_price * amount
|
|
|
|
def distribute_rallods(self, distribute: int) -> None:
|
|
self.rallods -= distribute
|
|
|
|
def spend_pollution_control(self, spend: int) -> None:
|
|
self.rallods -= spend
|
|
|
|
def plant(self, sq_to_plant: int) -> None:
|
|
self.rallods -= sq_to_plant * self.planting_cost
|
|
|
|
def print_status(self) -> None:
|
|
print(f"\n\nYOU NOW HAVE {self.rallods} RALLODS IN THE TREASURY.")
|
|
print(f"{int(self.countrymen)} COUNTRYMEN, ", end="")
|
|
if self.foreign_workers > 0:
|
|
print(f"{int(self.foreign_workers)} FOREIGN WORKERS, ", end="")
|
|
print(f"AND {self.land} SQ. MILES OF LAND.")
|
|
print(
|
|
f"THIS YEAR INDUSTRY WILL BUY LAND FOR {self.land_buy_price} "
|
|
"RALLODS PER SQUARE MILE."
|
|
)
|
|
print(
|
|
f"LAND CURRENTLY COSTS {self.planting_cost} RALLODS "
|
|
"PER SQUARE MILE TO PLANT.\n"
|
|
)
|
|
|
|
def handle_deaths(
|
|
self, distributed_rallods: int, pollution_control_spendings: int
|
|
) -> None:
|
|
starved_countrymen = max(
|
|
0, int(self.countrymen - distributed_rallods / COST_OF_LIVING)
|
|
)
|
|
|
|
if starved_countrymen > 0:
|
|
print(f"{starved_countrymen} COUNTRYMEN DIED OF STARVATION")
|
|
|
|
self.pollution_deaths = int(random() * (INITIAL_LAND - self.land))
|
|
if pollution_control_spendings >= POLLUTION_CONTROL_FACTOR:
|
|
self.pollution_deaths = int(
|
|
self.pollution_deaths
|
|
/ (pollution_control_spendings / POLLUTION_CONTROL_FACTOR)
|
|
)
|
|
if self.pollution_deaths > 0:
|
|
print(
|
|
f"{self.pollution_deaths} COUNTRYMEN DIED OF CARBON-MONOXIDE "
|
|
f"AND DUST INHALATION"
|
|
)
|
|
|
|
self.died_contrymen = starved_countrymen + self.pollution_deaths
|
|
if self.died_contrymen > 0:
|
|
funeral_cost = self.died_contrymen * COST_OF_FUNERAL
|
|
print(f" YOU WERE FORCED TO SPEND {funeral_cost} RALLODS ON ")
|
|
print("FUNERAL EXPENSES.")
|
|
self.rallods -= funeral_cost
|
|
if self.rallods < 0:
|
|
print(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD")
|
|
self.land += int(self.rallods / self.land_buy_price)
|
|
self.rallods = 0
|
|
self.countrymen -= self.died_contrymen
|
|
|
|
def handle_tourist_trade(self) -> None:
|
|
V1 = int(self.settled_people * 22 + random() * 500)
|
|
V2 = int((INITIAL_LAND - self.land) * 15)
|
|
tourist_trade_earnings = 0
|
|
if V1 > V2:
|
|
tourist_trade_earnings = V1 - V2
|
|
print(f" YOU MADE {tourist_trade_earnings} RALLODS FROM TOURIST TRADE.")
|
|
if V2 != 0 and not (V1 - V2 >= self.tourism_earnings):
|
|
print(" DECREASE BECAUSE ", end="")
|
|
reason = randint(0, 10)
|
|
if reason <= 2:
|
|
print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.")
|
|
elif reason <= 4:
|
|
print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.")
|
|
elif reason <= 6:
|
|
print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.")
|
|
elif reason <= 8:
|
|
print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.")
|
|
else:
|
|
print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.")
|
|
|
|
# NOTE: The following two lines had a bug in the original game:
|
|
self.tourism_earnings = abs(int(V1 - V2))
|
|
self.rallods += self.tourism_earnings
|
|
|
|
def handle_harvest(self, planted_sq: int) -> None:
|
|
crop_loss = int((INITIAL_LAND - self.land) * ((random() + 1.5) / 2))
|
|
if self.foreign_workers != 0:
|
|
print(f"OF {planted_sq} SQ. MILES PLANTED,")
|
|
if planted_sq <= crop_loss:
|
|
crop_loss = planted_sq
|
|
harvested = int(planted_sq - crop_loss)
|
|
print(f" YOU HARVESTED {harvested} SQ. MILES OF CROPS.")
|
|
unlucky_harvesting_worse = crop_loss - self.crop_loss_last_year
|
|
if crop_loss != 0:
|
|
print(" (DUE TO ", end="")
|
|
if unlucky_harvesting_worse > 2:
|
|
print("INCREASED ", end="")
|
|
print("AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)")
|
|
revenue = int((planted_sq - crop_loss) * (self.land_buy_price / 2))
|
|
print(f"MAKING {revenue} RALLODS.")
|
|
self.crop_loss_last_year = crop_loss
|
|
self.rallods += revenue
|
|
|
|
def handle_foreign_workers(
|
|
self,
|
|
sm_sell_to_industry: int,
|
|
distributed_rallods: int,
|
|
polltion_control_spendings: int,
|
|
) -> None:
|
|
foreign_workers_influx = 0
|
|
if sm_sell_to_industry != 0:
|
|
foreign_workers_influx = int(
|
|
sm_sell_to_industry + (random() * 10) - (random() * 20)
|
|
)
|
|
if self.foreign_workers <= 0:
|
|
foreign_workers_influx += 20
|
|
print(f"{foreign_workers_influx} WORKERS CAME TO THE COUNTRY AND")
|
|
|
|
surplus_distributed = distributed_rallods / COST_OF_LIVING - self.countrymen
|
|
population_change = int(
|
|
(surplus_distributed / 10)
|
|
+ (polltion_control_spendings / POLLUTION_CONTROL_FACTOR)
|
|
- ((INITIAL_LAND - self.land) / 50)
|
|
- (self.died_contrymen / 2)
|
|
)
|
|
print(f"{abs(population_change)} COUNTRYMEN ", end="")
|
|
if population_change < 0:
|
|
print("LEFT ", end="")
|
|
else:
|
|
print("CAME TO ", end="")
|
|
print("THE ISLAND")
|
|
self.countrymen += population_change
|
|
self.foreign_workers += foreign_workers_influx
|
|
|
|
def handle_too_many_deaths(self) -> None:
|
|
print(f"\n\n\n{self.died_contrymen} COUNTRYMEN DIED IN ONE YEAR!!!!!")
|
|
print("\n\n\nDUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY")
|
|
print("BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU")
|
|
message = randint(0, 10)
|
|
if message <= 3:
|
|
print("ALSO HAD YOUR LEFT EYE GOUGED OUT!")
|
|
if message <= 6:
|
|
print("HAVE ALSO GAINED A VERY BAD REPUTATION.")
|
|
if message <= 10:
|
|
print("HAVE ALSO BEEN DECLARED NATIONAL FINK.")
|
|
sys.exit()
|
|
|
|
def handle_third_died(self) -> None:
|
|
print()
|
|
print()
|
|
print("OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU")
|
|
print("WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)")
|
|
print("HATE YOUR GUTS.")
|
|
self.end_game()
|
|
|
|
def handle_money_mismanagement(self) -> None:
|
|
print()
|
|
print("MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID")
|
|
print("NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED")
|
|
print("OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE")
|
|
print("BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.")
|
|
print("THE CHOICE IS YOURS.")
|
|
print("IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER")
|
|
print("BEFORE PROCEEDING.")
|
|
sys.exit()
|
|
|
|
def handle_too_many_foreigners(self) -> None:
|
|
print("\n\nTHE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER")
|
|
print("OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND")
|
|
print("TAKEN OVER THE COUNTRY.")
|
|
self.end_game()
|
|
|
|
def end_game(self) -> None:
|
|
if random() <= 0.5:
|
|
print("YOU HAVE BEEN ASSASSINATED.")
|
|
else:
|
|
print("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW")
|
|
print("RESIDING IN PRISON.")
|
|
sys.exit()
|
|
|
|
def handle_congratulations(self) -> None:
|
|
print("\n\nCONGRATULATIONS!!!!!!!!!!!!!!!!!!")
|
|
print(f"YOU HAVE SUCCESFULLY COMPLETED YOUR {YEARS_IN_TERM} YEAR TERM")
|
|
print("OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT")
|
|
print("NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD")
|
|
print("LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT")
|
|
print("PLAYS THIS GAME.")
|
|
sys.exit()
|
|
|
|
|
|
def print_header() -> None:
|
|
print(" " * 34 + "KING")
|
|
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n")
|
|
|
|
|
|
def print_instructions() -> None:
|
|
print(
|
|
f"""\n\n\nCONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS
|
|
DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR
|
|
JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE
|
|
MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.
|
|
THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS {COST_OF_LIVING}
|
|
RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES
|
|
FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT
|
|
FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND
|
|
WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD
|
|
TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT
|
|
THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER
|
|
SQUARE MILE TO PLANT.
|
|
YOUR GOAL IS TO COMPLETE YOUR {YEARS_IN_TERM} YEAR TERM OF OFFICE.
|
|
GOOD LUCK!"""
|
|
)
|
|
|
|
|
|
def ask_how_many_sq_to_plant(state: GameState) -> int:
|
|
while True:
|
|
sq = ask_int("HOW MANY SQUARE MILES DO YOU WISH TO PLANT? ")
|
|
if sq < 0:
|
|
continue
|
|
elif sq > 2 * state.countrymen:
|
|
print(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.")
|
|
elif sq > state.farmland:
|
|
print(
|
|
f" SORRY, BUT YOU ONLY HAVE {state.farmland} "
|
|
"SQ. MILES OF FARM LAND."
|
|
)
|
|
elif sq * state.planting_cost > state.rallods:
|
|
print(
|
|
f" THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS "
|
|
"LEFT IN THE TREASURY."
|
|
)
|
|
else:
|
|
return sq
|
|
|
|
|
|
def ask_pollution_control(state: GameState) -> int:
|
|
while True:
|
|
rallods = ask_int(
|
|
"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? "
|
|
)
|
|
if rallods > state.rallods:
|
|
print(f" THINK AGAIN. YOU ONLY HAVE {state.rallods} RALLODS REMAINING.")
|
|
elif rallods < 0:
|
|
continue
|
|
else:
|
|
return rallods
|
|
|
|
|
|
def ask_sell_to_industry(state: GameState) -> int:
|
|
had_first_err = False
|
|
first = """(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE
|
|
FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,
|
|
THICKER TOP SOIL, ETC.)"""
|
|
err = f"""*** THINK AGAIN. YOU ONLY HAVE {state.farmland} SQUARE MILES OF FARM LAND."""
|
|
while True:
|
|
sm = input("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? ")
|
|
try:
|
|
sm_sell = int(sm)
|
|
except ValueError:
|
|
if not had_first_err:
|
|
print(first)
|
|
had_first_err = True
|
|
print(err)
|
|
continue
|
|
if sm_sell > state.farmland:
|
|
print(err)
|
|
elif sm_sell < 0:
|
|
continue
|
|
else:
|
|
return sm_sell
|
|
|
|
|
|
def ask_distribute_rallods(state: GameState) -> int:
|
|
while True:
|
|
rallods = ask_int(
|
|
"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? "
|
|
)
|
|
if rallods < 0:
|
|
continue
|
|
elif rallods > state.rallods:
|
|
print(
|
|
f" THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS IN THE TREASURY"
|
|
)
|
|
else:
|
|
return rallods
|
|
|
|
|
|
def resume() -> GameState:
|
|
while True:
|
|
years = ask_int("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ")
|
|
if years < 0:
|
|
sys.exit()
|
|
if years >= YEARS_IN_TERM:
|
|
print(f" COME ON, YOUR TERM IN OFFICE IS ONLY {YEARS_IN_TERM} YEARS.")
|
|
else:
|
|
break
|
|
treasury = ask_int("HOW MUCH DID YOU HAVE IN THE TREASURY? ")
|
|
if treasury < 0:
|
|
sys.exit()
|
|
countrymen = ask_int("HOW MANY COUNTRYMEN? ")
|
|
if countrymen < 0:
|
|
sys.exit()
|
|
workers = ask_int("HOW MANY WORKERS? ")
|
|
if workers < 0:
|
|
sys.exit()
|
|
while True:
|
|
land = ask_int("HOW MANY SQUARE MILES OF LAND? ")
|
|
if land < 0:
|
|
sys.exit()
|
|
if land > INITIAL_LAND:
|
|
farm_land = INITIAL_LAND - FOREST_LAND
|
|
print(f" COME ON, YOU STARTED WITH {farm_land:,} SQ. MILES OF FARM LAND")
|
|
print(f" AND {FOREST_LAND:,} SQ. MILES OF FOREST LAND.")
|
|
if land > FOREST_LAND:
|
|
break
|
|
return GameState(
|
|
rallods=treasury,
|
|
countrymen=countrymen,
|
|
foreign_workers=workers,
|
|
years_in_office=years,
|
|
)
|
|
|
|
|
|
def main() -> None:
|
|
print_header()
|
|
want_instructions = input("DO YOU WANT INSTRUCTIONS? ").upper()
|
|
if want_instructions == "AGAIN":
|
|
state = resume()
|
|
else:
|
|
state = GameState(
|
|
rallods=randint(59000, 61000),
|
|
countrymen=randint(490, 510),
|
|
planting_cost=randint(10, 15),
|
|
)
|
|
if want_instructions != "NO":
|
|
print_instructions()
|
|
|
|
while True:
|
|
state.set_market_conditions()
|
|
state.print_status()
|
|
|
|
# Users actions
|
|
sm_sell_to_industry = ask_sell_to_industry(state)
|
|
state.sell_land(sm_sell_to_industry)
|
|
|
|
distributed_rallods = ask_distribute_rallods(state)
|
|
state.distribute_rallods(distributed_rallods)
|
|
|
|
planted_sq = ask_how_many_sq_to_plant(state)
|
|
state.plant(planted_sq)
|
|
polltion_control_spendings = ask_pollution_control(state)
|
|
state.spend_pollution_control(polltion_control_spendings)
|
|
|
|
# Run the year
|
|
state.handle_deaths(distributed_rallods, polltion_control_spendings)
|
|
state.handle_foreign_workers(
|
|
sm_sell_to_industry, distributed_rallods, polltion_control_spendings
|
|
)
|
|
state.handle_harvest(planted_sq)
|
|
state.handle_tourist_trade()
|
|
|
|
if state.died_contrymen > 200:
|
|
state.handle_too_many_deaths()
|
|
if state.countrymen < 343:
|
|
state.handle_third_died()
|
|
elif (
|
|
state.rallods > 500
|
|
and state.died_contrymen - state.pollution_deaths >= 2
|
|
):
|
|
state.handle_money_mismanagement()
|
|
if state.foreign_workers > state.countrymen:
|
|
state.handle_too_many_foreigners()
|
|
elif YEARS_IN_TERM - 1 == state.years_in_office:
|
|
state.handle_congratulations()
|
|
else:
|
|
state.years_in_office += 1
|
|
state.died_contrymen = 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|