1.设计说明
1.1 简介
其实很久之前就写过五子棋,当时拿AWT写的界面,后面通过socket通信实现了联机对战操作,当时写五子棋写的可费劲了,现在又要写一次五子棋,不过是简单版的哈哈,一会就写完了。
描述:基于Java类和对象以及数组开发的一个小型五子棋游戏程序。游戏开始时,选择黑棋、白棋开局,将一枚棋子落在棋盘一坐标上,然后轮番落子,如此轮流下子,直到某一方首先在棋盘的竖、横或两斜四方向上的五子连成线,则该方该局获胜。
1.2 游戏说明
功能列表如下:
(1)输出棋盘;
(2)提示用户下子;
(3)查看用户是否出界或者落子位置是否被占用;
(4)轮番黑棋白棋选择坐标位置进行下子;
(5)判断游戏是否输赢;
(6)判断是否进入下一局;
(7)退出游戏。
2. 实现思路
- 棋盘设计为10*10格,棋盘类型Chess[][] 二维数组,所含属性String chessType; 棋盘首先chessType值是”➕”。
- 初始化二维数组
- 玩家选择黑白圈后,开始下棋。输入要下棋子的行列坐标,黑白棋子轮流落子,当一方连成五子或下满棋盘时,游戏结束(连成五子的一方获胜,下满棋盘为和棋)。
- 每一次落子成功后,马上判断以该位置为中心的八个方向:上、下、左、右、左上、左下、右上、右下是否有相同颜色的棋子连成五子,如果连成五子,则游戏结束,输出相应的信息。
- 当游戏一方胜利后显示胜利信息。从程序表面看,这是一个二维平面图,所以数据用二维数组来表示,数组两个下标可以表示棋盘上的位置,数组元素的值代表棋格上的状态,共有三种情况,分别是,⭕代表白棋,●代表黑棋,➕代表格子。
3. 实现流程
由于时间原因,写的很仓促,说是十分钟写,其实思考加编写加调试前后花了差不多半个小时,老标题党了,hiahia。
3.1 棋子类
首先要写一个棋子类用于存放棋子信息,它的属性主要是chessType(这枚棋子的种类,黑棋还是白棋),flag(棋盘对应的这个位置是否有棋,有棋给true,没棋就给false),每次将棋子下到棋盘上之后,要把flag给置true,表示已经有棋子了,如果还往这个位置下棋就报错。另外两个属性row,colum是我顺手写习惯写上的,没有用到可以省略。
package com.fiveChess;
/**
* Description :
* Created by Resumebb
* Date :2020/10/31
*/
public class ChessNode {
private String chessType;
private int row;
private int colum;
private boolean flag;
public ChessNode(String chessType, int row, int colum, boolean flag) {
this.chessType = chessType;
this.row = row;
this.colum = colum;
this.flag = flag;
}
public String getChessType() {
return chessType;
}
public void setChessType(String chessType) {
this.chessType = chessType;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColum() {
return colum;
}
public void setColum(int colum) {
this.colum = colum;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
3.2操作类
1.run函数
首先上一个run,用来控制操作流程,尽可能做高内聚低耦合,让每一个函数各司其职,专精一件事情。
这个run方法就是最开始进入的界面控制,先直接开始一次游戏,完成后判断用户输入,1重开一盘,0退出游戏。
public void run(){
int choice = 0;
boolean flag = false;
do {
initChessBoard();
show();
playChess();
System.out.println("继续扣1,退出扣0");
Scanner in = new Scanner(System.in);
choice = in.nextInt();
if(choice == 1){
flag = true;
}
}while (flag);
}
2.initChessBoard函数
该函数用于初始化棋盘,所有的chessType给置+,需求是给定10*10大小棋盘,也可以自己增加两个变量,生成自定义大小的棋盘
private void initChessBoard(){
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
chessNodes[i][j] = new ChessNode("➕",i,j,false);
}
}
System.out.println("初始化完成。");
}
3.show函数
用于打印棋盘信息
private void show(){
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.print(chessNodes[i][j].getChessType()+" ");
}
System.out.println();
}
System.out.println();
}
4.playChess函数
根据需求,要判断先手棋子,然后开始下棋。获取用户输入的xy坐标,先进行安全型检查,然后通过chessNode的flag属性可以判断该位置是否有棋,有棋重新输入坐标,没棋的话就将该位置的flag置true,并将chessType改为first,然后检查是否和棋,是否获胜,都不满足的话,交换棋子类型,继续循环,直至和棋或者一方胜出。
private void playChess(){
Scanner in = new Scanner(System.in);
boolean flag = false;
String first = "", second = "", temp = "";
//先手判断
do {
System.out.println("请选择:黑棋● | 白棋⭕");
String choice = in.next();
if(choice.equals("黑棋")){
first = "●";
second = "⭕";
flag = true;
}
else if(choice.equals("白棋")){
first = "⭕";
second = "●";
flag = true;
}
else{
System.out.println("输入有误,请重输:");
}}while (!flag);
//下棋操作
int x = 0, y = 0;
while(true) {
System.out.println("请输入"+first+"x,y坐标:");
x = in.nextInt()-1;
y = in.nextInt()-1;
//参数安全检查
if(x<0 || x>9 || y<0 || y>9){
System.out.println("输入有误,x:1-10,y:1-10,请重新输入:");
continue;
}
//判断原位置是否有棋
if (chessNodes[x][y].isFlag() == true) {
System.out.println("原位置已有棋,请重新输入x,y坐标:");
}
else {
chessNodes[x][y].setChessType(first);
chessNodes[x][y].setFlag(true);
size++;
//判和
if(peace()){
System.out.println("和棋!");
break;
}
if(judgeVectory(x,y,first)){
break;
}
//不满足胜利条件,交换顺序继续下
temp = first;
first = second;
second = temp;
show();
}
}
}
4. judgeVectory函数
首先用四个变量来分别存储水平,垂直,左右俩斜线四个大方向上的棋子数量。然后每次调用函数,以当前给定的x,y坐标下的棋子位置为中心,分别计算八个小方向上的 棋子数量,最后判断只要四个大方向的棋子数量和大于等于4就胜利,因为自身有一个棋子了,所以加上就是大于等于5。整个项目唯一要注意的点就是计算八个小方向上的棋子数量,比如我计算90°方向的数量,首先不能改变x,y坐标的值,否则会影响其他7个小方向的判断,然后判断该棋子正右是否由棋子,应该是x不变,y向右移动,我开始想当然的判断右边,x+1,明显不对,而且每次+1也不行,最好就是利用循环的i去加,减少变量使用,同时还要注意检查x坐标+i后是否越界,越界也不行。
private boolean judgeVectory(int x, int y, String chessType){
int vertical = 0; //垂直方向棋子数量
int level = 0; //水平方向棋子数量
int bevelLeft = 0; //正北为0,-45°斜线上棋子数量
int bevelRight = 0; //正北为0,45°斜线上棋子数量
//计算90°方向棋子数量
for (int i=1; i<5; i++) {
if (y+i < 10 && chessNodes[x][y+i].getChessType().equals(chessType)) {
level++;
} else {
break;
}
}
//计算-90°方向棋子数量
for (int i=1; i<5; i++) {
if (y-i >= 0 && chessNodes[x][y-i].getChessType().equals(chessType)){
level++;
} else {
break;
}
}
//计算0°方向棋子数量
for (int i=1; i<5; i++) {
if (x+i < 10 && chessNodes[x+i][y].getChessType().equals(chessType)){
vertical++;
} else {
break;
}
}
//计算180°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && chessNodes[x-i][y].getChessType().equals(chessType)){
vertical++;
} else {
break;
}
}
//计算45°方向棋子数量
for (int i=1; i<5; i++) {
if (x+i >= 0 && y+i >= 0 && chessNodes[x+i][y+i].getChessType().equals(chessType)){
bevelRight++;
} else {
break;
}
}
//计算225°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && y-i >= 0 && chessNodes[x-i][y-i].getChessType().equals(chessType)){
bevelRight++;
} else {
break;
}
}
//计算-45°方向棋子数量
for (int i=1; i<5; i++) {
if (y-i >= 0 && x+i >= 0 && chessNodes[x+i][y-i].getChessType().equals(chessType)){
bevelLeft++;
} else {
break;
}
}
//计算135°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && y+i >= 0 && chessNodes[x-i][y+i].getChessType().equals(chessType)){
bevelLeft++;
} else {
break;
}
}
//获胜条件
if(vertical >= 4 || level >=4 || bevelLeft >= 4 || bevelRight >= 4){
System.out.println(chessType+"胜利!");
return true;
}
return false;
}
5.chess类完整代码
package com.fiveChess;
import java.util.Scanner;
/**
* Description :
* Created by Resumebb
* Date :2020/10/31
*/
public class Chess {
private ChessNode[][] chessNodes;
private static int size;
public Chess(){
chessNodes = new ChessNode[10][10];
}
//棋盘初始化填值➕,10*10大小
private void initChessBoard(){
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
chessNodes[i][j] = new ChessNode("➕",i,j,false);
}
}
System.out.println("初始化完成。");
}
//显示棋盘
private void show(){
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.print(chessNodes[i][j].getChessType()+" ");
}
System.out.println();
}
System.out.println();
}
//下棋操作
private void playChess(){
Scanner in = new Scanner(System.in);
boolean flag = false;
String first = "", second = "", temp = "";
//先手判断
do {
System.out.println("请选择:黑棋● | 白棋⭕");
String choice = in.next();
if(choice.equals("黑棋")){
first = "●";
second = "⭕";
flag = true;
}
else if(choice.equals("白棋")){
first = "⭕";
second = "●";
flag = true;
}
else{
System.out.println("输入有误,请重输:");
}}while (!flag);
//下棋操作
int x = 0, y = 0;
while(true) {
System.out.println("请输入"+first+"x,y坐标:");
x = in.nextInt()-1;
y = in.nextInt()-1;
//参数安全检查
if(x<0 || x>9 || y<0 || y>9){
System.out.println("输入有误,x:1-10,y:1-10,请重新输入:");
continue;
}
//判断原位置是否有棋
if (chessNodes[x][y].isFlag() == true) {
System.out.println("原位置已有棋,请重新输入x,y坐标:");
}
else {
chessNodes[x][y].setChessType(first);
chessNodes[x][y].setFlag(true);
size++;
//判和
if(peace()){
System.out.println("和棋!");
break;
}
if(judgeVectory(x,y,first)){
break;
}
//不满足胜利条件,交换顺序继续下
temp = first;
first = second;
second = temp;
show();
}
}
}
//判断胜利
private boolean judgeVectory(int x, int y, String chessType){
int vertical = 0; //垂直方向棋子数量
int level = 0; //水平方向棋子数量
int bevelLeft = 0; //正北为0,-45°斜线上棋子数量
int bevelRight = 0; //正北为0,45°斜线上棋子数量
//计算90°方向棋子数量
for (int i=1; i<5; i++) {
if (y+i < 10 && chessNodes[x][y+i].getChessType().equals(chessType)) {
level++;
} else {
break;
}
}
//计算-90°方向棋子数量
for (int i=1; i<5; i++) {
if (y-i >= 0 && chessNodes[x][y-i].getChessType().equals(chessType)){
level++;
} else {
break;
}
}
//计算0°方向棋子数量
for (int i=1; i<5; i++) {
if (x+i < 10 && chessNodes[x+i][y].getChessType().equals(chessType)){
vertical++;
} else {
break;
}
}
//计算180°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && chessNodes[x-i][y].getChessType().equals(chessType)){
vertical++;
} else {
break;
}
}
//计算45°方向棋子数量
for (int i=1; i<5; i++) {
if (x+i >= 0 && y+i >= 0 && chessNodes[x+i][y+i].getChessType().equals(chessType)){
bevelRight++;
} else {
break;
}
}
//计算225°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && y-i >= 0 && chessNodes[x-i][y-i].getChessType().equals(chessType)){
bevelRight++;
} else {
break;
}
}
//计算-45°方向棋子数量
for (int i=1; i<5; i++) {
if (y-i >= 0 && x+i >= 0 && chessNodes[x+i][y-i].getChessType().equals(chessType)){
bevelLeft++;
} else {
break;
}
}
//计算135°方向棋子数量
for (int i=1; i<5; i++) {
if (x-i >= 0 && y+i >= 0 && chessNodes[x-i][y+i].getChessType().equals(chessType)){
bevelLeft++;
} else {
break;
}
}
//获胜条件
if(vertical >= 4 || level >=4 || bevelLeft >= 4 || bevelRight >= 4){
System.out.println(chessType+"胜利!");
return true;
}
return false;
}
//和棋判断
private boolean peace(){
if(size == 100){
return true;
}
return false;
}
public void run(){
int choice = 0;
boolean flag = false;
do {
initChessBoard();
show();
playChess();
System.out.println("继续扣1,退出扣0");
Scanner in = new Scanner(System.in);
choice = in.nextInt();
if(choice == 1){
flag = true;
}
}while (flag);
}
}
4.测试
4.1测试函数
public class Start {
public static void main(String[] args) {
Chess chess = new Chess();
chess.run();
}
}
测试截图
因为写的很仓促,就测试了几个例子,边界条件啥的都没测试,有可能会有bug,不过主要学习的是类与对象的思想,还有五子棋的判断流程,掌握了就可以了。