Piece
和Board
之间的关系?目前,我正在将棋子的位置存储在棋子中和板上。有什么方法可以改变这种情况吗?我考虑过一个
Game
包含一个Board
和两个Players
的实例(一个黑色,一个白色)。这些部分包含与董事会的联系,因为为了确定它们是否有效,我们需要了解与其他部分的关系。我可以为此使用设计模式吗?我应该使用接口代替超类吗?
Game.java
public class Game {
private Board board = new Board();
private Player white;
private Player black;
public Game() {
super();
}
public void setColorWhite(Player player) {
this.white = player;
}
public void setColorBlack(Player player) {
this.black = player;
}
public Board getBoard() {
return board;
}
public void setBoard(Board board) {
this.board = board;
}
public Player getWhite() {
return white;
}
public void setWhite(Player white) {
this.white = white;
}
public Player getBlack() {
return black;
}
public void setBlack(Player black) {
this.black = black;
}
public boolean initializeBoardGivenPlayers() {
if(this.black == null || this.white == null)
return false;
this.board = new Board();
for(int i=0; i<black.getPieces().size(); i++){
board.getSpot(black.getPieces().get(i).getX(), black.getPieces().get(i).getY()).occupySpot(black.getPieces().get(i));
}
return true;
}
}
Player.java
public class Player {
public final int PAWNS = 8;
public final int BISHOPS = 2;
public final int ROOKS = 2;
public boolean white;
private List<Piece> pieces = new ArrayList<>();
public Player(boolean white) {
super();
this.white = white;
}
public List<Piece> getPieces() {
return pieces;
}
public void initializePieces(){
if(this.white == true){
for(int i=0; i<PAWNS; i++){ // draw pawns
pieces.add(new Pawn(true,i,2));
}
pieces.add(new Rook(true, 0, 0));
pieces.add(new Rook(true, 7, 0));
pieces.add(new Bishop(true, 2, 0));
pieces.add(new Bishop(true, 5, 0));
pieces.add(new Knight(true, 1, 0));
pieces.add(new Knight(true, 6, 0));
pieces.add(new Queen(true, 3, 0));
pieces.add(new King(true, 4, 0));
}
else{
for(int i=0; i<PAWNS; i++){ // draw pawns
pieces.add(new Pawn(true,i,6));
}
pieces.add(new Rook(true, 0, 7));
pieces.add(new Rook(true, 7, 7));
pieces.add(new Bishop(true, 2, 7));
pieces.add(new Bishop(true, 5, 7));
pieces.add(new Knight(true, 1, 7));
pieces.add(new Knight(true, 6, 7));
pieces.add(new Queen(true, 3, 7));
pieces.add(new King(true, 4, 7));
}
}
}
Board.java
public class Board {
private Spot[][] spots = new Spot[8][8];
public Board() {
super();
for(int i=0; i<spots.length; i++){
for(int j=0; j<spots.length; j++){
this.spots[i][j] = new Spot(i, j);
}
}
}
public Spot getSpot(int x, int y) {
return spots[x][y];
}
}
Spot.java
public class Spot {
int x;
int y;
Piece piece;
public Spot(int x, int y) {
super();
this.x = x;
this.y = y;
piece = null;
}
public void occupySpot(Piece piece){
//if piece already here, delete it, i. e. set it dead
if(this.piece != null)
this.piece.setAvailable(false);
//place piece here
this.piece = piece;
}
public boolean isOccupied() {
if(piece != null)
return true;
return false;
}
public Piece releaseSpot() {
Piece releasedPiece = this.piece;
this.piece = null;
return releasedPiece;
}
}
零件。 java
public class Piece {
private boolean available;
private int x;
private int y;
public Piece(boolean available, int x, int y) {
super();
this.available = available;
this.x = x;
this.y = y;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY){
if(toX == fromX && toY == fromY)
return false; //cannot move nothing
if(toX < 0 || toX > 7 || fromX < 0 || fromX > 7 || toY < 0 || toY > 7 || fromY <0 || fromY > 7)
return false;
return true;
}
}
King.java
public class King extends Piece{
public King(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(Math.sqrt(Math.pow(Math.abs((toX - fromX)),2)) + Math.pow(Math.abs((toY - fromY)), 2) != Math.sqrt(2)){
return false;
}
return false;
}
}
Knight.java
public class Knight extends Piece{
public Knight(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX != fromX - 1 && toX != fromX + 1 && toX != fromX + 2 && toX != fromX - 2)
return false;
if(toY != fromY - 2 && toY != fromY + 2 && toY != fromY - 1 && toY != fromY + 1)
return false;
return true;
}
}
Bishop.java
public class Bishop extends Piece{
public Bishop(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX - fromX == toY - fromY)
return true;
return false;
}
}
Rook.java
public class Rook extends Piece{
public Rook(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
女王。 java
public class Queen extends Piece{
public Queen(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
//diagonal
if(toX - fromX == toY - fromY)
return true;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
#1 楼
在不进行深入代码审查的情况下(因为我没有很多特定的Java知识),让我们来看一看完整的“移动”在国际象棋中所需要的:玩家选择了移动。
部件会根据自己的移动规则进行合法移动。
除了纯粹基于移动的规则外,还有捕获逻辑,因此如果有一块坐在上面,主教就不能从a1-h8移开。 c3。
如果玩家之前处于检查中,并且移动未移除该支票,则必须将其撤消。
如果该移动暴露了支票,则必须将其撤消/禁止。
如果玩家捕获一块,取出一块(包括传人!)
如果一块是到达后排的棋子,则将其提升。
如果移动是is子,则相应地设置车子的新位置。 。但是国王和白嘴鸦只有在他们没有动弹的情况下才能城堡,因此您需要保持跟踪。如果国王通过支票进入城堡,那也是不允许的。
如果此举导致僵局或死刑,游戏就结束了。
可能还会更多(? )。这是一个复杂的步骤,不仅仅是计算并随后占用空间。并且move方法将包含用于验证上述步骤的所有代码:
检查
Piece.isValidMove(currentSpot, newSpot);
-由于国王移动了1个以上的空间,并且白嘴鸦跳了国王,因此这里可能需要进行逻辑运算。检查
Player.isChecked()
(这只是Player.Pieces["King"].CanBeCaptured()
的糖-这里有更多有趣的逻辑!)检查
newSpot
是否包含一个片断,如果包含,则newSpot.Piece.Remove()
; 构建一些逻辑来调用
Piece.CheckEnPassant()
(片断是典当,第一个向前移动2个步骤,越过敌人的棋子,该棋子在上一个动作中移入了捕获位置-玩得开心!)Piece.CheckPromote()
(棋子是棋子,移动在对面玩家的后排位置结束)检查Game.isOver()
是否检查Game.isStaleMate()
和Game.isCheckMate()
。您的Board类非常贫乏,您仅在代码中将其用作斑点数组的代理对象。您不妨将Board创建为游戏中的一系列景点。无论哪种情况,您都可以从所有逻辑中删除它,因为所有逻辑完全取决于要传入的X和Y。
UPDATE
I将从您的作品中删除您所有的位置属性。您仅将其用作代理来确定初始化期间该作品占据的位置。取而代之的是删除
Player.initializePieces()
,然后用正确的位置(Board.Spot.Piece = King等)将棋子初始化,然后让玩家选择颜色。评论
\ $ \ begingroup \ $
进一步的动作:接受棋子:如果棋子在其第一步中移动了两个位置,则对位的棋子可以在下一步中将其视为另一只棋子,就好像它只移动了一个位置。提供平局或放弃:其举棋手可以提供平局,其他玩家可以接受或拒绝。而采取此举的玩家可以放弃比赛。在不采取任何动作或典当的情况下进行50次移动后,玩家可以要求平局。如果第三次输入相同的位置,则相同。
\ $ \ endgroup \ $
– gnasher729
2014年12月5日在22:22
\ $ \ begingroup \ $
@凯尔·黑尔(Kyle Hale),我相信验证isValidMove不应是片段的责任,而应是验证者的责任。是不是?
\ $ \ endgroup \ $
– M Sach
16年11月20日在8:17
\ $ \ begingroup \ $
@MSach是的,您可能是对的,我将其移至Game类,只需将Source和Destination正方形添加为参数。
\ $ \ endgroup \ $
–凯尔·黑尔(Kyle Hale)
16-11-21在16:39
\ $ \ begingroup \ $
这实际上是面向对象设计以及说明折衷,封装和委托的绝佳非凡学习示例。这也取决于您的目标是什么,即如果两个玩家都是人类,您只需要简单的方法来验证他们的举动,而简单性应该比效率高,但是如果其中任何一个是AI,您就需要有效地生成和验证候选举动的方法(或者实际上一棵深度为n的树),对其评分并修剪。
\ $ \ endgroup \ $
–smci
17-6-10下午6:06
#2 楼
我的评论是关于游戏设计的。我看到实体的职责在很多地方都错了。我们可以将责任移交给董事会。棋盘和棋子不需要了解玩家。
棋子不应该移动。棋子可以提供到达目标路径的可能动作列表,但棋盘应该选择有效的路径。
棋盘应该检查“检查配合”条件。
游戏应该跟踪玩家的移动历史和棋子颜色选择。
播放器类应该只包含玩家详细信息。
下面是一个粗略的类图
#3 楼
一些快速快照像
if
这样的if (booleanVariable==true)
条件可以简化为if (booleanVariable)
你不应该像
public boolean white;
这样的公共变量没有
Game
,Board
的构造函数Player
和Piece
应该调用super()
,因为它们显然没有继承/扩展任何类。 一些设计要点
一个象棋游戏需要一个棋盘,2个玩家和32个棋子。
棋子是棋盘的一部分
玩家通过规则移动棋子
规则与棋子的类型和棋子在棋盘上的位置有关
这些规则需要被某个对象
Game
或RuleEvaluator
求值。#4 楼
考虑使用enum
,而不是使用布尔值来标记某物是否为某物(因此暗示它不是另一物)。在这种情况下,就灵活性而言,它不会给您带来任何好处(因为它好像不会出现红色,紫色或类似的东西),但是它会使您的代码更加清晰。 >在游戏中,应该单独设置一个setPlayers(Player black, Player white)
,而不是单独设置黑白,或者更好的是,让板子成为一个自己提供黑白Player
的工厂-如果甚至有理由拥有Player对象首先。#5 楼
对其他所有人的补充:Player
和Board
都需要知道自己和对手的位置。无法想到立即分解此问题的最佳方法,而是考虑他们将如何以最少的重复进行彼此交谈。我想将它放在Board
下更有意义,然后让Player
存储对Board
的引用并继承或组合其方法:*.isValid()
仅检查从和到坐标,它们当前不检查是否存在是干预友军或敌军,或者确实是占领了现场。我认为您应该在董事会级别的一项职能中做到这一点,如果您对每一部分都做到这一点将非常难看。您可能需要为每个片段生成一个辅助函数(迭代器?)以生成interveningSpots(fromX,fromY,toX,toY,pieceType)
,以便Board.validMove()
可以测试它们是否被占用。我个人将其重命名为Piece.isValid()
。 (如果您曾经实施升级,我们还将需要一个validMove()
,但同样,它将在董事会级别而不是作品或玩家上实现)。空零移动validPosition()
。这听起来像挑剔,但a)它可能错误地允许您通过“不做任何事情”来逃避配合b)它可能会破坏您或某人想要添加的任何AI的递归。有关validMove()
的更高性能和更紧凑代码的提示:您不需要使用sqrt;只需直接测试dist2 =(dx ^ 2 + dy ^ 2)是1还是2。您就不需要abs(dx),因为负数的平方为正。因此:@Override
public boolean isValid(...) {
if(!super.isValid(...)) {
return false;
int dist2 = Math.pow((toX - fromX), 2) + Math.pow((toY - fromY), 2);
return (dist2 == 1 || dist2 == 2);
}
#6 楼
您可以通过以下几种不同的方法来简化逻辑:如上所述,不用编写
if (condition == true)
而是写if (condition)
。也可以不用
if (condition == false)
而是写if (!condition)
。 br /> 如果您想写:
if (condition)
return true;
return false;
...而不要写
return condition;
。同样,而不是:
if (condition)
return false;
return true;
...写
return (!condition);
。如果您想写: br />
if (condition1)
return true;
if (condition2)
return true;
return false;
...而不是
return condition1 || condition2;
。通常,如果增加澄清性,请简化逻辑。
评论
Pawn.java文件在哪里?我没有发现。@Nitin Kumar我确实确实忘记了写下来,但由于某些硬件问题,我不再拥有该项目...
如果主教在白色位置,主教只能以对角线的形式移动,这意味着它只能以白色对角线的形式移动,否则以黑色移动