Chessistics/Scripts/Input/InputMapper.cs
Samuel Bouchet e6eaae43ab Initial commit: Chessistics prototype v0.3
Black box sim engine (commands in, events out) with 3 piece types
(Rook, Bishop, Knight), cargo transfer system with social status
priority, collision detection, and victory/defeat conditions.

57 tests covering rules, simulation, loading, and solvability.
Godot 4 presentation layer scaffolding.
2026-04-10 14:58:03 +02:00

161 lines
4.7 KiB
C#

using Godot;
using System;
using Chessistics.Engine.Model;
using Chessistics.Engine.Rules;
using Chessistics.Scripts.Board;
namespace Chessistics.Scripts.Input;
public partial class InputMapper : Node
{
[Signal]
public delegate void PlacementRequestedEventHandler(int kindIndex, int startCol, int startRow, int endCol, int endRow);
[Signal]
public delegate void RemovalRequestedEventHandler(int pieceId);
[Signal]
public delegate void CellClickedEventHandler(int col, int row);
[Signal]
public delegate void CancelledEventHandler();
public enum PlacementPhase { None, SelectingStart, SelectingEnd }
private BoardView _boardView = null!;
private PieceKind? _selectedKind;
private Coords? _selectedStart;
private PlacementPhase _phase = PlacementPhase.None;
private BoardSnapshot? _snapshot;
public PlacementPhase CurrentPhase => _phase;
public void Initialize(BoardView boardView)
{
_boardView = boardView;
}
public void SetSnapshot(BoardSnapshot snapshot) => _snapshot = snapshot;
public void SelectPieceKind(PieceKind kind)
{
_selectedKind = kind;
_selectedStart = null;
_phase = PlacementPhase.SelectingStart;
}
public void Cancel()
{
_selectedKind = null;
_selectedStart = null;
_phase = PlacementPhase.None;
_boardView.ClearHighlights();
EmitSignal(SignalName.Cancelled);
}
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventMouseButton mouseEvent && mouseEvent.Pressed)
{
if (mouseEvent.ButtonIndex == MouseButton.Right)
{
Cancel();
return;
}
if (mouseEvent.ButtonIndex == MouseButton.Left)
{
HandleLeftClick(mouseEvent.GlobalPosition);
}
}
if (@event is InputEventKey keyEvent && keyEvent.Pressed && keyEvent.Keycode == Key.Escape)
{
Cancel();
}
}
private void HandleLeftClick(Vector2 globalPos)
{
var localPos = _boardView.ToLocal(globalPos);
var coords = _boardView.PixelToCoords(localPos);
if (coords == null) return;
switch (_phase)
{
case PlacementPhase.SelectingStart:
OnStartSelected(coords.Value);
break;
case PlacementPhase.SelectingEnd:
OnEndSelected(coords.Value);
break;
default:
EmitSignal(SignalName.CellClicked, coords.Value.Col, coords.Value.Row);
break;
}
}
private void OnStartSelected(Coords start)
{
if (_selectedKind == null || _snapshot == null) return;
// Build a temporary board state for move validation
var boardState = GetBoardStateForValidation();
if (boardState == null) return;
var legalEnds = MoveValidator.GetLegalEndCells(_selectedKind.Value, start, boardState);
if (legalEnds.Count == 0) return;
_selectedStart = start;
_phase = PlacementPhase.SelectingEnd;
_boardView.ClearHighlights();
_boardView.HighlightCells(legalEnds, new Color("#4488FF88"));
var startCell = _boardView.GetCellView(start);
startCell?.SetHighlightColor(new Color("#44FFFF44"));
}
private void OnEndSelected(Coords end)
{
if (_selectedKind == null || _selectedStart == null) return;
var start = _selectedStart.Value;
var kind = _selectedKind.Value;
EmitSignal(SignalName.PlacementRequested, (int)kind, start.Col, start.Row, end.Col, end.Row);
// Reset placement state
_phase = PlacementPhase.None;
_selectedKind = null;
_selectedStart = null;
_boardView.ClearHighlights();
}
private BoardState? GetBoardStateForValidation()
{
// Reconstruct a minimal BoardState from snapshot for MoveValidator
// This is a read-only usage — we just need the grid and dimensions
if (_snapshot == null) return null;
// We need a LevelDef-like structure to create a BoardState
// For validation purposes, we create a fresh one from the snapshot data
var level = new LevelDef
{
Width = _snapshot.Width,
Height = _snapshot.Height,
Productions = [],
Demands = [],
Walls = [],
Stock = []
};
var state = BoardState.FromLevel(level);
// Copy grid from snapshot
for (int c = 0; c < _snapshot.Width; c++)
for (int r = 0; r < _snapshot.Height; r++)
state.Grid[c, r] = _snapshot.Grid[c, r];
return state;
}
}