def test_message(self):
     capture_output = io.StringIO()
     saved_stdout = sys.stdout
     try:
         sys.stdout = capture_output
         EventController()
         EventController()
         actual_message = capture_output.getvalue().strip()
         self.assertEqual(actual_message,
                          "EventController is a singleton and has already been instantiated. "
                          "Use EventController.get_instance() to get instance of the class."
                          )
     finally:
         sys.stdout = saved_stdout
Example #2
0
    def __init__(self):
        super().__init__()

        self.turn = 0

        # Singletons first
        self.event_controller = EventController()
        self.fun_stat_controller = FunStatController()

        self.accumulative_controller = AccumulativeController()
        self.city_generator_controller = CityGeneratorController()
        self.decree_controller = DecreeController()
        self.destruction_controller = DestructionController()
        self.disaster_controller = DisasterController()
        self.effort_controller = EffortController()

        self.game_over = False
 def __init__(self):
     super().__init__()
     self.event_controller = EventController.get_instance()
 def __init__(self):
     super().__init__()
     self.event_controller = EventController()
     self.contract_list = list()
class ActionController(Controller):
    def __init__(self):
        super().__init__()
        self.event_controller = EventController()
        self.contract_list = list()

    def handle_actions(self, player):
        player_action = player.action._chosen_action
        # Without a contract truck has no node to move to, ensure a contract is always active
        if player.truck.active_contract is not None or player_action == ActionType.select_contract:
            # Call the appropriate method for this action
            if (player_action == ActionType.select_contract):
                # Checks if contract_list is empty. If so, we have a problem
                if (len(self.contract_list) == 0):
                    raise ValueError("Contract list cannot be empty")
                # Selects the contract given in the player.action.action_parameter
                self.select_contract(player)
                player.time -= 1
                return ActionType.select_contract
            elif (player_action == ActionType.select_route):
                # Moves the player to the node given in the action_parameter
                #self.move(player, player_action.action.action_parameter)
                move = self.move(player)
                return [ActionType.select_route, move[0], move[1], move[2]]
        if (player_action == ActionType.buy_gas):
            self.buy_gas(player)
            player.time -= GameStats.gas_pumping_time_penalty
            return ActionType.buy_gas
        elif (player_action == ActionType.repair):
            self.heal(player)
            player.time -= GameStats.repair_pumping_time_penalty
            return ActionType.repair
        elif (player_action == ActionType.upgrade):
            self.upgrade_level(player, player.action.action_parameter)
            player.time -= GameStats.upgrade_time_penalty
            return ActionType.upgrade
        elif (player_action == ActionType.change_tires):
            self.upgrade_tires(player, player.action.action_parameter)
            player.time -= GameStats.upgrade_time_penalty
            return ActionType.change_tires
        elif (player_action == ActionType.set_speed):
            if isinstance(player.action.action_parameter, int):
                #This is an ActionType because the user client cannot directly influence truck values.
                player.truck.set_current_speed(player.action.action_parameter)
                player.time -= 1
                return ActionType.set_speed
            else:
                raise ValueError("Invalid speed parameter")
        else:
            self.print("Action aborted: no active contract!")
            player.time -= 1
            return ActionType.none

    # Action Methods ---------------------------------------------------------
    def move(self, player):
        param = player.action.action_parameter
        if type(param) == int:
            road = player.truck.active_contract.game_map.current_node.roads[
                param]
        elif type(param) == Road:
            road = param
        else:
            raise ValueError(
                "Attribute passed to move action was not an index or a road!")
        self.current_location = player.truck.active_contract.game_map.current_node
        time_taken = 0
        fuel_efficiency = GameStats.getMPG(
            player.truck.speed) * GameStats.costs_and_effectiveness[
                ObjectType.tires]['fuel_efficiency'][player.truck.tires]
        for route in self.current_location.roads:
            if route == road:  # May need to be redone
                player.truck.active_contract.game_map.get_next_node()
                event = self.event_controller.event_chance(
                    road, player, player.truck)
                time_taken = (road.length / player.truck.get_current_speed())
                gas_used = (road.length / fuel_efficiency) / (
                    player.truck.body.max_gas * 100)
                player.truck.body.current_gas -= gas_used
                player.time -= time_taken
        return [road.road_type, event[0], event[1]]

    # Retrieve by index and store in Player, then clear the list
    def select_contract(self, player):
        if isinstance(player.action.action_parameter,
                      int) and player.action.action_parameter >= -1:
            if len(self.contract_list) > int(player.action.action_parameter):
                player.truck.active_contract = self.contract_list[int(
                    player.action.action_parameter)]
                self.contract_list.clear()
            else:
                raise Exception("Invalid contract selection index!")
        elif isinstance(
                player.action.action_parameter, Contract
        ) and player.action.action_parameter in self.contract_list:
            player.truck.active_contract = player.action.action_parameter
            self.contract_list.clear()
        else:
            raise Exception(
                "Invalid contract selection parameter! Must be valid index or contract!"
            )

    def buy_gas(self, player):
        # Gas price is tied to node
        gasPrice = player.truck.active_contract.game_map.current_node.gas_price
        if (player.truck.money > 0):
            # Calculate what percent empty is the gas tank
            player.truck.body.update()
            percentGone = (1 - (round(player.truck.body.current_gas, 2) /
                                (player.truck.body.max_gas)))
            # Calculate the percentage the player could potentially buy
            maxPercent = round((player.truck.money / gasPrice) / 100, 2)
            if (percentGone < maxPercent):
                # If they can afford to fill up all the way, fill em up
                player.truck.money -= (percentGone * 100) * gasPrice
                player.truck.body.current_gas = player.truck.body.max_gas
            else:
                # Otherwise, give them the max percentage they can buy
                player.truck.money = 0
                player.truck.body.current_gas += (maxPercent *
                                                  player.truck.body.max_gas)

    def heal(self, player):
        healPrice = player.truck.active_contract.game_map.current_node.repair_price
        if (player.truck.money > 0):
            # Calculate what percent repair is missing
            percentRemain = 1 - (round(player.truck.health, 2) /
                                 GameStats.truck_starting_health)
            # Calculate what percent repair they can afford
            maxPercent = round((player.truck.money / healPrice) / 100, 2)
            if (percentRemain < maxPercent):
                # If they can afford it, repair the truck all the way
                player.truck.money -= (percentRemain * 100) * healPrice
                player.truck.health = GameStats.truck_starting_health
            else:
                # Otherwise, do the maximum repairs
                player.truck.money = 0
                player.truck.health += maxPercent * 100

    def upgrade_body(self, player, objEnum, typ):
        if objEnum is ObjectType.tank:
            # If the player doesn't currently have a tank and they have enough money for the base tank, give them a tank!
            if (not isinstance(player.truck.body, Tank)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.tank]['cost'][0] <= player.truck.money:
                player.truck.body = Tank()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.tank]['cost'][0]
            else:
                # otherwise, upgrade their current tank
                tnk = player.truck.body
                nxtLev = tnk.level + 1
                if tnk.level is not TankLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.tank]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.tank]['cost'][nxtLev]
                    player.truck.body.level = nxtLev
                else:
                    self.print("Not enough money or at max level for gas tank")
        if objEnum is ObjectType.headlights:
            if (not isinstance(player.truck.body, HeadLights)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.headlights]['cost'][0] <= player.truck.money:
                player.truck.body = HeadLights()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.headlights]['cost'][0]
            else:
                # otherwise, upgrade their current headlights
                lgt = player.truck.body
                nxtLev = lgt.level + 1
                if lgt.level is not HeadlightLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.
                        headlights]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.headlights]['cost'][nxtLev]
                    player.truck.body.level = nxtLev
                else:
                    self.print(
                        "Not enough money or at max level for headlights")
        if objEnum is ObjectType.sentryGun:
            if (not isinstance(player.truck.body, SentryGun)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.sentryGun]['cost'][0] <= player.truck.money:
                player.truck.body = SentryGun()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.sentryGun]['cost'][0]
            else:
                # otherwise, upgrade their current sentry gun
                gn = player.truck.body
                nxtLev = gn.level + 1
                if gn.level is not SentryGunLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.
                        sentryGun]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.sentryGun]['cost'][nxtLev]
                    player.truck.body.level = nxtLev
                else:
                    self.print(
                        "Not enough money or at max level for sentry gun")

    def upgrade_addons(self, player, objEnum, typ):
        if objEnum is ObjectType.policeScanner:
            # If the player doesn't currently have a scanner and they have enough money for the base scanner, give them a scanner!
            if (not isinstance(player.truck.addons, PoliceScanner)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.policeScanner]['cost'][0] <= player.truck.money:
                player.truck.addons = PoliceScanner()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.policeScanner]['cost'][0]
            else:
                # otherwise, upgrade their current scanner
                scn = player.truck.addons
                nxtLev = scn.level + 1
                if scn.level is not ScannerLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.
                        policeScanner]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.policeScanner]['cost'][nxtLev]
                    player.truck.addons.level = nxtLev
                else:
                    self.print(
                        "Not enough money or at max level for police scanner")
        if objEnum is ObjectType.rabbitFoot:
            # If the player doesn't currently have a scanner and they have enough money for the base rabbit foot, give them a foot!
            if (not isinstance(player.truck.addons, RabbitFoot)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.rabbitFoot]['cost'][0] <= player.truck.money:
                player.truck.addons = RabbitFoot()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.rabbitFoot]['cost'][0]
            else:
                # otherwise, upgrade their current scanner
                ft = player.truck.addons
                nxtLev = ft.level + 1
                if ft.level is not RabbitFootLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.
                        rabbitFoot]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.rabbitFoot]['cost'][nxtLev]
                    player.truck.addons.level = nxtLev
                else:
                    self.print(
                        "Not enough money or at max level for rabbit foot")
        if objEnum is ObjectType.GPS:
            # If the player doesn't currently have a scanner and they have enough money for the base scanner, give them a scanner!
            if (not isinstance(player.truck.addons, GPS)
                ) and GameStats.costs_and_effectiveness[
                    ObjectType.GPS]['cost'][0] <= player.truck.money:
                player.truck.addons = GPS()
                player.truck.money -= GameStats.costs_and_effectiveness[
                    ObjectType.GPS]['cost'][0]
            else:
                # otherwise, upgrade their current scanner
                gp = player.truck.addons
                nxtLev = gp.level + 1
                if gp.level is not GPSLevel.level_three and GameStats.costs_and_effectiveness[
                        ObjectType.GPS]['cost'][nxtLev] <= player.truck.money:
                    player.truck.money -= GameStats.costs_and_effectiveness[
                        ObjectType.GPS]['cost'][nxtLev]
                    player.truck.addons.level = nxtLev
                else:
                    self.print("Not enough money or at max level for GPS")

    def upgrade_tires(self, player, typ):
        tireLev = player.truck.tires
        if typ in TireType.__dict__.values(
        ) and typ is not tireLev and GameStats.tire_switch_cost <= player.truck.money:
            player.truck.tires = typ
            player.truck.money -= GameStats.tire_switch_cost
        else:
            self.print(
                "Either type is not in the enumeration, tiretype is already set to the type requested, or not enough money"
            )

    def upgrade_level(self, player, objEnum, typ=1):
        """
        Handles upgrading various object for the truck.
        """
        try:
            if not isinstance(player, Player):
                self.print("The player argument is not a Player object.")
                return
            # If the objects enum is an addon type, pass off to addon upgrade method
            elif objEnum in GameStats.addonObjects:
                self.upgrade_addons(player, objEnum, typ)
                player.truck.addons.update()
            # If the objects enum is a body type, pass off to body upgrade method
            elif objEnum in GameStats.body_objects:
                self.upgrade_body(player, objEnum, typ)
                player.truck.body.update()
            # The upgrade logic for tires is much simpler, but I have decided to modularize it for the sake of consistancy
            elif objEnum is ObjectType.tires:
                self.upgrade_tires(player, objEnum, typ)
            else:
                self.print(
                    "The object argument is not a valid upgradable object.")
                return
        except Exception as e:
            self.print(e)
    def test_get(self):
        test_ec = EventController()
        test_sc = SingletonController()

        self.assertEqual(test_ec, EventController.get_instance())
        self.assertEqual(test_sc, SingletonController.get_instance())
 def test_generate(self):
     EventController()
     SingletonController()
