from copy import deepcopy
from enum import Enum, auto
from functools import wraps
from kaggle_environments.helpers import Point, group_by, Direction
from typing import *
import sys
import math
import random
import kaggle_environments.helpers

# region Data Model Classes
class Observation(kaggle_environments.helpers.Observation):
    """
    Observation primarily used as a helper to construct the Board from the raw observation.
    This provides bindings for the observation type described at https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/envs/kore/kore.json
    """
    @property
    def kore(self) -> List[float]:
        """Serialized list of available kore per cell on the board."""
        return self["kore"]

    @property
    def players(self) -> List[List[int]]:
        """List of players and their assets."""
        return self["players"]

    @property
    def player(self) -> int:
        """The current agent's player index."""
        return self["player"]

class Configuration(kaggle_environments.helpers.Configuration):
    """
    Configuration provides access to tunable parameters in the environment.
    This provides bindings for the configuration type described at https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/envs/kore/kore.json
    """
    @property
    def agent_timeout(self) -> float:
        """Maximum runtime (seconds) to initialize an agent."""
        return self["agentTimeout"]

    @property
    def starting_kore(self) -> int:
        """The starting amount of kore available on the board."""
        return self["startingKore"]

    @property
    def size(self) -> int:
        """The number of cells vertically and horizontally on the board."""
        return self["size"]

    @property
    def spawn_cost(self) -> int:
        """The amount of kore to spawn a new ship."""
        return self["spawnCost"]

    @property
    def convert_cost(self) -> int:
        """The amount of ships needed from a fleet to create a shipyard."""
        return self["convertCost"]

    @property
    def regen_rate(self) -> float:
        """The rate kore regenerates on the board."""
        return self["regenRate"]

    @property
    def max_cell_kore(self) -> int:
        """The maximum kore that can be in any cell."""
        return self["maxRegenCellKore"]

    @property
    def random_seed(self) -> int:
        """The seed to the random number generator (0 means no seed)."""
        return self["randomSeed"]

class ShipyardActionType(Enum):
    SPAWN = auto()
    LAUNCH = auto()

    def __str__(self) -> str:
        return self.name

class ShipyardAction:

    def __init__(self, type: ShipyardActionType, num_ships: Optional[int], flight_plan: Optional[str]) -> None:
        self._type = type
        assert num_ships >= 0, "must be a non-negative number"
        assert num_ships == int(num_ships), "must be an integer"
        self._num_ships = num_ships
        self._flight_plan = flight_plan

    def __str__(self) -> str:
        if self._type == ShipyardActionType.SPAWN:
            return f'{self._type.name}_{self._num_ships}'
        if self._type == ShipyardActionType.LAUNCH:
            return f'{self._type.name}_{self._num_ships}_{self._flight_plan}'

    @property
    def name(self):
        return str(self)

    @staticmethod
    def from_str(raw: str):
        if not raw:
            return None
        if raw.startswith(ShipyardActionType.SPAWN.name):
            _, ship_str = raw.split("_")
            try:
                num_ships = int(ship_str.split(".")[0])
            except _:
                num_ships = 0
            return ShipyardAction.spawn_ships(num_ships)
        if raw.startswith(ShipyardActionType.LAUNCH.name):
            _, ship_str, plan_str = raw.split("_")
            try:
                num_ships = int(ship_str.split(".")[0])
            except _:
                num_ships = 0
            return ShipyardAction.launch_fleet_with_flight_plan(num_ships, plan_str)

    @staticmethod
    def launch_fleet_in_direction(number_ships: int, direction: Direction):
        flight_plan = None
        if isinstance(direction, Direction):
            flight_plan = direction.to_char()
        else:
            flight_plan = flight_plan.upper()
        return ShipyardAction.launch_fleet_with_flight_plan(number_ships, flight_plan)

    @staticmethod
    def launch_fleet_with_flight_plan(number_ships: int, flight_plan: str):
        flight_plan = flight_plan.upper()
        assert number_ships > 0, "must be a positive number_ships"
        assert number_ships == int(number_ships), "must be an integer number_ships"
        assert flight_plan is not None and len(flight_plan) > 0, "flight_plan must be a str of len > 0"
        assert flight_plan[0].isalpha() and flight_plan[0] in "NESW", "flight_plan must start with a valid direciton NESW"
        assert all([c in "NESWC0123456789" for c in flight_plan]), "flight_plan (" + flight_plan + ")can only contain NESWC0-9"
        if len(flight_plan) > Fleet.max_flight_plan_len_for_ship_count(number_ships):
            print("flight plan will be truncated: flight plan for " + str(number_ships) + " must be at most " + str(Fleet.max_flight_plan_len_for_ship_count(number_ships)))
        return ShipyardAction(ShipyardActionType.LAUNCH, number_ships, flight_plan)

    @staticmethod
    def spawn_ships(number_ships: int):
        assert number_ships == int(number_ships), "must be an integer number_ships"
        return ShipyardAction(ShipyardActionType.SPAWN, number_ships, None)

    @property
    def action_type(self) -> ShipyardActionType:
        return self._type

    @property
    def num_ships(self) -> Optional[int]:
        return self._num_ships

    @property
    def flight_plan(self) -> Optional[str]:
        return self._flight_plan

FleetId = NewType('FleetId', str)
ShipyardId = NewType('ShipyardId', str)
PlayerId = NewType('PlayerId', int)

class Cell:
    def __init__(self, position: Point, kore: float, shipyard_id: Optional[ShipyardId], fleet_id: Optional[FleetId], board: 'Board') -> None:
        self._position = position
        self._kore = kore
        self._shipyard_id = shipyard_id
        self._fleet_id = fleet_id
        self._board = board

    @property
    def position(self) -> Point:
        return self._position

    @property
    def kore(self) -> float:
        return self._kore

    @property
    def shipyard_id(self) -> Optional[ShipyardId]:
        return self._shipyard_id

    @property
    def fleet_id(self) -> Optional[FleetId]:
        return self._fleet_id

    @property
    def fleet(self) -> Optional['Fleet']:
        """Returns the fleet on this cell if it exists and None otherwise."""
        return self._board.fleets.get(self.fleet_id)

    @property
    def shipyard(self) -> Optional['Shipyard']:
        """Returns the shipyard on this cell if it exists and None otherwise."""
        return self._board.shipyards.get(self.shipyard_id)

    def neighbor(self, offset: Point) -> 'Cell':
        """Returns the cell at self.position + offset."""
        (x, y) = self.position + offset
        return self._board[x, y]

    @property
    def north(self) -> 'Cell':
        """Returns the cell north of this cell."""
        return self.neighbor(Direction.NORTH.to_point())

    @property
    def south(self) -> 'Cell':
        """Returns the cell south of this cell."""
        return self.neighbor(Direction.SOUTH.to_point())

    @property
    def east(self) -> 'Cell':
        """Returns the cell east of this cell."""
        return self.neighbor(Direction.EAST.to_point())

    @property
    def west(self) -> 'Cell':
        """Returns the cell west of this cell."""
        return self.neighbor(Direction.WEST.to_point())

