“连接四”吸引了我的眼球,我决定从最基本的开始。在这里,我有一个简单的实现,用于在命令行上玩两个人类玩家之间的游戏:
package net.coderodde.game.connect4;
import java.util.Objects;
/**
* This class implements the actual Connect Four board.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Jun 28, 2016)
*/
public class Board {
/**
* The number of columns in the board.
*/
private static final int BOARD_WIDTH = 7;
/**
* The number of rows in the board.
*/
private static final int BOARD_HEIGHT = 6;
/**
* The minimum length of a winning pattern.
*/
private static final int WINNING_PATTERN_LENGTH = 4;
private final PlayerColor[][] board = new PlayerColor[BOARD_HEIGHT]
[BOARD_WIDTH];
public int getWidth() {
return board[0].length;
}
public int getHeight() {
return board.length;
}
/**
* Performs a ply of the player with the color {@code color} putting a new
* piece at column {@code x}.
*
* @param x the column index.
* @param color the player color.
*/
public void put(final int x, final PlayerColor color) {
checkX(x);
checkColumnNotFull(x);
Objects.requireNonNull(color, "The input color is null.");
int y = board.length - 1;
while (board[y][x] != null) {
--y;
}
board[y][x] = color;
}
public PlayerColor checkVictory() {
if (checkVictory(PlayerColor.RED)) {
return PlayerColor.RED;
}
if (checkVictory(PlayerColor.YELLOW)) {
return PlayerColor.YELLOW;
}
return null;
}
public boolean isFull() {
for (int y = 0; y < board.length; ++y) {
for (int x = 0; x < board[0].length; ++x) {
if (board[y][x] == null) {
return false;
}
}
}
return true;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
for (int y = 0; y < board.length; ++y) {
sb.append("|");
for (int x = 0; x < board[0].length; ++x) {
final PlayerColor color = board[y][x];
sb.append(color != null ? color.toString() : " ");
sb.append("|");
}
sb.append("\n");
}
sb.append("---------------\n");
sb.append(" 1 2 3 4 5 6 7");
return sb.toString();
}
private boolean checkVictory(final PlayerColor color) {
// Check the horizontal patterns:
final int horizontalPatterns = getWidth() - WINNING_PATTERN_LENGTH + 1;
for (int startY = 0; startY < getHeight(); ++startY) {
next_pattern:
for (int startX = 0; startX < horizontalPatterns; ++startX) {
// Check a horizontal pattern:
for (int offset = 0;
offset < WINNING_PATTERN_LENGTH;
offset++) {
if (board[startY][startX + offset] != color) {
continue next_pattern;
}
}
return true;
}
}
// Check the vertical patterns:
final int verticalPatterns = getHeight() - WINNING_PATTERN_LENGTH + 1;
for (int startX = 0; startX < getWidth(); ++startX) {
next_pattern:
for (int startY = 0; startY < verticalPatterns; ++startY) {
for (int offset = 0;
offset < WINNING_PATTERN_LENGTH;
offset++) {
if (board[startY + offset][startX] != color) {
continue next_pattern;
}
}
return true;
}
}
// Check the diagonal patterns (from top-left to bottom-right):
for (int startY = 0; startY < verticalPatterns; ++startY) {
next_pattern:
for (int startX = 0; startX < horizontalPatterns; ++startX) {
for (int offset = 0;
offset < WINNING_PATTERN_LENGTH;
offset++) {
if (board[startY + offset][startX + offset] != color) {
continue next_pattern;
}
}
return true;
}
}
// Check the diagonal patterns (from top-right to bottom-left):
for (int startY = 0; startY < verticalPatterns; ++startY) {
next_pattern:
for (int startX = WINNING_PATTERN_LENGTH - 1;
startX < getWidth();
startX++) {
for (int offset = 0;
offset < WINNING_PATTERN_LENGTH;
offset++) {
if (board[startY + offset][startX - offset] != color) {
continue next_pattern;
}
}
return true;
}
}
// No victory yet for color 'color'.
return false;
}
public int getColumnHeight(final int x) {
int height = 0;
for (int y = board.length - 1; y >= 0; --y, ++height) {
if (board[y][x] == null) {
return height;
}
}
return height;
}
private void checkX(final int x) {
if (x < 0) {
throw new IndexOutOfBoundsException(
"The x-coordinate is negative: " + x);
}
if (x >= board[0].length) {
throw new IndexOutOfBoundsException(
"The x-coordinate is too large: " + x + ". Must be at " +
"most " + (board[0].length - 1) + ".");
}
}
private void checkColumnNotFull(final int x) {
if (getColumnHeight(x) == board.length) {
throw new IllegalStateException(
"The column at x-coordinate " + x + " is full.");
}
}
}package net.coderodde.game.connect4;
/**
* This enumeration defines the two player colors.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Jun 28, 2016)
*/
public enum PlayerColor {
RED ("X"),
YELLOW ("O");
private final String string;
PlayerColor(final String string) {
this.string = string;
}
@Override
public String toString() {
return string;
}
public PlayerColor invert() {
switch (this) {
case RED:
return PlayerColor.YELLOW;
case YELLOW:
return PlayerColor.RED;
default:
throw new IllegalStateException("Should not get here.");
}
}
}package net.coderodde.game.connect4;
import java.util.Scanner;
/**
* This class ties all the components into a command line Connect Four game.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Jun 28, 2016)
*/
public class Main {
private static final String NEW_GAME_REQUEST =
"Do you wish to play once more? Type \"no\" to exit, or anything " +
"else to replay.";
private static final String RED_WINS_MESSAGE =
"[GAME OVER] The red player wins!";
private static final String YELLOW_WINS_MESSAGE =
"[GAME OVER] The yellow player wins!";
private static final String TIE_MESSAGE = "[GAME OVER] It's a tie!";
private static final String EXIT_MESSAGE = "Bye!";
private static final String RED_PROMPT = "red> ";
private static final String YELLOW_PROMPT = "yellow> ";
private final Scanner scanner = new Scanner(System.in);
private Board board = new Board();
private PlayerColor currentPlayer;
public void run() {
while (true) {
PlayerColor winnerColor = gameLoop();
reportOutcome(winnerColor);
if (!newGameRequested()) {
break;
}
}
System.out.println(EXIT_MESSAGE);
}
private PlayerColor gameLoop() {
currentPlayer = PlayerColor.RED;
board = new Board();
System.out.println();
System.out.println(board);
while (true) {
PlayerColor winnerColor = board.checkVictory();
if (winnerColor != null || board.isFull()) {
return winnerColor;
}
final int column = readPly();
board.put(column, currentPlayer);
currentPlayer = currentPlayer.invert();
System.out.println();
System.out.println(board);
}
}
private void reportOutcome(final PlayerColor winnerColor) {
switch (winnerColor) {
case RED:
System.out.println(RED_WINS_MESSAGE);
break;
case YELLOW:
System.out.println(YELLOW_WINS_MESSAGE);
break;
default:
System.out.println(TIE_MESSAGE);
break;
}
}
private boolean newGameRequested() {
System.out.println(NEW_GAME_REQUEST);
final String input = scanner.next().trim().toLowerCase();
return !input.equals("no");
}
public static void main(final String[] args) {
final Main main = new Main();
main.run();
}
private int readPly() {
while (true) {
if (currentPlayer == PlayerColor.RED) {
System.out.print(RED_PROMPT);
} else if (currentPlayer == PlayerColor.YELLOW) {
System.out.print(YELLOW_PROMPT);
} else {
throw new IllegalStateException("Should not get here.");
}
final String command = scanner.next().trim();
try {
final int column = Integer.parseInt(command);
if (column < 1) {
System.out.println("Column index must be at least 1.");
continue;
} else if (column > board.getWidth()) {
System.out.println("Column index must be at most " +
board.getWidth());
continue;
}
final int columnIndex = column - 1;
if (board.getColumnHeight(columnIndex) == board.getHeight()) {
System.out.println("The " + nth(column) + " column is " +
"full.");
}
return columnIndex;
} catch (final NumberFormatException ex) {
System.out.println("\"" + command + "\" is not an integer!");
}
}
}
private static String nth(final int i) {
switch (i) {
case 1:
return "1st";
case 2:
return "2nd";
case 3:
return "3rd";
default:
return "" + i + "th";
}
}
}任何批评都是非常感谢的!
发布于 2016-06-28 14:11:00
/**
* Performs a ply of the player with the color {@code color} putting a new
* piece at column {@code x}.
*
* @param x the column index.
* @param color the player color.
*/
public void put(final int x, final PlayerColor color) {首先,错误,应该是“表演一出戏”。
其次,当所有文档都包含“列索引”时,为什么要使用final int x?为什么不..。final int columnIndex?
int y = board.length - 1;这很难读懂。使用您自己的助手方法:
int y = getHeight() - 1;public boolean isFull() {
for (int y = 0; y < board.length; ++y) {
for (int x = 0; x < board[0].length; ++x) {
if (board[y][x] == null) {
return false;
}
}
}
return true;
}奇怪的是,所有的连接-4是必须填补顶部排,以阻止所有剩余的比赛。也许这不是这个方法所检查的,但是如果您要使用isFull来检查一个新的移动是否可行,那么真正应该包含的是检查顶部的行是否有任何空闲空间。没有必要自下而上。
https://codereview.stackexchange.com/questions/133297
复制相似问题