所以,我正在尝试制作一个国际象棋引擎来温习一下我的生锈,我通常是一名 C# 程序员。
在 C# 中,对于我的数据表示,我有类似的内容:
public abstract class Piece
{
public Coordinate Location;
public abstract bool IsWhite {get;}
public abstract string PieceCode {get;} // e.g. K for a king
public abstract Move[] GetPossibleMoves(Board board);
}
public sealed class Pawn:Piece {//etc...}
Run Code Online (Sandbox Code Playgroud)
然后我的董事会将拥有一系列可以使用的所有组件。
我相信,在 Rust 中,这样的事情将是应用更高级枚举的好例子,所以像这样:
struct Piece {
position: Coordinate,
isWhite: bool,
charCode: char
}
enum PieceType {
King(Piece),
Queen(Piece),
Bishop(Piece),
Knight(Piece),
Rook(Piece),
Pawn(Piece)
}
Run Code Online (Sandbox Code Playgroud)
但随后我不太确定应该将实现放在哪里以获得可能的动作。每个Piece实例都不知道它是什么类型,将PieceType枚举添加到Piece结构中感觉就像是这种结构试图实现的目标的对立面。
我想我可以有一个Board带有 a 的结构Vec<PieceType>,并且有一个类似于GetMovesFor(PieceType)其中带有开关的方法?但在这一点上,感觉一种方法将完成的工作远远不止一项,它会包含每个部分的实现细节,而不是像我用 C# 构建它那样只包含一个部分的实现细节。
另一种选择是,我可以走与 C# 中非常相似的路线,只使用一个Piece特征,在每种类型上实现它,并为我的板提供一个Vec<Piece>. 但在这一点上,我觉得我只是在尝试模仿多态性,而不是以简单的方式做事。
所以我觉得我要么误解了这些扩展枚举的目标是什么,而这实际上并不是如何使用它们。或者,我遗漏了一些实现细节。
能够解决这两点的答案将是伟大的!
我认为最简单的模型通常是最好的,这就是一个片段有一种颜色和一种类型,它们都可以表示为没有有效负载的枚举。我认为当你的枚举并不真正需要有效负载时,你会有点迷失方向。
pub struct Piece {
pub kind: PieceKind,
pub color: PieceColor,
}
pub enum PieceKind {
Pawn,
Knight,
Bishop,
Rook,
Queen,
King,
}
pub enum PieceColor {
White,
Black,
}
Run Code Online (Sandbox Code Playgroud)
棋盘只是一个 8x8 的Pieces 数组,加上一些确定易位和过路移动合法性所需的附加信息:
pub struct Board {
pub pieces: [[Option<Piece>; 8]; 8],
pub white_can_castle_a: bool,
pub white_can_castle_h: bool,
pub black_can_castle_a: bool,
pub black_can_castle_h: bool,
// Some if the last piece moved was a pawn that was moved two spaces;
// contains the coordinates to check for a valid en passant capture.
pub last_double_pawn_move: Option<(usize, usize)>,
}
Run Code Online (Sandbox Code Playgroud)
通过此模型,您可以获得生成任何棋子的有效走法列表所需的所有信息。
请注意,这里的棋子没有位置数据;棋子的位置由其在棋盘中的位置决定。在我看来,您希望“获得可能的动作”成为主要存在于棋子上的操作是不正确的。您需要有关整个电路板的信息来确定这一点,通过让此方法接受来在您的模型中显示该信息Board。我将其建模为一种Board接受 x,y 坐标对的方法。
// This type could use more members to be able to annotate special
// moves like castling.
struct Move {
from: (usize, usize),
to: (usize, usize),
}
impl Board {
pub fn get_legal_moves_for(&self, piece: (usize, usize)) -> Vec<Move> {
todo!()
}
}
Run Code Online (Sandbox Code Playgroud)
我认为您感到困惑的部分原因是您试图使用特征来设计模型,以便在每种部件上具有多态性。虽然基于特征的多态性很好,但在这种模型中,它需要动态调度和堆分配(这在 Java 中才会发生),而 Rust 可以使用更有效的内存布局。基于 的多态性也没有任何问题match——事实上,这正是Either类型实现特征的方式!
| 归档时间: |
|
| 查看次数: |
117 次 |
| 最近记录: |