class Fleet:
    def __init__(self, fleet_id: FleetId, ship_count: int, direction: Direction, position: Point, kore: int, flight_plan: str, player_id: PlayerId, board: 'Board') -> None:
        self._id = fleet_id
        self._ship_count = ship_count
        self._direction = direction
        self._position = position
        self._flight_plan = flight_plan
        self._kore = kore
        self._player_id = player_id
        self._board = board

    @property
    def id(self) -> FleetId:
        return self._id

    @property
    def ship_count(self) -> int:
        return self._ship_count

    @property
    def direction(self) -> Direction:
        return self._direction

    @property
    def position(self) -> Point:
        return self._position

    @property
    def kore(self) -> int:
        return self._kore

    @property
    def player_id(self) -> PlayerId:
        return self._player_id

    @property
    def cell(self) -> Cell:
        """Returns the cell this fleet is on."""
        return self._board[self.position]

    @property
    def player(self) -> 'Player':
        """Returns the player that owns this ship."""
        return self._board.players[self.player_id]

    @property
    def flight_plan(self) -> str:
        """Returns the current flight plan of the fleet"""
        return self._flight_plan

    @property
    def collection_rate(self) -> float:
        """ln(ship_count) / 10"""
        return min(math.log(self.ship_count) / 20, .99)

    @staticmethod
    def max_flight_plan_len_for_ship_count(ship_count) -> int:
        """Returns the length of the longest possible flight plan this fleet can be assigned"""
        return math.floor(2 * math.log(ship_count)) + 1

    @property
    def _observation(self) -> List[int]:
        """Converts a fleet back to the normalized observation subset that constructed it."""
        return [self.position.to_index(self._board.configuration.size), self.kore, self.ship_count, self.direction.to_index(), self.flight_plan]

    def less_than_other_allied_fleet(self, other):
        if not self.ship_count == other.ship_count:
            return self.ship_count < other.ship_count
        if not self.kore == other.kore:
            return self.kore < other.kore
        return self.direction.to_index() > other.direction.to_index()

upgrade_times = [pow(i,2) + 1 for i in range(1, 10)]
SPAWN_VALUES = []
current = 0
for t in upgrade_times:
    current += t
    SPAWN_VALUES.append(current)

class Shipyard:
    def __init__(self, shipyard_id: ShipyardId, ship_count: int, position: Point, player_id: PlayerId, turns_controlled: int, board: 'Board', next_action: Optional[ShipyardAction] = None) -> None:
        self._id = shipyard_id
        self._ship_count = ship_count
        self._position = position
        self._player_id = player_id
        self._turns_controlled = turns_controlled
        self._board = board
        self._next_action = next_action

    @property
    def id(self) -> ShipyardId:
        return self._id

    @property
    def ship_count(self):
        return self._ship_count

    @property
    def position(self) -> Point:
        return self._position

    @property
    def player_id(self) -> PlayerId:
        return self._player_id

    @property
    def max_spawn(self) -> int:
        for idx, target in enumerate(SPAWN_VALUES):
            if self._turns_controlled < target:
                return idx + 1
        return len(SPAWN_VALUES) + 1

    @property
    def cell(self) -> Cell:
        """Returns the cell this shipyard is on."""
        return self._board[self.position]

    @property
    def player(self) -> 'Player':
        return self._board.players[self.player_id]

    @property
    def next_action(self) -> ShipyardAction:
        """Returns the action that will be executed by this shipyard when Board.next() is called (when the current turn ends)."""
        return self._next_action

    @next_action.setter
    def next_action(self, value: Optional[ShipyardAction]) -> None:
        """Sets the action that will be executed by this shipyard when Board.next() is called (when the current turn ends)."""
        self._next_action = value

    @property
    def _observation(self) -> List[int]:
        """Converts a shipyard back to the normalized observation subset that constructed it."""
        return [self.position.to_index(self._board.configuration.size), self.ship_count, self._turns_controlled]

class Player:
    def __init__(self, player_id: PlayerId, kore: int, shipyard_ids: List[ShipyardId], fleet_ids: List[FleetId], board: 'Board') -> None:
        self._id = player_id
        self._kore = kore
        self._shipyard_ids = shipyard_ids
        self._fleet_ids = fleet_ids
        self._board = board

    @property
    def id(self) -> PlayerId:
        return self._id

    @property
    def kore(self) -> int:
        return self._kore

    @property
    def shipyard_ids(self) -> List[ShipyardId]:
        return self._shipyard_ids

    @property
    def fleet_ids(self) -> List[FleetId]:
        return self._fleet_ids

    @property
    def shipyards(self) -> List[Shipyard]:
        """Returns all shipyards owned by this player."""
        return [
            self._board.shipyards[shipyard_id]
            for shipyard_id in self.shipyard_ids
        ]

    @property
    def fleets(self) -> List[Fleet]:
        """Returns all fleets owned by this player."""
        return [
            self._board.fleets[fleet_id]
            for fleet_id in self.fleet_ids
        ]

    @property
    def is_current_player(self) -> bool:
        """Returns whether this player is the current player (generally if this returns True, this player is you)."""
        return self.id == self._board.current_player_id

    @property
    def next_actions(self) -> Dict[str, str]:
        """Returns all queued fleet and shipyard actions for this player formatted for the kore interpreter to receive as an agent response."""
        shipyard_actions = {
            shipyard.id: shipyard.next_action.name
            for shipyard in self.shipyards
            if shipyard.next_action is not None
        }
        return {**shipyard_actions}

    @property
    def _observation(self):
        """Converts a player back to the normalized observation subset that constructed it."""
        shipyards = {shipyard.id: shipyard._observation for shipyard in self.shipyards}
        fleets = {fleet.id: fleet._observation for fleet in self.fleets}
        return [self.kore, shipyards, fleets]
# endregion

