python template

This commit is contained in:
Thefeli73 2020-09-27 13:46:19 +02:00
parent 802338fcad
commit 936469c1a5
5 changed files with 764 additions and 1 deletions

132
README.md
View File

@ -1 +1,131 @@
Considition-2020
# StarterKit Python Considition 2020
This is the StarterKit for Considition 2020, a help to get going as quickly as possible with the competition. The StarterKit contains four main parts.
- **The Main Program:** This is where you implement your solution. There is already an example solution implemented that works out of the box, but you will have to develop it further to get a better score.
- **The Game Layer:** A wrapper between the API and the Main Program. Helps you with formatting the input to the API and keep an updated game state.
- **The API:** A representation of the REST-API that the game is played with. Can be used directly or through the Game Layer.
- **The Game State:** A representation of the Game State and the information about the current game.
Each part us described in greater detail below. The competition itself is also described on [Considition.com/rules](considition.com/rules).
# Installation and running
Run *main.py*
# Main Program
The Main Program is a simple loop. Each run of the program does the following:
- Create a new game
- Start the game
- Take 700 actions
- This is where you can implement your solution. Depending on the current Game State, take actions that maximize your final score.
- Print the final score
# Game Layer
The game layer has all the functions you need to play the game.
**Game Setup**
- **New Game** Create a new game and get the *Game Info*.
- **Start Game** Start an already created game and get the initial *Game State*.
- **End Game** End a started game prematurely. Since there is a limit on how many games can be active at the same time for each team, you might have to use this to free up slots.
- **Score** Get the score for a finished game. The final turn of the game has to have happened for the score to be available.
- **Game Info** This can be used to get the *Game Info* of an already started game, for example if you want to resume an ongoing game after making changes.
- **Game State** This can be used to get the current *Game State* of an ongoing game.
**Actions**
Each Action returns an updated *Game State*
- **Place Foundation** Places a new building on a free spot on the map. Is used both for *Residences* and *Utility Buildings*. A building must be in either the *Available Residences* or *Available Utilities* and the current *Turn* has to be at least equal to the buildings *Release Tick* for it to be placed. The building has to be constructed before it has any effect on the game.
- **Build** Builds an already placed building. A building is finished when its *Build Progess* reaches 100.
- **Demolish** Demolishes a building. If a building has the attribute *Can Be Demolished* set to false, the demolish action will have no effect on that building.
- **Buy Upgrade** Buys and activates an upgrade for a *Residence*. If the building is already affected by the *Effect* of the upgrade, this will have no effect.
- **Maintenance** Repairs a *Residence*, resetting its *Health* to 100.
- **Adjust Energy** Sets the *Requested Energy In* for a *Residence* to the specified value. This is used to control the temperature of a building and costs **150 Funds** each time.
**Helpers**
- **Get Blueprint** Returns a blueprint matching the name of a building. This is useful to look up the static information of a building. There are variants for both *Residences* and *Utilities*.
- **Get Effect** Returns an effect matching that name. This is useful to look up what the effects on a building does.
# API
The definition of the API and what it returns can be found on [game.Considition.com/swagger](game.considition.com/swagger), or on [Considition.com/rules](considition.com/rules).
If you want to view the Replay of a game, use [visualizer.Considition.com/swagger](visualizer.considition.com).
# Game State
The Game State is split into two parts. One that is static per map, called *Game Info* and one that changes depending on your actions, called *Game State*.
**Game Info**
- **Game Id** The ID of the current game, useful if you want to view the replay or you have multiple games going at the same time.
- **Map Name** The name of the map you are currently playing on.
- **Max Turns** The maximum number of turns the game will go on for.
- **Max Temp** Approximately the highest temperature that can be reached on this map.
- **Min Temp** Approximately the lowest temperature that can be reached ont his map.
- **Map** An array of arrays of integers representing the map. Buildable slots are **0**'s. The map is not changing and thus will not reflect where buildings get placed.
- **Energy Levels** A list of the types of energy that can be purchased.
- **Energy Threshold** If the amount of energy you buy is above this threshold, this is the type of energy you have to buy. This changes depending on the map.
- **Cost per Mwh** The cost to buy the energy. This is the same even among different maps.
- **Co2 per Mwh** The amount of Co2 released when buying this energy. This is the same even among different maps.
- **Available Residences** The residences that can be bought on this map. Some buildings might not be available right away, depending on their *Release Tick*.
- **Building Name** The name of the building.
- **Cost** Cost in funds to buy the building.
- **Co2 Cost** Cost in Co2 to buy the building.
- **Base Energy Need** The lowest amount of energy needed to sustain the building. You always have to buy at least this much energy if able.
- **Build Speed** How much the build progress is increased each time you call **Build** on this building.
- **Type** A residence or a utility.
- **Release Tick** When is the building available on this map.
- **Max Pop** The maximum number of pops that can live in this residenceat the same time.
- **Income Per Pop** The income you gain each turn for each pop in this residence.
- **Emissivity** A multiplier on how much heat the residence loses to the environment depending on the difference in temperature.
- **Maintenance Cost** How much it costs to do the **Maintenance** action on this residence.
- **Decay Rate** How much *Health*, on average, this residence loses each turn.
- **Max Happinesss** The maximum happiness each pop can generate each turn in this residence.
- **Available Utilities** The utility buildings that can be bought on this map. Some buildings might not be available right away, depending on their *Release Tick*.
- **Building Name** The name of the building.
- **Cost** Cost in funds to buy the building.
- **Co2 Cost** Cost in Co2 to buy the building.
- **Base Energy Need** The lowest amount of energy needed to sustain the building. You always have to buy at least this much energy if able.
- **Build Speed** How much the build progress is increased each time you call **Build** on this building.
- **Type** A residence or a utility.
- **Release Tick** When is the building available on this map.
- **Effects** A list of *Effect Name* which describes which effects this utility will produce when finished.
- **Queue Increase** How much faster the *Queue* will grow, on average, if this utility is finished. Can only be applied once per type of utility.
- **Upgrades** A list of the upgrades that can be bought for residences.
- **Name** The name of the upgrade. This is the name that you use when calling **Buy Upgrade**.
- **Effect** The name of the effect this upgrade has.
- **Cost** The cost in funds to purhcase this upgrade.
- **Effects** A list of all effects.
- **Name** The name of the effect.
- **Radius** If the effect has a radius of 0 it only affects the building it is on. The radius is measured in manhattan distance.
- **Emissivity Multiplier** Changes the emissivity of the affected building.
- **Decay Multiplier** Changes the decay rate of the affected building.
- **Building Income Increase** Changes the amount of funds generated by this building. Can be negative.
- **Max Happiness Increase** Increases the maximum happiness each pop in this building can generate.
- **Mwh Production** Generates free energy that is automatically removed from the *Requested Energy*
- **Base Energy Mwh Increase** Increases the *Base Energy Need* of a building.
- **Co2 per Pop Increase** Increases the amount of Co2 generated by each pop in this building. Can be negative.
- **Decay Increase** A flat increase in the decay rate. Is applied before the **Decay Multiplier**.
**Game State**
- **Turn** The current turn of the game.
- **Funds** The amount of funds available to purchase energy, buildings, upgrades and take actions.
- **Total Co2** The total amount of Co2 generated during the game. This is used to help calculate your score.
- **Total Happinesss** The total amount of happiness generated during the game. This is used to help calculate your score.
- **Current Temp** The current outdoor temperature.
- **Queue Happiness** How happy the pops in the queue are. Keep the queue short to make them happier.
- **Housing Queue** How many pops are currently in the queue.
- **Residences** The built residences. On some maps there are already pre-constructed residences when the map starts.
- **Building Name** The name of the building. This matches the name in *Available Buildings* and in *Get Blueprint*.
- **Position X** The buildings x-position on the map.
- **Position Y** The buildings y-position on the map.
- **Effective Energy In** How much energy the building receives. This can differ from the *Requested Energy In* if you can't afford to purchase all your energy.
- **Build Progress** How close to finished the building is. At 100 the building is done.
- **Can Be Demolished** If the building can be demolished or not.
- **Effects** A list of *Effect Name* which tells which effects are currently active.
- **Current Pop** The number of pops currently living in the residence.
- **Temperature** The indoor temperature of the residence.
- **Requested Energy In** The energy this residence wants. Can be changed by calling **Adjust Energy**.
- **Happiness Per Tick Per Pop** The amount of happiness each pop generate on each turn. If the happiness is too low, pops will start to move out.
- **Health** The current health of the building. If it's too low the pops will start to become unhappy.
- **Utilities** The built utilities. On some maps there are already pre-constructed utilities when the map starts.
- **Building Name** The name of the building. This matches the name in *Available Buildings* and in *Get Blueprint*.
- **Position X** The buildings x-position on the map.
- **Position Y** The buildings y-position on the map.
- **Effective Energy In** How much energy the building receives. This can differ from the *Base Energy Need* if you can't afford to purchase all your energy.
- **Build Progress** How close to finished the building is. At 100 the building is done.
- **Can Be Demolished** If the building can be demolished or not.
- **Effects** A list of *Effect Name* which tells which effects are currently active.

