朋友们和未来的同事们大家好! 最近,我参加了一个真实项目的测试,并通过了,但恰巧由于个人原因无法参加RP本身。在像 RP 测试这样有趣的问题之后,通常的课程问题就不再那么有吸引力了,尤其是因为我已经解决了大部分问题。因此,为了不让自己的才华浪费在继续学习上,我决定制作一款多人网页游戏。其他游戏链接:
对我来说,井字棋似乎是最简单的游戏,因此我决定将任务分解为多个子任务:
第一个算法是检查整个字段
- 用于测试游戏逻辑的控制台应用程序
- 多人游戏
- 将玩家数据库附加到控制台应用程序
- 创建前端设计、编写页面模板、游戏界面
- 把它们放在一起
- 场地
- 两名玩家轮流,一名打十字,第二名打零。这很简单。
String[][] strings = {{"O", "O", "_"},
{"_", "X", "O"},
{"X", "X", "X"},
for (String [] ss : strings){
for (String s : ss) System.out.print(s + " ");
System.out.println(); //для перевода строки
}
屏幕将显示:
O O _
_ X O
X X X
但除了显示之外,我们还有数值的比较,这里的选择已经是可能的。你可以比较字符串,你可以创建一个特殊的枚举类(enum
),但我更喜欢比较数字,只有在屏幕上显示时才用“X”和“O”替换它们。例如,1 - “X”、2 - “O”、0 - “_”。那么,如何检查字段是否存在三重 X 或 O 匹配?
第一个算法是检查整个字段
int[][] canvas = {{00, 01, 02},
{10, 11, 12},
{20, 21, 22}}
获胜组合:
00-01-02, 10-11-12, 20-21-22, 00-10-20, 01-11-21, 02-12-22, 00-11-22, 20-11-02 — всего 8.
通过比较数字进行检查,但事实证明您每次都需要检查整个字段,所有 8 种组合。当然,这并不多,这不是搜索 0 到 10 亿范围内的阿姆斯特朗数,这里几乎没有计算,但你仍然想要比检查整个字段更优化的东西。我想到的第二个想法是仅检查上一步中标记的单元格,这样我们仍然可以确定获胜者,因为我们会知道谁做了这一步。因此,我们不是得到全部 8 种组合,而是只得到 2、3 或 4 种组合,具体取决于单元格,请参见图片: 现在我们需要弄清楚如何确定需要启动哪种组合?这是我意识到使用二维数组不是很方便。我决定考虑其他选择。起初我想到了这个字段可以保留为九位数字,例如我们在屏幕上显示的同一个字段可以这样写:220012111,我会用手指解释它是什么是...代码是相同的,1 - “X”,2 - “O”,0 - “”,这意味着 220012111 = “OO__XOXXX”,或者如果在每三个数字之后插入一个换行符并添加空格明晰:
О О _
_ Х О
Х Х Х
又这里,为了方便储存,发明了一种展示的装置,但是不方便比较!当我将单元格编号为1-9时,找到了解决方案,然后我想,因为在编程时倒计时是从0开始并如图所示编号的。 您没有注意到任何特殊情况吗?如果你看上图,就会清楚地看到,有 2 个组合的解决方案有一个奇数序列号,有 4 个组合的解决方案有序列号 4,有 3 个组合的解决方案有其余的。所以我得出的结论是,您需要将竞争环境保持在规则的数字数组中:数字之间的简单迭代,根据所选算法进行比较的能力,简单的输出到屏幕。至于比较算法本身。让我们按顺序进行:在所有选项中都会检查行和列,我们只检查它们。如果搜索没有结果,我们检查单元格编号是否为偶数/奇数,如果是奇数,那么我们返回游戏,进一步检查没有意义,如果是偶数,我们检查该单元格是否位于左对角线,该对角线的数字除以 4 余数为 0。如果是,则检查是否匹配,如果没有找到匹配,则检查数字 4,如果没有,则返回游戏,如果是的,我们进一步检查代码并返回检查最后一个对角线的结果。可能,对于一个没有准备的人来说,读完上面这组字母后很难理解,但有人可能会说代码本身有很多字母,可以更简单,我很乐意讨论这一点。我们已经整理好了字段,现在我们需要处理两个轮流的用户,每个人都有自己的符号,X或O。在第一阶段,我们没有任何多用户功能,所以最简单的方法是逐个使用图标。X 总是先走第一步,O 总是先走第二步,然后 X 再次走,依此类推。它要求被检查(true/false),如果true – 那么当前玩家是 X,如果false – 那么 O 并且在每次移动开始时 flag=!flag 它仍然以某种方式从玩家那里接收关于哪个玩家的信号他们选择的细胞。在这里,我们将需要我们难忘的BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
玩家将手机号码输入控制台,然后按 Enter 键将进行移动。与输入的数字相对应的单元格会将其值从 0 更改为 1 或 2,具体取决于复选框的当前状态,这已在上面的段落中讨论过。这就是验证输入很重要的地方,这样当单元格已填满时,没有人可以将 X 更改为 O :) 玩家可以在控制台中输入什么?
- 空行
- 字母、标点符号、括号...在一个单词中,非数字
- 错误的数字 - 负数或超出数组大小、占用的单元格。
Integer.parseInt("2");
它会抛出异常。我们可以通过拦截此异常来提供前两点的保护。NumberFormatException
对于第三点,我将创建另一个方法来检查输入的值,但最正确的方法是将字符串请求移动到将执行验证的单独方法中,并且它将仅返回一个数字。总而言之,我们创建了一个字段,创建了一个显示它的方法,创建了一个检查“该玩家是否赢了一个小时?”的方法,并验证了输入的数字。剩下的事情就很少了,检查平局 - 一个单独的方法,它运行数组并查找 0,并显示游戏结果。就这样,代码已经准备好了,游戏结果很小,只有一个类,所以强悍的复制粘贴者可以在不理解的情况下,将所有内容复制到他们的项目中并自己运行,我自己就是这样,但是现在我尽量不这样做,也不向任何人推荐它:)祝大家学习JAVA好运!ps 其余的要点 - 多人游戏和数据库稍后会出现,我已经开始学习材料了:)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GameField {
static int [] canvas = {0,0,0,
0,0,0,
0,0,0};
//012, 345, 678, 036, 147, 258, 048, 246
public static void main(String[] args){
boolean b;
boolean isCurrentX = false;
do {
isCurrentX = !isCurrentX;
drawCanvas();
System.out.println("mark " + (isCurrentX ? "X" : "O"));
int n = getNumber();
canvas[n] = isCurrentX ? 1 : 2;
b = !isGameOver(n);
if (isDraw()){
System.out.println("Draw");
return;
}
} while (b);
drawCanvas();
System.out.println();
System.out.println("The winner is " + (isCurrentX ? "X" : "O") + "!");
}
static int getNumber(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
try {
int n = Integer.parseInt(reader.readLine());
if (n >= 0 && n < canvas.length && canvas[n]==0){
return n;
}
System.out.println("Choose free cell and enter its number");
} catch (NumberFormatException e) {
System.out.println("Please enter the number");
} catch (IOException e) {
}
}
}
static boolean isGameOver(int n){
// 0 1 2
// 3 4 5
// 6 7 8
//поиск совпадений по горизонтали
int row = n-n%3; //номер строки - проверяем только её
if (canvas[row]==canvas[row+1] &&
canvas[row]==canvas[row+2]) return true;
//поиск совпадений по вертикали
int column = n%3; //номер столбца - проверяем только его
if (canvas[column]==canvas[column+3])
if (canvas[column]==canvas[column+6]) return true;
//мы здесь, значит, первый поиск не положительного результата
//если meaning n находится на одной из граней - возвращаем false
if (n%2!=0) return false;
//проверяем принадлежит ли к левой диагонали meaning
if (n%4==0){
//проверяем есть ли совпадения на левой диагонали
if (canvas[0] == canvas[4] &&
canvas[0] == canvas[8]) return true;
if (n!=4) return false;
}
return canvas[2] == canvas[4] &&
canvas[2] == canvas[6];
}
static void drawCanvas(){
System.out.println(" | | ");
for (int i = 0; i < canvas.length; i++) {
if (i!=0){
if (i%3==0) {
System.out.println();
System.out.println("_____|_____|_____");
System.out.println(" | | ");
}
else
System.out.print("|");
}
if (canvas[i]==0) System.out.print(" " + i + " ");
if (canvas[i]==1) System.out.print(" X ");
if (canvas[i]==2) System.out.print(" O ");
}
System.out.println();
System.out.println(" | | ");
}
public static boolean isDraw() {
for (int n : canvas) if (n==0) return false;
return true;
}
}
GO TO FULL VERSION