问题描述
我正在写一个Java国际象棋游戏,我正在尝试整理设计。 这是我到目前为止的课程:
游戏:由2个玩家对象和一个棋盘对象组成
玩家:
板:由2d阵列(8×8)的Square对象组成,每个对象可能/可能没有一块
King,Queen,Rook,Bishop,Knight,Pawn:
Piece:上述部分的超类,共享功能在这里
这就是我不喜欢的内容:我的Square类中有一个名为“board”的字段,因此我可以引用给定方块所属的板。 我不喜欢这种设计,因为它会导致克隆问题。
所以我想在片段类中重写一些功能而不进行这种回溯。 对于一个能够访问每个方块的板子来说非常棒,但是我不想为Square类提供getBoard()函数。
这是我需要重写的函数示例:
public Square getSquareOneMoveAway(Square start, int heightChange, int widthChange) {
Square candidateSquare = start.getBoard().getNearbySquare(start, heightChange, widthChange);
if (candidateSquare != null) {
if (candidateSquare.isEmpty()) {
return candidateSquare;
} else if (! candidateSquare.getPiece().getColor().equals(start.getPiece().getColor())) {
return candidateSquare;
}
else {
return null;
}
}
else {
return null;
}
}
请注意,在我的Player类中,我有以下方法:
canMovePiece(Square start,Square end,Board board),movePiece(Square start,Square end,Board board)等
我是否应该将此方法移入Board类中,这样我就可以访问板对象而无需从Square转到板上?
任何想法都非常感激,bclayman
1楼
在我看来,你过度设计了这个问题。 用另一个类代表电路板的方块真的有什么好处吗? 如果不是(我不这么认为)我只是摆脱了Square类。
class Board {
public static final int MAX_ROWS = 8;
public static final int MAX_COLS = 8;
private Piece[][] squares;
public Board() {
squares = new Piece[ MAX_ROWS ][ MAX_COLS ];
}
// ...
}
不过,我有一个Position类,它有一对和一列。
希望这可以帮助。
2楼
以下ChessBoard
定义用于存储碎片,存储它们的位置,并使用该信息来确定给定移动是否有效。
class ChessBoard implements Board {
Piece[][] pieces; // null if vacant at that position
@Override
public boolean isValidMove(Player player, Square start, Square end) {
Piece pieceStart = pieces[start.row][start.col];
Piece pieceEnd = pieces[end.row][end.col];
return (
pieceStart != null &&
pieceStart.getColor() == player.getColor() &&
pieceStart.isValidTransition(start, end) &&
(pieceEnd == null || pieceStart.canDefeat(pieceEnd))
);
}
}
请注意,移动是否有效的逻辑被封装在正在移动的部分中。
class Pawn implements Piece {
@Override
public boolean isValidTransition(Square start, Square end) {
int dH = end.col - start.col;
int dW = end.row - start.row;
// return if is valid transition for a pawn in terms of dH and dW
}
@Override
public boolean canDefeat(Piece otherPiece) {
return (
this.getColor() != otherPiece.getColor() &&
this.getStrength() > otherPiece.getStrength()
);
}
@Override
public int getStrength() { ... }
@Override
public Color getColor() { ... }
}
square类只是一个包含行和列的简单2元组。
class Square {
int row, col;
}
3楼
我是一个实用主义者,所以我不会把它作为课程,只是枚举。 所以:
enum Pieces
{
Pawn,
Rook,
Knight
// etc
};
然后我创建一个名为'Rule'的接口,如下所示:
interface Rule
{
void addRule(Pieces p);
};
其中,通过让一个类实现规则,我可以决定单元在游戏中如何相互作用(或者最好在它上面)。 这个类将是PawnRule,QueenRule等。这样做,可以为游戏添加尽可能多的规则并使用它们。 这不仅有利于可扩展性,而且为游戏本身带来了可行的基础。
class PawnRule implements Rule
{
private boolean pFirstMove = true;
// etc
void addRule(Pieces p)
{
if (Square.hasSpace(Space.FRONT) * 2 && pFirstMove)
{
// where renderer holds 2D/3D data pertaining to the piece
rendrerer.getModel("Pawn").moveByTwo(); // somehow
}
}
}
在设计方面,还有很多需要考虑的因素; 并且可能是枚举不是你想要的。 我们也不知道游戏是基于文本的,2D还是3D。 一般来说,如果它是基于文本的,那么实现这些东西会更容易,但是当它是3D时更加复杂。 我建议您绘制一个类图,甚至是通信图,这样您就可以知道国际象棋游戏中的类/枚举/接口如何相互作用。