class Board:
    def __init__(
        self,
        raw_observation: Dict[str, Any],
        raw_configuration: Union[Configuration, Dict[str, Any]],
        next_actions: Optional[List[Dict[str, str]]] = None
    ) -> None:
        """
        Creates a board from the provided observation, configuration, and next_actions as specified by
        https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/envs/kore/kore.json
        Board tracks players (by id), fleets (by id), shipyards (by id), and cells (by position).
        Each entity contains both key values (e.g. fleet.player_id) as well as entity references (e.g. fleet.player).
        References are deep and chainable e.g.
            [fleet.kore for player in board.players for fleet in player.fleets]
            fleet.player.shipyards[0].cell.north.east.fleet
        Consumers should not set or modify any attributes except and Shipyard.next_action
        """
        observation = Observation(raw_observation)
        # next_actions is effectively a Dict[Union[[FleetId, FleetAction], [ShipyardId, ShipyardAction]]]
        # but that type's not very expressible so we simplify it to Dict[str, str]
        # Later we'll iterate through it once for each fleet and shipyard to pull all the actions out
        next_actions = next_actions or ([{}] * len(observation.players))

        self._step = observation.step
        self._remaining_overage_time = observation.remaining_overage_time
        self._configuration = Configuration(raw_configuration)
        self._current_player_id = observation.player
        self._players: Dict[PlayerId, Player] = {}
        self._fleets: Dict[FleetId, Fleet] = {}
        self._shipyards: Dict[ShipyardId, Shipyard] = {}
        self._cells: Dict[Point, Cell] = {}

        size = self.configuration.size
        # Create a cell for every point in a size x size grid
        for x in range(size):
            for y in range(size):
                position = Point(x, y)
                kore = observation.kore[position.to_index(size)]
                # We'll populate the cell's fleets and shipyards in _add_fleet and _add_shipyard
                self.cells[position] = Cell(position, kore, None, None, self)

        for (player_id, player_observation) in enumerate(observation.players):
            # We know the len(player_observation) == 3 based on the schema -- this is a hack to have a tuple in json
            [player_kore, player_shipyards, player_fleets] = player_observation
            # We'll populate the player's fleets and shipyards in _add_fleet and _add_shipyard
            self.players[player_id] = Player(player_id, player_kore, [], [], self)
            player_actions = next_actions[player_id] or {}

            for (fleet_id, [fleet_index, fleet_kore, ship_count, direction, flight_plan]) in player_fleets.items():
                fleet_position = Point.from_index(fleet_index, size)
                fleet_direction = Direction.from_index(direction)
                self._add_fleet(Fleet(fleet_id, ship_count, fleet_direction, fleet_position, fleet_kore, flight_plan, player_id, self))

            for (shipyard_id, [shipyard_index, ship_count, turns_controlled]) in player_shipyards.items():
                shipyard_position = Point.from_index(shipyard_index, size)
                raw_action = player_actions.get(shipyard_id)
                action = ShipyardAction.from_str(raw_action)
                self._add_shipyard(Shipyard(shipyard_id, ship_count, shipyard_position, player_id, turns_controlled, self, action))

    @property
    def configuration(self) -> Configuration:
        return self._configuration

    @property
    def players(self) -> Dict[PlayerId, Player]:
        return self._players

    @property
    def fleets(self) -> Dict[FleetId, Fleet]:
        """Returns all fleets on the current board."""
        return self._fleets

    @property
    def shipyards(self) -> Dict[ShipyardId, Shipyard]:
        """Returns all shipyards on the current board."""
        return self._shipyards

    @property
    def cells(self) -> Dict[Point, Cell]:
        """Returns all cells on the current board."""
        return self._cells

    @property
    def step(self) -> int:
        return self._step

    @property
    def current_player_id(self) -> PlayerId:
        return self._current_player_id

    @property
    def current_player(self) -> Player:
        """Returns the current player (generally this is you)."""
        return self._players[self.current_player_id]

    @property
    def opponents(self) -> List[Player]:
        """
        Returns all players that aren't the current player.
        You can get all opponent fleets with [fleet for fleet in player.fleets for player in board.opponents]
        """
        return [player for player in self.players.values() if not player.is_current_player]

    @property
    def observation(self) -> Dict[str, Any]:
        """Converts a Board back to the normalized observation that constructed it."""
        size = self.configuration.size
        kore = [self[Point.from_index(index, size)].kore for index in range(size * size)]
        players = [player._observation for player in self.players.values()]

        return {
            "kore": kore,
            "players": players,
            "player": self.current_player_id,
            "step": self.step,
            "remainingOverageTime": self._remaining_overage_time,
        }

    def __deepcopy__(self, _) -> 'Board':
        actions = [player.next_actions for player in self.players.values()]
        return Board(self.observation, self.configuration, actions)

    def __getitem__(self, point: Union[Tuple[int, int], Point]) -> Cell:
        """
        This method will wrap the supplied position to fit within the board size and return the cell at that location.
        e.g. on a 3x3 board, board[2, 1] is the same as board[5, 1]
        """
        if not isinstance(point, Point):
            (x, y) = point
            point = Point(x, y)
        return self._cells[point % self.configuration.size]

    def __str__(self) -> str:
        """
        The board is printed in a grid with the following rules:
        Capital letters are shipyards
        Lower case letters are fleets
        Digits are cell kore and scale from 0-9 directly proportional to a value between 0 and self.configuration.max_cell_kore
        Player 1 is letter a/A
        Player 2 is letter b/B
        etc.
        """
        size = self.configuration.size
        result = ''
        for y in range(size):
            for x in range(size):
                cell = self[(x, size - y - 1)]
                result += '|'
                result += (
                    chr(ord('a') + cell.ship.player_id)
                    if cell.fleet is not None
                    else ' '
                )
                # This normalizes a value from 0 to max_cell kore to a value from 0 to 9
                normalized_kore = int(9.0 * cell.kore / float(self.configuration.max_cell_kore))
                result += str(normalized_kore)
                result += (
                    chr(ord('A') + cell.shipyard.player_id)
                    if cell.shipyard is not None
                    else ' '
                )
            result += '|\n'
        return result

    def _add_fleet(self: 'Board', fleet: Fleet) -> None:
        fleet.player.fleet_ids.append(fleet.id)
        fleet.cell._fleet_id = fleet.id
        self._fleets[fleet.id] = fleet

    def _add_shipyard(self: 'Board', shipyard: Shipyard) -> None:
        shipyard.player.shipyard_ids.append(shipyard.id)
        shipyard.cell._shipyard_id = shipyard.id
        shipyard.cell._kore = 0
        self._shipyards[shipyard.id] = shipyard

    def _delete_fleet(self: 'Board', fleet: Fleet) -> None:
        fleet.player.fleet_ids.remove(fleet.id)
        if fleet.cell.fleet_id == fleet.id:
            fleet.cell._fleet_id = None
        del self._fleets[fleet.id]

    def _delete_shipyard(self: 'Board', shipyard: Shipyard) -> None:
        shipyard.player.shipyard_ids.remove(shipyard.id)
        if shipyard.cell.shipyard_id == shipyard.id:
            shipyard.cell._shipyard_id = None
        del self._shipyards[shipyard.id]

    def get_fleet_at_point(self: 'Board', position: Point) -> Optional[Fleet]:
        matches = [fleet for fleet in self.fleets.values() if fleet.position == position]
        if matches:
            assert len(matches) == 1
            return matches[0]
        return None

    def get_shipyard_at_point(self: 'Board', position: Point) -> Optional[Shipyard]:
        matches = [shipyard for shipyard in self.shipyards.values() if shipyard.position == position]
        if matches:
            assert len(matches) == 1
            return matches[0]
        return None

    def get_cell_at_point(self: 'Board', position: Point):
        return self.cells.get(position)

    def print(self: 'Board') -> None:
        size = self.configuration.size
        player_chars = {
            pid: alpha
            for pid, alpha in  zip(self.players, "abcdef"[:len(self.players)])
        }
        print(self.configuration.size * "=")
        for i in range(size):
            row = ""
            for j in range(size):
                pos = Point(j, size - 1 - i)
                curr_cell = self.cells[pos]
                if curr_cell.shipyard is not None:
                    row += player_chars[curr_cell.shipyard.player_id].upper()
                elif curr_cell.fleet is not None:
                    row += player_chars[curr_cell.fleet.player_id]
                elif curr_cell.kore <= 50:
                    row += " "
                elif curr_cell.kore <= 250:
                    row += "."
                elif curr_cell.kore <= 400:
                    row += "*"
                elif curr_cell.kore > 400:
                    row += "o"
            print(row)
        print(self.configuration.size * "=")

    def print_kore(self: 'Board') -> None:
        size = self.configuration.size
        print(self.configuration.size * "=")
        for i in range(size):
            row = ""
            for j in range(size):
                pos = Point(j, size - 1 - i)
                curr_cell = self.cells[pos]
                row += str(int(curr_cell.kore)) + ","
            print(row)
        print(self.configuration.size * "=")

    def next(self) -> 'Board':
        """
        Returns a new board with the current board's next actions applied.
        The current board is unmodified.
        This can form a kore interpreter, e.g.
            next_observation = Board(current_observation, configuration, actions).next().observation
        """
        # Create a copy of the board to modify so we don't affect the current board
        board = deepcopy(self)
        configuration = board.configuration
        convert_cost = configuration.convert_cost
        spawn_cost = configuration.spawn_cost
        uid_counter = 0

        # This is a consistent way to generate unique strings to form fleet and shipyard ids
        def create_uid():
            nonlocal uid_counter
            uid_counter += 1
            return f"{self.step + 1}-{uid_counter}"

        # this checks the validity of a flight plan
        def is_valid_flight_plan(flight_plan):
            return len([c for c in flight_plan if c not in "NESWC0123456789"]) == 0

        # Process actions and store the results in the fleets and shipyards lists for collision checking
        for player in board.players.values():
            for shipyard in player.shipyards:
                if shipyard.next_action == None:
                    pass
                elif shipyard.next_action.num_ships == 0:
                    pass
                elif (shipyard.next_action.action_type == ShipyardActionType.SPAWN
                        and player.kore >= spawn_cost * shipyard.next_action.num_ships
                        and shipyard.next_action.num_ships <= shipyard.max_spawn):
                    # Handle SPAWN actions
                    player._kore -= spawn_cost * shipyard.next_action.num_ships
                    shipyard._ship_count += shipyard.next_action.num_ships
                elif shipyard.next_action.action_type == ShipyardActionType.LAUNCH and shipyard.ship_count >= shipyard.next_action.num_ships:
                    flight_plan = shipyard.next_action.flight_plan
                    if not flight_plan or not is_valid_flight_plan(flight_plan):
                        continue
                    shipyard._ship_count -= shipyard.next_action.num_ships
                    direction = Direction.from_char(flight_plan[0])
                    max_flight_plan_len = Fleet.max_flight_plan_len_for_ship_count(shipyard.next_action.num_ships)
                    if len(flight_plan) > max_flight_plan_len:
                        flight_plan = flight_plan[:max_flight_plan_len]
                    board._add_fleet(Fleet(FleetId(create_uid()), shipyard.next_action.num_ships, direction, shipyard.position, 0, flight_plan, player.id, board))

            # Clear the shipyard's action so it doesn't repeat the same action automatically
            for shipyard in player.shipyards:
                shipyard.next_action = None
                shipyard._turns_controlled += 1

            def find_first_non_digit(candidate_str):
                for i in range(len(candidate_str)):
                    if not candidate_str[i].isdigit():
                        return i
                else:
                    return len(candidate_str) + 1
                return 0

            for fleet in player.fleets:
                # remove any errant 0s
                while fleet.flight_plan and fleet.flight_plan.startswith("0"):
                    fleet._flight_plan = fleet.flight_plan[1:]
                if fleet.flight_plan and fleet.flight_plan[0] == "C" and fleet.ship_count >= convert_cost and fleet.cell.shipyard_id is None:
                    player._kore += fleet.kore
                    fleet.cell._kore = 0
                    board._add_shipyard(Shipyard(ShipyardId(create_uid()), fleet.ship_count - convert_cost, fleet.position, player.id, 0, board))
                    board._delete_fleet(fleet)
                    continue

                while fleet.flight_plan and fleet.flight_plan[0] == "C":
                    # couldn't build, remove the Convert and continue with flight plan
                    fleet._flight_plan = fleet.flight_plan[1:]

                if fleet.flight_plan and fleet.flight_plan[0].isalpha():
                    fleet._direction = Direction.from_char(fleet.flight_plan[0])
                    fleet._flight_plan = fleet.flight_plan[1:]
                elif fleet.flight_plan:
                    idx = find_first_non_digit(fleet.flight_plan)
                    digits = int(fleet.flight_plan[:idx])
                    rest = fleet.flight_plan[idx:]
                    digits -= 1
                    if digits > 0:
                        fleet._flight_plan = str(digits) + rest
                    else:
                        fleet._flight_plan = rest

                # continue moving in the fleet's direction
                fleet.cell._fleet_id = None
                fleet._position = fleet.position.translate(fleet.direction.to_point(), configuration.size)
                # We don't set the new cell's fleet_id here as it would be overwritten by another fleet in the case of collision.

            def combine_fleets(fid1: FleetId, fid2: FleetId) -> FleetId:
                f1 = board.fleets[fid1]
                f2 = board.fleets[fid2]
                if f1.less_than_other_allied_fleet(f2):
                    f1, f2 = f2, f1
                    fid1, fid2 = fid2, fid1
                f1._kore += f2.kore
                f1._ship_count += f2._ship_count
                board._delete_fleet(f2)
                return fid1

            # resolve any allied fleets that ended up in the same square
            fleets_by_loc = group_by(player.fleets, lambda fleet: fleet.position.to_index(configuration.size))
            for value in fleets_by_loc.values():
                value.sort(key=lambda fleet: (fleet.ship_count, fleet.kore, -fleet.direction.to_index()), reverse=True)
                fid = value[0].id
                for i in range (1, len(value)):
                    fid = combine_fleets(fid, value[i].id)

            # Lets just check and make sure.
            assert player.kore >= 0

        def resolve_collision(fleets: List[Fleet]) -> Tuple[Optional[Fleet], List[Fleet]]:
            """
            Accepts the list of fleets at a particular position (must not be empty).
            Returns the fleet with the most ships or None in the case of a tie along with all other fleets.
            """
            if len(fleets) == 1:
                return fleets[0], []
            fleets_by_ships = group_by(fleets, lambda fleet: fleet.ship_count)
            most_ships = max(fleets_by_ships.keys())
            largest_fleets = fleets_by_ships[most_ships]
            if len(largest_fleets) == 1:
                # There was a winner, return it
                winner = largest_fleets[0]
                return winner, [fleet for fleet in fleets if fleet != winner]
            # There was a tie for most ships, all are deleted
            return None, fleets

        # Check for fleet to fleet collisions
        fleet_collision_groups = group_by(board.fleets.values(), lambda fleet: fleet.position)
        for position, collided_fleets in fleet_collision_groups.items():
            winner, deleted = resolve_collision(collided_fleets)
            shipyard = group_by(board.shipyards.values(), lambda shipyard: shipyard.position).get(position)
            if winner is not None:
                winner.cell._fleet_id = winner.id
                max_enemy_size = max([fleet.ship_count for fleet in deleted]) if deleted else 0
                winner._ship_count -= max_enemy_size
            for fleet in deleted:
                board._delete_fleet(fleet)
                if winner is not None:
                    # Winner takes deleted fleets' kore
                    winner._kore += fleet.kore
                elif winner is None and shipyard and shipyard[0].player:
                    # Desposit the kore into the shipyard
                    shipyard[0].player._kore += fleet.kore
                elif winner is None:
                    # Desposit the kore on the square
                    board.cells[position]._kore += fleet.kore

        # Check for fleet to shipyard collisions
        for shipyard in list(board.shipyards.values()):
            fleet = shipyard.cell.fleet
            if fleet is not None and fleet.player_id != shipyard.player_id:
                if fleet.ship_count > shipyard.ship_count:
                    count = fleet.ship_count - shipyard.ship_count
                    board._delete_shipyard(shipyard)
                    board._add_shipyard(Shipyard(ShipyardId(create_uid()), count, shipyard.position, fleet.player.id, 1, board))
                    fleet.player._kore += fleet.kore
                    board._delete_fleet(fleet)
                else:
                    shipyard._ship_count -= fleet.ship_count
                    shipyard.player._kore += fleet.kore
                    board._delete_fleet(fleet)

        # Deposit kore from fleets into shipyards
        for shipyard in list(board.shipyards.values()):
            fleet = shipyard.cell.fleet
            if fleet is not None and fleet.player_id == shipyard.player_id:
                shipyard.player._kore += fleet.kore
                shipyard._ship_count += fleet.ship_count
                board._delete_fleet(fleet)

        # apply fleet to fleet damage on all orthagonally adjacent cells
        incoming_fleet_dmg = DefaultDict(lambda: DefaultDict(int))
        for fleet in board.fleets.values():
            for direction in Direction.list_directions():
                curr_pos = fleet.position.translate(direction.to_point(), board.configuration.size)
                fleet_at_pos = board.get_fleet_at_point(curr_pos)
                if fleet_at_pos and not fleet_at_pos.player_id == fleet.player_id:
                    incoming_fleet_dmg[fleet_at_pos.id][fleet.id] = fleet.ship_count

        # dump 1/2 kore to the cell of killed fleets
        # mark the other 1/2 kore to go to surrounding fleets proportionally
        to_distribute = DefaultDict(lambda: DefaultDict(int))
        for fleet_id, fleet_dmg_dict in incoming_fleet_dmg.items():
            fleet = board.fleets[fleet_id]
            damage = sum(fleet_dmg_dict.values())
            if damage >= fleet.ship_count:
                fleet.cell._kore += fleet.kore / 2
                to_split = fleet.kore / 2
                for f_id, dmg in fleet_dmg_dict.items():
                    to_distribute[f_id][fleet.position.to_index(board.configuration.size)] = to_split * dmg/damage
                board._delete_fleet(fleet)
            else:
                fleet._ship_count -= damage

        # give kore claimed above to surviving fleets, otherwise add it to the kore of the tile where the fleet died
        for fleet_id, loc_kore_dict in to_distribute.items():
            fleet = board.fleets.get(fleet_id)
            if fleet:
                fleet._kore += sum(loc_kore_dict.values())
            else:
                for loc_idx, kore in loc_kore_dict.items():
                    board.cells.get(Point.from_index(loc_idx, board.configuration.size))._kore += kore

        # Collect kore from cells into fleets
        for fleet in board.fleets.values():
            cell = fleet.cell
            delta_kore = round(cell.kore * min(fleet.collection_rate, .99), 3)
            if delta_kore > 0:
                fleet._kore += delta_kore
                cell._kore -= delta_kore

        # Regenerate kore in cells
        for cell in board.cells.values():
            if cell.fleet_id is None and cell.shipyard_id is None:
                if cell.kore < configuration.max_cell_kore:
                    next_kore = round(cell.kore * (1 + configuration.regen_rate), 3)
                    cell._kore = next_kore

        board._step += 1

        # self.print()

        return board

