diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dcbfb0..207f3fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,3 +92,4 @@ jobs: - uses: jamescurtin/isort-action@master with: requirementsFiles: "requirements.txt" + configuration: "--check-only --diff --trailing-comma --multi-line=3" diff --git a/pythonium/game_modes/__init__.py b/pythonium/game_modes/__init__.py index 98c209d..35a82c2 100644 --- a/pythonium/game_modes/__init__.py +++ b/pythonium/game_modes/__init__.py @@ -1,7 +1,9 @@ +from pythonium.game_modes.asteroid.game_mode import AsteroidsMode from pythonium.game_modes.classic_mode import ClassicMode from pythonium.game_modes.sandbox_mode import SandboxGameMode GAME_MODES = { 'classic': ClassicMode, 'sandbox': SandboxGameMode, + 'asteroid': AsteroidsMode, } diff --git a/pythonium/game_modes/asteroid/__init__.py b/pythonium/game_modes/asteroid/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pythonium/game_modes/asteroid/game_mode.py b/pythonium/game_modes/asteroid/game_mode.py new file mode 100644 index 0000000..2d5b96c --- /dev/null +++ b/pythonium/game_modes/asteroid/game_mode.py @@ -0,0 +1,73 @@ +from pythonium import ShipType, Transfer, Ship, Galaxy +from pythonium.core import Position +from pythonium.game_modes.classic_mode import ClassicMode +from pythonium.game_modes.asteroid.rules import get_asteroids, DestroyAsteroidsRule, DestroyShipRule, \ + CreateAsteroidsRule, MoveAsteroidsRule +from pythonium.rules.ship import ShipMoveRule + +SHIP_SPEED = 5 +SHIP_TYPE = ShipType( + name='traveler', + speed=SHIP_SPEED, + cost=Transfer(), + max_cargo=0, + max_mc=0, + attack=0, +) + + +class AsteroidsMode(ClassicMode): + ship_speed = SHIP_SPEED + ship_type = SHIP_TYPE + rules = [ + DestroyAsteroidsRule, + CreateAsteroidsRule, + ShipMoveRule, + MoveAsteroidsRule, + DestroyShipRule, + ] + + def __init__(self, max_turn=300, *args, **kwargs): + super().__init__( + max_turn=max_turn, + *args, + **kwargs + ) + + def build_galaxy(self, name, players): + ships = [] + ship_position = (self.map_size[0] / 2, self.map_size[1]) + for player in players: + ship = Ship( + player=player.name, + type=self.ship_type, + position=Position(ship_position), + max_cargo=self.ship_type.max_cargo, + max_mc=self.ship_type.max_mc, + attack=self.ship_type.attack, + speed=self.ship_type.speed, + ) + ships.append(ship) + return Galaxy(name=name, size=self.map_size, things=ships) + + def has_ended(self, galaxy, t): + if t == self.max_turn: + return True + + if not galaxy.known_races: + return True + + return False + + def galaxy_for_player(self, galaxy, player): + return galaxy + + def get_context(self, galaxy, players, turn): + asteroids = get_asteroids(galaxy) + return { + 'asteroids': len(asteroids), + 'score': [ + {'ships': 1} + for _ in galaxy.known_races + ] + } diff --git a/pythonium/game_modes/asteroid/player.py b/pythonium/game_modes/asteroid/player.py new file mode 100644 index 0000000..f0ea38a --- /dev/null +++ b/pythonium/game_modes/asteroid/player.py @@ -0,0 +1,18 @@ +from pythonium import Galaxy +from pythonium.core import Position +from pythonium.player import AbstractPlayer + + +class Player(AbstractPlayer): + name = 'explorer' + + def next_turn(self, galaxy: Galaxy, context: dict) -> Galaxy: + ships = galaxy.get_player_ships(self.name) + + for ship in ships: + ship.target = Position(( + ship.position[0], + 0, + )) + + return galaxy diff --git a/pythonium/game_modes/asteroid/rules.py b/pythonium/game_modes/asteroid/rules.py new file mode 100644 index 0000000..22a5f7a --- /dev/null +++ b/pythonium/game_modes/asteroid/rules.py @@ -0,0 +1,76 @@ +import random + +from pythonium.core import Position +from pythonium.game_modes.asteroid.things import Asteroid +from pythonium.rules.core import GalaxyRule + + +def get_asteroids(galaxy): + return [a for a in galaxy.things if isinstance(a, Asteroid)] + + +class DestroyAsteroidsRule(GalaxyRule): + + def execute(self) -> None: + to_remove = [] + asteroids = get_asteroids(self.galaxy) + for asteroid in asteroids: + if asteroid.position[0] > self.galaxy.size[0]: + to_remove.append(asteroid) + self.galaxy.things = [ + thing for thing in self.galaxy.things + if thing not in to_remove + ] + + +class DestroyShipRule(GalaxyRule): + + def execute(self) -> None: + asteroids = get_asteroids(self.galaxy) + to_destroy = [] + for ship in self.galaxy.ships: + nearby_asteroids = [ + a for a in asteroids + if self.galaxy.compute_distance( + ship.position, + a.position, + ) < 20 + ] + if nearby_asteroids: + to_destroy.append(ship) + self.galaxy.things = [ + thing for thing in self.galaxy.things + if thing not in to_destroy + ] + + +class CreateAsteroidsRule(GalaxyRule): + new_asteroid_period = 5 + + def execute(self) -> None: + asteroids = get_asteroids(self.galaxy) + nominal_asteroids = int(self.galaxy.turn / self.new_asteroid_period) + real_asteroids = len(asteroids) + pending_asteroids = nominal_asteroids - real_asteroids + for _ in range(pending_asteroids): + self.galaxy.things.append( + Asteroid(position=self._get_random_position()) + ) + + def _get_random_position(self) -> Position: + return Position(( + self.galaxy.size[0], + int(random.random() * self.galaxy.size[1]) + )) + + +class MoveAsteroidsRule(GalaxyRule): + + def execute(self) -> None: + asteroids = get_asteroids(self.galaxy) + for asteroid in asteroids: + new_position = Position(( + asteroid.position[0] - 10, + asteroid.position[1] + )) + asteroid.position = new_position diff --git a/pythonium/game_modes/asteroid/things.py b/pythonium/game_modes/asteroid/things.py new file mode 100644 index 0000000..b224554 --- /dev/null +++ b/pythonium/game_modes/asteroid/things.py @@ -0,0 +1,18 @@ +import math +import random +from typing import Tuple + +import attr + +from pythonium.core import StellarThing + + +def random_direction(): + angle = random.random() * math.pi + return math.cos(angle), math.sin(angle) + + +@attr.s(auto_attribs=True, repr=False) +class Asteroid(StellarThing): + thing_type = "planet" + direction: Tuple[float, float] = attr.ib(factory=random_direction) diff --git a/pythonium/game_modes/classic_mode.py b/pythonium/game_modes/classic_mode.py index 5324463..dc2f13a 100644 --- a/pythonium/game_modes/classic_mode.py +++ b/pythonium/game_modes/classic_mode.py @@ -44,7 +44,16 @@ class ClassicMode(GameMode): - # Define los atributos de las ships que se pueden construir. + rules = [ + ShipTransferRule, + PlanetBuildMinesRule, + PlanetSetTaxesRule, + ShipMoveRule, + ResolveShipsConflicts, + ResolvePlanetsConflicts, + PlanetBuildShipRule, + ProduceResources, + ] def __init__( self, @@ -89,16 +98,6 @@ def __init__( self.max_turn = max_turn self.max_ships = max_ships self.winner = None - self.rules = [ - ShipTransferRule, - PlanetBuildMinesRule, - PlanetSetTaxesRule, - ShipMoveRule, - ResolveShipsConflicts, - ResolvePlanetsConflicts, - PlanetBuildShipRule, - ProduceResources, - ] def build_galaxy(self, name, players): """