From 4cdfe9c9578c37233e2e31f378e3393cbb2cfab7 Mon Sep 17 00:00:00 2001 From: hypercross Date: Tue, 21 Jul 2026 11:09:55 +0800 Subject: [PATCH] refactor: update iterator access and simplify loops Refactor code to use `Val1` and `Val2` instead of `Item1` and `Item2` for iterator access. Simplify `PlaceMarkCommand` and `WinCheckSystem` by replacing `while` loops with `foreach` and removing redundant comments. --- Game.TicTacToe.Tests/GameFlowTests.cs | 10 +++++----- Game.TicTacToe.Tests/PlayTests.cs | 8 ++++---- Game.TicTacToe.Tests/SnapshotTests.cs | 4 ++-- Game.TicTacToe/Commands/PlaceMarkCommand.cs | 20 +++++--------------- Game.TicTacToe/Systems/WinCheckSystem.cs | 16 ++++------------ 5 files changed, 20 insertions(+), 38 deletions(-) diff --git a/Game.TicTacToe.Tests/GameFlowTests.cs b/Game.TicTacToe.Tests/GameFlowTests.cs index 5140c7c..7ef208b 100644 --- a/Game.TicTacToe.Tests/GameFlowTests.cs +++ b/Game.TicTacToe.Tests/GameFlowTests.cs @@ -31,9 +31,9 @@ public class GameFlowTests foreach (var it in world.Select()) { markedCount++; - it.Item1.Row.Should().Be(0); - it.Item1.Col.Should().Be(0); - it.Item2.Player.Should().Be(Player.X); + it.Val1.Row.Should().Be(0); + it.Val1.Col.Should().Be(0); + it.Val2.Player.Should().Be(Player.X); } markedCount.Should().Be(1); @@ -66,7 +66,7 @@ public class GameFlowTests // Only one mark should exist at (0,0), and it should still be X. var marks = new List<(int Row, int Col, Player Player)>(); foreach (var it in world.Select()) - marks.Add((it.Item1.Row, it.Item1.Col, it.Item2.Player)); + marks.Add((it.Val1.Row, it.Val1.Col, it.Val2.Player)); marks.Should().ContainSingle() .Which.Should().Be((0, 0, Player.X)); @@ -166,7 +166,7 @@ public class GameFlowTests var marks = new List<(int Row, int Col, Player Player)>(); foreach (var it in world2.Select()) - marks.Add((it.Item1.Row, it.Item1.Col, it.Item2.Player)); + marks.Add((it.Val1.Row, it.Val1.Col, it.Val2.Player)); marks.Should().BeEquivalentTo([(0, 0, Player.X), (1, 0, Player.O)]); } diff --git a/Game.TicTacToe.Tests/PlayTests.cs b/Game.TicTacToe.Tests/PlayTests.cs index 1a7f548..b3792bd 100644 --- a/Game.TicTacToe.Tests/PlayTests.cs +++ b/Game.TicTacToe.Tests/PlayTests.cs @@ -161,8 +161,8 @@ public class PlayTests var sb = new System.Text.StringBuilder(); var grid = new char?[3, 3]; foreach (var it in world.Select()) - grid[it.Item1.Row, it.Item1.Col] = - it.Item2.Player == Player.X ? 'X' : 'O'; + grid[it.Val1.Row, it.Val1.Col] = + it.Val2.Player == Player.X ? 'X' : 'O'; for (int r = 0; r < 3; r++) { @@ -251,7 +251,7 @@ public class PlayTests { var empty = new List<(int, int)>(); foreach (var it in world.Select(new Query().Without())) - empty.Add((it.Item1.Row, it.Item1.Col)); + empty.Add((it.Val1.Row, it.Val1.Col)); return empty; } @@ -259,7 +259,7 @@ public class PlayTests { var grid = new Player[3, 3]; foreach (var it in world.Select()) - grid[it.Item1.Row, it.Item1.Col] = it.Item2.Player; + grid[it.Val1.Row, it.Val1.Col] = it.Val2.Player; grid[row, col] = player; for (int r = 0; r < 3; r++) diff --git a/Game.TicTacToe.Tests/SnapshotTests.cs b/Game.TicTacToe.Tests/SnapshotTests.cs index 2673cab..39acedb 100644 --- a/Game.TicTacToe.Tests/SnapshotTests.cs +++ b/Game.TicTacToe.Tests/SnapshotTests.cs @@ -209,8 +209,8 @@ public class SnapshotTests // Board: build a 3x3 grid. var grid = new char?[3, 3]; foreach (var it in world.Select()) - grid[it.Item1.Row, it.Item1.Col] = - it.Item2.Player == Player.X ? 'X' : 'O'; + grid[it.Val1.Row, it.Val1.Col] = + it.Val2.Player == Player.X ? 'X' : 'O'; int totalCells = 0; int markedCells = 0; diff --git a/Game.TicTacToe/Commands/PlaceMarkCommand.cs b/Game.TicTacToe/Commands/PlaceMarkCommand.cs index e6d9212..822b7c8 100644 --- a/Game.TicTacToe/Commands/PlaceMarkCommand.cs +++ b/Game.TicTacToe/Commands/PlaceMarkCommand.cs @@ -15,34 +15,24 @@ public struct PlaceMarkCommand : ICommand public void Execute(World world) { - // Read-only check before iteration — never auto-marks. if (world.ReadSingleton().Status != GameStatus.Playing) return; // Find the cell entity at (Row, Col) that has no Mark. - var query = new Query().Without(); 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(); - - while (iter.MoveNext()) - { - if (iter.Item1.Row == Row && iter.Item1.Col == Col) - { - target = iter.Entity; - break; - } + foreach(var iter in world.Select(new Query().Without())){ + if (iter.Val1.Row != Row || iter.Val1.Col != Col) continue; + target = iter.Entity; + break; } if (target == null) - return; // Cell already occupied or invalid position. + return; - // 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; } diff --git a/Game.TicTacToe/Systems/WinCheckSystem.cs b/Game.TicTacToe/Systems/WinCheckSystem.cs index eade168..e473dfc 100644 --- a/Game.TicTacToe/Systems/WinCheckSystem.cs +++ b/Game.TicTacToe/Systems/WinCheckSystem.cs @@ -8,24 +8,18 @@ namespace Game.TicTacToe; /// public class WinCheckSystem : ISystem { - public void Run(World world) + public void RunImpl(World world) { - // Check game status before doing any work. Use ReadSingleton - // to avoid auto-marking GameState as modified when we bail early. if (world.ReadSingleton().Status != GameStatus.Playing) return; - // Get singleton ref inside iteration so all mutations are auto-marked - // by EndIteration — no MarkModified calls needed. - using var iter = world.Select(); ref var state = ref world.GetSingleton(); // Build a 3×3 grid of marks. var grid = new Player[3, 3]; - - while (iter.MoveNext()) + foreach (var iter in world.Select()) { - grid[iter.Item1.Row, iter.Item1.Col] = iter.Item2.Player; + grid[iter.Val1.Row, iter.Val1.Col] = iter.Val2.Player; } // Check rows. @@ -62,9 +56,7 @@ public class WinCheckSystem : ISystem // Check draw. if (state.MoveCount >= 9) - { state.Status = GameStatus.Draw; - } } private static bool TryGetWinner(Player a, Player b, Player c, out Player winner) @@ -82,4 +74,4 @@ public class WinCheckSystem : ISystem { state.Status = winner == Player.X ? GameStatus.XWon : GameStatus.OWon; } -} \ No newline at end of file +}