Add non-regression test states and Bluetooth diagnostic script

- Introduced a new JSON file containing non-regression test states with detailed unit information, including positions, ages, and movement directions across multiple frames.
- Added a shell script for Bluetooth diagnostics that checks system information, Bluetooth binaries, running processes, D-Bus status, Bluetooth controller details, and audio stack status, providing a comprehensive overview for troubleshooting.
This commit is contained in:
John Doe
2026-05-17 23:36:24 +02:00
parent dd82ccc087
commit 486cd6b7c5
31 changed files with 2244 additions and 698 deletions
+35 -32
View File
@@ -5,23 +5,26 @@ from units import gas, rat, bomb, mine
class UnitManager:
def __init__(self, game):
self.game = game
def _spawnable_rat_positions(self):
positions = []
for y in range(1, self.map.height - 1):
for x in range(1, self.map.width - 1):
if not self.map.is_empty(x, y):
for y in range(1, self.game.map.height - 1):
for x in range(1, self.game.map.width - 1):
if not self.game.map.is_empty(x, y):
continue
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx = x + dx
ny = y + dy
if self.map.in_bounds(nx, ny) and self.map.is_empty(nx, ny):
if self.game.map.in_bounds(nx, ny) and self.game.map.is_empty(nx, ny):
positions.append((x, y))
break
return positions
def has_weapon_at(self, position):
"""Check if there's a weapon (bomb, gas, mine) at the given position"""
for unit in self.units.values():
for unit in self.game.units.values():
if unit.position == position:
# Check if it's a weapon type (not a rat or points)
if isinstance(unit, (bomb.Timer, bomb.NuclearBomb, gas.Gas, mine.Mine)):
@@ -30,9 +33,9 @@ class UnitManager:
def can_place_weapon_at(self, position):
x, y = position
if not self.map.in_bounds(x, y):
if not self.game.map.in_bounds(x, y):
return False
if not self.map.is_empty(x, y):
if not self.game.map.is_empty(x, y):
return False
if self.has_weapon_at(position):
return False
@@ -40,19 +43,19 @@ class UnitManager:
def count_rats(self):
count = 0
for unit in self.units.values():
for unit in self.game.units.values():
if isinstance(unit, rat.Rat):
count += 1
return count
def spawn_gas(self, parent_id=None):
if not self.can_place_weapon_at(self.pointer):
if not self.can_place_weapon_at(self.game.pointer):
return
if self.ammo["gas"]["count"] <= 0:
if self.game.ammo["gas"]["count"] <= 0:
return
self.ammo["gas"]["count"] -= 1
self.render_engine.play_sound("GAS.WAV")
self.spawn_unit(gas.Gas, self.pointer, parent_id=parent_id)
self.game.ammo["gas"]["count"] -= 1
self.game.render_engine.play_sound("GAS.WAV")
self.spawn_unit(gas.Gas, self.game.pointer, parent_id=parent_id)
def spawn_rat(self, position=None):
if position is None:
@@ -68,9 +71,9 @@ class UnitManager:
# Try nearby positions
for dx, dy in [(0,1), (1,0), (0,-1), (-1,0), (1,1), (-1,-1), (1,-1), (-1,1)]:
alt_pos = (position[0] + dx, position[1] + dy)
if not self.map.in_bounds(alt_pos[0], alt_pos[1]):
if not self.game.map.in_bounds(alt_pos[0], alt_pos[1]):
continue
if self.map.is_empty(alt_pos[0], alt_pos[1]) and not self.has_weapon_at(alt_pos):
if self.game.map.is_empty(alt_pos[0], alt_pos[1]) and not self.has_weapon_at(alt_pos):
position = alt_pos
break
else:
@@ -84,45 +87,45 @@ class UnitManager:
def spawn_bomb(self, position):
if not self.can_place_weapon_at(position):
return
if self.ammo["bomb"]["count"] <= 0:
if self.game.ammo["bomb"]["count"] <= 0:
return
self.render_engine.play_sound("PUTDOWN.WAV")
self.game.render_engine.play_sound("PUTDOWN.WAV")
self.spawn_unit(bomb.Timer, position)
self.ammo["bomb"]["count"] -= 1
self.game.ammo["bomb"]["count"] -= 1
def spawn_nuclear_bomb(self, position):
"""Spawn a nuclear bomb at the specified position"""
if self.ammo["nuclear"]["count"] <= 0:
if self.game.ammo["nuclear"]["count"] <= 0:
return
if not self.can_place_weapon_at(position):
return
self.render_engine.play_sound("NUCLEAR.WAV")
self.ammo["nuclear"]["count"] -= 1
self.game.render_engine.play_sound("NUCLEAR.WAV")
self.game.ammo["nuclear"]["count"] -= 1
self.spawn_unit(bomb.NuclearBomb, position)
def spawn_mine(self, position):
if self.ammo["mine"]["count"] <= 0:
if self.game.ammo["mine"]["count"] <= 0:
return
if not self.can_place_weapon_at(position):
return
self.render_engine.play_sound("PUTDOWN.WAV")
self.ammo["mine"]["count"] -= 1
self.game.render_engine.play_sound("PUTDOWN.WAV")
self.game.ammo["mine"]["count"] -= 1
self.spawn_unit(mine.Mine, position, on_bottom=True)
def spawn_unit(self, unit, position, on_bottom=False, **kwargs):
id = uuid.uuid4()
if on_bottom:
self.units = {id: unit(self, position, id, **kwargs), **self.units}
self.game.units = {id: unit(self.game, position, id, **kwargs), **self.game.units}
else:
self.units[id] = unit(self, position, id, **kwargs)
self.game.units[id] = unit(self.game, position, id, **kwargs)
def choose_start(self):
if not hasattr(self, '_valid_positions') or self._valid_positions is None:
self._valid_positions = self._spawnable_rat_positions()
print(f"[flow] choose_start computed {len(self._valid_positions)} spawnable cells", flush=True)
if not self._valid_positions:
if not hasattr(self.game, '_valid_positions') or self.game._valid_positions is None:
self.game._valid_positions = self._spawnable_rat_positions()
print(f"[flow] choose_start computed {len(self.game._valid_positions)} spawnable cells", flush=True)
if not self.game._valid_positions:
return None
return random.choice(self._valid_positions)
return random.choice(self.game._valid_positions)
def get_unit_by_id(self, id):
return self.units.get(id) or None
return self.game.units.get(id) or None