276
api.py Normal file
View File

@ -0,0 +1,276 @@
import requests
from requests import RequestException
base_api_path = "https://game.considition.com/api/game/"
sess = None
def new_game(api_key, game_options=""):
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "new", json=game_options, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not create new game")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not create new game")
print("Something went wrong with the request: " + str(e))
def start_game(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "start" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not start game")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not start game")
print("Something went wrong with the request: " + str(e))
def end_game(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "end" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return
print("Fatal Error: could not end game")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not end game")
print("Something went wrong with the request: " + str(e))
def get_score(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "score" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not get score")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not get score")
print("Something went wrong with the request: " + str(e))
def get_game_info(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "gameInfo" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not get game info")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not get game info")
print("Something went wrong with the request: " + str(e))
def place_foundation(api_key, foundation, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/startBuild" + game_id, json=foundation, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action place foundation")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action place foundation")
print("Something went wrong with the request: " + str(e))
def build(api_key, pos, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/Build" + game_id, json=pos, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action build")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action build")
print("Something went wrong with the request: " + str(e))
def maintenance(api_key, pos, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/maintenance" + game_id, json=pos, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action maintenance")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action maintenance")
print("Something went wrong with the request: " + str(e))
def demolish(api_key, pos, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/demolish" + game_id, json=pos, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action demolish")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action demolish")
print("Something went wrong with the request: " + str(e))
def wait(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/wait" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action wait")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action wait")
print("Something went wrong with the request: " + str(e))
def adjust_energy(api_key, energy_level, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/adjustEnergy" + game_id, json=energy_level, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action adjust energy level")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action adjust energy level")
print("Something went wrong with the request: " + str(e))
def buy_upgrades(api_key, upgrade, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.post(base_api_path + "action/buyUpgrade" + game_id, json=upgrade, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not do action buy upgrades")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do action buy upgrades")
print("Something went wrong with the request: " + str(e))
def get_game_state(api_key, game_id=None):
if game_id:
game_id = "?GameId=" + game_id
else:
game_id = ""
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "gameState" + game_id, headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not get game state")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not do get game state")
print("Something went wrong with the request: " + str(e))
def get_games(api_key):
try:
global sess
if not sess:
sess = requests.Session()
response = sess.get(base_api_path + "games", headers={"x-api-key": api_key})
if response.status_code == 200:
return response.json()
print("Fatal Error: could not get games")
print(str(response.status_code) + " " + response.reason + ": " + response.text)
except RequestException as e:
print("Fatal Error: could not get games")
print("Something went wrong with the request: " + str(e))

155
game_layer.py Normal file
View File

@ -0,0 +1,155 @@
from typing import Tuple
import api
from game_state import GameState
class GameLayer:
def __init__(self, api_key):
self.game_state: GameState = None
self.api_key: str = api_key
def new_game(self, map_name: str = "training0"):
"""
Create a new game.
"""
if map_name:
game_options = {"mapName": map_name}
else:
game_options = ""
self.game_state = GameState(api.new_game(self.api_key, game_options))
def end_game(self):
"""
End the current game
"""
api.end_game(self.api_key, self.game_state.game_id)
def start_game(self):
"""
Starts the game.
"""
self.game_state.update_state(api.start_game(self.api_key, self.game_state.game_id))
def place_foundation(self, pos: Tuple[int, int], building_name: str):
"""
Places a building with name building_name at the given position.
:param pos: (int, int) - the position
:param building_name: string - the name, check available_residence_buildings or available_residence_utilities for which buildings are available
"""
position = {'X': pos[0], 'Y': pos[1]}
foundation = {'Position': position, 'BuildingName': building_name}
self.game_state.update_state(api.place_foundation(self.api_key, foundation, self.game_state.game_id))
def build(self, pos: Tuple[int, int]):
"""
Continues the construction of a building at the given position.
:param pos: (int, int) - the position
"""
position = {'position': {"X": pos[0], "Y": pos[1]}}
self.game_state.update_state(api.build(self.api_key, position, self.game_state.game_id))
def maintenance(self, pos: Tuple[int, int]):
"""
Performs maintenance on the building at the given position.
:param pos: (int, int) - the position
"""
position = {'position': {"x": pos[0], "y": pos[1]}}
self.game_state.update_state(api.maintenance(self.api_key, position, self.game_state.game_id))
def demolish(self, pos: Tuple[int, int]):
"""
Demolishes the building at the given position.
:param pos: (int, int) - the position
"""
position = {'position': {"x": pos[0], "y": pos[1]}}
self.game_state.update_state(api.demolish(self.api_key, position, self.game_state.game_id))
def adjust_energy_level(self, pos: Tuple[int, int], value: float):
"""
Adjusts the requested energy to value on the building at the given position.
:param pos: (int, int) - the position
:param value: float - the new requested value
"""
position = {"x": pos[0], "y": pos[1]}
self.game_state.update_state(api.adjust_energy(self.api_key, {"position": position, "value": value}, self.game_state.game_id))
def wait(self):
"""
Advances the game by one turn.
"""
self.game_state.update_state(api.wait(self.api_key, self.game_state.game_id))
def buy_upgrade(self, pos: Tuple[int, int], upgrade: str):
"""
Adds the specified upgrade to the building at the given position.
You can find the available upgrades in available_upgrades
Parameters
----------
:param pos: (int, int) - the position
:param upgrade: string - the upgrade to purchase
"""
position = {"x": pos[0], "y": pos[1]}
self.game_state.update_state(api.buy_upgrades(self.api_key, {"position": position, "upgradeAction": upgrade}, self.game_state.game_id))
def get_score(self):
"""
Gets the score for the game.
:return An object with partial and total scores.
"""
return api.get_score(self.api_key, self.game_state.game_id)
def get_game_info(self, game_id: str):
"""
Gets the game info of an already ongoing game and updates the state.
:param game_id: string - the id of the game to get info about.
"""
self.game_state = GameState(api.get_game_info(self.api_key, game_id))
def get_game_state(self, game_id: str):
"""
Gets the game state of an already ongoing game and updates the state. Can be used to resume a game.
:param game_id: string - the id of the game to get the state.
"""
self.game_state.update_state(api.get_game_state(self.api_key, game_id))
def get_blueprint(self, building_name: str):
"""
Returns the matching blueprint for a building
:param building_name: string - the name of the building to get a blueprint.
"""
res_blueprint = self.get_residence_blueprint(building_name)
if res_blueprint:
return res_blueprint
return self.get_utility_blueprint(building_name)
def get_residence_blueprint(self, building_name: str):
"""
Returns the matching blueprint for a residence
:param building_name: string - the name of the building to get a blueprint.
"""
for blueprint in self.game_state.available_residence_buildings:
if blueprint.building_name == building_name:
return blueprint
return None
def get_utility_blueprint(self, building_name: str):
"""
Return the matching blueprint for a utility building
:param building_name: string - the name of the building to get a blueprint.
"""
for blueprint in self.game_state.available_utility_buildings:
if blueprint.building_name == building_name:
return blueprint
return None
def get_effect(self, effect_name: str):
"""
Return the matching effect for an effect name.
:param effect_name: string - the name of the effect to get.
"""
for effect in self.game_state.effects:
if effect.name == effect_name:
return effect
return None

138
game_state.py Normal file
View File

@ -0,0 +1,138 @@
from typing import List
class GameState:
def __init__(self, map_values):
self.game_id: str = map_values["gameId"]
self.map_name: str = map_values["mapName"]
self.max_turns: int = map_values["maxTurns"]
self.max_temp: float = map_values["maxTemp"]
self.min_temp: float = map_values["minTemp"]
self.map: List[List[int]] = map_values["map"]
self.energy_levels: List[EnergyLevel] = []
for level in map_values["energyLevels"]:
self.energy_levels.append(EnergyLevel(level))
self.available_residence_buildings: List[BlueprintResidenceBuilding] = []
for building in map_values["availableResidenceBuildings"]:
self.available_residence_buildings.append(BlueprintResidenceBuilding(building))
self.available_utility_buildings: List[BlueprintUtilityBuilding] = []
for building in map_values["availableUtilityBuildings"]:
self.available_utility_buildings.append(BlueprintUtilityBuilding(building))
self.available_upgrades: List[Upgrade] = []
for upgrade in map_values['availableUpgrades']:
self.available_upgrades.append(Upgrade(upgrade))
self.effects: List[Effect] = []
for effect in map_values['effects']:
self.effects.append(Effect(effect))
self.turn: int = 0
self.funds: float = 0
self.total_co2: float = 0
self.total_happiness: float = 0
self.current_temp: float = 0
self.queue_happiness: float = 0
self.housing_queue: int = 0
self.residences: List[Residence] = []
self.utilities: List[Utility] = []
self.errors: List[str] = []
self.messages: List[str] = []
def update_state(self, state):
self.turn = state['turn']
self.funds = state['funds']
self.total_co2 = state['totalCo2']
self.total_happiness = state['totalHappiness']
self.current_temp = state['currentTemp']
self.queue_happiness = state['queueHappiness']
self.housing_queue = state['housingQueue']
self.residences = []
for building in state['residenceBuildings']:
self.residences.append(Residence(building))
self.utilities = []
for building in state['utilityBuildings']:
self.utilities.append(Utility(building))
self.errors = state['errors']
self.messages = state['messages']
class EnergyLevel:
def __init__(self, level_values):
self.energy_threshold: int = level_values['energyThreshold']
self.cost_per_mwh: float = level_values['costPerMwh']
self.co2_per_mwh: float = level_values['tonCo2PerMwh']
class Blueprint:
def __init__(self, blueprint):
self.building_name: str = blueprint['buildingName']
self.cost: int = blueprint['cost']
self.co2_cost: int = blueprint['co2Cost']
self.base_energy_need: float = blueprint['baseEnergyNeed']
self.build_speed: int = blueprint['buildSpeed']
self.type: str = blueprint['type']
self.release_tick: int = blueprint['releaseTick']
class BlueprintUtilityBuilding(Blueprint):
def __init__(self, blueprint_building):
super().__init__(blueprint_building)
self.effects: [str] = blueprint_building['effects']
self.queue_increase: float = blueprint_building['queueIncrease']
class BlueprintResidenceBuilding(Blueprint):
def __init__(self, blueprint_building):
super().__init__(blueprint_building)
self.max_pop: int = blueprint_building['maxPop']
self.income_per_pop: float = blueprint_building['incomePerPop']
self.emissivity: float = blueprint_building['emissivity']
self.maintenance_cost: int = blueprint_building['maintenanceCost']
self.decay_rate: float = blueprint_building['decayRate']
self.max_happiness = blueprint_building['maxHappiness']
class Upgrade:
def __init__(self, upgrade):
self.name: str = upgrade['name']
self.effect: str = upgrade['effect']
self.cost: int = upgrade['cost']
class Effect:
def __init__(self, effect):
self.name: str = effect['name']
self.radius: int = effect['radius']
self.emissivity_multiplier: float = effect['emissivityMultiplier']
self.decay_multiplier: float = effect['decayMultiplier']
self.building_income_increase: float = effect['buildingIncomeIncrease']
self.max_happiness_increase: float = effect['maxHappinessIncrease']
self.mwh_production: float = effect['mwhProduction']
self.base_energy_mwh_increase: float = effect['baseEnergyMwhIncrease']
self.co2_per_pop_increase: float = effect['co2PerPopIncrease']
self.decay_increase: float = effect['decayIncrease']
class Building:
def __init__(self, building):
self.building_name: str = building['buildingName']
self.X: int = building['position']['x']
self.Y: int = building['position']['y']
self.effective_energy_in: float = building['effectiveEnergyIn']
self.build_progress: int = building['buildProgress']
self.can_be_demolished: bool = building['canBeDemolished']
self.effects: List[str] = building['effects']
class Residence(Building):
def __init__(self, residence):
super().__init__(residence)
self.current_pop: int = residence['currentPop']
self.temperature: float = residence['temperature']
self.requested_energy_in: float = residence['requestedEnergyIn']
self.happiness_per_tick_per_pop: float = residence['happinessPerTickPerPop']
self.health: int = residence['health']
class Utility(Building):
def __init__(self, utility):
super().__init__(utility)

64
main.py Normal file
View File

@ -0,0 +1,64 @@
import api
from game_layer import GameLayer
api_key = "" # TODO: Your api key here
# The different map names can be found on considition.com/rules
map_name = "training1" # TODO: You map choice here. If left empty, the map "training1" will be selected.
game_layer: GameLayer = None
def main():
game_layer.new_game(map_name)
print("Starting game: " + game_layer.game_state.game_id)
game_layer.start_game()
while game_layer.game_state.turn < game_layer.game_state.max_turns:
take_turn()
print("Done with game: " + game_layer.game_state.game_id)
print("Final score was: " + str(game_layer.get_score()["finalScore"]))
def take_turn():
# TODO Implement your artificial intelligence here.
# TODO Take one action per turn until the game ends.
# TODO The following is a short example of how to use the StarterKit
state = game_layer.game_state
if len(state.residences) < 1:
for i in range(len(state.map)):
for j in range(len(state.map)):
if state.map[i][j] == 0:
x = i
y = j
break
game_layer.place_foundation((x, y), game_layer.game_state.available_residence_buildings[0].building_name)
else:
the_only_residence = state.residences[0]
if the_only_residence.build_progress < 100:
game_layer.build((the_only_residence.X, the_only_residence.Y))
elif the_only_residence.health < 50:
game_layer.maintenance((the_only_residence.X, the_only_residence.Y))
elif the_only_residence.temperature < 18:
blueprint = game_layer.get_residence_blueprint(the_only_residence.building_name)
energy = blueprint.base_energy_need + 0.5 \
+ (the_only_residence.temperature - state.current_temp) * blueprint.emissivity / 1 \
- the_only_residence.current_pop * 0.04
game_layer.adjust_energy_level((the_only_residence.X, the_only_residence.Y), energy)
elif the_only_residence.temperature > 24:
blueprint = game_layer.get_residence_blueprint(the_only_residence.building_name)
energy = blueprint.base_energy_need - 0.5 \
+ (the_only_residence.temperature - state.current_temp) * blueprint.emissivity / 1 \
- the_only_residence.current_pop * 0.04
game_layer.adjust_energy_level((the_only_residence.X, the_only_residence.Y), energy)
elif state.available_upgrades[0].name not in the_only_residence.effects:
game_layer.buy_upgrade((the_only_residence.X, the_only_residence.Y), state.available_upgrades[0].name)
else:
game_layer.wait()
for message in game_layer.game_state.messages:
print(message)
for error in game_layer.game_state.errors:
print("Error: " + error)
if __name__ == "__main__":
main()