我想知道我的方法是否正确,如何进行改进?此外,是否有办法摆脱PieceBoard之间的关系?目前,我正在将棋子的位置存储在棋子中和板上。有什么方法可以改变这种情况吗?

我考虑过一个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;
    }

}


评论

Pawn.java文件在哪里?我没有发现。

@Nitin Kumar我确实确实忘记了写下来,但由于某些硬件问题,我不再拥有该项目...

如果主教在白色位置,主教只能以对角线的形式移动,这意味着它只能以白色对角线的形式移动,否则以黑色移动

#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;这样的公共变量
没有GameBoard的构造函数PlayerPiece应该调用super(),因为它们显然没有继承/扩展任何类。

一些设计要点


一个象棋游戏需要一个棋盘,2个玩家和32个棋子。
棋子是棋盘的一部分
玩家通过规则移动棋子
规则与棋子的类型和棋子在棋盘上的位置有关
这些规则需要被某个对象GameRuleEvaluator求值。


#4 楼

考虑使用enum,而不是使用布尔值来标记某物是否为某物(因此暗示它不是另一物)。在这种情况下,就灵活性而言,它不会给您带来任何好处(因为它好像不会出现红色,紫色或类似的东西),但是它会使您的代码更加清晰。 >在游戏中,应该单独设置一个setPlayers(Player black, Player white),而不是单独设置黑白,或者更好的是,让板子成为一个自己提供黑白Player的工厂-如果甚至有理由拥有Player对象首先。

#5 楼

对其他所有人的补充:


PlayerBoard都需要知道自己和对手的位置。无法想到立即分解此问题的最佳方法,而是考虑他们将如何以最少的重复进行彼此交谈。我想将它放在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;


通常,如果增加澄清性,请简化逻辑。