Load materials from the Materials startup event
This commit is contained in:
parent
4a2d5d5cb7
commit
677f122a03
2 changed files with 120 additions and 7 deletions
|
@ -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})
|
||||
|
|
|
@ -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()))
|
||||
|
|
Loading…
Reference in a new issue