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

@@ -0,0 +1,47 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class Bishop : Piece
{
private static readonly ReadOnlyCollection<Path> BishopPaths = new(new List<Path>(4)
{
new Path(Direction.UpLeft, Distance.MultiStep),
new Path(Direction.UpRight, Distance.MultiStep),
new Path(Direction.DownLeft, Distance.MultiStep),
new Path(Direction.DownRight, Distance.MultiStep)
});
public static readonly ReadOnlyCollection<Path> PromotedBishopPaths = new(new List<Path>(8)
{
new Path(Direction.Up),
new Path(Direction.Left),
new Path(Direction.Right),
new Path(Direction.Down),
new Path(Direction.UpLeft, Distance.MultiStep),
new Path(Direction.UpRight, Distance.MultiStep),
new Path(Direction.DownLeft, Distance.MultiStep),
new Path(Direction.DownRight, Distance.MultiStep)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
BishopPaths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public static readonly ReadOnlyCollection<Path> Player2PromotedPaths =
PromotedBishopPaths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public Bishop(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.Bishop, owner, isPromoted)
{
}
public override IEnumerable<Path> MoveSet => IsPromoted ? PromotedBishopPaths : BishopPaths;
}
}

View File

@@ -0,0 +1,31 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class GoldGeneral : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(6)
{
new Path(Direction.Up),
new Path(Direction.UpLeft),
new Path(Direction.UpRight),
new Path(Direction.Left),
new Path(Direction.Right),
new Path(Direction.Down)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public GoldGeneral(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.GoldGeneral, owner, isPromoted)
{
}
public override IEnumerable<Path> MoveSet => Player1Paths;
}
}

View File

@@ -0,0 +1,27 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class King : Piece
{
internal static readonly ReadOnlyCollection<Path> KingPaths = new(new List<Path>(8)
{
new Path(Direction.Up),
new Path(Direction.Left),
new Path(Direction.Right),
new Path(Direction.Down),
new Path(Direction.UpLeft),
new Path(Direction.UpRight),
new Path(Direction.DownLeft),
new Path(Direction.DownRight)
});
public King(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.King, owner, isPromoted)
{
}
public override IEnumerable<Path> MoveSet => KingPaths;
}
}

View File

@@ -0,0 +1,32 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class Knight : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(2)
{
new Path(Direction.KnightLeft),
new Path(Direction.KnightRight)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public Knight(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.Knight, owner, isPromoted)
{
}
public override ReadOnlyCollection<Path> MoveSet => Owner switch
{
WhichPlayer.Player1 => IsPromoted ? GoldGeneral.Player1Paths : Player1Paths,
WhichPlayer.Player2 => IsPromoted ? GoldGeneral.Player2Paths : Player2Paths,
_ => throw new NotImplementedException(),
};
}
}

View File

@@ -0,0 +1,31 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class Lance : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(1)
{
new Path(Direction.Up, Distance.MultiStep),
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public Lance(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.Lance, owner, isPromoted)
{
}
public override ReadOnlyCollection<Path> MoveSet => Owner switch
{
WhichPlayer.Player1 => IsPromoted ? GoldGeneral.Player1Paths : Player1Paths,
WhichPlayer.Player2 => IsPromoted ? GoldGeneral.Player2Paths : Player2Paths,
_ => throw new NotImplementedException(),
};
}
}

View File

@@ -0,0 +1,31 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class Pawn : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(1)
{
new Path(Direction.Up)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public Pawn(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.Pawn, owner, isPromoted)
{
}
public override ReadOnlyCollection<Path> MoveSet => Owner switch
{
WhichPlayer.Player1 => IsPromoted ? GoldGeneral.Player1Paths : Player1Paths,
WhichPlayer.Player2 => IsPromoted ? GoldGeneral.Player2Paths : Player2Paths,
_ => throw new NotImplementedException(),
};
}
}

View File

