关于三子棋游戏的简易实现与N子棋胜利判断方法

要实现三子棋游戏,主要需要实现以下几个要求:>

  • 需要一个棋盘,既然需要一个棋盘,棋盘是在一个平面上的,所以我们需要创建一个二维数组
  • 棋盘的打印
  • 玩家下棋与电脑下棋
  • 判断胜利

因为在写三子棋游戏中,我分了两个文件,一个是game.c,一个是test.c。game.c主要是游戏的实现部分,而test.c是主函数测试部分,

并且相对应的给了一个game.h文件,用来实现函数各个声明与标识符常量的定义

这里先给出game.h以便更好了解各个标识符所代表的意义.


#include <stdio.h>#include <stdlib.h>#include <time.h>void InitBoard(char board[ROW][COL], int row, int col);void Displayboard(char board[ROW][COL], int row, int col);void PlayerMove(char board[ROW][COL], int row, int col);void ComputerMove(char board[ROW][COL], int row, int col);char IsWin(char board[ROW][COL], int row, int col);

以下是test.c文件代码内容:

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void menu()
{printf("**************************\n");printf("******    1.play   *******\n");printf("******    0.exit   *******\n");printf("**************************\n");
}void game()
{char ret = 0;char board[ROW][COL];//? NO,we can't do it, because we are so hard to change relveant value;//首先初始化棋盘InitBoard(board, ROW, COL);//接下来是打印棋盘Displayboard(board, ROW, COL);//接下来玩家下其while (1){PlayerMove(board, ROW, COL);Displayboard(board, ROW, COL);ret = IsWin(board, ROW, COL);if (ret != 'C'){break;}ComputerMove(board, ROW, COL);Displayboard(board, ROW, COL);ret = IsWin(board, ROW, COL);if (ret != 'C'){break;}}if (ret == '*'){printf("玩家赢\n");}else if (ret == '#'){printf("电脑赢\n");}else{printf("平局\n");}
}void test()
{int input = 0;do{menu();printf("请选择数字:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);}int main()
{srand((unsigned int)time(NULL));test();return 0;
}

接着为game.c文件代码内容:

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
}void Displayboard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}   printf("\n");if (i < row - 1){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}}printf("\n");}
}void PlayerMove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;while (1){printf("玩家下:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该坐标已被占用,请重新输入\n");}}else{printf("该坐标非法,请重新输入\n");}}
}void ComputerMove(char board[ROW][COL], int row, int col)
{printf("电脑下:>\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}int IsFull(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' ')return 1;}}return 0;
}char IsWin(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' '){return board[i][1];}}for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')return board[1][i];}if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[1][3] && board[1][1] != ' '){return board[1][1];}int ret = IsFull(board, row, col);if (1 == ret){return 'C';}else{return 'E';}
}

首先是test.c中的内容:

这里的test函数是为了存放我们想要实现的让玩家输入数字来判断是否进入游戏的一个函数,这里的srand函数是为了后面中电脑下棋的一个前提条件:

于是现在来到了我们的test函数中

首先还是常例的打印菜单函数,提示以下玩家应该选什么:

运行结果是这样

既然已经提示了,接下来总得输入点什么吧?因此上图的scanf与do…while循环便是为了来适配我们的选择,因为游戏至少执行一次,当你输入1的时候,进入游戏,结束游戏后,while判断input为真,可以重新输入数字。当输入为0时,do…while循环判定为假,直接退出循环,退出程序,当input输入其他值时,重新输入.现在我们输入几个数字之后来看一下效果:(下图的game函数暂时使用printf(“三子棋游戏”)来代替。

接下来轮到game函数部分,也是今天最重要的一部分,这其内部,我们将通过各类函数来实现三子棋游戏功能,先看代码:

刚开始想法是,先创建一个二维数组对吧,类似于这样:

但是行和列里面直接放置数字三是否不太合适呢,万一某天我们要玩五子棋,甚至是十字棋,我们要一个一个去改动与其相关的变量,因此,这里是不太合适的,因此,我们在game.h中定义两个标识符常量ROW,与COL,分别为行和列,这样每次只用更改ROW与COL的值就可以了(别忘记包含头文件噢)

数组定义好之后,接下来我们需要将其初始化,我们写一个Initboard函数来实现,先给大家看一看构建好的三子棋棋盘是什么样的。

旁边的横线与竖线是我们所起的装饰,可以很明显的看到,我们为数组每一个值都初始化为空格,这样也是以便后文的下棋。

写了一个Initboard函数过后,我们在game.h中进行声明并在game.c中进行定义

初始化过后,我们就可以来打印棋盘了,打印棋盘前,我们将棋盘分为两部分,分别打印,如下所示

将 %c |分为一组,—|分为另一组来进行打印,并且—|只用打印两组,也即为row-1组

因此,我们这样编写Displayboard函数

里层第一个for循环中为什么要加if(j<col-1)的条件?,因为我们在打印|时,每一行只要col-1条,在这里也每一行即为2条|,不信你可以去看下方上方三子棋的图喔,下方的if(j<col-1)同理,里层第二个for循环也一样,只需要在row-1行前打印—|就够了,请看下图

(之前分析时候的图)**

**这样处理之后,程序运行的结果为:

我们便成功的将其打印出来了。

棋盘有了,接下来总得下棋吧?我们编写一个PlayerMove函数来实现,既然是下棋,也不能只下一次,因此我们也要编写一个循环

如下图所示

接下来时PlayerMove函数的具体实现

此处我们将玩家下棋的字符弄为若玩家成功下棋,直接跳出循环,不用再继续了,若玩家输错,则可以重新输入。这里为什么我们会将board[x-1]y-1] 赋值为 呢,正是因为数组的下标从0开始,但玩家一般会觉得第一行就是第一行,因此,实际的坐标是比输入的坐标-1得到的。现在我们看一下效果**

