From 64ab1119bf4a12f43c15a0bb287b438a67a36ba0 Mon Sep 17 00:00:00 2001 From: primitiveType Date: Sat, 22 Apr 2023 12:37:06 -0700 Subject: [PATCH 1/3] - Change PieceUpdated Action to use event semantics. - Break PieceUpdated into 3 events to separate movement, removal and addition of pieces into separate events. --- .../PositionTests/PositionTests.cs | 64 ++++++++++++++++++- src/Rudzoft.ChessLib/Game.cs | 4 +- src/Rudzoft.ChessLib/IGame.cs | 4 +- src/Rudzoft.ChessLib/IPosition.cs | 48 +++++++++++++- src/Rudzoft.ChessLib/Position.cs | 30 +++++---- 5 files changed, 130 insertions(+), 20 deletions(-) diff --git a/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs b/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs index 5f62ac35..c67e5893 100644 --- a/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs +++ b/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs @@ -26,11 +26,18 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using Rudzoft.ChessLib.Factories; using Rudzoft.ChessLib.Types; +using Xunit.Abstractions; namespace Rudzoft.ChessLib.Test.PositionTests; public sealed class PositionTests { + private readonly ITestOutputHelper _testOutputHelper; + public PositionTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + [Fact] public void AddPieceTest() { @@ -88,4 +95,59 @@ public void KingBlocker() Assert.Equal(expectedSquare, actual); } -} \ No newline at end of file + + [Fact] + public void PieceMovedGeneratesEventWithPieceInfo() + { + int moveEventsReceived = 0; + int removeEventsReceived = 0; + int addEventsReceived = 0; + var moves = new[] + { + Move.Create(Square.F2, Square.F3), + Move.Create(Square.E7, Square.E5), + Move.Create(Square.G2, Square.G4), + Move.Create(Square.D7, Square.D6), + Move.Create(Square.H2, Square.H4), + Move.Create(Square.D8, Square.H4) + }; + + // construct game and start a new game + var game = GameFactory.Create(Fen.Fen.StartPositionFen); + game.Pos.IsProbing = false; + game.Pos.PieceMoved += PieceUpdated; + game.Pos.PieceAdded += PieceAdded; + game.Pos.PieceRemoved += PieceRemoved; + + var position = game.Pos; + + // make the moves necessary to create a mate + foreach (var move in moves) + position.MakeMove(move, game.Pos.State); + + //We should have received 6 move events and one remove. + Assert.Equal(6, moveEventsReceived); + Assert.Equal(1, removeEventsReceived); + Assert.Equal(0, addEventsReceived); + + void PieceUpdated(object sender, PieceMovedEventArgs args) + { + moveEventsReceived++; + Assert.NotEqual(Pieces.NoPiece, args.MovedPiece.Value); + _testOutputHelper.WriteLine($"{args.MovedPiece.Value} moved from {args.From} to {args.To}."); + } + void PieceRemoved(object sender, PieceRemovedEventArgs args) + { + removeEventsReceived++; + Assert.NotEqual(Pieces.NoPiece, args.RemovedPiece.Value); + _testOutputHelper.WriteLine($"{args.RemovedPiece.Value} removed from {args.EmptiedSquare}."); + } + + void PieceAdded(object sender, PieceAddedEventArgs args) + { + addEventsReceived++; + } + } + + +} diff --git a/src/Rudzoft.ChessLib/Game.cs b/src/Rudzoft.ChessLib/Game.cs index 364b7db6..85a0d5f6 100644 --- a/src/Rudzoft.ChessLib/Game.cs +++ b/src/Rudzoft.ChessLib/Game.cs @@ -57,8 +57,6 @@ static Game() Uci = new Uci(); } - public Action PieceUpdated => _pos.PieceUpdated; - public int MoveNumber => 0; //(PositionIndex - 1) / 2 + 1; public BitBoard Occupied => Pos.Pieces(); @@ -156,4 +154,4 @@ public ulong Perft(int depth, bool root = true) return tot; } -} \ No newline at end of file +} diff --git a/src/Rudzoft.ChessLib/IGame.cs b/src/Rudzoft.ChessLib/IGame.cs index ef20d316..b6371e4a 100644 --- a/src/Rudzoft.ChessLib/IGame.cs +++ b/src/Rudzoft.ChessLib/IGame.cs @@ -35,8 +35,6 @@ namespace Rudzoft.ChessLib; public interface IGame : IEnumerable { - Action PieceUpdated { get; } - BitBoard Occupied { get; } IPosition Pos { get; } @@ -60,4 +58,4 @@ public interface IGame : IEnumerable Player CurrentPlayer(); ulong Perft(int depth, bool root = true); -} \ No newline at end of file +} diff --git a/src/Rudzoft.ChessLib/IPosition.cs b/src/Rudzoft.ChessLib/IPosition.cs index de7cf116..488c9938 100644 --- a/src/Rudzoft.ChessLib/IPosition.cs +++ b/src/Rudzoft.ChessLib/IPosition.cs @@ -38,7 +38,9 @@ public interface IPosition : IEnumerable { bool IsProbing { get; set; } - Action PieceUpdated { get; set; } + public event PieceAddedEvent PieceAdded; + public event PieceMovedEvent PieceMoved; + public event PieceRemovedEvent PieceRemoved; ChessMode ChessMode { get; set; } @@ -202,3 +204,47 @@ public interface IPosition : IEnumerable IPositionValidator Validate(PositionValidationTypes type = PositionValidationTypes.Basic); } + +public delegate void PieceRemovedEvent(object sender, PieceRemovedEventArgs args); + +public class PieceRemovedEventArgs +{ + public Square EmptiedSquare { get; } + public Piece RemovedPiece { get; } + + public PieceRemovedEventArgs(Square emptiedSquare, Piece removedPiece) + { + EmptiedSquare = emptiedSquare; + RemovedPiece = removedPiece; + } +} + +public delegate void PieceMovedEvent(object sender, PieceMovedEventArgs args); + +public class PieceMovedEventArgs +{ + public Square From { get; } + public Square To { get; } + public Piece MovedPiece { get; } + + public PieceMovedEventArgs(Square from, Square to, Piece movedPiece) + { + From = from; + To = to; + MovedPiece = movedPiece; + } +} + +public delegate void PieceAddedEvent(object sender, PieceAddedEventArgs args); + +public class PieceAddedEventArgs +{ + public Square Square { get; } + public Piece NewPiece { get; } + + public PieceAddedEventArgs(Square square, Piece newPiece) + { + Square = square; + NewPiece = newPiece; + } +} diff --git a/src/Rudzoft.ChessLib/Position.cs b/src/Rudzoft.ChessLib/Position.cs index 44896084..ceb80b8e 100644 --- a/src/Rudzoft.ChessLib/Position.cs +++ b/src/Rudzoft.ChessLib/Position.cs @@ -77,6 +77,14 @@ public Position(IBoard board, IPieceValue pieceValues) public BitBoard Checkers => State.Checkers; + /// + /// To let something outside the library be aware of changes (like a UI etc) + /// + public event PieceRemovedEvent PieceRemoved; + + public event PieceAddedEvent PieceAdded; + public event PieceMovedEvent PieceMoved; + public ChessMode ChessMode { get; set; } public Square EnPassantSquare @@ -96,11 +104,6 @@ public bool IsMate public bool IsRepetition => State.Repetition >= 3; - /// - /// To let something outside the library be aware of changes (like a UI etc) - /// - public Action PieceUpdated { get; set; } - public IPieceValue PieceValue { get; } public int Ply { get; private set; } @@ -120,7 +123,7 @@ public void AddPiece(Piece pc, Square sq) Board.AddPiece(pc, sq); if (!IsProbing) - PieceUpdated?.Invoke(new PieceSquareEventArgs(pc, sq)); + PieceAdded?.Invoke(this, new PieceAddedEventArgs(sq, pc)); } public bool AttackedByKing(Square sq, Player p) @@ -973,9 +976,14 @@ public BitBoard PinnedPieces(Player p) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RemovePiece(Square sq) { + Piece removedPiece = Board.PieceAt(sq); + Board.RemovePiece(sq); + if (!IsProbing) - PieceUpdated?.Invoke( new PieceSquareEventArgs(Piece.EmptyPiece, sq)); + { + PieceRemoved?.Invoke(this, new PieceRemovedEventArgs(sq, removedPiece)); + } } public bool SeeGe(Move m, Value threshold) @@ -1353,7 +1361,7 @@ private void MovePiece(Square from, Square to) if (IsProbing) return; - PieceUpdated?.Invoke(new PieceSquareEventArgs(Board.PieceAt(from), to)); + PieceMoved?.Invoke(this, new PieceMovedEventArgs(from, to, Board.PieceAt(to))); } /// @@ -1446,9 +1454,7 @@ private void SetupCastleling(ReadOnlySpan castleling) Square RookSquare(Square startSq, Piece rook) { Square targetSq; - for (targetSq = startSq; Board.PieceAt(targetSq) != rook; --targetSq) - { - } + for (targetSq = startSq; Board.PieceAt(targetSq) != rook; --targetSq) { } return targetSq; } @@ -1500,4 +1506,4 @@ Square RookSquare(Square startSq, Piece rook) return result; } -} \ No newline at end of file +} From 15da7a1189eef381a2fc07742a8485b10de99b89 Mon Sep 17 00:00:00 2001 From: primitiveType Date: Sat, 22 Apr 2023 12:53:56 -0700 Subject: [PATCH 2/3] - move event stuff into its own folder --- .../PositionTests/PositionTests.cs | 1 + .../Events/PieceAddedEvent.cs | 3 ++ .../Events/PieceAddedEventArgs.cs | 15 +++++++ .../Events/PieceMovedEvent.cs | 3 ++ .../Events/PieceMovedEventArgs.cs | 17 +++++++ .../Events/PieceRemovedEvent.cs | 3 ++ .../Events/PieceRemovedEventArgs.cs | 15 +++++++ src/Rudzoft.ChessLib/IPosition.cs | 45 +------------------ src/Rudzoft.ChessLib/Position.cs | 1 + 9 files changed, 59 insertions(+), 44 deletions(-) create mode 100644 src/Rudzoft.ChessLib/Events/PieceAddedEvent.cs create mode 100644 src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs create mode 100644 src/Rudzoft.ChessLib/Events/PieceMovedEvent.cs create mode 100644 src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs create mode 100644 src/Rudzoft.ChessLib/Events/PieceRemovedEvent.cs create mode 100644 src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs diff --git a/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs b/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs index c67e5893..ee391346 100644 --- a/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs +++ b/src/Rudzoft.ChessLib.Test/PositionTests/PositionTests.cs @@ -24,6 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +using Rudzoft.ChessLib.Events; using Rudzoft.ChessLib.Factories; using Rudzoft.ChessLib.Types; using Xunit.Abstractions; diff --git a/src/Rudzoft.ChessLib/Events/PieceAddedEvent.cs b/src/Rudzoft.ChessLib/Events/PieceAddedEvent.cs new file mode 100644 index 00000000..6f44827c --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceAddedEvent.cs @@ -0,0 +1,3 @@ +namespace Rudzoft.ChessLib.Events; + +public delegate void PieceAddedEvent(object sender, PieceAddedEventArgs args); \ No newline at end of file diff --git a/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs new file mode 100644 index 00000000..14e53c65 --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs @@ -0,0 +1,15 @@ +using Rudzoft.ChessLib.Types; + +namespace Rudzoft.ChessLib.Events; + +public class PieceAddedEventArgs +{ + public Square Square { get; } + public Piece NewPiece { get; } + + public PieceAddedEventArgs(Square square, Piece newPiece) + { + Square = square; + NewPiece = newPiece; + } +} \ No newline at end of file diff --git a/src/Rudzoft.ChessLib/Events/PieceMovedEvent.cs b/src/Rudzoft.ChessLib/Events/PieceMovedEvent.cs new file mode 100644 index 00000000..eda97451 --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceMovedEvent.cs @@ -0,0 +1,3 @@ +namespace Rudzoft.ChessLib.Events; + +public delegate void PieceMovedEvent(object sender, PieceMovedEventArgs args); diff --git a/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs new file mode 100644 index 00000000..a22544a8 --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs @@ -0,0 +1,17 @@ +using Rudzoft.ChessLib.Types; + +namespace Rudzoft.ChessLib.Events; + +public class PieceMovedEventArgs +{ + public Square From { get; } + public Square To { get; } + public Piece MovedPiece { get; } + + public PieceMovedEventArgs(Square from, Square to, Piece movedPiece) + { + From = from; + To = to; + MovedPiece = movedPiece; + } +} \ No newline at end of file diff --git a/src/Rudzoft.ChessLib/Events/PieceRemovedEvent.cs b/src/Rudzoft.ChessLib/Events/PieceRemovedEvent.cs new file mode 100644 index 00000000..088e28bc --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceRemovedEvent.cs @@ -0,0 +1,3 @@ +namespace Rudzoft.ChessLib.Events; + +public delegate void PieceRemovedEvent(object sender, PieceRemovedEventArgs args); \ No newline at end of file diff --git a/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs new file mode 100644 index 00000000..09bfa09f --- /dev/null +++ b/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs @@ -0,0 +1,15 @@ +using Rudzoft.ChessLib.Types; + +namespace Rudzoft.ChessLib.Events; + +public class PieceRemovedEventArgs +{ + public Square EmptiedSquare { get; } + public Piece RemovedPiece { get; } + + public PieceRemovedEventArgs(Square emptiedSquare, Piece removedPiece) + { + EmptiedSquare = emptiedSquare; + RemovedPiece = removedPiece; + } +} \ No newline at end of file diff --git a/src/Rudzoft.ChessLib/IPosition.cs b/src/Rudzoft.ChessLib/IPosition.cs index 488c9938..f044a004 100644 --- a/src/Rudzoft.ChessLib/IPosition.cs +++ b/src/Rudzoft.ChessLib/IPosition.cs @@ -28,6 +28,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using System.Collections.Generic; using System.Text; using Rudzoft.ChessLib.Enums; +using Rudzoft.ChessLib.Events; using Rudzoft.ChessLib.Fen; using Rudzoft.ChessLib.Types; using Rudzoft.ChessLib.Validation; @@ -204,47 +205,3 @@ public interface IPosition : IEnumerable IPositionValidator Validate(PositionValidationTypes type = PositionValidationTypes.Basic); } - -public delegate void PieceRemovedEvent(object sender, PieceRemovedEventArgs args); - -public class PieceRemovedEventArgs -{ - public Square EmptiedSquare { get; } - public Piece RemovedPiece { get; } - - public PieceRemovedEventArgs(Square emptiedSquare, Piece removedPiece) - { - EmptiedSquare = emptiedSquare; - RemovedPiece = removedPiece; - } -} - -public delegate void PieceMovedEvent(object sender, PieceMovedEventArgs args); - -public class PieceMovedEventArgs -{ - public Square From { get; } - public Square To { get; } - public Piece MovedPiece { get; } - - public PieceMovedEventArgs(Square from, Square to, Piece movedPiece) - { - From = from; - To = to; - MovedPiece = movedPiece; - } -} - -public delegate void PieceAddedEvent(object sender, PieceAddedEventArgs args); - -public class PieceAddedEventArgs -{ - public Square Square { get; } - public Piece NewPiece { get; } - - public PieceAddedEventArgs(Square square, Piece newPiece) - { - Square = square; - NewPiece = newPiece; - } -} diff --git a/src/Rudzoft.ChessLib/Position.cs b/src/Rudzoft.ChessLib/Position.cs index ceb80b8e..44364d5c 100644 --- a/src/Rudzoft.ChessLib/Position.cs +++ b/src/Rudzoft.ChessLib/Position.cs @@ -32,6 +32,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using System.Text; using Microsoft.Extensions.ObjectPool; using Rudzoft.ChessLib.Enums; +using Rudzoft.ChessLib.Events; using Rudzoft.ChessLib.Extensions; using Rudzoft.ChessLib.Fen; using Rudzoft.ChessLib.Hash; From de8ff08ba272820ab8cc1fb1576d12952b27bf73 Mon Sep 17 00:00:00 2001 From: primitiveType Date: Sat, 22 Apr 2023 12:54:50 -0700 Subject: [PATCH 3/3] - convert args to structs --- src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs | 4 ++-- src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs | 4 ++-- src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs index 14e53c65..dea80504 100644 --- a/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs +++ b/src/Rudzoft.ChessLib/Events/PieceAddedEventArgs.cs @@ -2,7 +2,7 @@ namespace Rudzoft.ChessLib.Events; -public class PieceAddedEventArgs +public struct PieceAddedEventArgs { public Square Square { get; } public Piece NewPiece { get; } @@ -12,4 +12,4 @@ public PieceAddedEventArgs(Square square, Piece newPiece) Square = square; NewPiece = newPiece; } -} \ No newline at end of file +} diff --git a/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs index a22544a8..8187b4e5 100644 --- a/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs +++ b/src/Rudzoft.ChessLib/Events/PieceMovedEventArgs.cs @@ -2,7 +2,7 @@ namespace Rudzoft.ChessLib.Events; -public class PieceMovedEventArgs +public struct PieceMovedEventArgs { public Square From { get; } public Square To { get; } @@ -14,4 +14,4 @@ public PieceMovedEventArgs(Square from, Square to, Piece movedPiece) To = to; MovedPiece = movedPiece; } -} \ No newline at end of file +} diff --git a/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs b/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs index 09bfa09f..35b252ce 100644 --- a/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs +++ b/src/Rudzoft.ChessLib/Events/PieceRemovedEventArgs.cs @@ -2,7 +2,7 @@ namespace Rudzoft.ChessLib.Events; -public class PieceRemovedEventArgs +public struct PieceRemovedEventArgs { public Square EmptiedSquare { get; } public Piece RemovedPiece { get; } @@ -12,4 +12,4 @@ public PieceRemovedEventArgs(Square emptiedSquare, Piece removedPiece) EmptiedSquare = emptiedSquare; RemovedPiece = removedPiece; } -} \ No newline at end of file +}