Load materials from the Materials startup event

This commit is contained in:
Correl Roush 2022-01-23 02:01:17 -05:00
parent 4a2d5d5cb7
commit 677f122a03
2 changed files with 120 additions and 7 deletions

View file

@ -27,13 +27,15 @@ def _load() -> typing.Dict[str, Material]:
lines = path.read_text().splitlines()
reader = csv.reader(lines[1:])
return {
symbol: Material(name, type_, category, int(grade))
symbol.lower(): Material(name, type_, category, int(grade))
for fdevid, symbol, grade, type_, category, name in reader
}
materials: typing.Dict[str, Material] = _load()
_Inventory = typing.TypeVar("_Inventory", bound="Inventory")
class Inventory(collections.UserDict):
"""A mapping of every available material with an associated quantity."""
@ -47,11 +49,18 @@ class Inventory(collections.UserDict):
self.update(items)
def __setitem__(self, key, value) -> None:
if key not in materials:
normalized_key = key.lower()
if normalized_key not in materials:
raise KeyError(key)
if value < 0:
raise ValueError(value)
super().__setitem__(key, value)
super().__setitem__(normalized_key, value)
def __getitem__(self, key: str) -> int:
normalized_key = key.lower()
if normalized_key not in materials:
raise KeyError(key)
return super().__getitem__(normalized_key)
def has(self, items: typing.Union[typing.Dict[str, int], "Inventory"]) -> bool:
return all([self[name] >= quantity for name, quantity in items.items()])
@ -62,6 +71,23 @@ class Inventory(collections.UserDict):
def __sub__(self, other: "Inventory") -> "Inventory":
return Inventory({name: self[name] - qty for name, qty in other.items()})
@classmethod
def from_event(
cls: typing.Type[_Inventory], event: typing.Dict[str, typing.Any]
) -> _Inventory:
if event.get("event") != "Materials":
raise ValueError("Not a 'Materials' event")
return cls(
{
material["Name"]: material["Count"]
for material in [
*event.get("Raw", []),
*event.get("Manufactured", []),
*event.get("Encoded", []),
]
}
)
class Materials(Inventory):
"""Same as Inventory, but omits zeroed materials."""
@ -75,18 +101,20 @@ class Materials(Inventory):
self.update(items)
def __setitem__(self, key: str, value: int) -> None:
if key not in materials:
normalized_key = key.lower()
if normalized_key not in materials:
raise KeyError(key)
if value < 0:
raise ValueError(value)
if value == 0:
return
super().__setitem__(key, value)
super().__setitem__(normalized_key, value)
def __getitem__(self, key: str) -> int:
if key not in materials:
normalized_key = key.lower()
if normalized_key not in materials:
raise KeyError(key)
return self.data.get(key, 0)
return self.data.get(normalized_key.lower(), 0)
def __add__(self, other: "Inventory") -> "Materials":
return Materials({name: self[name] + other[name] for name in materials})

View file

@ -1,4 +1,6 @@
import fractions
import json
import pathlib
import typing
import unittest
@ -86,6 +88,9 @@ class InventoryTests(unittest.TestCase):
) -> "materials.Inventory":
return materials.Inventory(items)
def from_event(self, event: typing.Dict[str, typing.Any]) -> "materials.Inventory":
return materials.Inventory.from_event(event)
def test_create_empty(self) -> None:
inventory = self.make()
self.assertEqual(set(materials.materials.keys()), set(inventory.keys()))
@ -140,6 +145,83 @@ class InventoryTests(unittest.TestCase):
a - b
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",
"Raw": [
{"Name": "manganese", "Count": 127},
{"Name": "iron", "Count": 37},
{"Name": "phosphorus", "Count": 2},
{"Name": "nickel", "Count": 5},
{"Name": "lead", "Count": 69},
{"Name": "germanium", "Count": 12},
],
"Manufactured": [
{
"Name": "salvagedalloys",
"Name_Localised": "Salvaged Alloys",
"Count": 1,
},
{
"Name": "crystalshards",
"Name_Localised": "Crystal Shards",
"Count": 36,
},
{
"Name": "shieldemitters",
"Name_Localised": "Shield Emitters",
"Count": 36,
},
],
"Encoded": [
{
"Name": "bulkscandata",
"Name_Localised": "Anomalous Bulk Scan Data",
"Count": 28,
},
{
"Name": "shieldcyclerecordings",
"Name_Localised": "Distorted Shield Cycle Recordings",
"Count": 66,
},
{
"Name": "archivedemissiondata",
"Name_Localised": "Irregular Emission Data",
"Count": 6,
},
],
}
self.assertEqual(
self.make(
{
"manganese": 127,
"iron": 37,
"phosphorus": 2,
"nickel": 5,
"lead": 69,
"germanium": 12,
"salvagedalloys": 1,
"crystalshards": 36,
"shieldemitters": 36,
"bulkscandata": 28,
"shieldcyclerecordings": 66,
"archivedemissiondata": 6,
}
),
self.from_event(event),
)
def test_load_from_invalid_event(self) -> None:
event: typing.Dict[str, typing.Any] = {}
with self.assertRaises(ValueError) as exc:
self.from_event(event)
self.assertEqual(exc.exception.args, ("Not a 'Materials' event",))
class MaterialsTests(InventoryTests):
def make(
@ -147,6 +229,9 @@ class MaterialsTests(InventoryTests):
) -> "materials.Materials":
return materials.Materials(items)
def from_event(self, event: typing.Dict[str, typing.Any]) -> "materials.Materials":
return materials.Materials.from_event(event)
def test_create_empty(self) -> None:
empty = self.make()
self.assertEqual(set(), set(empty.keys()))