学习如何编码可能会令人沮丧,但是如果您将体验游戏化,那么沮丧就会变得更容易忍受。
将学习游戏化的方法之一是实际编写一些游戏。学习时最流行的一些编程游戏包括:
- 一名猜数字的人。
- 剪刀石头布。
- 蛇或者蜈蚣。
- 太空侵略者。
- 跳棋或者国际象棋。
难度处于中等水平的是井字游戏。如果你能编写一个猜数字游戏或石头剪刀布游戏,那么你应该能够编写一个 Java 井字游戏,尽管它的挑战性要大得多。
Java 井字游戏的编码并不像跳棋或国际象棋那么困难,但是当您尝试实现更复杂的棋盘游戏时,关于多维数组、异常处理和流控制的许多经验教训将对您有所帮助。
如何编写 Java 井字游戏
要编写 Java 井字游戏程序,我们将遵循以下八个步骤,使我们能够逐步实现完成游戏的目标:
- 创建一个名为的可运行 Java 类
TicTacToe
。 - 声明所有必需的变量。
- 打印一个基本的井字游戏棋盘。
- 从两个玩家处获取用户输入。
- 检查是否有获胜的玩法。
- 如果比赛没有获胜,则更换球员。
- 如果所有方格都被占据,则游戏结束。
- 运行 Java 井字游戏应用程序。
步骤 1:创建TicTacToe Java 类
首先,创建一个名为的类TicTacToe
,该类具有可运行的 main 方法,如下所示。
本例中的所有代码都位于TicTacToe
类的 main 方法中,或者位于声明为此类一部分的方法中。您也可以选择在 JShell 中运行此示例,我始终推荐使用 JShell 来学习 Java 和快速制作原型。
/* 用 Java 编写的井字游戏 */
public class TicTacToe {
public static void main(String[] args)
{
}
}
第 2 步:声明所需变量
井字棋盘有 9 个方格。在我们的游戏中,我们会显示每个未选中方格的编号,并询问玩家要标记哪个方格。
char [] board = { '1','2','3',
'4','5','6',
'7','8','9' };
我们还需要记录轮到谁了,以及已经玩了多少个方格。如果九个方格都玩完了,没有获胜者,游戏就会以平局结束。
var numberOfSquaresPlayed = 0;
var whoseTurnItIs = 'x' ;
为此,我们从一个包含数字 1-9 的字符数组开始,如下所示:
步骤 3:打印井字棋棋盘
每当选择一个方格,我们就会重新绘制棋盘。
由于这是一款简单的主机游戏,因此棋盘的显示并不复杂。它看起来就像下面的图片一样:
我们在名为的方法中输入生成和打印出 Java 井字游戏板的逻辑printTheBoard()
:
private static void printTheBoard(char[] board) { System.out.println( board[0] + " | " + board[1] + " | " + board[2]); System.out.println( " - + - + - " ); System.out.println( board[3] + " | " + board[4] + " | " + board[5]); System.out.println( " - + - + - " ); System.out.println( board[6] + " | " + board[7] + " | " + board[8]); }
首次绘制棋盘时,它仅显示数字:
1 | 2 | 3
-+-+-
4| 5 | 6
- + - + -
7 | 8 | 9
随着游戏的进行,棋盘会用 x 和 o 进行更新。完整的井字游戏 Java 战斗如下所示:
X | 氧 | X
- + - + -
X | 5 | 氧
- + - + -
X | 氧 | 9
步骤 4:获取用户输入
只要小于numberOfSquaresPlayed
9,我们就会向玩家显示棋盘的当前状态并提示他们选择一个方格,利用 Java 的Scanner
类进行用户输入:
while ( numberOfSquaresPlayed < 9)
{
printTheBoard ( board );
System. out .printf("选择玩家 %s 的方格: ", whoseTurnItIs );
var scanner = new java.util.Scanner(System. in );
var input = scanner.nextInt();
board[input-1] = whoseTurnItIs;
}
请注意,char
根据轮到谁,数组会用 X 或 O 进行更新。
棋盘[输入-1] = whoseTurnItIs;
由于数组是从零开始的,因此我们从用户提供的数字中减一。如果用户选择数字 5 的平方,则它对应于数组中的索引 4。
第 5 步:查看获胜者
每次用户选择一个方块时,我们都会检查他们是否完成一行并赢得了游戏。
赢得井字游戏有八种方法:
- 三条水平线。
- 三条垂直线。
- 两条穿过广场的线。
在这种情况下,条件逻辑会变得很难看,因为必须根据当前玩家的字母检查可能获胜的行中的每个方格。
第一条水平线的检查可能看起来像这样:
if ((board[0] == whoseTurnItIs) &&
(board[1] == whoseTurnItIs) &&
(board[2] == whoseTurnItIs))
{
System.out.println ("你赢了!!!恭喜! ");
break ;
}
需要进行八次这样的检查来判断比赛是否获胜,这可能会变得很难看。
另一个选项稍微不那么冗长,涉及使用这种类型的鲜为人知的功能char
。
char 是整数类型
很少有人知道,Java 中的实际上是整数类型。你可以像对int、double 或 floatchar
进行数学运算一样对其进行数学运算。
这意味着您可以将给定行中的三个数字相加chars
,看看结果是否等于“x”字符乘以自身三次。如果相等,则说明一行中有三个“x” 。如果轮到第二个玩家,则chars
对“o”执行相同操作。char
以下逻辑使用字符的基于整数的性质来查看给定的行、列或交叉是否已完成:
if ( (board[0] + board[1] + board[2] == (whoseTurnItIs * 3)) // 第一行
|| (board[3] + board[4] + board[5] == (whoseTurnItIs * 3)) // 第二行
|| (board[6] + board[7] + board[8] == (whoseTurnItIs * 3)) // 第三行
|| (board[0] + board[3] + board[6] == (whoseTurnItIs * 3)) // 第一列
|| (board[1] + board[4] + board[7] == (whoseTurnItIs * 3)) // 第二列
|| (board[2] + board[5] + board[8] == (whoseTurnItIs * 3)) // 第三列
|| (board[0] + board[4] + board[8] == (whoseTurnItIs * 3)) // 第一 对角线
|| (board[2] + board[4] + board[6] == (whoseTurnItIs * 3)) // 第二条对角线
)
{
printTheBoard (board);
System. out .println("你赢了!!!恭喜! ");
break ;
} else {
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
}
享受成功执行数学运算的喜悦char
。你可能在整个职业生涯中都不会再看到char
像这样使用 Java。
第 6 步:轮流
如果我们的条件检查显示一行已经完成,我们会祝贺玩家并跳出循环,正如我们从上面的代码中看到的那样:
printTheBoard (board);
System. out .println("你赢了!!!恭喜! ");
break ;
如果一行未完成,我们会增加所玩方块的数量并改变回合。我们使用三元运算符来实现这一点。
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
Java 的条件运算符
三元运算符是一种快捷方式,它简化了基于条件语句结果的分配。
我们可以简单地说:
if (whoseTurnItIs == 'x')
{
whoseTurnItIs = 'o';
} else {
whoseTurnItIs = 'x';
}
但是,我们使用三元运算符来使语法更精确。
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
作为一名新开发人员,我一直不喜欢三元运算符的神秘语法。作为一名经验丰富的 Java 开发人员,我仍然不喜欢它,但我更欣赏它。
第七步:处理领带
如果游戏进行九次仍没有获胜者,则退出循环。
此时,我们宣布比赛打平,并向双方表示祝贺:
if (numberOfSquaresPlayed == 9)
{
printTheBoard (board);
System.out.println ("一场恶战,打成平局!" );
}
步骤 8:运行井字游戏 Java 游戏
将所有这些代码放在一起并保存更改,然后运行 Java 井字游戏。
只要您提供有效的输入并遵循快乐的路径,游戏就会完美执行。
TicTacToe
以下是到目前为止编写的完整、可运行的Java 类代码:
package com.mcnz.vector;
public class TicTacTest {
public static void main(String[] args)
{
char[] board = { '1', '2', '3',
'4', '5', '6',
'7', '8', '9' };
var numberOfSquaresPlayed = 0;
var whoseTurnItIs = 'x';
while (numberOfSquaresPlayed < 9)
{
printTheBoard(board);
System.out.printf("Choose a square player %s:", whoseTurnItIs);
var scanner = new java.util.Scanner(System.in);
var input = scanner.nextInt();
board[input - 1] = whoseTurnItIs;
if ( (board[0] + board[1] + board[2] == (whoseTurnItIs * 3)) // first row
|| (board[3] + board[4] + board[5] == (whoseTurnItIs * 3)) // second row
|| (board[6] + board[7] + board[8] == (whoseTurnItIs * 3)) // third row
|| (board[0] + board[3] + board[6] == (whoseTurnItIs * 3)) // first column
|| (board[1] + board[4] + board[7] == (whoseTurnItIs * 3)) // second column
|| (board[2] + board[5] + board[8] == (whoseTurnItIs * 3)) // third column
|| (board[0] + board[4] + board[8] == (whoseTurnItIs * 3)) // first diagonal
|| (board[2] + board[4] + board[6] == (whoseTurnItIs * 3)) // second diagonal
)
{
printTheBoard(board);
System.out.println("You won!!! Congratulations!");
break;
} else {
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
}
}
}
private static void printTheBoard(char[] board)
{
System.out.printf("%n %s | %s | %s %n", board[0], board[1], board[2]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n", board[3], board[4], board[5]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n%n", board[6], board[7], board[8]);
}
} /* Java井字游戏结束*/
增强 Java Tic-Tac-Toe 应用程序
通过实现核心逻辑,您可以通过增强 Java 井字游戏来推动您的编程知识的发展。
可能的增强包括以下内容:
- 验证用户输入是否在要求的范围内。
- 执行异常处理来处理运行时错误。
- 将核心逻辑重构为更小的方法。
- 允许游戏继续进行,直到玩家决定退出。
- 从 Swing 包中添加 GUI 组件。
- 使用 Scanner 类的自动关闭功能。
- 使用枚举来定义轮到谁了。
- 使用Java字符串格式化函数进行显示功能。
- 使服务器自动化,以便游戏支持单人模式。
Java 井字游戏源代码
稍微增强的 Java 井字游戏的完整代码如下。添加您自己的增强功能,进一步加深您对 Java 的理解。
/* Java tic-tac-toe Game source code */
package com.mcnz.tictactoe;
public class TicTacToe {
public static void main(String[] args) {
char[] board = { '1', '2', '3',
'4', '5', '6',
'7', '8', '9' };
var numberOfSquaresPlayed = 0;
var whoseTurnItIs = 'x';
var gameEndingMessage = "";
while (numberOfSquaresPlayed < 9) {
printTheBoard(board);
getTheUserToSelectTheirSquare(board, whoseTurnItIs);
if (theyWonTheGame(board, whoseTurnItIs)) {
gameEndingMessage = "You won!!! Congratulations!";
break;
} else if (numberOfSquaresPlayed == 9) {
gameEndingMessage = "A tough battle fought to a draw!";
} else {
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
continue;
}
}
printTheBoard(board);
System.out.println(gameEndingMessage);
}
private static void printTheBoard(char[] board) {
System.out.printf("%n %s | %s | %s %n", board[0], board[1], board[2]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n", board[3], board[4], board[5]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n%n", board[6], board[7], board[8]);
}
private static void getTheUserToSelectTheirSquare(char[] board, char whoseTurnItIs) {
do {
try {
System.out.printf("Would player %s please choose an unchosen square:", whoseTurnItIs);
var scanner = new java.util.Scanner(System.in);
var input = scanner.nextInt();
if (Character.isDigit(board[input - 1])) {
board[input - 1] = whoseTurnItIs;
break;
} else {
System.out.println("Sorry, that's taken.");
}
} catch (Exception e) {
System.out.println("Something went wrong. Let's try that again.");
}
printTheBoard(board);
} while (true);
}
private static boolean theyWonTheGame(char[] board, char whoseTurnItIs) {
return (board[0] + board[1] + board[2] == (whoseTurnItIs * 3)) // first row
|| (board[3] + board[4] + board[5] == (whoseTurnItIs * 3)) // second row
|| (board[6] + board[7] + board[8] == (whoseTurnItIs * 3)) // third row
|| (board[0] + board[3] + board[6] == (whoseTurnItIs * 3)) // first column
|| (board[1] + board[4] + board[7] == (whoseTurnItIs * 3)) // second column
|| (board[2] + board[5] + board[8] == (whoseTurnItIs * 3)) // third column
|| (board[0] + board[4] + board[8] == (whoseTurnItIs * 3)) // first cross
|| (board[2] + board[4] + board[6] == (whoseTurnItIs * 3)); // second cross
}
}