Begin building trade calculations

This commit is contained in:
Correl Roush 2022-01-24 23:04:12 -05:00
parent 677f122a03
commit 7cbd8e2fb7
2 changed files with 52 additions and 12 deletions

View File

@ -3,6 +3,7 @@ import csv
import dataclasses
import enum
import fractions
import functools
import importlib.resources
import typing
@ -11,6 +12,7 @@ from elite_engineering import trade
@dataclasses.dataclass
class Material:
symbol: str
name: str
type_: str
category: str
@ -27,7 +29,7 @@ def _load() -> typing.Dict[str, Material]:
lines = path.read_text().splitlines()
reader = csv.reader(lines[1:])
return {
symbol.lower(): Material(name, type_, category, int(grade))
symbol.lower(): Material(symbol.lower(), name, type_, category, int(grade))
for fdevid, symbol, grade, type_, category, name in reader
}
@ -66,10 +68,22 @@ class Inventory(collections.UserDict):
return all([self[name] >= quantity for name, quantity in items.items()])
def __add__(self, other: "Inventory") -> "Inventory":
return Inventory({name: self[name] + qty for name, qty in other.items()})
return Inventory({name: self[name] + other[name] for name in materials})
def __sub__(self, other: "Inventory") -> "Inventory":
return Inventory({name: self[name] - qty for name, qty in other.items()})
return Inventory({name: self[name] - other[name] for name in materials})
def trades(self, symbol: str, quantity: int) -> "Materials":
if self.has(Materials({symbol: quantity})):
return Materials({})
raise ValueError
def trade_for(self, other: "Inventory") -> "Inventory":
def accumulate(inv: "Inventory", mat: typing.Tuple[str, int]) -> "Inventory":
symbol, quantity = mat
return inv - inv.trades(symbol, quantity)
return functools.reduce(accumulate, other.items(), self)
@classmethod
def from_event(

View File

@ -25,8 +25,12 @@ class TradeCalculationTests(unittest.TestCase):
actual = [
[
self.format_ratio(
materials.Material("name", "raw", "category", grade_in).trade_ratio(
materials.Material("name", "raw", "category", grade_out)
materials.Material(
"symbol", "name", "raw", "category", grade_in
).trade_ratio(
materials.Material(
"symbol", "name", "raw", "category", grade_out
)
)
)
for grade_in in [1, 2, 3, 4, 5]
@ -47,8 +51,10 @@ class TradeCalculationTests(unittest.TestCase):
actual = [
[
self.format_ratio(
materials.Material("name", "raw", "category", grade_in).trade_ratio(
materials.Material("name", "raw", "other", grade_out)
materials.Material(
"symbol", "name", "raw", "category", grade_in
).trade_ratio(
materials.Material("symbol", "name", "raw", "other", grade_out)
)
)
for grade_in in [1, 2, 3, 4, 5]
@ -70,8 +76,12 @@ class TradeCalculationTests(unittest.TestCase):
actual = [
[
self.format_ratio(
materials.Material("name", "raw", "category", grade_in).trade_ratio(
materials.Material("name", "encoded", "other", grade_out)
materials.Material(
"symbol", "name", "raw", "category", grade_in
).trade_ratio(
materials.Material(
"symbol", "name", "encoded", "other", grade_out
)
)
)
for grade_in in [1, 2, 3, 4, 5]
@ -146,9 +156,6 @@ class InventoryTests(unittest.TestCase):
self.assertEqual(exc.exception.args, (-1,))
def test_load_from_materials_event(self) -> None:
event = json.loads(
pathlib.Path(__file__).parent.joinpath("events/materials.json").read_text()
)
event = {
"timestamp": "2022-01-23T02:58:12Z",
"event": "Materials",
@ -222,6 +229,25 @@ class InventoryTests(unittest.TestCase):
self.from_event(event)
self.assertEqual(exc.exception.args, ("Not a 'Materials' event",))
def test_trade_unnecessary(self) -> None:
inventory = self.make({"carbon": 3, "niobium": 1})
recipe = materials.Materials({"carbon": 3})
self.assertEqual(inventory, inventory.trade_for(recipe))
def test_trade_impossible(self) -> None:
inventory = self.make()
recipe = materials.Materials({"carbon": 3})
with self.assertRaises(ValueError):
inventory.trade_for(recipe)
@unittest.skip("Not implemented")
def test_trade_grade_2_for_grade_1(self) -> None:
inventory = self.make({"vanadium": 1, "niobium": 1})
recipe = materials.Materials({"carbon": 3})
self.assertEqual(
self.make({"carbon": 3, "niobium": 1}), inventory.trade_for(recipe)
)
class MaterialsTests(InventoryTests):
def make(