From 4eb648d712bf7b1efdb1c65a767d605ef720b8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20L=C3=BCcke?= Date: Mon, 2 Jun 2025 18:23:17 +0200 Subject: [PATCH] Erste Version --- .gitignore | 1 + MechFabrik/__init__.py | 42 ++++++++++++ MechFabrik/bauteile/__init__.py | 103 ++++++++++++++++++++++++++++++ MechFabrik/reader.py | 36 +++++++++++ MechFabrik/tabellen/bauteile.csv | 20 ++++++ MechFabrik/tabellen/reaktoren.csv | 80 +++++++++++++++++++++++ MechFabrik/tabellen/waffen.csv | 23 +++++++ tests/test_mech_bau.py | 71 ++++++++++++++++++++ 8 files changed, 376 insertions(+) create mode 100644 .gitignore create mode 100755 MechFabrik/__init__.py create mode 100755 MechFabrik/bauteile/__init__.py create mode 100755 MechFabrik/reader.py create mode 100755 MechFabrik/tabellen/bauteile.csv create mode 100755 MechFabrik/tabellen/reaktoren.csv create mode 100755 MechFabrik/tabellen/waffen.csv create mode 100755 tests/test_mech_bau.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f21b54 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/venv/ diff --git a/MechFabrik/__init__.py b/MechFabrik/__init__.py new file mode 100755 index 0000000..81b7d03 --- /dev/null +++ b/MechFabrik/__init__.py @@ -0,0 +1,42 @@ +from MechFabrik.bauteile import Mech, InnerStructure, Gyroskope, Area, AreaNames, Cockpit, Reaktor +from MechFabrik.reader import ComponentReader + + +class MechFabrik(object): + + def __init__(self, name: str, tonnage: float, movement_rate: int): + self.__components = ComponentReader() + self.__reactor_value = int(movement_rate * tonnage) + gyroscope = Gyroskope(float(round(self.__reactor_value/100))) + inner_structure = self.__build_inner_structure(tonnage, movement_rate) + self._mech = Mech(name, tonnage, movement_rate, inner_structure) + + def __build_inner_structure(self, tonnage: float, movement_rate: int) -> InnerStructure: + reactor_value = int(movement_rate * tonnage) + gyroscope = Gyroskope(float(round(reactor_value/100))) + inner_structure = InnerStructure(self.__components.inner_structure_from(tonnage), gyroscope) + inner_structure.add_area(AreaNames.HEAD, self.__build_head_area()) + self.__build_middle_torso_area(inner_structure) + return inner_structure + + def __build_head_area(self) -> Area: + area = Area() + cockpit = Cockpit() + area.cockpit = cockpit + return area + + def __build_middle_torso_area(self, inner_structure: InnerStructure) -> Area: + area_middle = Area() + area_left = Area() + area_right = Area() + reactor = Reaktor(self.__reactor_value, self.__components.reactor_tonnage_from(self.__reactor_value)) + area_middle.reactor = reactor + area_middle.children = [area_right, area_left] + inner_structure.add_area(AreaNames.LEFT_TORSO, area_left) + inner_structure.add_area(AreaNames.RIGHT_TORSO, area_right) + inner_structure.add_area(AreaNames.MIDDLE_TORSO, area_middle) + return area_middle + + + def auslieferung(self) -> Mech: + return self._mech diff --git a/MechFabrik/bauteile/__init__.py b/MechFabrik/bauteile/__init__.py new file mode 100755 index 0000000..eb5d07f --- /dev/null +++ b/MechFabrik/bauteile/__init__.py @@ -0,0 +1,103 @@ +import csv +import enum +import os +from typing import Any + + +class AreaNames(enum.Enum): + HEAD = 'Kopf' + MIDDLE_TORSO = 'Torso Mitte' + RIGHT_TORSO = 'Rechter Torso' + LEFT_TORSO = 'Linker Torso' + + + +class Cockpit: + @property + def tonnage(self) -> float: + return 3.0 + + +class Reaktor: + + def __init__(self, value: int, tonnage: float): + self._tonnage = tonnage + self._value = value + + @property + def value(self): + return self._value + + @property + def tonnage(self): + return self._tonnage + + +class Area: + _content: dict[str, Any] + + def __init__(self): + self.__dict__['_content'] = {} + + def __setattr__(self, key, value): + self.__dict__['_content'][key] = value + + def __getattr__(self, item): + return self.__dict__['_content'].get(item) + + +class Gyroskope: + def __init__(self, tonnage: float): + self._tonnage = tonnage + + @property + def tonnage(self) -> float: + return self._tonnage + + +class InnerStructure: + + def __init__(self, tonnage: float, gyroskope: Gyroskope): + self._gyroskope = gyroskope + self._tonnage = tonnage + self._areas = dict() + + @property + def tonnage(self) -> float: + return self._tonnage + + @property + def gyroskope(self) -> Gyroskope: + return self._gyroskope + + @property + def areas(self) -> dict: + return self._areas + + def add_area(self,index: AreaNames, area: Area): + self._areas[index] = area + + +class Mech(object): + + def __init__(self, name: str, tonnage: float, movement_rate: int, inner_structure: InnerStructure): + self._movement_rate = movement_rate + self._tonnage = tonnage + self._name = name + self._inner_structure = inner_structure + + @property + def name(self) -> str: + return self._name + + @property + def tonnage(self) -> float: + return self._tonnage + + @property + def inner_structure(self) -> InnerStructure: + return self._inner_structure + + @property + def movement_rate(self) -> int: + return self._movement_rate \ No newline at end of file diff --git a/MechFabrik/reader.py b/MechFabrik/reader.py new file mode 100755 index 0000000..d951a5f --- /dev/null +++ b/MechFabrik/reader.py @@ -0,0 +1,36 @@ +import csv +import os.path + + +# noinspection SpellCheckingInspection +class CsvDialect (csv.Dialect): + lineterminator='\r\n' + delimiter = ',' + quotechar = '"' + quoting=csv.QUOTE_NONNUMERIC + + +class ComponentReader: + + def __init__(self): + self._inner_structure_data = {} + self._reactor_data = {} + self._weapon_data = {} + with open(os.path.join(os.path.dirname(__file__), 'tabellen', 'bauteile.csv')) as csvfile: + component_reader = csv.DictReader(csvfile, dialect=CsvDialect) + for row in component_reader: + self._inner_structure_data[float(row['GTonnage'])] = row + with open(os.path.join(os.path.dirname(__file__), 'tabellen', 'reaktoren.csv')) as csvfile: + component_reader = csv.DictReader(csvfile, dialect=CsvDialect) + for row in component_reader: + self._reactor_data[float(row['RW'])] = row + with open(os.path.join(os.path.dirname(__file__), 'tabellen', 'waffen.csv')) as csvfile: + component_reader = csv.DictReader(csvfile, dialect=CsvDialect) + for row in component_reader: + self._weapon_data[row['Waffentyp']] = row + + def inner_structure_from(self, tonnage: float) -> float: + return float(self._inner_structure_data.get(tonnage, {}).get('Tonnage IS', 0.0)) + + def reactor_tonnage_from(self, reactor_value: int) -> float: + return float(self._reactor_data.get(reactor_value, {}).get('Tonnage', 0.0)) diff --git a/MechFabrik/tabellen/bauteile.csv b/MechFabrik/tabellen/bauteile.csv new file mode 100755 index 0000000..dfe0433 --- /dev/null +++ b/MechFabrik/tabellen/bauteile.csv @@ -0,0 +1,20 @@ +"GTonnage","Tonnage IS","Tonnage Endo","TorsoMitte","TorsoSeite","Arm","Bein","Tonnage" "SD" +10,1.0,0.5,4,3,1,2,0.5 +15,1.5,1.0,5,4,2,3,0.5 +20,2.0,1.0,6,5,3,4,0.5 +25,2.5,1.5,8,6,4,6,0.5 +30,3.0,1.5,10,7,5,7,0.5 +35,3.5,2.0,11,8,6,8,0.5 +40,4.0,2.0,12,10,6,10,0.5 +45,4.5,2.5,14,11,7,11,0.5 +50,5.0,2.5,16,12,8,12,0.5 +55,5.5,3.0,18,13,9,13,0.5 +60,6.0,3.0,20,14,10,14,1 +65,6.5,3.5,21,15,10,15,1 +70,7.0,3.5,22,15,11,15,1 +75,7.5,4.0,23,16,12,16,1 +80,8.0,4.0,25,17,13,17,1 +85,8.5,4.25,27,18,14,18,1 +90,9.0,4.5,29,19,15,19,2 +95,9.5,4.75,30,20,16,20,2 +100,10.0,5.0,31,21,17,21,2 \ No newline at end of file diff --git a/MechFabrik/tabellen/reaktoren.csv b/MechFabrik/tabellen/reaktoren.csv new file mode 100755 index 0000000..de92a35 --- /dev/null +++ b/MechFabrik/tabellen/reaktoren.csv @@ -0,0 +1,80 @@ +"RW","Tonnage","TonnageXL","Hersteller" +10,0.50,0.50,"unbekant" +15,0.50,0.50,"unbekant" +20,0.50,0.50,"unbekant" +25,0.50,0.50,"unbekant" +30,1.00,0.50,"unbekant" +35,1.00,0.50,"unbekant" +40,1.00,0.50,"unbekant" +45,1.00,0.50,"unbekant" +50,1.50,1.00,"unbekant" +55,1.50,1.00,"unbekant" +60,1.50,1.00,"unbekant" +65,2.00,1.00,"unbekant" +70,2.00,1.00,"unbekant" +75,2.00,1.00,"unbekant" +80,2.50,1.50,"unbekant" +85,2.50,1.50,"unbekant" +90,3.00,1.50,"unbekant" +95,3.00,1.50,"unbekant" +100,3.00,1.50,"unbekant" +105,3.50,2.00,"unbekant" +110,3.50,2.00,"unbekant" +115,4.00,2.00,"unbekant" +120,4.00,2.00,"unbekant" +125,4.00,2.00,"unbekant" +130,4.50,2.50,"unbekant" +135,4.50,2.50,"unbekant" +140,5.00,2.50,"unbekant" +145,5.00,2.50,"unbekant" +150,5.50,3.00,"unbekant" +155,5.50,3.00,"unbekant" +160,6.00,3.00,"unbekant" +165,6.00,3.00,"unbekant" +170,6.00,3.00,"unbekant" +175,7.00,3.50,"unbekant" +180,7.00,3.50,"unbekant" +185,7.50,4.00,"unbekant" +190,7.50,4.00,"unbekant" +195,8.00,4.00,"unbekant" +200,8.50,4.50,"unbekant" +205,8.50,4.50,"unbekant" +210,9.00,4.50,"unbekant" +215,9.50,5.00,"unbekant" +220,10.00,5.00,"unbekant" +225,10.00,5.00,"unbekant" +230,10.50,5.50,"unbekant" +235,11.00,5.50,"unbekant" +240,11.50,6.00,"unbekant" +245,12.00,6.00,"unbekant" +250,12.50,6.50,"unbekant" +255,13.00,6.50,"unbekant" +260,13.50,7.00,"unbekant" +265,14.00,7.00,"unbekant" +270,14.50,7.50,"unbekant" +275,15.50,8.00,"unbekant" +280,16.00,8.00,"unbekant" +285,16.50,8.50,"unbekant" +290,17.50,9.00,"unbekant" +295,18.00,9.00,"unbekant" +300,19.00,9.50,"unbekant" +305,19.50,10.00,"unbekant" +310,20.50,10.50,"unbekant" +315,21.50,11.00,"unbekant" +320,22.50,11.50,"unbekant" +325,23.50,12.00,"unbekant" +330,24.50,12.50,"VOX" +335,25.50,13.00,"unbekant" +340,27.00,13.50,"unbekant" +345,28.50,14.50,"unbekant" +350,29.50,15.00,"unbekant" +355,31.50,16.00,"unbekant" +360,33.00,16.50,"unbekant" +365,34.50,17.50,"unbekant" +370,36.50,18.50,"unbekant" +375,38.50,19.50,"unbekant" +380,41.00,20.50,"unbekant" +385,43.50,22.00,"unbekant" +390,46.00,23.00,"unbekant" +395,49.00,24.50,"unbekant" +400,52.50,26.50,"unbekant" \ No newline at end of file diff --git a/MechFabrik/tabellen/waffen.csv b/MechFabrik/tabellen/waffen.csv new file mode 100755 index 0000000..480f444 --- /dev/null +++ b/MechFabrik/tabellen/waffen.csv @@ -0,0 +1,23 @@ +"Waffentyp","Wärme","Schaden","Minimal","Nah","Mittel","Weit","Tonage","Zeilen","Schuss/Tonne" +"L-Laser",1,3,0,1,2,3,0.5,1 +"L-I-Laser",2,3,0,1,2,3,1,1 +"M-Laser",3,5,0,"1 - 3","4 - 6","7 - 9",1,1 +"M-I-Laser",4,6,0,"1 - 2","3 - 4","5 - 6",2,1 +"S-Laser",8,8,0,"1 - 5","6 - 10","11 - 15",5,2 +"ER-S-Laser",12,8,0,"1 - 7","8 - 14","15 - 19",5,2 +"S-I-Laser",10,9,0,"1 - 3","4 - 7","8 - 10",7,2 +"PPK",10,10,3,"1 - 6","7 - 12","13 - 18",7,3 +"ER-PPK",15,10,0,"1 - 7","8 - 14","15 - 23",7,3 +"LSR-5",2,"LSR",6,"1 - 7","8 - 14","15 - 21",2,1,24 +"LSR-10",4,"LSR",6,"1 - 7","8 - 14","15 - 21",5,2,12 +"LSR-15",5,"LSR",6,"1 - 7","8 - 14","15 - 21",6,3,8 +"LSR-20",6,"LSR",6,"1 - 7","8 - 14","15 - 21",10,5,6 +"KSR-2",2,"KSR",0,"1 - 3","4 - 6","7 - 9",1,1,50 +"KSR-4",3,"KSR",0,"1 - 3","4 - 6","7 - 9",2,1,25 +"KSR-6",4,"KSR",0,"1 - 3","4 - 6","7 - 9",3,2,15 +"AK-2",1,2,6,"1 - 8","9 - 16","17 - 24",6,1,45 +"AK-5",1,3,5,"1 - 6","7 - 12","13 - 18",8,4,20 +"AK-10",3,10,0,"1 - 5","6 - 10","11 - 15",12,7,10 +"AK-20",7,20,0,"1 - 3","4 - 6","7 - 9",14,10,5 +"MG",0,2,0,1,2,3,0.5,1,200 +"Flammer",3,2,0,1,2,3,1,1 diff --git a/tests/test_mech_bau.py b/tests/test_mech_bau.py new file mode 100755 index 0000000..ad49a02 --- /dev/null +++ b/tests/test_mech_bau.py @@ -0,0 +1,71 @@ +import unittest + +from MechFabrik import MechFabrik +from MechFabrik.bauteile import InnerStructure, Gyroskope, AreaNames, Area, Cockpit, Reaktor, Mech + + +class TestMechBau(unittest.TestCase): + + def test_simple(self): + fabrik = MechFabrik('Heuschrecke', 20.0, 8) + mech = fabrik.auslieferung() + self.assertIsInstance(mech, Mech) + self.assertIsInstance(mech.name, str) + self.assertEqual('Heuschrecke', mech.name) + self.assertIsInstance(mech.tonnage, float) + self.assertEqual(20.0, mech.tonnage) + self.assertIsInstance(mech.movement_rate, int) + self.assertEqual(8, mech.movement_rate) + + self.assertIsInstance(mech.inner_structure, InnerStructure) + self.assertIsInstance(mech.inner_structure.tonnage, float) + self.assertEqual(2.0, mech.inner_structure.tonnage) + + self.assertIsInstance(mech.inner_structure.gyroskope, Gyroskope) + self.assertIsInstance(mech.inner_structure.gyroskope.tonnage, float) + self.assertEqual(2.0, mech.inner_structure.gyroskope.tonnage) + self.assertIsInstance(mech.inner_structure.areas, dict) + + area_head = mech.inner_structure.areas.get(AreaNames.HEAD) + self.assertIsInstance(area_head, Area) + cockpit = area_head.cockpit + self.assertIsInstance(cockpit, Cockpit) + self.assertIsInstance(cockpit.tonnage, float) + self.assertEqual(3.0, cockpit.tonnage) + + middle_torso = mech.inner_structure.areas.get(AreaNames.MIDDLE_TORSO) + self.assertIsInstance(middle_torso, Area) + reactor = middle_torso.reactor + self.assertIsInstance(reactor, Reaktor) + self.assertIsInstance(reactor.value, int) + self.assertEqual(160, reactor.value) + self.assertIsInstance(reactor.tonnage, float) + self.assertEqual(6.0, reactor.tonnage) + self.assertIsNone(middle_torso.parent) + self.assertIsInstance(middle_torso.children, list) + #right_torso = self._test_area(mech = mech, parent = middle_torso, index = AreaNames.RIGHT_TORSO) + #left_torso = self._test_area(mech = mech, parent = middle_torso, index = AreaNames.LEFT_TORSO) + #self.assertCountEqual([right_torso, left_torso], middle_torso.children) + + #self._test_limbs(mech = mech, parent = right_torso, index = AreaNames.RIGHT_ARM) + #self._test_limbs(mech = mech, parent = right_torso, index = AreaNames.RIGHT_LEG) + #self._test_limbs(mech = mech, parent = left_torso, index = AreaNames.LEFT_ARM) + #self._test_limbs(mech = mech, parent = left_torso, index = AreaNames.LEFT_LEG) + + def _test_area(self, mech: Mech, parent: Area, index: AreaNames): + side_torso = mech.inner_structure.areas.get(index) + self.assertIsInstance(side_torso, Area) + self.assertIsInstance(side_torso.parent, Area) + self.assertEqual(parent, side_torso.parent) + self.assertIsInstance(side_torso.children, list) + self.assertCountEqual([0, 0], side_torso.children) + return side_torso + + def _test_limbs(self, mech: Mech, parent: Area, index: AreaNames): + limbs_area = mech.inner_structure.areas.get(index) + self.assertIsInstance(limbs_area, Area) + self.assertIsInstance(limbs_area.parent, Area) + self.assertEqual(parent, limbs_area.parent) + self.assertIsInstance(limbs_area.children, list) + self.assertCountEqual([], limbs_area.children) +