From 460e0156e8ec9b5bdb439d2097ef34ec5463118c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20L=C3=BCcke?= Date: Thu, 25 Jun 2026 15:35:51 +0200 Subject: [PATCH] tests: verbessere die Verantwortung der Trefferpunkte-Verarbeitung --- MechFabrik/Uml/Mech.puml | 103 ++++++++-------------- MechFabrik/Uml/MechStructure.puml | 75 ++++++++++++++++ MechFabrik/Uml/StrikeProcessSequence.puml | 31 +++++++ MechFabrik/bauteile/__init__.py | 14 +++ tests/test_mech/__init__.py | 45 +++++++--- tests/test_mech_bau.py | 27 ++++-- tests/test_mech_process.py | 95 +++++++++++++++----- 7 files changed, 281 insertions(+), 109 deletions(-) create mode 100644 MechFabrik/Uml/MechStructure.puml create mode 100644 MechFabrik/Uml/StrikeProcessSequence.puml diff --git a/MechFabrik/Uml/Mech.puml b/MechFabrik/Uml/Mech.puml index cafbfda..2ead09e 100644 --- a/MechFabrik/Uml/Mech.puml +++ b/MechFabrik/Uml/Mech.puml @@ -1,87 +1,58 @@ @startuml 'https://plantuml.com/object-diagram -object Mech <> { +object Mech <> +abstract Area <> { + next_area: Area + item_lines: # + armor: # +} +abstract AreaItem <> { + item_lines: # +} + +object InnerStructure <> { heater: x } -object InnerStructure <> -object Gyroskope <> -object Sustainment -object Sensors + +object OuterAmor <> { + armor: # +} + object Head <> { item_lines: 6 - inner_armor: # - amor: # } -object Cockpit <> -object Reaktor <> -object TorsoMiddle <> { + +object Torso <> { item_lines: 12 - inner_armor: # - amor: # } -object TorsoLeft <> { + +object SideTorso <> { item_lines: 12 - inner_armor: # - amor: # } -object ArmLeft <> { + +object Arm <> { item_lines: 12 - inner_armor: # - amor: # } -object LegLeft <> { + +object Leg <> { item_lines: 6 - inner_armor: # - amor: # } -object TorsoRight <> { - item_lines: 12 - inner_armor: # - amor: # -} -object ArmRight <> { - item_lines: 12 - inner_armor: # - amor: # -} -object LegRight <> { - item_lines: 6 - inner_armor: # - amor: # -} -object JointAL as "Joint" -object ActivatorAL as "Activator" -object JointLL as "Joint" -object ActivatorLL as "Activator" -object JointAR as "Joint" -object ActivatorAR as "Activator" -object JointLR as "Joint" -object ActivatorLR as "Activator" + +Area *- "1,*" OuterAmor +AreaItem "*" -* Area + +Head <|-- Area +Torso <|-- Area +SideTorso <|-- Area +Arm <|-- Area +Leg <|-- Area Mech *-- InnerStructure InnerStructure *-- Head -InnerStructure *-- TorsoMiddle -Mech *- Gyroskope -Head *- Cockpit -Head *-- Sustainment -Head *-- Sensors -Mech *- Reaktor -Gyroskope .. InnerStructure -Reaktor ... InnerStructure -TorsoMiddle *-- TorsoLeft -TorsoMiddle *-- TorsoRight -TorsoLeft *-- ArmLeft -TorsoLeft *-- LegLeft -TorsoRight *-- ArmRight -TorsoRight *-- LegRight -ArmLeft *-- JointAL -ArmLeft *-- ActivatorAL -ArmRight *-- JointAR -ArmRight *-- ActivatorAR -LegRight *-- JointLR -LegRight *-- ActivatorLR -LegLeft *-- JointLL -LegLeft *-- ActivatorLL +InnerStructure *-- Torso +Torso *-- SideTorso +SideTorso *-- "0|2" Arm +SideTorso *-- "2|4" Leg @enduml diff --git a/MechFabrik/Uml/MechStructure.puml b/MechFabrik/Uml/MechStructure.puml new file mode 100644 index 0000000..c69fe37 --- /dev/null +++ b/MechFabrik/Uml/MechStructure.puml @@ -0,0 +1,75 @@ +@startuml +'https://plantuml.com/object-diagram + +object Mech <> { + heater: x +} + +object Head <> { + item_lines: 6 +} +object Sustainment <> +object Sensors <> +object Cockpit <> <> + +object InnerStructure <> +object Gyroskope <> <> +object Reaktor <> <> +object TorsoMiddle <> { + item_lines: 12 +} +object TorsoLeft <> { + item_lines: 12 +} +object ArmLeft <> { + item_lines: 12 +} +object LegLeft <> { + item_lines: 6 +} +object TorsoRight <> { + item_lines: 12 +} +object ArmRight <> { + item_lines: 12 +} +object LegRight <> { + item_lines: 6 +} +object JointAL as "Joint" <> +object ActivatorAL as "Activator" <> +object JointLL as "Joint" <> +object ActivatorLL as "Activator" <> +object JointAR as "Joint" <> +object ActivatorAR as "Activator" <> +object JointLR as "Joint" <> +object ActivatorLR as "Activator" <> + + +Mech *- Gyroskope +Head *- Cockpit +Head *-- Sustainment +Head *-- Sensors + +Mech *-- InnerStructure +InnerStructure *-- Head +InnerStructure *-- TorsoMiddle +Mech *- Reaktor +Gyroskope .. TorsoMiddle +Reaktor .. TorsoMiddle +TorsoMiddle *-- TorsoLeft +TorsoMiddle *-- TorsoRight +TorsoLeft *-- ArmLeft +TorsoLeft *-- LegLeft +TorsoRight *-- ArmRight +TorsoRight *-- LegRight +ArmLeft *-- JointAL +ArmLeft *-- ActivatorAL +ArmRight *-- JointAR +ArmRight *-- ActivatorAR +LegRight *-- JointLR +LegRight *-- ActivatorLR +LegLeft *-- JointLL +LegLeft *-- ActivatorLL + +@enduml diff --git a/MechFabrik/Uml/StrikeProcessSequence.puml b/MechFabrik/Uml/StrikeProcessSequence.puml new file mode 100644 index 0000000..1c6d360 --- /dev/null +++ b/MechFabrik/Uml/StrikeProcessSequence.puml @@ -0,0 +1,31 @@ +@startuml +'https://plantuml.com/sequence-diagram + +autonumber + +actor Gegner + +actor Selbst +database InnerStructure +collections Zone +entity ZoneEvent + +Gegner -> Selbst: Treffer +Selbst -> InnerStructure: verarbeite Treffer +InnerStructure -> Zone: suche getroffene Außen-Zone +return Zone +InnerStructure -> ZoneEvent: erstelle **ZonenEvent** +return **ZonenEvent** +alt aktuelles **ZoneEvent** hat noch nicht alle Trefferpunkte verarbeitet + alt **Zone** hat noch Panzerung + InnerStructure -> ZonenEvent: trage Trefferpunkte ab + return ZoneEvent + else **Zone** hat keine Panzerung + InnerStructure -> Zone: hole Weiterleitung-Zone + return Zone + InnerStructure -> ZoneEvent: erstelle **ZonenEvent** für weitergeleitete **Zone** + return ZoneEvent + end +end + +@enduml \ No newline at end of file diff --git a/MechFabrik/bauteile/__init__.py b/MechFabrik/bauteile/__init__.py index 4036d17..35c30ca 100755 --- a/MechFabrik/bauteile/__init__.py +++ b/MechFabrik/bauteile/__init__.py @@ -2,6 +2,20 @@ import enum from typing import Any +class ZoneNames(enum.Enum): + HEAD = 'Kopf' + MIDDLE_TORSO_FRONT = 'Torso Mitte Vorn' + MIDDLE_TORSO_REAR = 'Torso Mitte Rücken' + RIGHT_TORSO_FRONT = 'Rechter Torso Vorn' + RIGHT_TORSO_REAR = 'Rechter Torso Rücken' + LEFT_TORSO_FRONT = 'Linker Torso Vorn' + LEFT_TORSO_REAR = 'Linker Torso Rücken' + RIGHT_LEG = 'Rechtes Bein' + RIGHT_ARM = 'Rechter Arm' + LEFT_LEG = 'Linkes Bein' + LEFT_ARM = 'Linker Arm' + + class AreaNames(enum.Enum): HEAD = 'Kopf' MIDDLE_TORSO = 'Torso Mitte' diff --git a/tests/test_mech/__init__.py b/tests/test_mech/__init__.py index 1cacc84..9072332 100644 --- a/tests/test_mech/__init__.py +++ b/tests/test_mech/__init__.py @@ -1,7 +1,7 @@ import unittest from MechFabrik import MechFabrik -from MechFabrik.bauteile import AreaNames +from MechFabrik.bauteile import AreaNames, ZoneNames INNER_ARMOR = { AreaNames.HEAD: 3, @@ -15,26 +15,43 @@ INNER_ARMOR = { } OUTER_ARMOR = { - AreaNames.HEAD: 6, - AreaNames.MIDDLE_TORSO: 9, - AreaNames.LEFT_TORSO: 8, - AreaNames.RIGHT_TORSO: 8, - AreaNames.LEFT_ARM: 5, - AreaNames.RIGHT_ARM: 5, - AreaNames.LEFT_LEG: 7, - AreaNames.RIGHT_LEG: 7, + ZoneNames.HEAD: 6, + ZoneNames.MIDDLE_TORSO_FRONT: 9, + ZoneNames.MIDDLE_TORSO_REAR: 4, + ZoneNames.LEFT_TORSO_FRONT: 8, + ZoneNames.LEFT_TORSO_REAR: 3, + ZoneNames.RIGHT_TORSO_FRONT: 8, + ZoneNames.RIGHT_TORSO_REAR: 3, + ZoneNames.LEFT_ARM: 5, + ZoneNames.RIGHT_ARM: 5, + ZoneNames.LEFT_LEG: 7, + ZoneNames.RIGHT_LEG: 7, } +NEXT_OUTER_ZONE = { + ZoneNames.HEAD: AreaNames.HEAD, + ZoneNames.MIDDLE_TORSO_FRONT: AreaNames.MIDDLE_TORSO, + ZoneNames.MIDDLE_TORSO_REAR: AreaNames.MIDDLE_TORSO, + ZoneNames.LEFT_TORSO_FRONT: AreaNames.LEFT_TORSO, + ZoneNames.LEFT_TORSO_REAR: AreaNames.LEFT_TORSO, + ZoneNames.RIGHT_TORSO_FRONT: AreaNames.RIGHT_TORSO, + ZoneNames.RIGHT_TORSO_REAR: AreaNames.RIGHT_TORSO, + ZoneNames.LEFT_ARM: AreaNames.LEFT_ARM, + ZoneNames.RIGHT_ARM: AreaNames.RIGHT_ARM, + ZoneNames.LEFT_LEG: AreaNames.LEFT_LEG, + ZoneNames.RIGHT_LEG: AreaNames.RIGHT_LEG, +} + class AbstractTestMechAmor(unittest.TestCase): def setUp(self): fabrik = MechFabrik('Heuschrecke', 20.0, 8) - fabrik.set_head_armor(OUTER_ARMOR[AreaNames.HEAD]) - fabrik.set_middle_torso_armor(OUTER_ARMOR[AreaNames.MIDDLE_TORSO]) - fabrik.set_side_torso_armor(OUTER_ARMOR[AreaNames.LEFT_TORSO]) - fabrik.set_arm_armor(OUTER_ARMOR[AreaNames.LEFT_ARM]) - fabrik.set_leg_armor(OUTER_ARMOR[AreaNames.LEFT_LEG]) + fabrik.set_head_armor(OUTER_ARMOR[ZoneNames.HEAD]) + fabrik.set_middle_torso_armor(OUTER_ARMOR[ZoneNames.MIDDLE_TORSO_FRONT],OUTER_ARMOR[ZoneNames.MIDDLE_TORSO_REAR]) + fabrik.set_side_torso_armor(OUTER_ARMOR[ZoneNames.LEFT_TORSO_FRONT],OUTER_ARMOR[ZoneNames.LEFT_TORSO_REAR]) + fabrik.set_arm_armor(OUTER_ARMOR[ZoneNames.LEFT_ARM]) + fabrik.set_leg_armor(OUTER_ARMOR[ZoneNames.LEFT_LEG]) self.mech = fabrik.auslieferung() diff --git a/tests/test_mech_bau.py b/tests/test_mech_bau.py index 86c16f8..1a8a168 100755 --- a/tests/test_mech_bau.py +++ b/tests/test_mech_bau.py @@ -1,7 +1,9 @@ import unittest from MechFabrik import MechFabrik -from MechFabrik.bauteile import InnerStructure, Gyroskope, AreaNames, Area, Cockpit, Item, ItemTypes, Reaktor, Mech +from MechFabrik.bauteile import InnerStructure, Gyroskope, AreaNames, Area, Cockpit, Item, ItemTypes, OuterAmor, \ + Reaktor, Mech, \ + Zone, ZoneNames from test_mech import AbstractTestMechAmor, INNER_ARMOR, OUTER_ARMOR @@ -20,9 +22,16 @@ class TestMechBau(unittest.TestCase): for ara_name in AreaNames: area = mech.inner_structure.areas.get(ara_name) - should_inner_amor = INNER_ARMOR[ara_name] - self.assertEqual(should_inner_amor, area.inner_armor) - self.assertEqual(0, area.armor) + should_amor = INNER_ARMOR[ara_name] + self.assertIsInstance(area, Zone) + self.assertIsInstance(area, Area) + self.assertEqual(should_amor, area.armor) + + for zone_name in ZoneNames: + zone = mech.inner_structure.zones.get(zone_name) + self.assertIsInstance(zone, Zone) + self.assertIsInstance(zone, OuterAmor) + self.assertEqual(0, zone.armor) self.assertIsInstance(mech.inner_structure, InnerStructure) self.assertIsInstance(mech.inner_structure.tonnage, float) @@ -44,6 +53,8 @@ class TestMechBau(unittest.TestCase): middle_torso = self._test_middle_torso(mech) right_torso = self._test_areas(mech=mech, parent=middle_torso, index=AreaNames.RIGHT_TORSO, children=2) left_torso = self._test_areas(mech=mech, parent=middle_torso, index=AreaNames.LEFT_TORSO, children=2) + self.assertIsInstance(area_head.parent, Area) + self.assertEqual(middle_torso, area_head.parent) self.assertCountEqual([right_torso, left_torso], middle_torso.children) right_arm = self._test_areas(mech=mech, parent=right_torso, index=AreaNames.RIGHT_ARM, children=0) @@ -148,7 +159,7 @@ class TestMechBau(unittest.TestCase): class TestMechAmor(AbstractTestMechAmor): def test_build(self): - for area_name in AreaNames: - area = self.mech.inner_structure.areas.get(area_name) - should_outer_armor = OUTER_ARMOR[area_name] - self.assertEqual(should_outer_armor, area.armor) + for zone_name in ZoneNames: + zone = self.mech.inner_structure.zones.get(zone_name) + should_outer_armor = OUTER_ARMOR[zone_name] + self.assertEqual(should_outer_armor, zone.armor) diff --git a/tests/test_mech_process.py b/tests/test_mech_process.py index 328cce4..b35ad29 100755 --- a/tests/test_mech_process.py +++ b/tests/test_mech_process.py @@ -1,32 +1,85 @@ import unittest -from test_mech import AbstractTestMechAmor, INNER_ARMOR, OUTER_ARMOR -from MechFabrik.bauteile import AreaNames, AreaStatus +from test_mech import AbstractTestMechAmor, INNER_ARMOR, NEXT_OUTER_ZONE, OUTER_ARMOR +from MechFabrik.bauteile import Area, AreaStatus, OuterAmor, StrikeEvent, ZoneNames class TestMechAmor(AbstractTestMechAmor): def test_process(self): - for area_name in AreaNames: - area = self.mech.inner_structure.areas.get(area_name) - start_armor = OUTER_ARMOR[area_name] - start_inner_armor = INNER_ARMOR[area_name] + for zone_name in ZoneNames: + with self.subTest(msg=zone_name.value): + zone = self.mech.inner_structure.zones.get(zone_name) + area = zone.area + start_outer_armor = OUTER_ARMOR[zone_name] + start_inner_armor = INNER_ARMOR[NEXT_OUTER_ZONE[zone_name]] - self.assertEqual(start_armor, area.armor) - self.assertEqual(start_inner_armor, area.inner_armor) - self.assertEqual(AreaStatus.FINE, area.state) + self.assertEqual(start_outer_armor, zone.armor) + self.assertEqual(area, zone.parent) + self.assertEqual(start_inner_armor, area.armor) + self.assertEqual(AreaStatus.FINE, zone.state) + self.assertEqual(AreaStatus.FINE, area.state) - self.mech.strike(area_name, start_armor - 3) - self.assertEqual(3, area.armor) - self.assertEqual(start_inner_armor, area.inner_armor) - self.assertEqual(AreaStatus.FINE, area.state) + event = self.mech.strike(zone_name, 10) + self.assertEqual(start_outer_armor, zone.armor) + self.assertEqual(start_inner_armor, area.armor) + self.assertEqual(AreaStatus.FINE, zone.state) + self.assertEqual(AreaStatus.FINE, area.state) + self.assertIsInstance(event, StrikeEvent) + self.assertEqual(zone, event.zone) + self.assertEqual(10, event.hits) + self.assertEqual(area, event.zone.parent) - self.mech.strike(area_name, 4) - self.assertEqual(0, area.armor) - self.assertEqual(start_inner_armor - 1, area.inner_armor) - self.assertEqual(AreaStatus.CRITICAL_STRIKE, area.state) + def test_strike(self): + start_outer_armor = 11 + start_area_armor = 5 + start_parent_armor = 3 + parent = Area() + parent.armor = start_parent_armor + area = Area() + area.armor = start_area_armor + area.parent = parent + zone = OuterAmor(area) + zone.armor = start_outer_armor - self.mech.strike(area_name, start_inner_armor - 1) - self.assertEqual(0, area.armor) - self.assertEqual(0, area.inner_armor) - self.assertEqual(AreaStatus.DESTROYED, area.state) + self.assertEqual(start_outer_armor, zone.armor) + self.assertEqual(start_area_armor, area.armor) + self.assertEqual(AreaStatus.FINE, zone.state) + self.assertEqual(AreaStatus.FINE, area.state) + + event = StrikeEvent(zone, start_outer_armor - 3).process_event() + self.assertEqual(3, zone.armor) + self.assertEqual(start_area_armor, area.armor) + self.assertEqual(AreaStatus.DAMAGED, zone.state) + self.assertEqual(AreaStatus.FINE, area.state) + self.assertIsInstance(event, StrikeEvent) + self.assertEqual(zone, event.zone) + self.assertEqual(0, event.hits) + + event = StrikeEvent(zone, 4).process_event() + self.assertEqual(0, zone.armor) + self.assertEqual(start_area_armor - 1, area.armor) + self.assertEqual(AreaStatus.DESTROYED, zone.state) + self.assertEqual(AreaStatus.DAMAGED, area.state) + self.assertIsInstance(event, StrikeEvent) + self.assertEqual(area, event.zone) + self.assertEqual(0, event.hits) + + event = StrikeEvent(zone, start_area_armor - 1).process_event() + self.assertEqual(0, zone.armor) + self.assertEqual(0, area.armor) + self.assertEqual(AreaStatus.DESTROYED, zone.state) + self.assertEqual(AreaStatus.DESTROYED, area.state) + self.assertIsInstance(event, StrikeEvent) + self.assertEqual(area, event.zone) + self.assertEqual(0, event.hits) + + event = StrikeEvent(zone, 1).process_event() + self.assertEqual(0, zone.armor) + self.assertEqual(0, area.armor) + self.assertEqual(AreaStatus.DESTROYED, zone.state) + self.assertEqual(AreaStatus.DESTROYED, area.state) + self.assertIsInstance(event, StrikeEvent) + self.assertNotEqual(area, event.zone) + self.assertEqual(area.parent, event.zone) + self.assertEqual(0, event.hits)