def board_agent(agent: Callable[[Board], None]):
    """
    Decorator used to create an agent that modifies a board rather than an observation and a configuration
    Automatically returns the modified board's next actions

    @board_agent
    def my_agent(board: Board) -> None:
        ...
    """
    @wraps(agent)
    def agent_wrapper(obs, config) -> Dict[str, str]:
        board = Board(obs, config)
        agent(board)
        return board.current_player.next_actions

    if agent.__module__ is not None and agent.__module__ in sys.modules:
        setattr(sys.modules[agent.__module__], agent.__name__, agent_wrapper)
    return agent_wrapper


import pygame, sys
from pygame.locals import *
import math

class Ray:
    def __init__(self, game, x, y, heading):
        self.x = x
        self.y = y
        self.game = game
        # self.player = player

        # self.angle = (math.pi*2) - player.heading # 0 <= theta < 2pi now
        self.angle = heading
        self.endX = self.x
        self.endY = self.y

        self.r = 0
    def getGridCoord(self, x, y):
        return (math.floor(x / self.game.map.s), math.floor(y / self.game.map.s))

    # returns true if point corresponds to wall
    # @param point: grid coordinates not standard pixels
    def checkCollision(self, point):
        return point in self.game.map.world

    def withinWorld(self, x, y):
        return (x > 0 and x < self.game.w) and (y > 0 and y < self.game.h)

    # def calculateStep(self, x, y):
    #     mapX, mapY = self.getGridCoord(x,y)
    #     return 0 #placeholder

    def cast(self):
        # tao = self.angle%(2*math.pi)
        # rayFacingUp =  tao <= math.pi and tao >= 0
        # rayFacingRight = tao+(math.pi/2) < math.pi and tao+(math.pi/2) > 0
        rayFacingUp =  self.angle <= math.pi and self.angle >= 0
        rayFacingRight = self.angle <= math.pi/2 or self.angle >= 3*math.pi/2
        # print(math.degrees(self.angle))

        #Ax, Ay is point of collision through horizontal checking
        if(rayFacingUp):
            Ay = math.floor(self.y/self.game.map.s) * (self.game.map.s) - 1
            Ya = -1 * self.game.map.s
            Xa = self.game.map.s/math.tan(self.angle)
        #if ray facing down
        else:
            Ay = math.floor(self.y/self.game.map.s) * (self.game.map.s) + self.game.map.s
            Ya = self.game.map.s
            Xa = -self.game.map.s/math.tan(self.angle)

        Ax = self.x + (self.y - Ay)/math.tan(self.angle)

        #infinitely large number so it losses the comparison
        # if this does cause some performance issue TODO:
        dist1 = math.pow(10, 9)
        while(self.withinWorld(Ax, Ay)):
            if(self.checkCollision(self.getGridCoord(Ax, Ay))):
                dist1 = math.sqrt(math.pow(self.x - Ax, 2) + math.pow(self.y - Ay, 2))
                break
            Ax += Xa;
            Ay += Ya
            # print(Ax, Ay)

        # DEBUG
        # pygame.draw.line(self.game.win, (255,0,0), (self.x, self.y), (Ax, Ay))
        # pygame.draw.line(self.game.win, (0,0,255), (Ax, Ay), (Ax + Xa, Ay + Ya))

        #Bx, By is point of collision through vertical checking
        if(rayFacingRight):
            Bx = math.floor(self.x/self.game.map.s) * (self.game.map.s) + self.game.map.s
            Xb = self.game.map.s
            Yb = -self.game.map.s*math.tan(self.angle)
        else:
            Bx = math.floor(self.x/self.game.map.s) * (self.game.map.s) - 1
            Xb = -1 * self.game.map.s
            Yb = self.game.map.s*math.tan(self.angle)
        By = self.y+(self.x - Bx)*math.tan(self.angle)

        dist2 = math.pow(10, 9)
        while(self.withinWorld(Bx, By)):
            if(self.checkCollision(self.getGridCoord(Bx, By))):
                dist2 = math.sqrt(math.pow(self.x - Bx, 2) + math.pow(self.y - By, 2))
                break
            Bx += Xb;
            By += Yb
            # print(Bx, By)

        # DEBUG
        # pygame.draw.line(self.game.win, (127,127,127), (self.x, self.y), (Bx, By))
        # pygame.draw.line(self.game.win, (0,0,255), (Bx, By), (Bx + Xb, By + Yb))

        self.r = min(dist1, dist2)
        self.endX += self.r * math.cos(self.angle)
        self.endY -= self.r * math.sin(self.angle)

    def test(self):
        testDistance = 50
        self.endX += testDistance * math.cos(self.angle)
        self.endY -= testDistance * math.sin(self.angle)

    def draw(self):
        pygame.draw.line(self.game.win, (255,0,0), (self.x, self.y), (self.endX, self.endY))


