方格和井字棋的面向对象设计

来源:爱站网时间:2021-09-13编辑:网友分享
我列出了两款游戏之间的相似之处,目的是将其扩展到国际象棋,但对我的设计提出了质疑。相似之处-项目(行,列)在木板上的位置...

问题描述


[我列出了两款游戏之间的相似之处,目的是将其扩展到国际象棋,但对我的设计提出质疑。

相似之处

  • 物品-物品在船上的位置(行,列)
  • Board-nxn网格碎片
  • 游戏-包含棋盘和玩家列表
  • 玩家-播放器名称

差异

  • 在检查器中,您可以沿不同的方向移动,所以我创建了一个独立的抽象类,称为Checker,该类继承了Piece并实现了一个Moveable接口,该接口返回pieces move。因此Pawn和King必须实现此方法并提供其动作。

问题和疑虑

  • 我在质疑这种设计,因为我也可以创建一个抽象方法和一个接口,但是这不能扩展到国际象棋。
  • 我也不知道如何将玩家与井字游戏中的标记(例如x或o)联系起来。我使用哈希图将玩家映射到其标记。
  • 我有一些重复的代码,其中我有一个枚举颜色,但我也有一个可变标记,这有点相同。不确定如何补救。
  • 是否可以类型转换对象?由于棋盘不知道棋子的类型,我必须在Checkers类中执行此操作
List> moves = ((Checker)piece).getPossibleMoves();

注意

我还没有完成所有的实现工作,例如知道玩家何时获胜,处理极端情况或典当何时成为国王。同时,为了简便起见,我还为播放器进行了硬编码,如果这是一个好的方向,请只提供反馈。

public class Piece {
    private String marker;
    protected int row;
    protected int col;

    public Piece(String marker, int row, int col) {
        this.marker = marker;
        this.col = col;
        this.row = row;
    }

    public String getMarker() {
        return marker;
    }

    public void setMarker(String marker) {
        this.marker = marker;
    }

    public int getRow() {
        return row;
    }

    public void setRow(int row) {
        this.row = row;
    }

    public int getCol() {
        return col;
    }

    public void setCol(int col) {
        this.col = col;
    }
}

public class Player {
    private String name;

    public Player(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Board {
    private Piece[][] grid;

    public Board(int rows, int cols) {
        grid = new Piece[rows][cols];
    }

    private boolean isSpotEmpty(int row, int col) {
        return grid[row][col] == null;
    }

    public void move(Piece piece) {
        if(isSpotEmpty(piece.getRow(), piece.getCol())) {
            grid[piece.getRow()][piece.getCol()] = piece;
        } else {
            throw new InvalidStateException("Invalid Move");
        }
    }

    public void showBoard() {
        for(int i = 0; i  players;
    protected Board board;
    public abstract void startGame();
    public abstract Piece getPieceFromInput(Player player, String marker);
}




这里是井字游戏


public class TicTacToe extends Game {
    private static final int BOARD_SIZE = 3;
    private HashMap playerMap;

    public TicTacToe() {
        board = new Board(BOARD_SIZE, BOARD_SIZE);
        players = new ArrayList();
        players.add(new Player("player1"));
        players.add(new Player("player2"));
        playerMap.put(players.get(0), "o");
        playerMap.put(players.get(1), "x");
    }

    @Override
    public void startGame() {
        boolean playerOneTurn = true;
        Player currPlayer;
        Piece piece;
        while(1 

这里是跳棋

public abstract class Checker extends Piece implements Movable {
    protected Color color;

    public Checker(String marker, int row, int col, Color color) {
        super(marker, row, col);
        this.color = color;
    }

}

public enum Color {
    RED, BLACK
}

public class King extends Checker {

    public King(String marker, int row, int col, Color color) {
        super(marker, row, col, color);
    }

    @Override
    public List> getPossibleMoves() {
        List> list = new ArrayList();
        //go up/down
        for(int i = 0; i > getPossibleMoves() {
        List> list = new ArrayList();
        if(color == Color.RED) {
            list.add(Arrays.asList(row - 1,col - 1));
            list.add(Arrays.asList(row - 1,row + 1));
        } else {
            list.add(Arrays.asList(row + 1,row + 1));
            list.add(Arrays.asList(row + 1,row - 1));
        }
        return list;
    }
}

public interface Movable {
    List> getPossibleMoves();
}

public class Checkers extends Game {
    private static final int BOARD_SIZE = 8;
    private Board board;
    private List players;
    private HashMap playerMap;

    public Checkers() {
        board = new Board(BOARD_SIZE, BOARD_SIZE);
        players = new ArrayList();
        players.add(new Player("alice"));
        players.add(new Player("bob"));
        playerMap = new HashMap();
        playerMap.put(players.get(0), "o");
        playerMap.put(players.get(1), "x");
    }

    @Override
    public void startGame() {
        setBoard();
        boolean playerOneTurn  = true;
        Player currPlayer = null;
        String playerMarker = "";
        while(1  BOARD_SIZE - 4; i--) {
            for(int j = 0; j > moves = ((Checker)piece).getPossibleMoves();
        Scanner sc = new Scanner(System.in);
        System.out.println(player.getName() + " Please put your new piece to row : col");
        int row = sc.nextInt();
        int col = sc.nextInt();
        boolean isMoveValid = false;
        for(int i = 0; i 

这里玩游戏

public class GameMain {

    public static void main(String[] args) {
        Game checkers = new Checkers();
        Game tictactoe = new TicTacToe();
        checkers.startGame();
        tictactoe.startGame();
    }
}

思路:


[这可能是一个更好的论坛,可以在https://gamedev.stackexchange.com/中发布问题,但是我有一些观点,有些观点可能是错误的,但是也许它们会有所帮助(似乎是一个有趣的项目)。

1)我在质疑这种设计,因为我也可以创建一个抽象方法与一个接口,但这不能扩展到国际象棋。

您可能希望坚持使用接口,因为它们可以使您以较少的重构来扩展功能,因为您可以实现多个而不是扩展一个。使用默认方法,如果需要,您还可以包括任何通用代码。

2)我也不知道如何将玩家与井字游戏中的标记(例如x或o)联系起来。我使用哈希图将玩家映射到其标记。

关于将项目分配给作品,您目前的做法没有错。您可能需要研究使其变得更好一点,例如Piece implements Movable, Drawable(从上面返回界面注释)。关于棋子的存储位置,如果您想将棋子保留在游戏中并让游戏确定棋子的所有可用移动方式和有效性。或者,如果玩家或棋子本身负责确定棋盘的可用性,也可以将它们移入Player.Collection。

例如:

public TicTacToe() {
    this.players.add(new Player("Player 1", Color.RED, initPieces());
    this.players.add(new Player("Player 2", Color.BLACK, initPieces());
}

Color.RED | BLACK将在玩家控制时应用于该作品。例如,如果您有一个游戏,玩家可以窃取其他玩家令牌,则向玩家添加新令牌的行为将自动更新其颜色。然后根据您的操作在调用piece.draw();piece.draw(canvas)时应用颜色。

3)我对一些检查程序有一些代码重复,其中我有一个枚举颜色,但是我也有一个变量标记,这有点相同。不确定如何补救。

如果使用以上注释,则可以执行以下操作:

Collection> initPieces(String mark) {
    return Arrays.asList(new Piece(mark), ...);  // create 5
}

public Person(String name, Color color, Collection initialPieces) {
    // for initialPieces set piece color to color
}

4)可以对对象进行类型转换吗?由于棋盘不知道棋子的类型,我必须在Checkers类中执行此操作

[如果在实现Piece时使用了Movable接口,那么您就无需进行投射,因为这两个游戏/游戏板都将知道:

List> moves = piece.getPossibleMoves();

this.board = new Board();

这将再次确保board.getPeice(x,y)将返回Checker,并且不需要强制转换。这取决于游戏稍后会发生什么以及规则是什么。

5)基于游戏实现边缘案例-典当成为国王的跳棋。

[在大多数游戏中,移动后会产生结果。例如,您已经提到:

  • 跳棋,如果他们跳了,您将删除另一个玩家棋子
  • 跳棋者,如果他们到达棋盘的另一端,您将成为典当王
  • 国际象棋,如果他们降落,您将删除另一个玩家的棋子

在您的Checkers游戏示例中,您需要在setNewPiecePosition之后处理成功动作的地方调用一些东西。对于检查程序,您将需要此方法:

  1. 检查开始和结束位置,并确定中间是否有其他玩家Piece。如果是这样,您可以从棋盘上(和/或其他玩家的棋子列表中)删除该棋子。
  2. 确定玩家是否可以再次移动,以便如果他们跳了某人,则同一玩家可以从更新的可用移动列表中再次选择。
  3. 确定新位置是​​否在棋盘的尽头,然后用玩家集合中的国王替换Pawn。

上一篇:用正则表达式java替换字符串

下一篇:如何在方法和线程之间共享字符串?

您可能感兴趣的文章

相关阅读