此然玩家下完了,也应该轮到电脑下了吧?这里我们编写一个ComputerMove函数来实现电脑下棋,如下所示

此处的x与y我们让其生成0~2随机值,这样可以对应到数组每个元素的下标,并且当数组该下表所对应的值为空格时,赋值为’#;直接跳出循环。

当玩家下完与电脑下完之后,我们需要判断其是否胜利,因此我们编写IsWin函数来判断是否胜利,若胜利,我们返回此时下棋的那个字符,若平局,我们返回字符‘E’,若未平局也未胜利,则返回 ‘C’,代表游戏继续。下面是IsWin函数的具体实现方法。

此处在判断每一行与每一列,对角线元素是否相同后,若都不相同,则有可能是平局,因此我们写了一个IsFull函数,来判断是否还有棋盘中是否还有空格,如果有空格,则证明还未平局。那我们就return ‘C’,否则,return‘E’,代表平局。IsFull函数的实现方法:

运行出来的结果为:

下面是程序的改进方法:

在判断胜利方面,我们其实把程序写死了,也即为只能判断三子棋的胜利,现在我要改动数值玩五子棋,那么其实这个程序已经无法再使用了,因此,我对胜利的判断有以下思考:即计算所下的那个位置的字符所在的行其总个数,列的总个数,对角线的总个数

下面我将画一张图来表示

下面对代码进行改动

因为我们每次下棋后都要进行判断,因此干脆在下棋中直接进行判断即可,对程序改动如下:

对PlayerMove与ComputerMove改为有返回值类型的函数

在ComputerMove与PlayerMove后面增加了IsWin函数

IsWin函数便实现我们刚才的通过加和来判断输赢,我们重点来看一下其怎么实现:

char IsWin(char board[ROW][COL], int x, int y)
{int total = 1;int i = 0;int j = 0;//判断一行中元素个数是否为3for (i = y+1; i <= COL - 1; i++){if (board[x][i] == board[x][y]){total++;}}for (i = y - 1; i >= 0; i--){if (board[x][i] == board[x][y]){total++;}}if (total == ROW){return board[x][y];}//判断一列total = 1;for (i = x + 1; i <= ROW - 1; i++){if (board[i][y] == board[x][y])total++;}for (i = x - 1; i >= 0; i--){if (board[i][y] == board[x][y])total++;}if (total == COL){return board[x][y];}total = 1;//判断对角线for (i = x - 1, j = y + 1; i >= 0 && j <= COL - 1; i--, j++){if (board[i][j] == board[x][y])total++;}for (i = x +1, j = y -1; i<=ROW-1&&j>=0; i++,j--){if (board[i][j] == board[x][y])total++;}if (total == COL){return board[x][y];}total = 1;for (i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--){if (board[i][j] == board[x][y])total++;}for (i = x + 1, j = x + 1; i <= ROW - 1 && j <= COL - 1; i++, j++){if (board[i][j] == board[x][y])total++;}if (total == COL){return board[x][y];}int rec = IsFull(board,ROW,COL);if (rec == 1){return 'E';}else{return 'C';}
}

此处便是判断一行,我们将我们下棋的那个点的坐标作为参数传值进去,同时判断其左边与右边与其相同的元素个数,定义一个变量total,为了计算相同元素个数,我们已经下的那一次棋也算为相同元素个数之1,因此其赋值为1,

判断列数则与其上面相同,如下所示

判断对角线时,对角线有两种情况,我们需要分别来考虑,第一种情况是这样的

还有一种情况:

因此,我们也就可以写出对角线的相同元素和的代码,但别忘了还有判断平局与继续的IsFull函数,把他直接跟着后面就可以了

这样的话就顺利写出来了现在来看一下五子棋的效果