'''
==================================
ColorScheme Dice Roll Pictuanary
Created by: Yuliya Vaskiv
Date: 05/27/2021
...................................

The dice game that requires
user input on how many dices to roll.
The number on dice is randomly picked by app
and those number are presented on picture
in each round with different color

==============================================

Notes:
The app can still use modifications toward
the graphing each square that represent number on dice.
Because rows and columns are changing each time
depending on the roll for dice
05/27/2021
'''

import random
import turtle

def gameO():
    print('---------------------------')
    a = int (input ("Dice(s) to roll?: "))
    return a

def createList(diceRoll):
    l = []
    for i in range (diceRoll):
        r = random.randint(1, 6)
        l.append(r)
    return l

def drawSquares(t, l, pointA, pointB, rowCount, size, color):

    totalColumntLength = int ((len(l) / rowCount) + 1)

    column = int((len(l) / totalColumntLength))

    for j in range (len(l)):

        t.speed(0.00001)

        for p in range(1000):
            if j == column * p:
                if (pointA == 0 and pointB == 0):
                    pointA = pointA
                    pointB = pointB

                pointA = pointA + ( 6 * size) + size
                pointB = pointB + (column * size)

        for k in range(l[j]):

            xDistr = k * size + pointA
            yDistr = pointB - j * size

            t.color('grey')
            t.up()
            t.goto(xDistr , yDistr)
            t.down()

            t.fillcolor(color)
            t.begin_fill()

            for side in range(4):
                t.forward(size)
                t.right(90)
            t.end_fill()

