我的Checker系列中的下一篇文章: F#库的F#包装器,以使从C#代码中调用这些方法更加简洁。
public enum Player
{
White, Black
}
public enum PieceType
{
Checker,
King
}
public static class Extensions
{
public static Player Convert(this Checkers.Types.Player value) =>
Equals(value, Checkers.Types.Player.Black) ? Player.Black : Player.White;
public static Checkers.Types.Player ConvertBack(this Player value) =>
value == Player.Black ? Checkers.Types.Player.Black : Checkers.Types.Player.White;
public static PieceType Convert(this Checkers.Types.PieceType value) =>
Equals(value, Checkers.Types.PieceType.Checker) ? PieceType.Checker : PieceType.King;
public static Checkers.Types.PieceType ConvertBack(this PieceType value) =>
value == PieceType.Checker ? Checkers.Types.PieceType.Checker : Checkers.Types.PieceType.King;
public static Piece Convert(this FSharpOption<Checkers.Piece.Piece> piece)
{
if (Equals(piece, Checkers.Piece.whiteChecker))
{
return Piece.WhiteChecker;
}
if (Equals(piece, Checkers.Piece.whiteKing))
{
return Piece.WhiteKing;
}
if (Equals(piece, Checkers.Piece.blackChecker))
{
return Piece.BlackChecker;
}
if (Equals(piece, Checkers.Piece.blackKing))
{
return Piece.BlackKing;
}
return null;
}
public static FSharpOption<Checkers.Piece.Piece> ConvertBack(this Piece piece)
{
if (Equals(piece, Piece.WhiteChecker))
{
return Checkers.Piece.whiteChecker;
}
if (Equals(piece, Piece.WhiteKing))
{
return Checkers.Piece.whiteKing;
}
if (Equals(piece, Piece.BlackChecker))
{
return Checkers.Piece.blackChecker;
}
if (Equals(piece, Piece.BlackKing))
{
return Checkers.Piece.blackKing;
}
return null;
}
}public class Coord
{
public int Row { get; }
public int Column { get; }
public Coord(int row, int column)
{
Row = row;
Column = column;
}
public static Coord operator +(Coord coord1, Coord cooord2)
{
return new Coord(coord1.Row + cooord2.Row, coord1.Column + cooord2.Column);
}
public static implicit operator Coord(Checkers.Types.Coord coord)
{
return new Coord(coord.Row, coord.Column);
}
public static implicit operator Checkers.Types.Coord(Coord coord)
{
return new Checkers.Types.Coord(coord.Row, coord.Column);
}
public static implicit operator Coord(FSharpOption<Checkers.Types.Coord> coord)
{
return Equals(coord, FSharpOption<Checkers.Types.Coord>.None)
? null
: new Coord(coord.Value.Row, coord.Value.Column);
}
public static implicit operator FSharpOption<Checkers.Types.Coord>(Coord coord)
{
return coord == null
? FSharpOption<Checkers.Types.Coord>.None
: FSharpOption<Checkers.Types.Coord>.Some(new Checkers.Types.Coord(coord.Row, coord.Column));
}
}public class Piece
{
public Player Player { get; }
public PieceType PieceType { get; }
public Piece(Player player, PieceType pieceType)
{
Player = player;
PieceType = pieceType;
}
public static Piece WhiteChecker =>
new Piece(Player.White, PieceType.Checker);
public static Piece WhiteKing =>
new Piece(Player.White, PieceType.King);
public static Piece BlackChecker =>
new Piece(Player.Black, PieceType.Checker);
public static Piece BlackKing =>
new Piece(Player.Black, PieceType.King);
public override bool Equals(object obj)
{
if (obj == null || typeof(Piece) != obj.GetType())
{
return false;
}
var value = (Piece)obj;
return Player.Equals(value.Player) &&
PieceType.Equals(value.PieceType);
}
public override int GetHashCode() => Player.GetHashCode() ^ PieceType.GetHashCode();
}public class Board
{
public List<List<Piece>> GameBoard { get; }
public Board(IEnumerable<IEnumerable<FSharpOption<Checkers.Piece.Piece>>> board)
{
GameBoard = board.Select(row => row.Select(piece => piece.Convert()).ToList()).ToList();
}
public Board() : this(Checkers.Board.defaultBoard) { }
public Piece this[Coord coord] => GameBoard[coord.Row][coord.Column];
public static implicit operator Board(FSharpList<FSharpList<FSharpOption<Checkers.Piece.Piece>>> value)
{
return new Board(value);
}
public static implicit operator FSharpList<FSharpList<FSharpOption<Checkers.Piece.Piece>>>(Board value)
{
return Checkers.Board.listFromSeq(value.GameBoard.Select(row => row.Select(piece => piece.ConvertBack())));
}
}public class GameController : INotifyPropertyChanged
{
public GameController(Board board, Player currentPlayer, Coord currentCoord = null)
{
Board = board;
CurrentPlayer = currentPlayer;
CurrentCoord = currentCoord;
}
public Player CurrentPlayer { get; }
public Coord CurrentCoord { get; }
private Board _board;
public Board Board
{
get { return _board; }
set
{
Debug.Assert(value.GameBoard != null);
_board = value;
OnPropertyChanged();
}
}
public GameController(Checkers.GameController.GameController gameController)
:this(gameController.Board, gameController.CurrentPlayer.Convert(), gameController.CurrentCoord) { }
public GameController()
: this(new Board(), Player.Black) { }
public GameController Move(Coord startCoord, Coord endCoord) =>
Checkers.PublicAPI.movePiece(startCoord, endCoord, this);
public GameController Move(IEnumerable<Coord> moves) =>
Checkers.PublicAPI.move(moves.Select(item => (Checkers.Types.Coord)item), this);
public bool IsValidMove(Coord startCoord, Coord endCoord) =>
Checkers.PublicAPI.isValidMove(startCoord, endCoord, this);
public IEnumerable<Coord> GetMove(int searchDepth) =>
Checkers.PublicAPI.getMove(searchDepth, this).Select(coord => (Coord)coord);
public Player? GetWinningPlayer()
{
var player = Checkers.PublicAPI.isWon(this);
return Equals(player, FSharpOption<Checkers.Types.Player>.None) ? new Player?() : player.Value.Convert();
}
public static implicit operator GameController(Checkers.GameController.GameController controller)
{
return new GameController(controller);
}
public static implicit operator Checkers.GameController.GameController(GameController controller)
{
return new Checkers.GameController.GameController(controller.Board, controller.CurrentPlayer.ConvertBack(),
controller.CurrentCoord);
}
public static implicit operator GameController(FSharpOption<Checkers.GameController.GameController> controller)
{
return Equals(controller, FSharpOption<Checkers.GameController.GameController>.None)
? null
: new GameController(controller.Value);
}
public static implicit operator FSharpOption<Checkers.GameController.GameController>(GameController controller)
{
return controller == null
? FSharpOption<Checkers.GameController.GameController>.None
: FSharpOption<Checkers.GameController.GameController>.Some(
new Checkers.GameController.GameController(controller.Board, controller.CurrentPlayer.ConvertBack(),
controller.CurrentCoord));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}发布于 2016-12-27 21:59:35
为什么每次检索Piece类的公共静态属性时都需要创建一个新的片段实例并返回它?
我倾向于将它们声明为静态只读字段或静态获取属性,如下所示:
public static Piece WhiteChecker { get; } =
new Piece(Player.White, PieceType.Checker);
public static Piece WhiteKing { get; } =
new Piece(Player.White, PieceType.King);
public static Piece BlackChecker { get; } =
new Piece(Player.Black, PieceType.Checker);
public static Piece BlackKing { get; } =
new Piece(Player.Black, PieceType.King);如果类不是用于继承的,可以考虑将它们设置为sealed。
在当前的实现中,(假设)以下条件可能返回true对象的Piece对象:
if (obj == null || typeof(Piece) != obj.GetType())原因:对于从Piece派生的某些类型的对象,obj.GetType()返回不等于Piece的类型。
另一种方法是在考虑继承的情况下比较类型:
if (!typeof(Piece).IsInstanceOfType(obj))为什么不在IEquatable<Piece>类中实现Piece接口?当您调用Equals方法来比较两个PieceS时,它将消除不必要的装箱:
public class Piece : IEquatable<Piece>
{
...
public override bool Equals(object obj)
{
return Equals(obj as Piece);
}
public bool Equals(Piece other)
{
return other != null
&& Player.Equals(other.Player)
&& PieceType.Equals(other.PieceType);
}
...
}https://codereview.stackexchange.com/questions/150982
复制相似问题