@@ -0,0 +1,78 @@
using Shogi.Domain.Pathing;
using System.Diagnostics;
namespace Shogi.Domain.Pieces
{
[DebuggerDisplay("{WhichPiece} {Owner}")]
public abstract class Piece
{
/// <summary>
/// Creates a clone of an existing piece.
/// </summary>
public static Piece Create(Piece piece) => Create(piece.WhichPiece, piece.Owner, piece.IsPromoted);
public static Piece Create(WhichPiece piece, WhichPlayer owner, bool isPromoted = false)
{
return piece switch
{
WhichPiece.King => new King(owner, isPromoted),
WhichPiece.GoldGeneral => new GoldGeneral(owner, isPromoted),
WhichPiece.SilverGeneral => new SilverGeneral(owner, isPromoted),
WhichPiece.Bishop => new Bishop(owner, isPromoted),
WhichPiece.Rook => new Rook(owner, isPromoted),
WhichPiece.Knight => new Knight(owner, isPromoted),
WhichPiece.Lance => new Lance(owner, isPromoted),
WhichPiece.Pawn => new Pawn(owner, isPromoted),
_ => throw new ArgumentException($"Unknown {nameof(WhichPiece)} when cloning a {nameof(Piece)}.")
};
}
// TODO: MoveSet doesn't account for Player2's pieces which are upside-down.
public abstract IEnumerable<Path> MoveSet { get; }
public WhichPiece WhichPiece { get; }
public WhichPlayer Owner { get; private set; }
public bool IsPromoted { get; private set; }
public bool IsUpsideDown => Owner == WhichPlayer.Player2;
protected Piece(WhichPiece piece, WhichPlayer owner, bool isPromoted = false)
{
WhichPiece = piece;
Owner = owner;
IsPromoted = isPromoted;
}
public bool CanPromote => !IsPromoted
&& WhichPiece != WhichPiece.King
&& WhichPiece != WhichPiece.GoldGeneral;
public void Promote() => IsPromoted = CanPromote;
/// <summary>
/// Prep the piece for capture by changing ownership and demoting.
/// </summary>
public void Capture(WhichPlayer newOwner)
{
Owner = newOwner;
IsPromoted = false;
}
public IEnumerable<Vector2> GetPathFromStartToEnd(Vector2 start, Vector2 end)
{
var steps = new List<Vector2>(10);
var path = this.MoveSet.GetNearestPath(start, end);
var position = start;
while (Vector2.Distance(start, position) < Vector2.Distance(start, end))
{
position += path.Direction;
steps.Add(position);
}
if (position == end)
{
return steps;
}
return Array.Empty<Vector2>();
}
}
}

View File

@@ -0,0 +1,52 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
public sealed class Rook : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(4)
{
new Path(Direction.Up, Distance.MultiStep),
new Path(Direction.Left, Distance.MultiStep),
new Path(Direction.Right, Distance.MultiStep),
new Path(Direction.Down, Distance.MultiStep)
});
private static readonly ReadOnlyCollection<Path> PromotedPlayer1Paths = new(new List<Path>(8)
{
new Path(Direction.Up, Distance.MultiStep),
new Path(Direction.Left, Distance.MultiStep),
new Path(Direction.Right, Distance.MultiStep),
new Path(Direction.Down, Distance.MultiStep),
new Path(Direction.UpLeft),
new Path(Direction.UpRight),
new Path(Direction.DownLeft),
new Path(Direction.DownRight)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(m => m.Invert())
.ToList()
.AsReadOnly();
public static readonly ReadOnlyCollection<Path> Player2PromotedPaths =
PromotedPlayer1Paths
.Select(m => m.Invert())
.ToList()
.AsReadOnly();
public Rook(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.Rook, owner, isPromoted)
{
}
public override ReadOnlyCollection<Path> MoveSet => Owner switch
{
WhichPlayer.Player1 => IsPromoted ? PromotedPlayer1Paths : Player1Paths,
WhichPlayer.Player2 => IsPromoted ? Player2PromotedPaths : Player2Paths,
_ => throw new NotImplementedException(),
};
}
}

View File

@@ -0,0 +1,35 @@
using Shogi.Domain.Pathing;
using System.Collections.ObjectModel;
namespace Shogi.Domain.Pieces
{
internal class SilverGeneral : Piece
{
public static readonly ReadOnlyCollection<Path> Player1Paths = new(new List<Path>(4)
{
new Path(Direction.Up),
new Path(Direction.UpLeft),
new Path(Direction.UpRight),
new Path(Direction.DownLeft),
new Path(Direction.DownRight)
});
public static readonly ReadOnlyCollection<Path> Player2Paths =
Player1Paths
.Select(p => p.Invert())
.ToList()
.AsReadOnly();
public SilverGeneral(WhichPlayer owner, bool isPromoted = false)
: base(WhichPiece.SilverGeneral, owner, isPromoted)
{
}
public override ReadOnlyCollection<Path> MoveSet => Owner switch
{
WhichPlayer.Player1 => IsPromoted ? GoldGeneral.Player1Paths : Player1Paths,
WhichPlayer.Player2 => IsPromoted ? GoldGeneral.Player2Paths : Player2Paths,
_ => throw new NotImplementedException(),
};
}
}