'''==========================================================='''
print ("Welcome to Dice Representation")
print ("To stop the game press key 0")

colorList = ['black', 'red', 'blue', 'purple', 'yellow', 'green', 'orange',
             'black', 'red', 'blue', 'purple', 'yellow', 'green', 'orange',
             'black', 'red', 'blue', 'purple', 'yellow', 'green', 'orange']
tu = turtle.Turtle()

run = 0
flag = True
x = -600
y = 50
while flag == True:
    diceToRoll = gameO()
    if diceToRoll  == 0:
        flag = False
    else:
        rollList = (createList(diceToRoll))
        print(rollList)

        drawSquares(tu, rollList, x, y, 10, 30, colorList[run])
        run = run + 1


import RPi.GPIO as GPIO
GPIO.setmode( GPIO.BCM )
GPIO.setwarnings( 0 )

print( "input copy" )

led = 18
powerOn = 23
powerOff = 24

GPIO.setup( led, GPIO.OUT )
GPIO.setup( powerOn, GPIO.IN, pull_up_down=GPIO.PUD_DOWN )
GPIO.setup(powerOff, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
while True:
   if( GPIO.input(powerOn) ):
      GPIO.output( led, GPIO.HIGH )
   elif(GPIO.input(powerOff)):
      GPIO.output( led, GPIO.LOW )


import numpy as np
import pickle
import tensorflow as tf
from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Conv2D, ZeroPadding2D, Activation, Input, concatenate
from keras.layers.normalization import BatchNormalization
from keras.layers.pooling import MaxPooling2D
from keras.layers.merge import Concatenate
from keras.layers.core import Lambda, Flatten, Dense
from keras.initializers import glorot_uniform, RandomNormal
from keras.models import Model

from keras.engine.topology import Layer
from keras.regularizers import l2
from keras import backend as K

from batch_generator import BatchManager
def get_siamese_model(input_shape):
	left_input = Input(input_shape)
	right_input = Input(input_shape)

	model = Sequential()
	model.add(Conv2D(64, (10, 10), activation='relu', input_shape=input_shape, \
		 kernel_regularizer=l2(2e-4)))
	model.add(MaxPooling2D())
	model.add(Conv2D(128, (7, 7), activation='relu', \
		kernel_regularizer=l2(2e-4)))
	model.add(MaxPooling2D())
	model.add(Conv2D(128, (4, 4), activation='relu', \
		kernel_regularizer=l2(2e-4)))
	model.add(MaxPooling2D())
	model.add(Conv2D(256, (4, 4), activation='relu', \
		kernel_regularizer=l2(2e-4)))
	model.add(Flatten())
	model.add(Dense(4096, activation='sigmoid', kernel_regularizer=l2(1e-3) ))
	left_encoded = model(left_input)
	right_encoded = model(right_input)

	L1_layer = Lambda(lambda tensors: K.abs(tensors[0] - tensors[1]))
	L1_distance = L1_layer([left_encoded, right_encoded])

	prediction = Dense(1, activation='sigmoid')(L1_distance)
	siamese_network = Model(inputs=[left_input, right_input], output=prediction)
	return siamese_network

def test_oneshot_once(model, validation_batch, N, verbose=True):
	pairs, targets = validation_batch
	if targets.shape[0] < N:
		raise ValueError('supported images are : {} which is less than \
			Classification Way: {}'.format(pairs[1].shape, N))
# 	if verbose:
# 		print('Evaluating model on validation set with random {} way one-shot learning tasks...'.format(N))
	probabilities = model.predict(pairs)
	if np.argmax(probabilities) == np.argmax(targets):
		return True
	else: return False

def test_model(model, batch_manager, N, epochs, batch_size, verbose=True):
	true_positive = 0
	for i in range(epochs):
# 		print('Evaluating model on random vevaluation set of batch_size {}, in {} way classification'.format( \
# 			batch_size, N))
		validation_batch = batch_manager.get_test_batch(batch_size=batch_size)
		if test_oneshot_once(model, validation_batch, N) is True:
			true_positive += 1
		if verbose: print('[evaluating] : Accuracy: {}%  - {} way one shot learning'.format((100 * true_positive)/(i+1), N))
	percent = (100 * true_positive)/epochs
	print('Accuracy: {}%  - {} way one shot learning'.format(percent, N))
	return percent

if __name__=='__main__':
	siamese = get_siamese_model((105, 105, 1))
	siamese.summary()
	optimizer = Adam(lr = 0.00006)
	siamese.compile(loss="binary_crossentropy", optimizer=optimizer)

	training_path = './../fellowship.ai/omniglot/python/training.pkl'
	evaluation_path = './../fellowship.ai/omniglot/python/evaluating.pkl'
	with open(training_path, 'rb') as readFile:
		(Xtrain, _, train_classes) = pickle.load(readFile)
	print('training alphabets: ')
	print(list(train_classes.keys()))
	with open(evaluation_path, 'rb') as readFile:
		(Xeval, _, eval_classes) = pickle.load(readFile)
	print('evaluating alphabets:')
	print(list(eval_classes.keys()))


n = int(input())

visited = set()
primes = set()

for i in range(2, n+1):

    if i in visited:
        continue
    primes.add(i)

    k = i
    while k <= n:
        visited.add(k)
        k += i

def convert(num):

    target = list(map(int, list(str(num))))
    return sum([i * i for i in target])

def determine(num, visited):
    global targets, others

    if num in visited:
        others.update(visited)
        return
    visited.add(num)

    converted = convert(num)
    if converted == 1:
        targets.update(visited)
        return
    determine(converted, visited)

targets = set()
others = set()
for num in primes:
    start = num
    if num not in targets or num not in others:
        determine(num, set())

answers = sorted(list(targets&primes))

for answer in answers:
    print(answer)


import fastapi
import uvicorn

from flair.data import Sentence
from flair.models import SequenceTagger

from pydantic import BaseModel

model = SequenceTagger.load('flair/ner-english-ontonotes-large')

app = fastapi.FastAPI()

class Document(BaseModel):
    body: str

class DocumentResponse(BaseModel):
    classes: list

from typing import Dict, List

@app.post("/")
async def document_classification(document: Document):
    response = {}
    sentence = Sentence(document.body)
    model.predict(sentence, return_probabilities_for_all_classes=True)

    taglist = []

    for entity in sentence.get_spans('ner'):
        pair = {"tag": entity.tag, "text":entity.text}
        taglist.append(pair)

    response["classes"] = taglist

    return response

if __name__ == "__main__":
    uvicorn.run(
        "test_main:app",
        host="0.0.0.0",
        port=8083,
        reload=False,
    )


import pytest

import numpy.testing as npt

import numpy as np
from ..rvs import NormalRV

class TestNormalRVs:
    def test_NormalRV(self):
        with pytest.raises(ValueError):
            # Testing mismatched dimensions, note M acts on the right
            mean = np.array([0, 1])
            M = np.array([[0, 1, 2], [1, 1, -1]])
            NormalRV(mean, M)

        mean = np.array([0, 0, 1])
        M = np.array([[0, 1, 2], [1, 1, -1]])
        T = NormalRV(mean, M)
        assert T.k == 2
        assert T.m == 3
        npt.assert_allclose(T.M, M)
        npt.assert_allclose(T.mean, mean)
        npt.assert_allclose(M.T.dot(M), T.covar)

        Y = T.U_sample(10, np.random.RandomState(123))
        assert Y.shape == (10, T.k)

        Y = T.sample(10)
        assert Y.shape == (10, T.m)

        X = mean[None, :]
        n = T.m
        log_PX = T.log_prob_X(np.eye(T.m), np.eye(n), X)
        assert log_PX.shape == (1,)
        Y = T.mean_given_X()
        npt.assert_allclose(Y, X)

        qZZ, qZX = T.moments_marg_over_X(log_PX, X)
        assert qZZ.shape == (T.m, T.m)
        assert qZX.shape == (T.m, n)

    def test_NormalRV_estimates(self):
        mean = np.array([0, 0, 1])
        M = np.array([[0, 1, 2], [1, 1, -1]])
        T = NormalRV(mean, M)
        rnd = np.random.RandomState(123)
        est_mean, est_cov = T.estimated_mean_and_covariance(10000, rnd=rnd)

        npt.assert_allclose(est_mean, T.mean, atol=0.1)
        npt.assert_allclose(est_cov, T.covar, atol=0.1)


"""empty message

Revision ID: 63dc4ee8748a
Revises: 2d8cab9a28c2
Create Date: 2020-05-05 00:26:29.690250

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '63dc4ee8748a'
down_revision = '2d8cab9a28c2'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('user', sa.Column('master_id', sa.Integer(), nullable=True))
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('user', 'master_id')
    # ### end Alembic commands ###


import h5py
import numpy as np
import gcsfs
import pickle

def split_data(array, res):
    for i in range(25):
        temp = np.dsplit(array, np.array([i, i + 13, i + 25]))
        res['IN'].append(temp[1])
        res['OUT'].append(temp[2])

def run(pklname):
    # DATA_PATH = file

    FS = gcsfs.GCSFileSystem(project="Assignment1",
                            token="./hardy-portal-318606-3c8e02bd3a5d.json")

    # print(end)
    # with FS.open(f'gs://assignment1-data/data/vil/2018/{DATA_PATH}.h5', 'rb') as data_file:
    #     data = h5py.File(data_file, 'r')
    #     s = np.s_[0:end:1]
    #     vil = data['vil'][s]

    with FS.open(f'gs://assignment1-data/res/pkl/{pklname}', 'rb') as pklRes:
        vil = pickle.load(pklRes)

    res = {'IN':[],"OUT":[]}
    # for i in vil:
    #     split_data(i, res)
    split_data(vil, res)

    res["IN"] = np.array(res["IN"])
    res["OUT"] = np.array(res["OUT"])

    res["IN"] = (res["IN"].astype(np.float32) - 33.44) / 47.54
    res["OUT"] = (res["OUT"].astype(np.float32) - 33.44) / 47.54

    return res["IN"], res["OUT"]

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(description='Run pipeline on the cloud')
    parser.add_argument('-f','--file', help='File Path', default='SEVIR_VIL_STORMEVENTS_2018_0101_0630')
    parser.add_argument('-e','--end', help='End', default=1)
    args = vars(parser.parse_args())

    IN, OUT = run(file=args['file'], end=int(args['end']))

    with h5py.File("data.h5", 'w') as data:
       data['IN'] = IN
       data['OUT'] = OUT

   # with h5py.File("data.h5", 'r') as data:
   #      IN = data["IN"]
   #      OUT = data["OUT"]
    print("The shape of IN: " + str(IN.shape))
    print("The shape of OUT: " + str(OUT.shape))


import sys

def part1(data):
    total = 0
    groups = (d.split(",") for d in data)
    groups = [[[int(i) for i in e.split("-")] for e in g] for g in groups]
    for a, b in groups:
        if a[0] <= b[0] and a[1] >= b[1]:
            total += 1
        elif b[0] <= a[0] and b[1] >= a[1]:
            total += 1

    return total

def part2(data):
    total = 0
    groups = (d.split(",") for d in data)
    groups = [[[int(i) for i in e.split("-")] for e in g] for g in groups]
    for a, b in groups:
        if b[0] <= a[0] <= b[1] or a[0] <= b[0] <= a[1]:
            total += 1

    return total

if __name__ == "__main__":
    d = sys.stdin.read().split("\n")
    print("part 1:", part1(d))
    print("part 2:", part2(d))


import sys

N = int(input())
balls = []  # 각각 (공번호, 색, 크기)를 저장
for i in range(1, N+1):
    color, size = map(int, sys.stdin.readline().split())
    balls.append((i, color, size))

balls.sort(key=lambda x : x[2])  # 크기를 기준으로 정렬

total_sum = 0  # 현재 공보다 크기가 작은 공들의 크기 총합
color_sum = [0 for i in range(N+1)]  # (idx = 색상) 현재 공보다 크기가 작은 같은 색 공들의 크기 총합
answer = [0 for i in range(N+1)]  # (idx = 공번호) 전체 공 점수 - 같은 색 공 점수

j = 0
for i in range(N):
    while balls[j][2] < balls[i][2]:
        total_sum += balls[j][2]
        color_sum[balls[j][1]] += balls[j][2]
        j += 1
    answer[balls[i][0]] = total_sum - color_sum[balls[i][1]]

for i in range(1, N+1):
    print(answer[i])


'''
갖고 있는 송전탑 개수 차이의 최소값
union find 가능?
'''

def find_set(x, parents):
    if parents[x] == x:
        return x

    parents[x] = find_set(parents[x], parents)
    return parents[x]

def union(x, y, parents):
    x = find_set(x, parents)
    y = find_set(y, parents)

    if x == y:
        return

    if x < y:
        parents[y] = x
    else:
        parents[x] = y

def solution(n, wires):
    answer = 0
    min_v = int(1e9)
    # 어떤 거 제외하실?
    for i in range(len(wires)):
        parents = [i for i in range(n+1)]
        for j in range(len(wires)):
            if j == i:  # i번 째 wires 제외
                continue
            f = wires[j][0]
            t = wires[j][1]
            union(f, t, parents)

        # 두 개의 집합
        first = 0
        second = 0
        temp = 0

        for j in range(1,n+1):
            # wires 배열 순서에 따라 부모 찾기가 잘 안되는 경우도 생겨서 다시 해줘야 함
            find_set(j,parents)
            if temp == 0:
                temp = parents[j]
            if parents[j] == temp:
                first += 1
            else:
                second += 1

        # 차이?
        answer = abs(first - second)
        if min_v > answer:
            min_v = answer

    return min_v


import os
import sys

sys.path.insert(0, os.path.abspath("../"))

from tokenization_kbalbert import KbAlbertCharTokenizer
from transformers import AutoModelForSequenceClassification, pipeline

kb_albert_model_path = "../kb-albert-char-base-v1"
model_output_path = "nsmc_outputs"
model = AutoModelForSequenceClassification.from_pretrained(model_output_path)
tokenizer = KbAlbertCharTokenizer.from_pretrained(kb_albert_model_path)

nsmc_classifier = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer, framework="pt")

reviews = ["이 영화 최악이었어!", "볼거리가 많은 내 인생 영화 ㅎㅎ"]
results = nsmc_classifier(reviews)
for result in results:
    print(f"label: {result['label']}, with score: {round(result['score'], 4)}")


#!/usr/bin/evn python3

def constant_f(arg):
    """
    Функции-константа:

    Написать функцию, принимающую аргумент, возвращающая
    новую функцию без аргументов, которая возрващает этот аргумент

    >>> f = constant_f(1)
    >>> val = f()
    >>> val
    1
    """

    def n():
        return arg

    return n

def argdict(*args, **kwargs):
    """
    Словарь аргументов:

    Написать функцию, которая возвращает словарь из аргументов
    для позиционных аргументов ключ-индекс позиции, а значения -
    сами аргументы, а для именнованных - имя аргумента и его значение

    >>> argdict(0, 1, 2, name = "Name")
    {0: 0, 1: 1, 2: 2, name: "Name"}
    """
    dict1 = {}
    i = 0
    for n in args:
        dict1[i] = n
        i += 1

    for k, v in kwargs.items():
        dict1[k] = v
    return dict1

def filter_by_key(d, filtering):
    """
    Фильтрация по предикату ключа

    Написать функцию, которая на вход получает словарь и функцию-предикат от одного
    аргументь. Функция должна возвращать новый словарь с парами ключ-значения
    из входного словаря, но только в том случае, если ключ у этой пары удовлетворяет
    функции-предикату (то есть, когда filtering(key) == True)

    Пример: если filtering=lambda x: isinstance(x, int) and x % 2 == 0,
    тогда в словаре должны остаться только пары с ключами-чётными числами

    >>> filtering = lambda x: isinstance(x, int) and x % 2 0
    >>> filter_by_key({'a': 2, 5: 3, 't': 5, 10: 'Yes', 20: True}, filtering)
    {10: 'Yes', 20: 'True'}
    """
    d1 = {}
    for key, value in d.items():

        if isinstance(key, int) and key % 2 == 0:
            d1[key] = value
    return d1

def argmax_dict(d):
    """
    Ключ наибольшего значения

    Написать функцию, которая на вход получает словарь, а на выход возврашает
    ключ, для которого в словаре наибольшее значение:

    Пример:
    >>> argmax_dict({0: 2, 1: 5, 2: 10})
    2
    >>> argmax_dict9({0: 2, 1: 20, 3: 10})
    1
    """

    return not_implemented

def compose(*funcs):
    """
    Композиция функций

    Написать функцию, которая принимает набор других фунций от одного аргумента
    и возвращающую новыю функцию, которая является компоизицией этих
    функций. То есть для двух функций f(y) и g(x) их комопзиция
    f(g(x)): результат выполнения f для аргумента, которым является g(x)

    Пример:
    >>> plus_1 = lambda x: x + 1
    >>> mult_2 = lambda x: x * 2
    >>> f = compose(plus_1, mult_2)
    >>> f(1)
    3
    """
    return not_implemented

# =====================================================
# testing stuff
from funtests import CasesTestGen, not_implemented  # noqa: E402
import unittest  # noqa: E402

class FilterByKeyTest(CasesTestGen):
    def test_filter_by_key(self):
        cases = (
            (({i: i for i in range(10)}, lambda x: x % 2 == 0), {i: i for i in range(0, 10, 2)}),
            ((dict(zip("OnlyUpperShouldStay", range(50))), str.isupper), {'O': 0, 'U': 4, 'S': 15}),
        )
        self.execute_equal_subcases(filter_by_key, cases)

class ArgmaxTest(CasesTestGen):
    def test_argmax_dict(self):
        cases = (
            (({0: 2, 1: 5, 2: 10},), 2),
            (({0: 2, 1: 20, 3: 10},), 1))

        self.execute_equal_subcases(argmax_dict, cases)

class ArgDictTest(CasesTestGen):
    def test_argdict(self):
        cases = (
            ((0, 1, 2), {"name": "Name", "value": "Value"}, {0: 0, 1: 1, 2: 2, "name": "Name", "value": "Value"}),
            ((0, 1, 2), {}, {0: 0, 1: 1, 2: 2}),
            ((10, 0), {}, {0: 10, 1: 0}),
        )
        for case in cases:
            with self.subTest(case=case):
                args = case[0]
                kwargs = case[1]
                expected = case[2]
                val = argdict(*args, **kwargs)
                if val == not_implemented:
                    self.skipTest('не реализован')
                self.assertEqual(argdict(*args, **kwargs), expected)

class ComposeTest(CasesTestGen):
    def test_compose(self):
        cases = (
            ((lambda x: x + 1, lambda x: x * 2), (1,), 3),
            ((lambda x: x + 1, lambda x: x + 2, lambda x: x + 3), (1,), 7),
        )
        self.execute_genfunction_subcases(compose, cases)

class ConstantFTest(CasesTestGen):
    def test_constant_f(self):
        cases = (
            ((0,), tuple(), 0),
            (("abc",), tuple(), "abc"),
            (([1, 2, 3],), tuple(), [1, 2, 3]),
        )
        self.execute_genfunction_subcases(constant_f, cases)

if __name__ == '__main__':
    unittest.main(verbosity=2)


# -*- encoding: utf-8 -*-
from __future__ import unicode_literals

import struct

class Definition(object):

    _definition = tuple()
    _struct_rule = ''
    _struct_size = None
    _names = []

    def __init__(self, data):
        self.data = data

    @classmethod
    def init_cache(cls):
        names = []
        rules = []

        for name, rule in cls._definition:
            names.append(name)
            rules.append(rule)

        cls._names = names
        rule = '<' + ''.join(rules)
        cls._struct_rule = rule
        cls._struct_size = struct.calcsize(rule)

    @classmethod
    def _unpack(cls, raw):
        unpacked = struct.unpack(cls._struct_rule, raw)
        return dict(zip(cls._names, unpacked))

    @classmethod
    def from_file(cls, fileobj):
        data = fileobj.read(cls._struct_size)
        return cls(cls._unpack(data))