Example #8
0
class MasterController(Controller):
    def __init__(self):
        super().__init__()

        self.turn = 0

        # Singletons first
        self.event_controller = EventController()
        self.fun_stat_controller = FunStatController()

        self.accumulative_controller = AccumulativeController()
        self.city_generator_controller = CityGeneratorController()
        self.decree_controller = DecreeController()
        self.destruction_controller = DestructionController()
        self.disaster_controller = DisasterController()
        self.effort_controller = EffortController()

        self.game_over = False

    # Receives all clients for the purpose of giving them the objects they will control
    def give_clients_objects(self, client):
        client.city = City()
        client.team_name = client.code.team_name()
        client.city.city_name = client.code.city_name()
        city_type = client.code.city_type()

        self.city_generator_controller.handle_actions(client, city_type)

    # Generator function. Given a key:value pair where the key is the identifier for the current world and the value is
    # the state of the world, returns the key that will give the appropriate world information
    def game_loop_logic(self, start=1):
        self.turn = start

        # Basic loop from 1 to max turns
        while True:
            # Wait until the next call to give the number
            yield self.turn
            # Increment the turn counter by 1
            self.turn += 1
            # If the next turn number is above the max, the iterator ends
            if self.turn > config.MAX_TURNS:
                break

    # Receives world data from the generated game log and is responsible for interpreting it
    def interpret_current_turn_data(self, client, world, turn):
        # Turn disaster occurrence into a real disaster
        for disaster in world['disasters']:
            d = disaster['disaster']
            l = disaster['level']
            dis = None
            if d is DisasterType.earthquake:
                dis = Earthquake(l)
            elif d is DisasterType.fire:
                dis = Fire(l)
            elif d is DisasterType.blizzard:
                dis = Blizzard(l)
            elif d is DisasterType.monster:
                dis = Monster(l)
            elif d is DisasterType.tornado:
                dis = Tornado(l)
            elif d is DisasterType.ufo:
                dis = Ufo(l)

            if dis is None:
                raise TypeError(
                    f'Attempt to create disaster failed because given type: {disaster}, does not exist.'
                )

            client.disasters.append(dis)

            self.fun_stat_controller.total_disasters += 1
            self.event_controller.add_event({
                "event_type": EventType.disaster_spawned,
                "turn": turn,
                "disaster": dis.to_json()
            })

        # Run decrees immediately after disasters are generated (before player has a chance to set a new one)
        self.decree_controller.execute_decree(client)

        # read the sensor results from the game map, converting strings to ints and/or floats
        world['sensors'] = {
            int(key): {int(key2): float(val2)
                       for key2, val2 in val.items()}
            for key, val in world['sensors'].items()
        }

        # give client their corresponding sensor odds
        for sensor in client.city.sensors.values():
            sensor.sensor_results = world['sensors'][sensor.sensor_type][
                sensor.level]

        # Accumulations should occur before the player takes their turn
        self.accumulative_controller.update(client)

    # Receive a specific client and send them what they get per turn. Also obfuscates necessary objects.
    def client_turn_arguments(self, client, world, turn):
        actions = Action()
        client.action = actions

        obfuscated_city = deepcopy(client.city)
        obfuscated_city.obfuscate()
        for building in obfuscated_city.buildings.values():
            building.obfuscate()
        for sensor in obfuscated_city.sensors.values():
            sensor.obfuscate()

        obfuscated_disasters = deepcopy(client.disasters)
        for disaster in obfuscated_disasters:
            disaster.obfuscate()

        args = (
            self.turn,
            actions,
            obfuscated_city,
            obfuscated_disasters,
        )
        return args

    # Perform the main logic that happens per turn
    def turn_logic(self, client, world, turn):
        self.event_controller.update(turn)

        self.effort_controller.handle_actions(client)
        self.decree_controller.update_decree(client.action.get_decree())
        self.destruction_controller.handle_actions(client)
        self.disaster_controller.handle_actions(client)

        # Fun stat controller interjection
        self.fun_stat_controller.total_population_ever += client.city.population
        self.fun_stat_controller.total_structure_ever += client.city.structure

        if client.city.structure <= 0:
            self.print("Game is ending because city has been destroyed.")
            self.game_over = True

        if client.city.population <= 0:
            self.print("Game is ending because population has died.")
            self.game_over = True

    # Return serialized version of game
    def create_turn_log(self, client, world, turn):
        data = dict()

        # Retrieve all events on this turn
        data['events'] = [
            event for event in self.event_controller.get_events()
            if event.get('turn') == turn
        ]

        data['rates'] = world['rates']

        data['player'] = client.to_json()

        return data

    # Gather necessary data together in results file
    def return_final_results(self, client, world, turn):
        # data is the json information what will be written to the results file
        data = {
            "Team": client.
            team_name,  # TODO: Replace with an engine-safe ID of each team
            "Score": turn,
            "Events": self.event_controller.get_events(),
            "Error": client.error,
            "Statistics": self.fun_stat_controller.export()
        }
        return data

    # Return if the game should be over
    def game_over_check(self):
        return self.game_over