我正在制作一个Tic脚趾游戏,可以在控制台上玩,或者对抗另一个人,或者简单的人工智能。虽然有点粗糙,但很管用。我所关心的是它对坚实和其他设计原则的坚持程度,因为这是我第一次在实践中使用它们。我希望能回顾一下我的课程的结构和任何建议。我共享一个从GitHub链接,因为这里有太多的代码来发布所有的东西。
这些是一些最大的课程,给我一种不安的感觉。
GameBoard.class -拥有棋盘并保存玩家的标志
package board;
import java.util.ArrayList;
public class GameBoard {
private Cell[] board;
private ArrayList<Integer> availableSpots;
public GameBoard(int n) {
availableSpots = new ArrayList<Integer>();
//the game board
board = new Cell[n];
for (int i = 0; i < n; i++) {
board[i] = new Cell();
}
//list of initial open cells
for (int i = 0; i < 9; i++) {
availableSpots.add(i);
}
}
public Cell[] getBoard() {
return board;
}
public void addMarker(int n, String s) {
if (availableSpots.contains(n)) {
board[n].setMarker(s);
removeSpotFromList(n);
//System.out.println(availableSpots.size());
}
else {
System.out.println("Cell not available");
}
}
public String getCellValue(int n) {
return board[n].getMarker();
}
public ArrayList<Integer> getAvailableSpots() {
return availableSpots;
}
//remove number from arraylist
public void removeSpotFromList(int n) {
availableSpots.set(n, null);
availableSpots.trimToSize();
for (int i=0; i<availableSpots.size(); i++) {
//System.out.println(availableSpots.get(i) + ", ");
}
}
}
Game.class -玩家之间的切换和每个回合的呼叫
import board.GameBoard;
import board.PrintBoard;
import consuleInput.InputReader;
import import players.Playable;
import players.PlayerGroup;
public class Game {
public static void play() {
Modes modes = new Modes();
InputReader ir = new InputReader();
GameBoard bg = new GameBoard(9);
PrintBoard pb = new PrintBoard();
PlayerGroup pg = new PlayerGroup();
GameStateChecker gsc = new GameStateChecker();
System.out.println("choose a mode:");
System.out.println("1. Player vs player");
System.out.println("2. player v computer");
System.out.println("3. computer vs computer");
int mode = ir.toIntegerReader("type below");
modes.chooseMode(mode, pg);
pb.print(bg);
int counter = 9;
Playable currentPlayer;
boolean hasWinner = false;
int player = 0;
//int choice;
do{
currentPlayer = pg.getPlayer(player);
//int choice = ir.toIntegerReader("pick a square (0-8):");
bg.addMarker(currentPlayer.playerMove(bg.getAvailableSpots()), currentPlayer.getMarker());
pb.print(bg);
hasWinner = gsc.checkPatterns(bg, currentPlayer);
//System.out.println("is there a winner " + hasWinner);
counter--;
if (player == 0) {
player = 1;
}
else {
player = 0;
}
/*
currentPlayer = pg.getPlayer(1);
choice = ir.toIntegerReader("pick a square (0-8):");
bg.addMarker(choice, currentPlayer.getMarker());
pb.print(bg);
hasWinner = gsc.checkPatterns(bg, currentPlayer);
counter--;
*/
}
while (!hasWinner);
}
}
发布于 2017-10-09 09:59:28
除了RobAu的评论外,我认为addMarker
方法可以简化为:
board[n].setMarker(s);
通过将单元格的可用性检查委托给Cell
类。我认为最好从IllegalArgumentException定义自己的异常。
public void setMarker(String marker) {
if(!marker.equals(" "))
throw new CellIsNotAvailableException();
this.marker = marker;
}
我要指出的另一件事是命名方法和变量的方式。人们应该始终正确地命名它们的方法和变量,这样就不需要添加注释来解释这些事情做了什么(写注释解释它们存在的原因是很好的)。尽可能地用代码来表达自己!以addMarker
为例。我认为addMarker
最好写成markCellWithMarker(int cellNumber, String marker)
(我认为X和O是游戏中使用的令牌),getCellValue
则是getMarkerAt(int cellNumber)
。
应用这些更改,下面是GameBoard类的重构版本:
public class GameBoard {
private Cell[] board;
public GameBoard(int numberOfCells) {
board = new Cell[numberOfCells];
for (int i = 0; i < numberOfCells; i++) {
board[i] = new Cell();
}
}
public void markCellWithMarker(int cellNumber, String token) {
board[cellNumber].setMarker(token);
}
public String getMarkerAt(int cellNumber) {
return board[cellNumber].getMarker();
}
}
至于游戏类,它并没有真正证明它的存在就像现在这样。它只包含一个应该运行游戏的方法(如果我正确地阅读了您的代码)。将它重构成这样可能证明它的存在是有道理的:
public class Game {
private GameBoard gameBoard;
private Player[] players;
private int turnNumber;
//In case you want a two player game.
public Game(int numberOfCells, Player player1, player player2){
gameBoard = new GameBoard(numberOfCells);
setFirstTurnPlayer(player1, player2);
}
//In case you want a single player game against the computer.
public Game(int numberOfCells, Player player){
gameBoard = new GameBoard(numberOfCells);
Player computer = new Player("computer");
setFirstTurnPlayer(player1, computer);
}
private void setFirstTurnPlayer(Player player1, Player player2){
//It's up to you how you decide the turnorder: die roll, coin toss or something.
//The first one in the player array is considered as the turn player.
}
public String getTurnPlayer(){
return players[turnNumber%2].getName();
}
public void markCellWithMarker(int cellNumber){
String markerToPlace = players[turnNumber%2].getPlayerMarker()
gameBoard.markCellWithMarker(cellNumber, markerToPlace)
checkIfTurnPlayerWinsTheGame()
turnNumber++;
}
//GameStateChecker code moved here. I think this one can be made shorter and more readable.
public void checkIfTurnPlayerWinsTheGame(){
//Rename currentPlayer as turnPlayer
Player currentPlayer = players[turnNumber%2]
if ((board[0].getMarker().equals(currentPlayer.getMarker()) && board[1].getMarker().equals(currentPlayer.getMarker()) && board[2].getMarker().equals(currentPlayer.getMarker())) ||
(board[3].getMarker().equals(currentPlayer.getMarker()) && board[4].getMarker().equals(currentPlayer.getMarker()) && board[5].getMarker().equals(currentPlayer.getMarker())) ||
(board[6].getMarker().equals(currentPlayer.getMarker()) && board[7].getMarker().equals(currentPlayer.getMarker()) && board[8].getMarker().equals(currentPlayer.getMarker())) ||
(board[0].getMarker().equals(currentPlayer.getMarker()) && board[3].getMarker().equals(currentPlayer.getMarker()) && board[6].getMarker().equals(currentPlayer.getMarker())) ||
(board[1].getMarker().equals(currentPlayer.getMarker()) && board[4].getMarker().equals(currentPlayer.getMarker()) && board[5].getMarker().equals(currentPlayer.getMarker())) ||
(board[2].getMarker().equals(currentPlayer.getMarker()) && board[5].getMarker().equals(currentPlayer.getMarker()) && board[8].getMarker().equals(currentPlayer.getMarker())) ||
(board[0].getMarker().equals(currentPlayer.getMarker()) && board[4].getMarker().equals(currentPlayer.getMarker()) && board[8].getMarker().equals(currentPlayer.getMarker())) ||
(board[2].getMarker().equals(currentPlayer.getMarker()) && board[4].getMarker().equals(currentPlayer.getMarker()) && board[6].getMarker().equals(currentPlayer.getMarker())))
throw new GameIsOverException(currentPlayer.getName() + " wins!")
}
这是我为一款名为代码的游戏编写的ConnectFour,我认为它有点类似于toe。这可能会帮助你看到我在这里提到的一些关于正确命名和其他东西的东西。
发布于 2017-10-09 10:46:13
没有大的意义有一个Movable
接口和类ComputerMove
和HumanMove
。它们可能包含在相应的Playable
类中。即使您希望将它们作为单独的类,用户也不应该直接创建它们,让Playable
类在它们的构造函数中这样做。
ConsoleInput
类中的命名
toIntegerReader
方法返回一个int
的事实是违反直觉的。该方法的更好名称是readInt
。reader
方法- readString
也是如此。已分配但未使用的input
字段。
https://codereview.stackexchange.com/questions/177471
复制相似问题