mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Doctrine load from YAML (#3291)
This PR refactors the Doctrine class to load from YAML files in the resources folder instead of being hardcoded as a step towards making doctrines moddable (Issue #829). I haven't added anything to the changelog as a couple of things should get cleaned up first: - As far as I can tell, the flags in the Doctrine class (cap, cas, sead etc.) aren't used anywhere. Need to test further, and if they're truly not used, will remove them. - Probably need to update the Wiki
This commit is contained in:
parent
a213215c3f
commit
4631ee0d74
@ -1,3 +1,9 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import yaml
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
@ -15,6 +21,16 @@ class GroundUnitProcurementRatios:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data: dict[str, float]) -> GroundUnitProcurementRatios:
|
||||||
|
unit_class_enum_from_name = {unit.value: unit for unit in UnitClass}
|
||||||
|
r = {}
|
||||||
|
for unit_class in data:
|
||||||
|
if unit_class not in unit_class_enum_from_name:
|
||||||
|
raise ValueError(f"Could not find unit type {unit_class}")
|
||||||
|
r[unit_class_enum_from_name[unit_class]] = float(data[unit_class])
|
||||||
|
return GroundUnitProcurementRatios(r)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Doctrine:
|
class Doctrine:
|
||||||
@ -79,122 +95,78 @@ class Doctrine:
|
|||||||
|
|
||||||
ground_unit_procurement_ratios: GroundUnitProcurementRatios
|
ground_unit_procurement_ratios: GroundUnitProcurementRatios
|
||||||
|
|
||||||
|
_by_name: ClassVar[dict[str, Doctrine]] = {}
|
||||||
|
_loaded: ClassVar[bool] = False
|
||||||
|
|
||||||
MODERN_DOCTRINE = Doctrine(
|
@classmethod
|
||||||
"modern",
|
def register(cls, doctrine: Doctrine) -> None:
|
||||||
cap=True,
|
if doctrine.name in cls._by_name:
|
||||||
cas=True,
|
duplicate = cls._by_name[doctrine.name]
|
||||||
sead=True,
|
raise ValueError(f"Doctrine {doctrine.name} is already loaded")
|
||||||
strike=True,
|
cls._by_name[doctrine.name] = doctrine
|
||||||
antiship=True,
|
|
||||||
rendezvous_altitude=feet(25000),
|
@classmethod
|
||||||
hold_distance=nautical_miles(25),
|
def named(cls, name: str) -> Doctrine:
|
||||||
push_distance=nautical_miles(20),
|
if not cls._loaded:
|
||||||
join_distance=nautical_miles(20),
|
cls.load_all()
|
||||||
max_ingress_distance=nautical_miles(45),
|
return cls._by_name[name]
|
||||||
min_ingress_distance=nautical_miles(10),
|
|
||||||
ingress_altitude=feet(20000),
|
@classmethod
|
||||||
min_patrol_altitude=feet(15000),
|
def all_doctrines(cls) -> list[Doctrine]:
|
||||||
max_patrol_altitude=feet(33000),
|
if not cls._loaded:
|
||||||
pattern_altitude=feet(5000),
|
cls.load_all()
|
||||||
cap_duration=timedelta(minutes=30),
|
return list(cls._by_name.values())
|
||||||
cap_min_track_length=nautical_miles(15),
|
|
||||||
cap_max_track_length=nautical_miles(40),
|
@classmethod
|
||||||
cap_min_distance_from_cp=nautical_miles(10),
|
def load_all(cls) -> None:
|
||||||
cap_max_distance_from_cp=nautical_miles(40),
|
if cls._loaded:
|
||||||
cap_engagement_range=nautical_miles(50),
|
return
|
||||||
cas_duration=timedelta(minutes=30),
|
for doctrine_file_path in Path("resources/doctrines").glob("**/*.yaml"):
|
||||||
sweep_distance=nautical_miles(60),
|
with doctrine_file_path.open(encoding="utf8") as doctrine_file:
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
data = yaml.safe_load(doctrine_file)
|
||||||
{
|
cls.register(
|
||||||
UnitClass.TANK: 3,
|
Doctrine(
|
||||||
UnitClass.ATGM: 2,
|
name=data["name"],
|
||||||
UnitClass.APC: 2,
|
cap=data["cap"],
|
||||||
UnitClass.IFV: 3,
|
cas=data["cas"],
|
||||||
UnitClass.ARTILLERY: 1,
|
sead=data["sead"],
|
||||||
UnitClass.SHORAD: 2,
|
strike=data["strike"],
|
||||||
UnitClass.RECON: 1,
|
antiship=data["antiship"],
|
||||||
}
|
rendezvous_altitude=feet(data["rendezvous_altitude_ft_msl"]),
|
||||||
|
hold_distance=nautical_miles(data["hold_distance_nm"]),
|
||||||
|
push_distance=nautical_miles(data["push_distance_nm"]),
|
||||||
|
join_distance=nautical_miles(data["join_distance_nm"]),
|
||||||
|
max_ingress_distance=nautical_miles(
|
||||||
|
data["max_ingress_distance_nm"]
|
||||||
|
),
|
||||||
|
min_ingress_distance=nautical_miles(
|
||||||
|
data["min_ingress_distance_nm"]
|
||||||
|
),
|
||||||
|
ingress_altitude=feet(data["ingress_altitude_ft_msl"]),
|
||||||
|
min_patrol_altitude=feet(data["min_patrol_altitude_ft_msl"]),
|
||||||
|
max_patrol_altitude=feet(data["max_patrol_altitude_ft_msl"]),
|
||||||
|
pattern_altitude=feet(data["pattern_altitude_ft_msl"]),
|
||||||
|
cap_duration=timedelta(minutes=data["cap_duration_minutes"]),
|
||||||
|
cap_min_track_length=nautical_miles(
|
||||||
|
data["cap_min_track_length_nm"]
|
||||||
|
),
|
||||||
|
cap_max_track_length=nautical_miles(
|
||||||
|
data["cap_max_track_length_nm"]
|
||||||
|
),
|
||||||
|
cap_min_distance_from_cp=nautical_miles(
|
||||||
|
data["cap_min_distance_from_cp_nm"]
|
||||||
|
),
|
||||||
|
cap_max_distance_from_cp=nautical_miles(
|
||||||
|
data["cap_max_distance_from_cp_nm"]
|
||||||
|
),
|
||||||
|
cap_engagement_range=nautical_miles(
|
||||||
|
data["cap_engagement_range_nm"]
|
||||||
|
),
|
||||||
|
cas_duration=timedelta(minutes=data["cas_duration_minutes"]),
|
||||||
|
sweep_distance=nautical_miles(data["sweep_distance_nm"]),
|
||||||
|
ground_unit_procurement_ratios=GroundUnitProcurementRatios.from_dict(
|
||||||
|
data["ground_unit_procurement_ratios"]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
COLDWAR_DOCTRINE = Doctrine(
|
|
||||||
name="coldwar",
|
|
||||||
cap=True,
|
|
||||||
cas=True,
|
|
||||||
sead=True,
|
|
||||||
strike=True,
|
|
||||||
antiship=True,
|
|
||||||
rendezvous_altitude=feet(22000),
|
|
||||||
hold_distance=nautical_miles(15),
|
|
||||||
push_distance=nautical_miles(10),
|
|
||||||
join_distance=nautical_miles(10),
|
|
||||||
max_ingress_distance=nautical_miles(30),
|
|
||||||
min_ingress_distance=nautical_miles(10),
|
|
||||||
ingress_altitude=feet(18000),
|
|
||||||
min_patrol_altitude=feet(10000),
|
|
||||||
max_patrol_altitude=feet(24000),
|
|
||||||
pattern_altitude=feet(5000),
|
|
||||||
cap_duration=timedelta(minutes=30),
|
|
||||||
cap_min_track_length=nautical_miles(12),
|
|
||||||
cap_max_track_length=nautical_miles(24),
|
|
||||||
cap_min_distance_from_cp=nautical_miles(8),
|
|
||||||
cap_max_distance_from_cp=nautical_miles(25),
|
|
||||||
cap_engagement_range=nautical_miles(35),
|
|
||||||
cas_duration=timedelta(minutes=30),
|
|
||||||
sweep_distance=nautical_miles(40),
|
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
|
||||||
{
|
|
||||||
UnitClass.TANK: 4,
|
|
||||||
UnitClass.ATGM: 2,
|
|
||||||
UnitClass.APC: 3,
|
|
||||||
UnitClass.IFV: 2,
|
|
||||||
UnitClass.ARTILLERY: 1,
|
|
||||||
UnitClass.SHORAD: 2,
|
|
||||||
UnitClass.RECON: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
cls._loaded = True
|
||||||
WWII_DOCTRINE = Doctrine(
|
|
||||||
name="ww2",
|
|
||||||
cap=True,
|
|
||||||
cas=True,
|
|
||||||
sead=False,
|
|
||||||
strike=True,
|
|
||||||
antiship=True,
|
|
||||||
hold_distance=nautical_miles(10),
|
|
||||||
push_distance=nautical_miles(5),
|
|
||||||
join_distance=nautical_miles(5),
|
|
||||||
rendezvous_altitude=feet(10000),
|
|
||||||
max_ingress_distance=nautical_miles(7),
|
|
||||||
min_ingress_distance=nautical_miles(5),
|
|
||||||
ingress_altitude=feet(8000),
|
|
||||||
min_patrol_altitude=feet(4000),
|
|
||||||
max_patrol_altitude=feet(15000),
|
|
||||||
pattern_altitude=feet(5000),
|
|
||||||
cap_duration=timedelta(minutes=30),
|
|
||||||
cap_min_track_length=nautical_miles(8),
|
|
||||||
cap_max_track_length=nautical_miles(18),
|
|
||||||
cap_min_distance_from_cp=nautical_miles(0),
|
|
||||||
cap_max_distance_from_cp=nautical_miles(5),
|
|
||||||
cap_engagement_range=nautical_miles(20),
|
|
||||||
cas_duration=timedelta(minutes=30),
|
|
||||||
sweep_distance=nautical_miles(10),
|
|
||||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios(
|
|
||||||
{
|
|
||||||
UnitClass.TANK: 3,
|
|
||||||
UnitClass.ATGM: 3,
|
|
||||||
UnitClass.APC: 3,
|
|
||||||
UnitClass.ARTILLERY: 1,
|
|
||||||
UnitClass.SHORAD: 3,
|
|
||||||
UnitClass.RECON: 1,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
ALL_DOCTRINES = [
|
|
||||||
COLDWAR_DOCTRINE,
|
|
||||||
MODERN_DOCTRINE,
|
|
||||||
WWII_DOCTRINE,
|
|
||||||
]
|
|
||||||
|
|||||||
@ -19,12 +19,7 @@ from game.data.building_data import (
|
|||||||
WW2_FREE,
|
WW2_FREE,
|
||||||
WW2_GERMANY_BUILDINGS,
|
WW2_GERMANY_BUILDINGS,
|
||||||
)
|
)
|
||||||
from game.data.doctrine import (
|
from game.data.doctrine import Doctrine
|
||||||
COLDWAR_DOCTRINE,
|
|
||||||
Doctrine,
|
|
||||||
MODERN_DOCTRINE,
|
|
||||||
WWII_DOCTRINE,
|
|
||||||
)
|
|
||||||
from game.data.groups import GroupRole
|
from game.data.groups import GroupRole
|
||||||
from game.data.units import UnitClass
|
from game.data.units import UnitClass
|
||||||
from game.dcs.aircrafttype import AircraftType
|
from game.dcs.aircrafttype import AircraftType
|
||||||
@ -106,7 +101,7 @@ class Faction:
|
|||||||
jtac_unit: Optional[AircraftType] = field(default=None)
|
jtac_unit: Optional[AircraftType] = field(default=None)
|
||||||
|
|
||||||
# doctrine
|
# doctrine
|
||||||
doctrine: Doctrine = field(default=MODERN_DOCTRINE)
|
doctrine: Doctrine = field(default=Doctrine.named("modern"))
|
||||||
|
|
||||||
# List of available building layouts for this faction
|
# List of available building layouts for this faction
|
||||||
building_set: List[str] = field(default_factory=list)
|
building_set: List[str] = field(default_factory=list)
|
||||||
@ -238,14 +233,7 @@ class Faction:
|
|||||||
|
|
||||||
# Load doctrine
|
# Load doctrine
|
||||||
doctrine = json.get("doctrine", "modern")
|
doctrine = json.get("doctrine", "modern")
|
||||||
if doctrine == "modern":
|
faction.doctrine = Doctrine.named(doctrine)
|
||||||
faction.doctrine = MODERN_DOCTRINE
|
|
||||||
elif doctrine == "coldwar":
|
|
||||||
faction.doctrine = COLDWAR_DOCTRINE
|
|
||||||
elif doctrine == "ww2":
|
|
||||||
faction.doctrine = WWII_DOCTRINE
|
|
||||||
else:
|
|
||||||
faction.doctrine = MODERN_DOCTRINE
|
|
||||||
|
|
||||||
# Load the building set
|
# Load the building set
|
||||||
faction.building_set = []
|
faction.building_set = []
|
||||||
|
|||||||
@ -11,17 +11,14 @@ from shapely import transform
|
|||||||
from shapely.geometry import shape
|
from shapely.geometry import shape
|
||||||
from shapely.geometry.base import BaseGeometry
|
from shapely.geometry.base import BaseGeometry
|
||||||
|
|
||||||
from game.data.doctrine import Doctrine, ALL_DOCTRINES
|
from game.data.doctrine import Doctrine
|
||||||
from .ipsolver import IpSolver
|
from .ipsolver import IpSolver
|
||||||
from .waypointsolver import WaypointSolver
|
from .waypointsolver import WaypointSolver
|
||||||
from ..theater.theaterloader import TERRAINS_BY_NAME
|
from ..theater.theaterloader import TERRAINS_BY_NAME
|
||||||
|
|
||||||
|
|
||||||
def doctrine_from_name(name: str) -> Doctrine:
|
def doctrine_from_name(name: str) -> Doctrine:
|
||||||
for doctrine in ALL_DOCTRINES:
|
return Doctrine.named(name)
|
||||||
if doctrine.name == name:
|
|
||||||
return doctrine
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
|
|
||||||
def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry:
|
def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry:
|
||||||
|
|||||||
32
resources/doctrines/coldwar.yaml
Normal file
32
resources/doctrines/coldwar.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: coldwar
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: true
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
rendezvous_altitude_ft_msl: 22000
|
||||||
|
hold_distance_nm: 15
|
||||||
|
push_distance_nm: 10
|
||||||
|
join_distance_nm: 10
|
||||||
|
max_ingress_distance_nm: 30
|
||||||
|
min_ingress_distance_nm: 10
|
||||||
|
ingress_altitude_ft_msl: 18000
|
||||||
|
min_patrol_altitude_ft_msl: 10000
|
||||||
|
max_patrol_altitude_ft_msl: 24000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 12
|
||||||
|
cap_max_track_length_nm: 24
|
||||||
|
cap_min_distance_from_cp_nm: 8
|
||||||
|
cap_max_distance_from_cp_nm: 25
|
||||||
|
cap_engagement_range_nm: 35
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 40
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 4
|
||||||
|
ATGM: 2
|
||||||
|
APC: 3
|
||||||
|
IFV: 2
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 2
|
||||||
|
Recon: 1
|
||||||
32
resources/doctrines/modern.yaml
Normal file
32
resources/doctrines/modern.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: modern
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: true
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
rendezvous_altitude_ft_msl: 25000
|
||||||
|
hold_distance_nm: 25
|
||||||
|
push_distance_nm: 20
|
||||||
|
join_distance_nm: 20
|
||||||
|
max_ingress_distance_nm: 45
|
||||||
|
min_ingress_distance_nm: 10
|
||||||
|
ingress_altitude_ft_msl: 20000
|
||||||
|
min_patrol_altitude_ft_msl: 15000
|
||||||
|
max_patrol_altitude_ft_msl: 33000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 15
|
||||||
|
cap_max_track_length_nm: 40
|
||||||
|
cap_min_distance_from_cp_nm: 10
|
||||||
|
cap_max_distance_from_cp_nm: 40
|
||||||
|
cap_engagement_range_nm: 50
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 60
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 3
|
||||||
|
ATGM: 2
|
||||||
|
APC: 2
|
||||||
|
IFV: 3
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 2
|
||||||
|
Recon: 1
|
||||||
31
resources/doctrines/ww2.yaml
Normal file
31
resources/doctrines/ww2.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
name: ww2
|
||||||
|
cap: true
|
||||||
|
cas: true
|
||||||
|
sead: false
|
||||||
|
strike: true
|
||||||
|
antiship: true
|
||||||
|
hold_distance_nm: 10
|
||||||
|
push_distance_nm: 5
|
||||||
|
join_distance_nm: 5
|
||||||
|
rendezvous_altitude_ft_msl: 10000
|
||||||
|
max_ingress_distance_nm: 7
|
||||||
|
min_ingress_distance_nm: 5
|
||||||
|
ingress_altitude_ft_msl: 8000
|
||||||
|
min_patrol_altitude_ft_msl: 4000
|
||||||
|
max_patrol_altitude_ft_msl: 15000
|
||||||
|
pattern_altitude_ft_msl: 5000
|
||||||
|
cap_duration_minutes: 30
|
||||||
|
cap_min_track_length_nm: 8
|
||||||
|
cap_max_track_length_nm: 18
|
||||||
|
cap_min_distance_from_cp_nm: 0
|
||||||
|
cap_max_distance_from_cp_nm: 5
|
||||||
|
cap_engagement_range_nm: 20
|
||||||
|
cas_duration_minutes: 30
|
||||||
|
sweep_distance_nm: 10
|
||||||
|
ground_unit_procurement_ratios:
|
||||||
|
Tank: 3
|
||||||
|
ATGM: 3
|
||||||
|
APC: 3
|
||||||
|
Artillery: 1
|
||||||
|
SHORAD: 3
|
||||||
|
Recon: 1
|
||||||
43
tests/data/test_doctrine.py
Normal file
43
tests/data/test_doctrine.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from game.data.doctrine import Doctrine, GroundUnitProcurementRatios
|
||||||
|
from game.data.units import UnitClass
|
||||||
|
|
||||||
|
|
||||||
|
def test_ground_unit_procurement_ratios_empty() -> None:
|
||||||
|
r = GroundUnitProcurementRatios({})
|
||||||
|
for unit_class in UnitClass:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_ground_unit_procurement_ratios_single_item() -> None:
|
||||||
|
r = GroundUnitProcurementRatios({UnitClass.TANK: 1})
|
||||||
|
for unit_class in UnitClass:
|
||||||
|
if unit_class == UnitClass.TANK:
|
||||||
|
assert r.for_unit_class(unit_class) == 1.0
|
||||||
|
else:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_ground_unit_procurement_ratios_multiple_items() -> None:
|
||||||
|
r = GroundUnitProcurementRatios({UnitClass.TANK: 1, UnitClass.ATGM: 1})
|
||||||
|
for unit_class in UnitClass:
|
||||||
|
if unit_class in [UnitClass.TANK, UnitClass.ATGM]:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.5
|
||||||
|
else:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_ground_unit_procurement_ratios_from_dict() -> None:
|
||||||
|
r = GroundUnitProcurementRatios.from_dict({"Tank": 1, "ATGM": 1})
|
||||||
|
for unit_class in UnitClass:
|
||||||
|
if unit_class in [UnitClass.TANK, UnitClass.ATGM]:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.5
|
||||||
|
else:
|
||||||
|
assert r.for_unit_class(unit_class) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_doctrine() -> None:
|
||||||
|
# This test checks for the presence of a doctrine named "modern" as this doctrine is used as a default
|
||||||
|
modern_doctrine = Doctrine.named("modern")
|
||||||
|
assert modern_doctrine.name == "modern"
|
||||||
@ -8,7 +8,7 @@ import pytest
|
|||||||
from dcs.terrain import Caucasus
|
from dcs.terrain import Caucasus
|
||||||
from shapely import Point, MultiPolygon, Polygon, unary_union
|
from shapely import Point, MultiPolygon, Polygon, unary_union
|
||||||
|
|
||||||
from game.data.doctrine import ALL_DOCTRINES
|
from game.data.doctrine import Doctrine
|
||||||
from game.flightplan.ipsolver import IpSolver
|
from game.flightplan.ipsolver import IpSolver
|
||||||
from game.flightplan.waypointsolver import NoSolutionsError
|
from game.flightplan.waypointsolver import NoSolutionsError
|
||||||
from game.flightplan.waypointstrategy import point_at_heading
|
from game.flightplan.waypointstrategy import point_at_heading
|
||||||
@ -70,7 +70,7 @@ def fuzzed_solver_fixture(
|
|||||||
departure = Point(0, 0)
|
departure = Point(0, 0)
|
||||||
target = point_at_heading(departure, target_heading, fuzzed_target_distance)
|
target = point_at_heading(departure, target_heading, fuzzed_target_distance)
|
||||||
solver = IpSolver(
|
solver = IpSolver(
|
||||||
departure, target, random.choice(ALL_DOCTRINES), fuzzed_threat_poly
|
departure, target, random.choice(Doctrine.all_doctrines()), fuzzed_threat_poly
|
||||||
)
|
)
|
||||||
solver.set_debug_properties(tmp_path, Caucasus())
|
solver.set_debug_properties(tmp_path, Caucasus())
|
||||||
return solver
|
return solver
|
||||||
@ -98,4 +98,4 @@ def test_fuzz_ipsolver(fuzzed_solver: IpSolver, run_number: int) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_can_construct_solver_with_empty_threat() -> None:
|
def test_can_construct_solver_with_empty_threat() -> None:
|
||||||
IpSolver(Point(0, 0), Point(0, 0), ALL_DOCTRINES[0], MultiPolygon([]))
|
IpSolver(Point(0, 0), Point(0, 0), Doctrine.named("coldwar"), MultiPolygon([]))
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from typing import Any, TypeVar, Generic
|
|||||||
from shapely import Point, MultiPolygon
|
from shapely import Point, MultiPolygon
|
||||||
from shapely.geometry import shape
|
from shapely.geometry import shape
|
||||||
|
|
||||||
from game.data.doctrine import Doctrine, ALL_DOCTRINES
|
from game.data.doctrine import Doctrine
|
||||||
from game.flightplan.ipsolver import IpSolver
|
from game.flightplan.ipsolver import IpSolver
|
||||||
from game.flightplan.waypointsolver import WaypointSolver, NoSolutionsError
|
from game.flightplan.waypointsolver import WaypointSolver, NoSolutionsError
|
||||||
from game.flightplan.waypointsolverloader import WaypointSolverLoader
|
from game.flightplan.waypointsolverloader import WaypointSolverLoader
|
||||||
@ -18,10 +18,7 @@ ReducerT = TypeVar("ReducerT")
|
|||||||
|
|
||||||
|
|
||||||
def doctrine_from_name(name: str) -> Doctrine:
|
def doctrine_from_name(name: str) -> Doctrine:
|
||||||
for doctrine in ALL_DOCTRINES:
|
return Doctrine.named(name)
|
||||||
if doctrine.name == name:
|
|
||||||
return doctrine
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
|
|
||||||
class Reducer(Generic[ReducerT], Iterator[ReducerT], ABC):
|
class Reducer(Generic[ReducerT], Iterator[ReducerT], ABC):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user