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; // Find the cell entity at (Row, Col) that has no Mark. // Use the iterator API with early-exit via break. var query = world.Query().With().Without().Build(); Entity? target = null; using var iter = world.Select(query); while (iter.MoveNext()) { if (iter.Current1.Row == Row && iter.Current1.Col == Col) { target = iter.CurrentEntity; break; } } if (target == null) return; // Cell already occupied or invalid position. // Place the mark. ComponentAdded is sufficient — MarkModified // is only needed when mutating an existing component via GetComponent. world.AddComponent(target.Value, new Mark { Player = state.CurrentPlayer }); // Advance turn. state.MoveCount++; state.CurrentPlayer = state.CurrentPlayer == Player.X ? Player.O : Player.X; world.MarkModified(World.SingletonEntity); } }