JAVA 一个简单的控制台五子棋程序 一看就会

news/2025/3/19 14:41:11/

1、绘制棋盘

定义一个二维数组来绘制棋盘,第一行第一列用来显示坐标,其他为0表示没有棋子,黑方为1,白方为2。

static int[][] map = new int[17][17]; // 二位数组作为棋盘

在这里只需要将第一行第一列的坐标信息填充进去即可。

public int[][] buildMap() {for (int j = 0; j < 16; j++) // 仅需构建棋盘边界 map是静态变量初始值为0map[0][j] = j;for (int i = 0; i < 16; i++)map[i][0] = i;return map;}

棋盘大小为16*16,我在这里定义为17*17,是想把每次下棋的坐标也存在数组里,方便后续判断是否胜利。

2、显示棋盘

由于坐标信息有一位数和两位数,直接打印不能对齐,而使用制表符间距太宽,所以我在这里选择了这种方法打印棋盘,可以完美对齐。

public void showMap(int[][] map) {for (int i = 0; i < 16; i++) {for (int j = 0; j < 16; j++) {if (i == 0 && j > 9)System.out.print(map[i][j] + "  ");else if (i >= 10 && j == 0) // 为了对齐棋盘System.out.print(map[i][j] + "  ");elseSystem.out.print(map[i][j] + "   ");}System.out.println("");}
}

3、开始下棋

五子棋需要区分黑白方,我们可以设置一个成员变量来判定该谁下棋。

该变量为1时,黑方下棋;为-1时,白方下棋。

int side = 1; // 该变量表示哪一方下棋,取值为1, -1

要注意几点

  • 对用户错误的输入要采取措施
  • 下棋的前提是该坐标处没有棋子
  • 取二维数组多出来的部分存储刚刚下的棋子坐标,用来判定是否胜利
  • 一方确定下完之后才能改变side变量
public int[][] updateMap(int[][] map) {Scanner input = new Scanner(System.in);if (side == 1) { // side = 1 表示黑方下棋,完成后side改变符号,白方下棋System.out.println("现在黑方下棋,请输入棋盘坐标:");int i = input.nextInt();int j = input.nextInt();if (i < 1 || i > 15 || j < 1 || j > 15) { // 分辨错误输入System.out.println("输入有误,请重新输入");return map; // 若输入有误,退出此函数}if (map[i][j] == 0) { // 前提是该位置没有棋子map[i][j] = 1;side = -side; // 变换符号map[16][0] = i; // 记录刚下的棋子的坐标,有用map[16][1] = j;} elseSystem.out.println("输入有误,请重新输入");} else {System.out.println("现在白方下棋,请输入棋盘坐标:");int i = input.nextInt();int j = input.nextInt();if (i < 1 || i > 15 || j < 1 || j > 15) {System.out.println("输入有误,请重新输入");return map;}if (map[i][j] == 0) {map[i][j] = 2;side = -side;map[16][0] = i;map[16][1] = j;} elseSystem.out.println("输入有误,请重新输入");}return map;
}

4、判定胜利

考虑五子相连的情况

  • 横排
  • 竖排
  • 左斜(撇)
  • 右斜(捺)

判定胜利的方法有很多种,最简单暴力的就是遍历二维数组,这种方法浪费空间消耗时间,这里不需要用。

想到我们之前保存的棋子坐标了吗?每下一次棋,我们可以从这颗棋子的左右判定是否成立横排五子相连,同样的,也可以从这颗棋子的上下判定是否成立竖排五子相连。

先设定一个变量count = 1,如果左右有棋子和该棋子数字一样(不为0),则count++,最后的结果count大于等于5,则横排五子相连。

还需要考虑一个问题!

如果是在棋盘右边界的棋子,就不能继续向右查找。其他方向同理。

因此,当向右查找时,如果查找到右边界上的棋子,则一定要退出循环。

int count = 1;
int x1 = x; // 定义两组坐标,用于变换
int x2 = x;
while (true) { // 查询该棋子右边if (x1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 + 1;if (map[x][y] == map[x1][y]) {count++;} else {break;}
}while (true) { // 查询该棋子左边if (x2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 - 1;if (map[x][y] == map[x2][y]) {count++;} else {break;}
}

如果你看懂了上面这段代码,那么相信你也能写出其他三个方向的判定。下面附上我判定胜利的方法代码块。

  • 返回布尔类型,若胜利则返回true
  • 传参为当前棋盘数组
  • 时刻防止数组越界
  • 检查完行之后要检查列,需要将x1, x2, y1, y2(用于移动查找的坐标)恢复为刚下的棋子坐标
public boolean checkMap(int[][] map) {int count = 1;int count1 = 1;int count2 = 1;int count3 = 1;int x = map[16][0]; // 刚下的棋子的坐标int y = map[16][1];int x1 = x; // 定义两组坐标,用于变换int x2 = x;int y1 = y;int y2 = y;// 每两个while为一组,分别检查 行、列、左斜、右斜while (true) { // 查询该棋子右边if (x1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 + 1;if (map[x][y] == map[x1][y]) {count++;} else {break;}}while (true) { // 查询该棋子左边if (x2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 - 1;if (map[x][y] == map[x2][y]) {count++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子下边if (y1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;y1 = y1 + 1;if (map[x][y] == map[x][y1]) {count1++;} else {break;}}while (true) { // 查询该棋子下边if (y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;y2 = y2 - 1;if (map[x][y] == map[x][y2]) {count1++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子右下if (x1 == 15 || y1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 + 1;y1 = y1 + 1;if (map[x][y] == map[x1][y1]) {count2++;} else {break;}}while (true) { // 查询该棋子左上if (x2 == 1 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 - 1;y2 = y2 - 1;if (map[x][y] == map[x2][y2]) {count2++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子左下if (x2 == 1 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 - 1;y1 = y1 + 1;if (map[x][y] == map[x1][y1]) {count3++;} else {break;}}while (true) { // 查询该棋子右上if (x2 == 15 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 + 1;y2 = y2 - 1;if (map[x][y] == map[x2][y2]) {count3++;} else {break;}}if (count >= 5 || count1 >= 5 || count2 >= 5 || count3 >= 5) { // 其中有一组大于等于五个即胜利if (map[x][y] == 1)System.out.println("黑方获胜!");elseSystem.out.println("白方获胜!");return true; // 返回true 程序结束}return false; // 无人胜利返回false 程序继续执行
}

下面附上完整代码。

package csdn;//该程序完成了控制台版本五子棋import java.util.Scanner;public class Gobang {static int[][] map = new int[17][17]; // 二位数组作为棋盘int side = 1; // 该变量表示哪一方下棋,取值为1, -1public static void main(String[] args) {Gobang gobang = new Gobang(); // 构造类gobang.buildMap(); // 构建棋盘while (true) {gobang.showMap(map); // 显示棋盘gobang.updateMap(map); // 更新棋盘if (gobang.checkMap(map)) { // 检查棋盘,若获胜则退出循环gobang.showMap(map);break;}}}/*** 空构造函数*/public Gobang() {}/*** 构建棋盘* * @return*/public int[][] buildMap() {for (int j = 0; j < 16; j++) // 仅需构建棋盘边界 map是静态变量初始值为0map[0][j] = j;for (int i = 0; i < 16; i++)map[i][0] = i;return map;}/*** 显示棋盘,传参为二维数组* * @param*/public void showMap(int[][] map) {for (int i = 0; i < 16; i++) {for (int j = 0; j < 16; j++) {if (i == 0 && j > 9)System.out.print(map[i][j] + "  ");else if (i >= 10 && j == 0) // 为了对齐棋盘System.out.print(map[i][j] + "  ");elseSystem.out.print(map[i][j] + "   ");}System.out.println("");}}/*** 更新棋盘,根据用户输入的坐标更改二位数组的内容* * @param map* @return*/public int[][] updateMap(int[][] map) {Scanner input = new Scanner(System.in);if (side == 1) { // side = 1 表示黑方下棋,完成后side改变符号,白方下棋System.out.println("现在黑方下棋,请输入棋盘坐标:");int i = input.nextInt();int j = input.nextInt();if (i < 1 || i > 15 || j < 1 || j > 15) { // 分辨错误输入System.out.println("输入有误,请重新输入");return map; // 若输入有误,退出此函数}if (map[i][j] == 0) { // 前提是该位置没有棋子map[i][j] = 1;side = -side; // 变换符号map[16][0] = i; // 记录刚下的棋子的坐标,有用map[16][1] = j;} elseSystem.out.println("输入有误,请重新输入");} else {System.out.println("现在白方下棋,请输入棋盘坐标:");int i = input.nextInt();int j = input.nextInt();if (i < 1 || i > 15 || j < 1 || j > 15) {System.out.println("输入有误,请重新输入");return map;}if (map[i][j] == 0) {map[i][j] = 2;side = -side;map[16][0] = i;map[16][1] = j;} elseSystem.out.println("输入有误,请重新输入");}return map;}/*** 检查是否有一方获胜* @param map* @return*/public boolean checkMap(int[][] map) {int count = 1;int count1 = 1;int count2 = 1;int count3 = 1;int x = map[16][0]; // 刚下的棋子的坐标int y = map[16][1];int x1 = x; // 定义两组坐标,用于变换int x2 = x;int y1 = y;int y2 = y;// 每两个while为一组,分别检查 行、列、左斜、右斜while (true) { // 查询该棋子右边if (x1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 + 1;if (map[x][y] == map[x1][y]) {count++;} else {break;}}while (true) { // 查询该棋子左边if (x2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 - 1;if (map[x][y] == map[x2][y]) {count++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子下边if (y1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;y1 = y1 + 1;if (map[x][y] == map[x][y1]) {count1++;} else {break;}}while (true) { // 查询该棋子下边if (y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;y2 = y2 - 1;if (map[x][y] == map[x][y2]) {count1++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子右下if (x1 == 15 || y1 == 15) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 + 1;y1 = y1 + 1;if (map[x][y] == map[x1][y1]) {count2++;} else {break;}}while (true) { // 查询该棋子左上if (x2 == 1 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 - 1;y2 = y2 - 1;if (map[x][y] == map[x2][y2]) {count2++;} else {break;}}x1 = x; // 恢复坐标x2 = x;y1 = y;y2 = y;while (true) { // 查询该棋子左下if (x2 == 1 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x1 = x1 - 1;y1 = y1 + 1;if (map[x][y] == map[x1][y1]) {count3++;} else {break;}}while (true) { // 查询该棋子右上if (x2 == 15 || y2 == 1) // 防止数组越界,下在边界上的棋子不予判定break;x2 = x2 + 1;y2 = y2 - 1;if (map[x][y] == map[x2][y2]) {count3++;} else {break;}}if (count >= 5 || count1 >= 5 || count2 >= 5 || count3 >= 5) { // 其中有一组大于等于五个即胜利if (map[x][y] == 1)System.out.println("黑方获胜!");elseSystem.out.println("白方获胜!");return true; // 返回true 程序结束}return false; // 无人胜利返回false 程序继续执行}
}

运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

都看到这了,不评论一个再走?


http://www.ppmy.cn/news/846624.html

相关文章

SQL SERVER 大小写敏感设置及排序规则详解

最近操作数据库查询时,提示对象名无效&#xff0c;发现是因为数据库大小写敏感导致,可以通过排序规则设置如下&#xff1a; 排序规则名称由两部份构成&#xff0c;前半部份是指本排序规则所支持的字符集。 如:Chinese_PRC_CS_AI_WS 前半部份&#xff1a;指UNICODE字…

JAVA学习第一阶段模块二

模块二 Java面向对象 类和对象 类和对象及引用 对象主要指现实生活中客观存在的实体&#xff0c;在Java语言中对象体现为内存空间中的一块存储区域。 类的定义方法 class 类名{类体; }class Person{ //类名命名&#xff1a;通常情况下&#xff0c;当类名由多个单词组成时…

《CSS世界》:一本CSS领域的内功心法修炼手册

来源 | https://chrisdeo.github.io 前言 《CSS世界》这本书可以说是张鑫旭的一本CSS领域的内功心法修炼手册了&#xff0c;阅读这本书&#xff0c;其实是为了印证一些自身在CSS学习上的一些东西&#xff0c;所以&#xff0c;有了这篇读书笔记&#xff0c;记录一些我不是很清晰…

小学校园里计算机文字,中小学计算机教学论文(共2228字).doc

中小学计算机教学论文(共2228字) 中小学计算机教学论文(共2228字) 一、中小学计算机教学现状 计算机作为信息时代发展产物&#xff0c;对人们的生活影响深远&#xff0c;并逐渐成为不可或缺的重要部分。我国计算机教学随着时代的发展&#xff0c;从无到有、从少到多、时至今日&…

工程图字体宋体仿宋_设计干货来了!最热门的宋体字要如何设计搭配?

字体设计搭配是一位优秀设计师必须掌握的学问,宋体字作为汉字最常见的一种字形,如何将宋体运用搭配好呢?一流设计网来为您逐一分析。 虽然说宋体字叫做宋体字,但是如果要追溯宋体字的起源,我们还得从唐朝说起。 唐朝时期,佛教在中国开始盛行开来,唐朝皇帝甚至派出唐僧师…

生僻字怎么用计算机的,最实用生僻字输入方案大全

介绍生僻字输入方法的文章看到过不少,但或过于偏颇,或因条件苛刻使用不便。本文总结最实用的方法,弥补这个不足。 汉字有上万之多,但常用的也就几千个。用电脑写文章偶尔会遇到一些不常用的汉字,看起来面熟但就是不知该如何发音,因而惯用的拼音输入法也就难以派上用场。因…

Python脚本小工具之文件与内容搜索

目录 一、前言 二、代码 三、结果 一、前言 ​日常工作中&#xff0c;经常需要在指定路径下查找指定类型的文件&#xff0c;或者是指定内容的查找&#xff0c;在window环境中&#xff0c;即可以使用一些工具如notepad或everything&#xff0c;也可以使用python脚本。但在l…

CSDN博客的文字颜色、字体和字号设置

CSDN博客的文字颜色、字体和字号设置 一、文本颜色设置方法一代码效果 方法二代码效果 二、文本字号设置代码效果 三、文本字体设置代码效果 四、综合效果代码效果分享 一、文本颜色设置 方法一 代码 <font color red>1.我是文本 红色red</font> <font colo…