oecs-sharp/Game.TicTacToe/Commands/PlaceMarkCommand.cs

50 lines
1.5 KiB
C#

using MessagePack;
using OECS;
namespace Game.TicTacToe;
/// <summary>
/// Places the current player's mark on the cell at (Row, Col).
/// Validates that the cell is empty and the game is still playing.
/// </summary>
[MessagePackObject]
public struct PlaceMarkCommand : ICommand
{
[Key(0)] public int Row;
[Key(1)] public int Col;
public void Execute(World world)
{
// Read-only check before iteration — never auto-marks.
if (world.ReadSingleton<GameState>().Status != GameStatus.Playing)
return;
// Find the cell entity at (Row, Col) that has no Mark.
var query = new Query<Cell>().Without<Mark>();
Entity? target = null;
// Fetch singleton ref inside iteration so mutations are auto-marked.
using var iter = world.Select(query);
ref var state = ref world.GetSingleton<GameState>();
while (iter.MoveNext())
{
if (iter.Item1.Row == Row && iter.Item1.Col == Col)
{
target = iter.Entity;
break;
}
}
if (target == null)
return; // Cell already occupied or invalid position.
// Place the mark.
world.AddComponent(target.Value, new Mark { Player = state.CurrentPlayer });
// Advance turn. Mutations auto-marked via EndIteration — no MarkModified needed.
state.MoveCount++;
state.CurrentPlayer = state.CurrentPlayer == Player.X ? Player.O : Player.X;
}
}