井字游戏
首先分解任务:
1.如何来显示井字棋的棋盘
2.创建一个3X3的矩阵(chessPiece)来实时记录两个棋手的走棋
3.对异常情况的捕获,用户的输入可能存在哪些不合法的情况
4.怎样判断最终是谁赢了,或者平局
嗯,这只是一个从逻辑上的划分,在写代码时有些功能可能可以在同一个方法模块里实现,也有可能要继续细分——一个功能需要多个方法协同完成。
1.关于如何来显示棋盘,需要记录落子的那个矩阵chessPiece来配合。两个嵌套的循环三次的循环(在遍历到最后一次时需加上一个额外的横向分隔/纵向分隔),在遍历时,同时配合chessPiece来确定棋盘的各个位置上该是‘O’还是‘X’,或者就是空的。
2.关于chessPiece。指定一个位置,若无人落子,则对应下标的元素为0,;若执X选手落子其上,则对应元素为-1;若执O选手落子其上,对应元素为1
3.关于异常。我总结有二:1)用户在已经落子的位置上再落一子;2)用户输入的位置不合法。
4.关于裁定输赢。若某一行或某一列或某一对角线上全为‘O’或者全为‘X’,则为执O选手获胜或执X选手获胜。当棋盘落满子也未出现上面的情况时,平局。
chessPiece是贯穿整个程序的一个“线索”。
运行结果(局部):
一些细节的梳理还是难以用自然的语言表达。
完整代码:
import java.util.Scanner;
public class Ticktacktoe {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
char answer = 'y';
while(answer == 'y') {
int[][] chessPiece = new int[3][3];
int step = 0;
while(whoWin(chessPiece) == 0 && step != 9) {
chessBoard(chessPiece);
if(step % 2 != 0) {
System.out.print("Enter a row (1, 2, or 3) for player X:");
int row = input.nextInt() - 1;
System.out.print("Enter a column (1, 2, or 3) for player X:");
int column = input.nextInt() - 1;
int judge = isLegal(row, column, chessPiece);
if(judge == -1) {
System.out.println("You input a wrong place, please input a right one!");
continue;
}
else if(judge == 0)
chessPiece[row][column] = -1;
else {
System.out.println("This site has been taken up!");
System.out.println("Please put your chess at another place!");
continue;
}
}
else {
System.out.print("Enter a row (1, 2, or 3) for player O:");
int row = input.nextInt() - 1;
System.out.print("Enter a column (1, 2, or 3) for player O:");
int column = input.nextInt() - 1;
int judge = isLegal(row, column, chessPiece);
if(judge == -1) {
System.out.println("You input a wrong place, please input a right one!");
continue;
}
else if(judge == 0)
chessPiece[row][column] = 1;
else {
System.out.println("This site has been taken up!");
System.out.println("Please put your chess at another place!");
continue;
}
}
step++;
}
chessBoard(chessPiece);
if(step == 9)
System.out.println("You were neck and neck!");
else if(whoWin(chessPiece) == -1)
System.out.println("X player won");
else
System.out.println("O player won");
System.out.print("Do you want another ticktacktoe? Enter y or n:");
String answer_string = input.next();
answer = answer_string.charAt(0);
}
System.out.println("Why not have another ticktacktoe?");
}
public static void chessBoard(int[][] chessPiece) {
for(int i = 0 ; i < 3; i++) {
System.out.printf("-------------------\n");
for(int j = 0; j < 3; j++) {
System.out.printf("| %c ", chessTranslation(chessPiece[i][j]));
if(j == 2)
System.out.printf("|");
}
System.out.printf("\n");
if(i == 2)
System.out.printf("-------------------\n");
}
}
public static char chessTranslation(int location){
if(location == -1)
return 'X';
else if(location == 1)
return 'O';
else
return ' ';
}
public static int whoWin(int[][] cB) {
int result = 0;
if(cB[0][0] + cB[1][1] + cB[2][2] == 3)
result = 1;
else if(cB[0][0] + cB[1][1] + cB[2][2] == -3)
result = -1;
else if(cB[0][2] + cB[1][1] + cB[2][0] == 3)
result = 1;
else if(cB[0][2] + cB[1][1] + cB[2][0] == -3)
result = -1;
else if(cB[0][0] + cB[0][1] + cB[0][2] == 3)
result = 1;
else if(cB[0][0] + cB[0][1] + cB[0][2] == -3)
result = -1;
else if(cB[1][0] + cB[1][1] + cB[1][2] == 3)
result = 1;
else if(cB[1][0] + cB[1][1] + cB[1][2] == -3)
result = -1;
else if(cB[2][0] + cB[2][1] + cB[2][2] == 3)
result = 1;
else if(cB[2][0] + cB[2][1] + cB[2][2] == -3)
result = -1;
else if(cB[0][0] + cB[1][0] + cB[2][0] == 3)
result = 1;
else if(cB[0][0] + cB[1][0] + cB[2][0] == -3)
result = -1;
else if(cB[0][1] + cB[1][1] + cB[2][1] == 3)
result = 1;
else if(cB[0][1] + cB[1][1] + cB[2][1] == -3)
result = -1;
else if(cB[0][2] + cB[1][2] + cB[2][2] == 3)
result = 1;
else if(cB[0][2] + cB[1][2] + cB[2][2] == -3)
result = -1;
else
result = 0;
return result;
}
public static int isLegal(int row, int column, int[][] cB) {
if(row > 2 || row < 0 || column > 2 || column < 0)
return -1;
else if(cB[row][column] == 0)
return 0;
else
return 1;
}
}
没想到会超过100行。。。
用类来重写
最近学了类,我想用类来重写这个程序。这个程序在现实中的映射涉及三个对象:
棋盘,执X选手,执O选手
不过所谓的下棋者,不过是对棋盘进行了一系列的操作,故只需要一个棋盘类就够了。
棋盘类:
public class ChessboardObject {
private int[][] board = new int[3][3];
public ChessboardObject() {
}
/*
** 鉴于这个棋盘类的数据域只有一个二维数组且创建时并无特殊要求,
** 故不设置带参数的构造方法
*/
/**判断当前位置是否还未落子*/
public boolean isEmpty(int row, int column) {
if(this.board[row][column] == 0)
return true;
else
return false;
}
/**落子操作*/
public int move(int row, int column, int step) {
/*
** step为偶数时,执X选手落子;step为奇数时,执O选手落子(step从0开始计数)
** 当board[row][column]为0时,当前位置为空;
** 当board[row][column]为1时,当前位置落X;
** 当board[row][column]为-1时,当前位置落O
*/
boolean flag = this.isEmpty(row, column);
if(flag) {
if(step % 2 == 0) {
this.board[row][column] = 1;
}
else {
this.board[row][column] = -1;
}
step++;
}
else
System.out.println("该位置不可落子!");
return step;
}
/**可视化转换器*/
public char translation(int location){
if(location == 1)
return 'X';
else if(location == -1)
return 'O';
else
return ' ';
}
/**打印棋局*/
public void printBoard() {
int chess;
for(int i = 0 ; i < 3; i++) {
System.out.printf("-------------------\n");
for(int j = 0; j < 3; j++) {
chess = this.board[i][j];
System.out.printf("| %c ", translation(chess));
if(j == 2)
System.out.printf("|");
}
System.out.printf("\n");
if(i == 2)
System.out.printf("-------------------\n");
}
}
/**判断输赢*/
public int whoWin() {
/*
** 当board的某一行/某一列/某一对角线上的元素之和为3时,执X选手获胜;
** 当board的某一行/某一列/某一对角线上的元素之和为-3时,执O选手获胜;
** 否则,还未决出胜负
*/
int result = 0;
if(this.board[0][0] + this.board[1][1] + this.board[2][2] == 3)
result = 1;
else if(this.board[0][0] + this.board[1][1] + this.board[2][2] == -3)
result = -1;
else if(this.board[0][2] + this.board[1][1] + this.board[2][0] == 3)
result = 1;
else if(this.board[0][2] + this.board[1][1] + this.board[2][0] == -3)
result = -1;
else if(this.board[0][0] + this.board[0][1] + this.board[0][2] == 3)
result = 1;
else if(this.board[0][0] + this.board[0][1] + this.board[0][2] == -3)
result = -1;
else if(this.board[1][0] + this.board[1][1] + this.board[1][2] == 3)
result = 1;
else if(this.board[1][0] + this.board[1][1] + this.board[1][2] == -3)
result = -1;
else if(this.board[2][0] + this.board[2][1] + this.board[2][2] == 3)
result = 1;
else if(this.board[2][0] + this.board[2][1] + this.board[2][2] == -3)
result = -1;
else if(this.board[0][0] + this.board[1][0] + this.board[2][0] == 3)
result = 1;
else if(this.board[0][0] + this.board[1][0] + this.board[2][0] == -3)
result = -1;
else if(this.board[0][1] + this.board[1][1] + this.board[2][1] == 3)
result = 1;
else if(this.board[0][1] + this.board[1][1] + this.board[2][1] == -3)
result = -1;
else if(this.board[0][2] + this.board[1][2] + this.board[2][2] == 3)
result = 1;
else if(this.board[0][2] + this.board[1][2] + this.board[2][2] == -3)
result = -1;
else
result = 0;
return result;
}
}
主函数:
import java.util.Scanner;
public class TestTicktacktoe {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
char answer = 'y';
while(answer == 'y') {
ChessboardObject ticktacktoe = new ChessboardObject();
int step = 0;
while(ticktacktoe.whoWin() == 0 && step != 9) {
ticktacktoe.printBoard();
if(step %2 == 0)
System.out.println("现在是执X选手的回合:");
else
System.out.println("现在是执O选手的回合:");
System.out.print("请输入行坐标(1,2,3)> ");
int row = input.nextInt() - 1;
System.out.print("请输入列坐标(1,2,3)> ");
int column = input.nextInt() - 1;
if(isLegal(row, column))
step = ticktacktoe.move(row, column, step);
else
System.out.println("指定的位置无效!");
}
ticktacktoe.printBoard();
if(step == 9)
System.out.println("棋逢对手!");
else if(ticktacktoe.whoWin() == 1)
System.out.println("执X选手获胜!");
else
System.out.println("执O选手获胜!");
System.out.print("您还想来一局井字棋游戏吗?\n"
+ "y or n > ");
String answer_string = input.next();
answer = answer_string.charAt(0);
}
}
/**判断输入的位置是否越界*/
public static boolean isLegal(int row, int column) {
if(row > 2 || row < 0 || column > 2 || column < 0)
return false;
else
return true;
}
}