From 1d4896f1f22a88c49ef116887efbe9a40a105457 Mon Sep 17 00:00:00 2001 From: Eugene Blikh Date: Tue, 28 Apr 2026 03:38:39 +0300 Subject: [PATCH] systems-power: HUD geometry + hudHitTest with tests systems-power --- hud.go | 30 +++++++++++++++++++ hud_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 hud.go create mode 100644 hud_test.go diff --git a/hud.go b/hud.go new file mode 100644 index 0000000000000000000000000000000000000000..6b090279801d3289cfc1b284e76aa7c7eb79cf93 --- /dev/null +++ b/hud.go @@ -0,0 +1,30 @@ +package main + +// HUD geometry constants. All values are in virtual pixels (640×360 grid). +// HudY is the top edge of the HUD strip; the five power columns begin at HudX +// and are each HudColW pixels wide. The reactor-readout band occupies the +// horizontal range [0, HudX). +const ( + HudY = 272 + HudX = 200 + HudColW = 40 + HudColCount = 5 +) + +// hudHitTest maps a virtual-pixel coordinate to the RoomRole whose power column +// was clicked. Returns ok=false for any coordinate outside the column strip: +// - py < HudY (above the HUD) +// - px < HudX (reactor-readout band to the left) +// - px >= HudX + HudColCount*HudColW (right of last column) +// +// Columns are flush (no gutters). Column i covers [HudX+i*HudColW, HudX+(i+1)*HudColW). +func hudHitTest(px, py int) (RoomRole, bool) { + if py < HudY { + return 0, false + } + if px < HudX || px >= HudX+HudColCount*HudColW { + return 0, false + } + idx := (px - HudX) / HudColW + return RoomRole(idx), true +} diff --git a/hud_test.go b/hud_test.go new file mode 100644 index 0000000000000000000000000000000000000000..dfda1799964660980f3ab0cf68ffc2869d0a156d --- /dev/null +++ b/hud_test.go @@ -0,0 +1,83 @@ +package main + +import "testing" + +// TestHudHitTest_aboveHud verifies that a pixel above the HUD strip returns ok=false. +func TestHudHitTest_aboveHud(t *testing.T) { + _, ok := hudHitTest(HudX+HudColW/2, HudY-1) + if ok { + t.Errorf("expected ok=false for py=%d (above HudY=%d)", HudY-1, HudY) + } +} + +// TestHudHitTest_leftOfColumns verifies that a pixel in the reactor-readout band +// to the left of the column strip returns ok=false. +func TestHudHitTest_leftOfColumns(t *testing.T) { + _, ok := hudHitTest(HudX-1, HudY) + if ok { + t.Errorf("expected ok=false for px=%d (left of HudX=%d)", HudX-1, HudX) + } +} + +// TestHudHitTest_rightOfColumns verifies that a pixel at or beyond the right edge +// of the column strip returns ok=false. +func TestHudHitTest_rightOfColumns(t *testing.T) { + px := HudX + HudColCount*HudColW + _, ok := hudHitTest(px, HudY) + if ok { + t.Errorf("expected ok=false for px=%d (right edge, HudX+5*HudColW=%d)", px, HudX+HudColCount*HudColW) + } +} + +// TestHudHitTest_eachColumnCenter verifies that the pixel at the horizontal centre +// of column i maps to RoomRole(i) with ok=true. +func TestHudHitTest_eachColumnCenter(t *testing.T) { + roles := []RoomRole{RolePilot, RoleWeapons, RoleShields, RoleMedBay, RoleEngines} + for i, want := range roles { + px := HudX + i*HudColW + HudColW/2 + py := HudY + got, ok := hudHitTest(px, py) + if !ok { + t.Errorf("column %d centre px=%d: expected ok=true", i, px) + continue + } + if got != want { + t.Errorf("column %d centre px=%d: got role %d, want %d", i, px, got, want) + } + } +} + +// TestHudHitTest_columnEdges verifies inclusive left-edge and exclusive right-edge +// semantics for each column. +func TestHudHitTest_columnEdges(t *testing.T) { + py := HudY + + for i := 0; i < HudColCount; i++ { + // Left edge of column i — inclusive, must return RoomRole(i). + leftPx := HudX + i*HudColW + got, ok := hudHitTest(leftPx, py) + if !ok { + t.Errorf("column %d left edge px=%d: expected ok=true", i, leftPx) + } else if got != RoomRole(i) { + t.Errorf("column %d left edge px=%d: got role %d, want %d", i, leftPx, got, RoomRole(i)) + } + + // Right edge of column i (first pixel of next column) — exclusive. + rightPx := HudX + (i+1)*HudColW + if i < HudColCount-1 { + // Should belong to column i+1. + got, ok = hudHitTest(rightPx, py) + if !ok { + t.Errorf("column %d right-exclusive px=%d: expected ok=true (belongs to col %d)", i, rightPx, i+1) + } else if got != RoomRole(i+1) { + t.Errorf("column %d right-exclusive px=%d: got role %d, want %d", i, rightPx, got, RoomRole(i+1)) + } + } else { + // Last column: right edge is out of bounds. + _, ok = hudHitTest(rightPx, py) + if ok { + t.Errorf("last column right-exclusive px=%d: expected ok=false", rightPx) + } + } + } +}