本文完。

关于三子棋游戏的简易实现与N子棋胜利判断方法相关推荐

  1. C语言实现三子棋游戏—可扩展到任意N子棋

    C语言实现三子棋 游戏介绍 游戏编程思路 游戏代码详解 主函数 游戏菜单函数 游戏逻辑函数 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 判断输赢 完整代码 test.c game_chess.c gam ...

  2. 三子棋(n行n列n子棋)详解

    哈喽亲爱的小伙伴们大家好,真的是好久不见.前一阵子过完年之后进行了漫长的"请年茬",现在刚刚开学,从今天开始更新,基本上不出意外还是两天一篇左右.上一期给小伙伴们讲解了数组,这期来 ...

  3. html战棋游戏战棋游戏,六款不可错过的战棋游戏 将领才华始于纸上谈兵

    战棋游戏,就是在地图上按格移动人物进行作战的回合游戏模式."步步惊心"的战斗模式.掌控全场的战场指挥感.史诗般的精彩剧情,战棋游戏的这些特点,吸引了众多玩家.那些绞尽脑汁考虑每回合 ...

  4. python井字棋游戏代码_Python实现的井字棋(Tic Tac Toe)游戏示例

    Python实现的井字棋(Tic Tac Toe)游戏示例 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  Python实现的井字棋(Tic Tac Toe)游戏示 ...

  5. [CareerCup] 17.2 Tic Tac Toe 井字棋游戏

    17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...

  6. 用C语言实现简单的一字棋游戏

    问题分析设计目录 棋盘显示和标记以及棋盘的设计 搜索树叶子节点设计 搜索树设计 节点静态估值计算 完整代码 总结 棋盘显示和标记以及棋盘的设计 用int一维数组表示一字棋的棋盘位置,0~8,数组位置i ...

  7. php 井字棋,怎样用JS做出井字棋游戏

    这次给大家带来怎样用JS做出井字棋游戏,用JS做出井字棋游戏的注意事项有哪些,下面就是实战案例,一起来看一下. 最近有一门课结束了,需要做一个井字棋的游戏,我用JavaScript写了一个.首先界面应 ...

  8. MCTS蒙特卡洛搜索树实现井字棋游戏

    利用蒙特卡洛搜索树实现简单的井字棋游戏,重点不是井字棋,是熟悉蒙特卡洛搜索树的应用,而且我们知道,MCTS可以应用到非常复杂的博弈游戏中,比如象棋,围棋,在搜索空间非常大的时候,普通的极大极小搜索树无 ...

  9. 成三棋、九子棋、十二子棋

    目录 成三棋 九子棋 十二子棋 成三棋 apk下载:资源分享汇总 (这个apk做的很差,有重大bug) 规则: 1.游戏分两个阶段――下棋阶段和走棋阶段.在第一阶段(下棋阶段)下棋双方各有9颗棋子,将 ...

最新文章

  1. 小猿圈Linux学习-Linux种搜索的命令
  2. 输入命令导出oracle
  3. matlab 图片批量读取
  4. 62. Search in Rotated Sorted Array【medium】
  5. 人工智能靠人工:标注员1天要听1000条录音
  6. 【渝粤教育】国家开放大学2019年春季 2507学前儿童艺术教育(音乐) 参考试题
  7. 内存数据库和关系数据库之间的数据同步原理
  8. mysql 分库分表 建表,mysql 分库分表 建表MySQL常用操作
  9. 粒子群优化算法(2)离散粒子群算法
  10. 语音识别技术在智能家居中的应用有哪些?
  11. 视频编解码(七):profilelevel简介、ffmpeg如何控制profilelevel、编码效率
  12. python正则库安装_python中正则表达式regex库的使用
  13. 第一章:Ruby 安装 - Windows
  14. python输入整数_限制输入整数的5种情况(学数学学Python编程)
  15. 深度学习 - 生成对抗网络
  16. [历朝通俗演义-蔡东藩-前汉]第011回 降真龙光韬泗水 斩大蛇夜走丰乡
  17. G_分包具体详情及处理
  18. CentOS7 通过 cups 与 Windows 共享 HP 1020 打印机
  19. 区块链基础知识与关键技术解析
  20. 这么有“艾”的端午节,此处应@博物杂志!

热门文章

  1. Microsoft fsx 飞行模拟器 SDK的一些心得
  2. OpenG利用glreadPixel实现截屏功能
  3. 【狄克特斯拉算法验证】
  4. Excel怎样设置标题行,Excel工作表中标题行的处理
  5. [02]Hello World!
  6. 电脑的学名为电子计算机
  7. Swing 美化包-JTattoo
  8. 第二本书unit5 lvm管理
  9. 《华盛人》技术服务支持
  10. 003-位运算异或“∧”使特定bit位翻转