Merged in better-communication (pull request #49)

Better communication
This commit is contained in:
2022-05-10 22:14:25 +00:00
parent 04f2d115ad
commit 8951cd4223
26 changed files with 1397 additions and 811 deletions

View File

@@ -1,7 +1,6 @@
using FluentAssertions;
using FluentAssertions.Execution;
using System;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
@@ -9,10 +8,10 @@ namespace Shogi.Domain.UnitTests
{
public class ShogiShould
{
private readonly ITestOutputHelper output;
public ShogiShould(ITestOutputHelper output)
private readonly ITestOutputHelper logger;
public ShogiShould(ITestOutputHelper logger)
{
this.output = output;
this.logger = logger;
}
[Fact]
@@ -73,6 +72,8 @@ namespace Shogi.Domain.UnitTests
act.Should().Throw<InvalidOperationException>();
board["D5"].Should().BeNull();
board["D6"].Should().BeNull();
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
}
[Fact]
@@ -81,16 +82,19 @@ namespace Shogi.Domain.UnitTests
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
var expectedPiece = board["A3"];
// Act - P1 "moves" pawn to the position it already exists at.
var act = () => shogi.Move("A3", "A3", false);
// Assert
act.Should().Throw<InvalidOperationException>();
board["A3"].Should().NotBeNull();
board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board["A3"].Should().Be(expectedPiece);
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
}
}
[Fact]
@@ -99,17 +103,21 @@ namespace Shogi.Domain.UnitTests
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
var expectedPiece = board["A1"];
expectedPiece!.WhichPiece.Should().Be(WhichPiece.Lance);
// Act - Move Lance illegally
var act = () => shogi.Move("A1", "D5", false);
// Assert
act.Should().Throw<InvalidOperationException>();
board["A1"].Should().NotBeNull();
board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["A5"].Should().BeNull();
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board["A1"].Should().Be(expectedPiece);
board["A5"].Should().BeNull();
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
}
}
[Fact]
@@ -118,18 +126,20 @@ namespace Shogi.Domain.UnitTests
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
var expectedPiece = board["A7"];
expectedPiece!.Owner.Should().Be(WhichPlayer.Player2);
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
board["A7"].Should().NotBeNull();
board["A7"]!.Owner.Should().Be(WhichPlayer.Player2);
// Act - Move Player2 Pawn when it is Player1 turn.
var act = () => shogi.Move("A7", "A6", false);
// Assert
act.Should().Throw<InvalidOperationException>();
board["A7"].Should().NotBeNull();
board["A7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["A6"].Should().BeNull();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board["A7"].Should().Be(expectedPiece);
board["A6"].Should().BeNull();
}
}
[Fact]
@@ -138,17 +148,21 @@ namespace Shogi.Domain.UnitTests
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
var lance = board["A1"];
var pawn = board["A3"];
lance!.Owner.Should().Be(pawn!.Owner);
// Act - Move P1 Lance through P1 Pawn.
var act = () => shogi.Move("A1", "A5", false);
// Assert
act.Should().Throw<InvalidOperationException>();
board["A1"].Should().NotBeNull();
board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["A3"].Should().NotBeNull();
board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["A5"].Should().BeNull();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board["A1"].Should().Be(lance);
board["A3"].Should().Be(pawn);
board["A5"].Should().BeNull();
}
}
[Fact]
@@ -157,18 +171,22 @@ namespace Shogi.Domain.UnitTests
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
var knight = board["B1"];
var pawn = board["C3"];
knight!.Owner.Should().Be(pawn!.Owner);
// Act - P1 Knight tries to capture P1 Pawn.
var act = () => shogi.Move("B1", "C3", false);
// Arrange
act.Should().Throw<InvalidOperationException>();
board["B1"].Should().NotBeNull();
board["B1"]!.WhichPiece.Should().Be(WhichPiece.Knight);
board["C3"].Should().NotBeNull();
board["C3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board["B1"].Should().Be(knight);
board["C3"].Should().Be(pawn);
board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
}
}
[Fact]
@@ -184,26 +202,28 @@ namespace Shogi.Domain.UnitTests
// P1 Bishop puts P2 in check
shogi.Move("B2", "G7", false);
board.InCheck.Should().Be(WhichPlayer.Player2);
var lance = board["I9"];
// Act - P2 moves Lance while in check.
var act = () => shogi.Move("I9", "I8", false);
// Assert
act.Should().Throw<InvalidOperationException>();
board.InCheck.Should().Be(WhichPlayer.Player2);
board["I9"].Should().NotBeNull();
board["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["I8"].Should().BeNull();
using (new AssertionScope())
{
act.Should().Throw<InvalidOperationException>();
board.InCheck.Should().Be(WhichPlayer.Player2);
board["I9"].Should().Be(lance);
board["I8"].Should().BeNull();
}
}
[Fact]
// TODO: Consider nesting classes to share this setup in a constructor but have act and assert as separate facts.
public void PreventInvalidDrops_MoveSet()
{
// Arrange
var board = new ShogiBoardState();
var shogi = new Shogi(board);
// P1 Pawn
shogi.Move("C3", "C4", false);
// P2 Pawn
@@ -224,7 +244,6 @@ namespace Shogi.Domain.UnitTests
shogi.Move("H9", "I9", false);
// P2 Pawn captures P1 Pawn
shogi.Move("I4", "I3", false);
board.Player1Hand.Count.Should().Be(4);
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
@@ -232,37 +251,36 @@ namespace Shogi.Domain.UnitTests
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
// Act | Assert - Illegally placing Knight from the hand in farthest row.
// Act | Assert - Illegally placing Knight from the hand in farthest rank.
board["H9"].Should().BeNull();
shogi.Move()
var dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9"));
dropSuccess.Should().BeFalse();
shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
var act = () => shogi.Move(WhichPiece.Knight, "H9");
act.Should().Throw<InvalidOperationException>();
board["H9"].Should().BeNull();
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// Act | Assert - Illegally placing Knight from the hand in second farthest row.
shogi.Board["H8"].Should().BeNull();
dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H8"));
dropSuccess.Should().BeFalse();
shogi.Board["H8"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
board["H8"].Should().BeNull();
act = () => shogi.Move(WhichPiece.Knight, "H8");
act.Should().Throw<InvalidOperationException>();
board["H8"].Should().BeNull();
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// Act | Assert - Illegally place Lance from the hand.
shogi.Board["H9"].Should().BeNull();
dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9"));
dropSuccess.Should().BeFalse();
shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
board["H9"].Should().BeNull();
act = () => shogi.Move(WhichPiece.Knight, "H9");
act.Should().Throw<InvalidOperationException>();
board["H9"].Should().BeNull();
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
// Act | Assert - Illegally place Pawn from the hand.
shogi.Board["H9"].Should().BeNull();
dropSuccess = shogi.Move(new Move(WhichPiece.Pawn, "H9"));
dropSuccess.Should().BeFalse();
shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
board["H9"].Should().BeNull();
act = () => shogi.Move(WhichPiece.Pawn, "H9");
act.Should().Throw<InvalidOperationException>();
board["H9"].Should().BeNull();
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
// Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn.
// TODO
// // Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn.
// // TODO
}
//[Fact]
@@ -289,14 +307,14 @@ namespace Shogi.Domain.UnitTests
// var shogi = new Shogi(moves);
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
// shogi.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
// shogi.Board["E5"].Should().BeNull();
// boardState["E5"].Should().BeNull();
// // Act - P2 places a Bishop while in check.
// var dropSuccess = shogi.Move(new Move(WhichPiece.Bishop, "E5"));
// // Assert
// dropSuccess.Should().BeFalse();
// shogi.Board["E5"].Should().BeNull();
// boardState["E5"].Should().BeNull();
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
// shogi.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
//}
@@ -320,9 +338,9 @@ namespace Shogi.Domain.UnitTests
// using (new AssertionScope())
// {
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
// shogi.Board["I9"].Should().NotBeNull();
// shogi.Board["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
// shogi.Board["I9"].Owner.Should().Be(WhichPlayer.Player2);
// boardState["I9"].Should().NotBeNull();
// boardState["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
// boardState["I9"].Owner.Should().Be(WhichPlayer.Player2);
// }
// // Act - P1 tries to place a piece where an opponent's piece resides.
@@ -333,126 +351,112 @@ namespace Shogi.Domain.UnitTests
// {
// dropSuccess.Should().BeFalse();
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
// shogi.Board["I9"].Should().NotBeNull();
// shogi.Board["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
// shogi.Board["I9"].Owner.Should().Be(WhichPlayer.Player2);
// boardState["I9"].Should().NotBeNull();
// boardState["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
// boardState["I9"].Owner.Should().Be(WhichPlayer.Player2);
// }
//}
//[Fact]
//public void Check()
//{
// // Arrange
// var moves = new[]
// {
// // P1 Pawn
// new Move("C3", "C4"),
// // P2 Pawn
// new Move("G7", "G6"),
// };
// var shogi = new Shogi(moves);
[Fact]
public void Check()
{
// Arrange
var boardState = new ShogiBoardState();
var shogi = new Shogi(boardState);
// P1 Pawn
shogi.Move("C3", "C4", false);
// P2 Pawn
shogi.Move("G7", "G6", false);
// // Act - P1 Bishop, check
// shogi.Move(new Move("B2", "G7"));
// Act - P1 Bishop, check
shogi.Move("B2", "G7", false);
// // Assert
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
//}
// Assert
boardState.InCheck.Should().Be(WhichPlayer.Player2);
}
//[Fact]
//public void Promote()
//{
// // Arrange
// var moves = new[]
// {
// // P1 Pawn
// new Move("C3", "C4" ),
// // P2 Pawn
// new Move("G7", "G6" )
// };
// var shogi = new Shogi(moves);
[Fact]
public void Promote()
{
// Arrange
var boardState = new ShogiBoardState();
var shogi = new Shogi(boardState);
// P1 Pawn
shogi.Move("C3", "C4", false);
// P2 Pawn
shogi.Move("G7", "G6", false);
// // Act - P1 moves across promote threshold.
// var moveSuccess = shogi.Move(new Move("B2", "G7", true));
// Act - P1 moves across promote threshold.
shogi.Move("B2", "G7", true);
// // Assert
// using (new AssertionScope())
// {
// moveSuccess.Should().BeTrue();
// shogi.Board["B2"].Should().BeNull();
// shogi.Board["G7"].Should().NotBeNull();
// shogi.Board["G7"].WhichPiece.Should().Be(WhichPiece.Bishop);
// shogi.Board["G7"].Owner.Should().Be(WhichPlayer.Player1);
// shogi.Board["G7"].IsPromoted.Should().BeTrue();
// }
//}
// Assert
using (new AssertionScope())
{
boardState["B2"].Should().BeNull();
boardState["G7"].Should().NotBeNull();
boardState["G7"]!.WhichPiece.Should().Be(WhichPiece.Bishop);
boardState["G7"]!.Owner.Should().Be(WhichPlayer.Player1);
boardState["G7"]!.IsPromoted.Should().BeTrue();
}
}
//[Fact]
//public void CheckMate()
//{
// // Arrange
// var moves = new[]
// {
// // P1 Rook
// new Move("H2", "E2"),
// // P2 Gold
// new Move("F9", "G8"),
// // P1 Pawn
// new Move("E3", "E4"),
// // P2 other Gold
// new Move("D9", "C8"),
// // P1 same Pawn
// new Move("E4", "E5"),
// // P2 Pawn
// new Move("E7", "E6"),
// // P1 Pawn takes P2 Pawn
// new Move("E5", "E6"),
// // P2 King
// new Move("E9", "E8"),
// // P1 Pawn promotes, threatens P2 King
// new Move("E6", "E7", true),
// // P2 King retreat
// new Move("E8", "E9"),
// };
// var shogi = new Shogi(moves);
// output.WriteLine(shogi.PrintStateAsAscii());
[Fact]
public void Capture()
{
// Arrange
var boardState = new ShogiBoardState();
var shogi = new Shogi(boardState);
var p1Bishop = boardState["B2"];
p1Bishop!.WhichPiece.Should().Be(WhichPiece.Bishop);
shogi.Move("C3", "C4", false);
shogi.Move("G7", "G6", false);
// // Act - P1 Pawn wins by checkmate.
// var moveSuccess = shogi.Move(new Move("E7", "E8"));
// output.WriteLine(shogi.PrintStateAsAscii());
// Act - P1 Bishop captures P2 Bishop
shogi.Move("B2", "H8", false);
// // Assert - checkmate
// moveSuccess.Should().BeTrue();
// shogi.IsCheckmate.Should().BeTrue();
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
//}
// Assert
boardState["B2"].Should().BeNull();
boardState["H8"].Should().Be(p1Bishop);
//[Fact]
//public void Capture()
//{
// // Arrange
// var moves = new[]
// {
// new Move("C3", "C4"),
// new Move("G7", "G6")
// };
// var shogi = new Shogi(moves);
boardState
.Player1Hand
.Should()
.ContainSingle(p => p.WhichPiece == WhichPiece.Bishop && p.Owner == WhichPlayer.Player1);
}
// // Act - P1 Bishop captures P2 Bishop
// var moveSuccess = shogi.Move(new Move("B2", "H8"));
[Fact]
public void CheckMate()
{
// Arrange
var boardState = new ShogiBoardState();
var shogi = new Shogi(boardState);
// P1 Rook
shogi.Move("H2", "E2", false);
// P2 Gold
shogi.Move("F9", "G8", false);
// P1 Pawn
shogi.Move("E3", "E4", false);
// P2 other Gold
shogi.Move("D9", "C8", false);
// P1 same Pawn
shogi.Move("E4", "E5", false);
// P2 Pawn
shogi.Move("E7", "E6", false);
// P1 Pawn takes P2 Pawn
shogi.Move("E5", "E6", false);
// P2 King
shogi.Move("E9", "E8", false);
// P1 Pawn promotes; threatens P2 King
shogi.Move("E6", "E7", true);
// P2 King retreat
shogi.Move("E8", "E9", false);
// // Assert
// moveSuccess.Should().BeTrue();
// shogi.Board["B2"].Should().BeNull();
// shogi.Board["H8"].WhichPiece.Should().Be(WhichPiece.Bishop);
// shogi.Board["H8"].Owner.Should().Be(WhichPlayer.Player1);
// shogi.Board.Values
// .Where(p => p != null)
// .Should().ContainSingle(piece => piece.WhichPiece == WhichPiece.Bishop);
// Act - P1 Pawn wins by checkmate.
shogi.Move("E7", "E8", false);
// shogi.Player1Hand
// .Should()
// .ContainSingle(p => p.WhichPiece == WhichPiece.Bishop && p.Owner == WhichPlayer.Player1);
//}
// Assert - checkmate
boardState.IsCheckmate.Should().BeTrue();
boardState.InCheck.Should().Be(WhichPlayer.Player2);
}
}
}