using MessagePack; using OECS; namespace TicTacToe; /// /// Places the current player's mark on the cell at (Row, Col). /// Validates that the cell is empty and the game is still playing. /// [MessagePackObject] public struct PlaceMarkCommand : ICommand { [Key(0)] public int Row; [Key(1)] public int Col; public void Execute(World world) { ref var state = ref world.GetSingleton(); if (state.Status != GameStatus.Playing) return; // Copy to locals so the lambda in ForEach can capture them // (this is a struct, so `this` cannot be captured directly). int row = Row; int col = Col; // Find the cell entity at (Row, Col) that has no Mark. var query = world.Query().With().Without().Build(); Entity? target = null; world.ForEach(query, (Entity entity, ref Cell cell) => { if (cell.Row == row && cell.Col == col) target = entity; }); if (target == null) return; // Cell already occupied or invalid position. // Place the mark. world.AddComponent(target.Value, new Mark { Player = state.CurrentPlayer }); world.MarkModified(target.Value); // Advance turn. state.MoveCount++; state.CurrentPlayer = state.CurrentPlayer == Player.X ? Player.O : Player.X; world.MarkModified(World.SingletonEntity); } }