三子棋:是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。

本程序可修改为多子棋,只需要修改#define定义的常量大小就行

#define ROW 3
#define COL 3

#define ROW 10
#define COL 10

程序目录:

一、创建头文件文件、源文件(整体代码)

二、游戏基本逻辑(每部分代码的分析)

1.游戏主页

2.玩家选择玩游戏还是退出游戏

3.初始化棋盘

4.打印棋盘

5.玩家下棋

6.判断输赢

7.电脑下棋

8.判断输赢

三、游戏结果

1.通过判断显示获胜方

2.打印游戏主页,是否再玩一次游戏

程序的具体内容:

一、先创建一个头文件、两个源文件,将代码有规律有逻辑的存放,方便调试

头文件:game.h 用于游戏代码中的函数(包括库函数、自定义函数)声明、符号定义

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3//初始化棋盘
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);//判断行
char Winhang(char board[ROW][COL], int row, int col);//判断列
char Winlie(char board[ROW][COL], int row, int col);//判断对角线
char Windjx(char board[ROW][COL], int row, int col);//判断平局
int IsFull(char board[ROW][COL], int row, int col);

源文件:game.c 用于游戏代码的实现,在其中写入自定义函数的相关内容

#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)
{printf("\n");int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");//分割信息“---|---|---”if (i < row - 1){int j = 0;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;printf("\n");printf("玩家请下棋\n");while (1){printf("请输入坐标(以行数和列数为坐标):》");scanf("%d %d", &x, &y);if (x>=0 && x <= row && y>=0 && 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)
{int x = 0;int y = 0;printf("电脑下棋\n");while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}//判断输赢
char Iswin(char board[ROW][COL], int row, int col)
{char ret = 0;//判断行赢   赢了返回temp   没赢返回sret = Winhang(board, ROW, COL);if (ret != 's'){return ret;}//判断列赢ret = Winlie(board, ROW, COL);if(ret!='s'){return ret;}//判断对角线ret = Windjx(board, ROW, COL);if (ret != 's'){return ret;}//判断平局if (IsFull(board, row, col)){return 'q';}return 'c';}//判断行
char Winhang(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;
again:while (i < row){temp = board[i][0];if (board[i][0] != ' '){while (j < col){if (board[i][j] == board[i][0]){j++;}else{i++;j = 0;goto again;}}return temp;}else{i++;}}return 's';
}char Winlie(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;
again:while (j<col){temp = board[0][j];if (board[0][j] != ' '){while (i<row){if (board[i][j] == board[0][j]){i++;}else{j++;i = 0;goto again;}}return temp;}else{j++;}}return 's';
}//判断对角线
char Windjx(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;//第一条对角线//for (i = 0, j = 0; i < row, j < col; i++, j++)while(i < row && j < col){if (board[0][0]!=' '){temp = board[0][0];if (board[0][0] == board[i][j]){i++;j++;}else{goto again;}}else{goto again;}}return temp;//第二条对角线
again:i = 0;j = COL-1;temp = board[0][j];while(i<row && j<col && j>=0){if (temp != ' '){if (temp == board[i][j]){i++;j--;}else{return 's';}}else{return 's';}}return temp;}//判断平局
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 0;}}}return 1;
}

  源文件:test.c 用于测试游戏的逻辑

#include"game.h"void game()
{char ret = 0;char board[ROW][COL] = { 0 };//初始化棋盘Initboard(board, ROW, COL);//打印棋盘Displayboard(board, ROW, COL);while (1){//玩家下棋Playermove(board, ROW, COL);Displayboard(board, ROW, COL);// 判断输赢  返回*玩家赢   返回#电脑赢     返回q平局    返回c继续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");Displayboard(board, ROW, COL);}if (ret == '#'){printf("电脑赢了\n");Displayboard(board, ROW, COL);}if (ret == 'q'){printf("平局了\n");Displayboard(board, ROW, COL);}
}
void menu()
{printf("       三子棋\n");printf("********************************\n");printf("*********0.exit  1.paly*********\n");printf("********************************\n");}
int main()
{srand((unsigned int)time(NULL));//设置随机数的的生成起点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);return 0;
}

二、游戏的逻辑

1.游戏主页:需要给玩家两个选择(0.退出游戏        1.玩游戏),我们将游戏主页写入函数中,需要时直接调用,避免代码重复书写带来麻烦。

//游戏主页
void menu()
{printf("       三子棋\n");printf("********************************\n");printf("*********0.exit  1.paly*********\n");printf("********************************\n");}

玩家选择退出游戏:0.exit 对应的退出程序

玩家选择玩游戏:1.play 对应进入游戏主程序

switch语句来实现:对于两种选择0和1,有不同的答案,对于输入其它数字,则输入错误,需要重新选择,因此可以使用switch语句来实现。

 do......while循环:由于必须要有一个正确的选择,所以需要循环此过程,直到选择出一个结果,此处我们选择do......while循环,此循环的特点是至少执行循环一次,即进入游戏就得选择,循环的判断部分我们用玩家输入的input来作为判断,用它的好处在于除了选择 0 ,输入的其它正整数(除0外的其它值为真)都将会执行该循环,直到做出正确的选择。

int main()
{srand((unsigned int)time(NULL));//设置随机数的的生成起点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);return 0;
}

2.初始化棋盘和棋子:三子棋的棋盘是一个九宫格,首先需要一个二维数组来存放玩家与电脑下的棋子,先将该二维数组初始化为0,用“ * ”表示玩家棋子,用“ # ”表示电脑棋子,棋盘的初始化和打印也需要运用到二维数组。下面我将用自定义函数一一实现各部分的内容。

初始化棋盘(函数):Initboard(board, ROW, COL);

函数传参内容包括:二维数组board[ ][ ]        #define定义的标识符常量ROW(行数)、COL(列数)

函数定义:

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] = ' ';}}
}

函数中用char board[ROW][COL]接收传递过来二维数组,int row、int col分别接收传过来的ROW、COL。先将二维数组初始化,全部放入'空格'。

3.打印棋盘:棋盘由棋子部分、分割部分(界线)两部分组成

将表格细分开为:“ %c | %c | %c ”、“---|---|---”,可以观察到:最后一个字符后没有“|”,而在最后一行没有分割线“---”,仅有“|”,我们针对每一层次需要打印的内容用 if 语句来约束实现。

打印棋盘:Displayboard(board, ROW, COL);

函数定义:

void Displayboard(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");//分割信息“---|---|---”if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}printf("\n");}}
}

4.玩家下棋:下棋的过程是一个循环的过程“ 玩家下棋→打印棋盘→判断输赢→电脑下棋→打印棋盘→判断输赢 ”,并且该循环为死循环,直到分出胜负后才满足跳出循环的条件,此处用循环while(1)来实现。无论是对于玩家下棋还是电脑下棋,都需要判断下棋的位置是否是空的,若该位置有棋子了,则不能在此再落子;若输入的坐标超出范围了,则需要提醒玩家输入坐标有错,需要重新输入。

玩家下棋:Playermove(board, ROW, COL);

函数定义:

void Playermove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家请下棋\n");while (1){printf("请输入坐标(以行数和列数为坐标):》");scanf("%d %d", &x, &y);if (x>=0 && x <= row && y>=0 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("该位置已有棋子,请重新下棋\n");}}else{printf("输入错误,请重新输入坐标\n");}}
}

玩家通过输入对应的行数、列数确定落子的位置,玩家棋子用“ * ”表示。

 5.判断输赢:分别对行、列、对角线进行判断,若有三子相同连在一起则为赢。此处需要用一个变量来承接返回值,用来反馈判断结果,再输出结果。

返回值“ c ”:表示暂无胜负,继续程序

返回值“ * ”:表示玩家赢了

返回值“ # ”:表示电脑赢了

返回值“ q ”:表示平局

判断输赢:Iswin(board, ROW, COL);

函数定义:

char Iswin(char board[ROW][COL], int row, int col)
{char ret = 0;//判断行赢   赢了返回temp   没赢返回sret = Winhang(board, ROW, COL);if (ret != 's'){return ret;}//判断列赢ret = Winlie(board, ROW, COL);if(ret!='s'){return ret;}//判断对角线ret = Windjx(board, ROW, COL);if (ret != 's'){return ret;}return 'c';
}

在该函数中又包含了三个函数,分别用于判断行、列、对角线的情况,均用变量ret承接返回值。

向函数Iswin(board, ROW, COL)反馈其返回值

返回“ s ”:表示没有赢的情况

返回“ temp ”:其值可能为“ * ”、“ # ”,分别表示玩家、电脑满足判断的条件

判断行:Winhang(board, ROW, COL);

函数定义:

char Winhang(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;
again:while (i < row){temp = board[i][0];if (board[i][0] != ' '){while (j < col){if (board[i][j] == board[i][0]){j++;}else{i++;j = 0;goto again;}}return temp;}else{i++;}}return 's';
}

判断思路:先判断每一行的第一个元素是否为空格,若为空格则直接跳转到下一行的判断;若不为空格,再依次判断本行后面的元素是否与第一个元素相同,若中途有与第一个元素不同的元素出现,则直接跳出while循环进行下一行的判断;若本行元素均与本行的第一个元素相同,则跳出循环,返回本行的第一个元素。

判断列:Winlie(board, ROW, COL);

函数定义:

char Winlie(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;
again:while (j<col){temp = board[0][j];if (board[0][j] != ' '){while (i<row){if (board[i][j] == board[0][j]){i++;}else{j++;i = 0;goto again;}}return temp;}else{j++;}}return 's';
}

判断思路:先判断每一列的第一个元素是否为空格,若为空格则直接跳转到下一列的判断;若不为空格,再依次判断本列后面的元素是否与第一个元素相同,若中途有与第一个元素不同的元素出现,则直接跳出while循环进行下一列的判断;若本列元素均与本行的第一个元素相同,则跳出循环,返回本列的第一个元素。

判断对角线:Windjx(board, ROW, COL);

函数定义:

char Windjx(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;char temp = 0;//第一条对角线//for (i = 0, j = 0; i < row, j < col; i++, j++)while(i < row && j < col){if (board[0][0]!=' '){temp = board[0][0];if (board[0][0] == board[i][j]){i++;j++;}else{goto again;}}else{goto again;}}return temp;//第二条对角线
again:i = 0;j = COL-1;temp = board[0][j];while(i<row && j<col && j>=0){if (temp != ' '){if (temp == board[i][j]){i++;j--;}else{return 's';}}else{return 's';}}return temp;}

判断思路:对角线有两条对角线

第一条对角线:先判断对角线第一个元素board [0][0]是否为空格,若为空格则直接跳转到第二条对角线的判断;若不为空格,则判断该对角线上的第二个元素board [1][1]是否与第一个元素相同,再依次判断本对角线后面的元素是否与第一个元素相同;若均相同则返回第一个元素;若不同,则跳转到第二条对角线的判断。

第二条对角线:先判断对角线第一个元素board [0][COL-1](若为三子棋就是board [0][2])是否为空格,若为空格则返回“ s ”;若不为空格,则判断该对角线上的第二个元素board [i][j](若为三子棋则对应board [1][1])是否与第一个元素相同,再依次判断本对角线后面的元素是否与第一个元素相同;若均相同则返回第一个元素;若不同,则返回“ s ”

判断平局:IsFull(board, row, col);

函数定义:

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 0;}}}return 1;
}

判断思路:经过行、列、对角线的判断,若棋盘上再也没有空格存在,则该情况为平局。用if()语句来控制返回值,若括号内值为1,则返回“ q ”;若括号内值为0,则不执行if()语句,直接按照程序顺序返回“ c ”。

        6.电脑下棋:此处需要生成随机数表示下棋是随机下,若想电脑掌握更好的下棋步骤,需要对下棋步骤进行要求,此过程复杂,暂时不编写。

电脑下棋:Computermove(board, ROW, COL);

函数定义:

void Computermove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("电脑下棋\n");while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}

用函数rand()生成随机数,为了让随机数满足棋盘中每个位置的坐标要求,若为三子棋则需要随机生成0 、1 、2,用随机数分别对行数和列数取余就行,为而调用rand()函数就需要调用srand()函数来生成随机数的起点,在调用srand()函数时需要使用time()函数来形成时间戳,这样就能成功生成随机数,而这样的函数只需要调用一次就行了,所以将它放入了main函数。对time()函数传入一个空指针NULL,将其返回值用强制类型转换(unsigned int)为无符号的整形。

再对电脑的棋子进行判断

三、游戏结果:对判断输赢的返回值进行判断最后的赢家,并打印出结果和游戏主页,让玩家在次选择是否再玩一次。

三子棋——可修改为多子棋相关推荐

  1. 三子棋游戏(支持多子棋)

    目录 前言 一.创建三子棋的思路过程? 二.游戏模块 1.棋盘初始化 2.开始下棋 3.判断输赢 三.测试模块 四.源码 总结 前言 用c语言实现一个三子棋的游戏,当然也可以实现多子棋,修改一点参数即 ...

  2. 三子棋(五子棋,多子棋)的实现:c语言

    ​​​ 想必大家都玩过三子棋,话不多说,解释一下游戏规则,在九宫格中,每一行或每一列中出现三个相同的棋子,或者正对角线,逆对角线出现相同的棋子,则获胜,如下图 下面对代码进行实现: 文章目录 #1.打 ...

  3. 我看你骨骼惊奇,送你本武林秘籍--《三子棋至多子棋的扩展》

    前言: 这篇文章将会手把手带你从程序设计需求出发,用代码思维来实现三子棋游戏. 每一步都会按照这个流程进行 1.要实现什么(程序设计需求) 例如:三子棋的游戏规则 用户的游玩方式 2.怎么实现 代码设 ...

  4. 【C/C++】题解:从三子棋到多子棋

    [C/C++]题解:三子棋延伸为多子棋 导读 该篇文章将会从三子棋延伸到多子棋,介绍如何实现一个多子棋程序,并希望可以体会到如何去设计一个简单的程序,如何去抽象出每个函数模块,掌握编写函数的方法论: ...

  5. 三子棋实现(多子棋实现)

    整体思路: 首先,因为三子棋实现较为复杂,因此需要分模块编写,分为game.c,gsme.h和text.c模块.game.c中存放游戏实现的代码,game.h中存放有关游戏实现的函数声明,text.c ...

  6. C语言三子棋游戏进阶版详解(包括多子棋)

    目录 一,总体思路介绍 二,具体思路的实现 1.初始化游戏界面 2.初始化棋盘 3.打印棋盘 4.玩家移动 5.电脑移动 6.判断输赢 三,源码展示 game.h game.c test.c 一,总体 ...

  7. 简单c语言实现三子棋/多子棋

    简单c语言实现三子棋/多子棋主要是想实现以下几个功能 (先做再循环)do while 一.目录: 1.play 0.exit 二.选择:(Switch)选择 三.进行游戏: 1.储存数据 - 二维数组 ...

  8. 多子棋(三子棋plus版本)

    目录 前言: 一.n子棋的思路. 二.代码实现 1.棋盘初始化和打印 2.游戏主体 1.玩家下棋和电脑下棋 3.判断游戏胜利: 三.源码文件 前言: 为了便于读者理解,代码将分块实现,最后会合并在一起 ...

  9. 【c语言版】带你领悟多子棋游戏

    三子棋以及N子棋的实现 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 判断输赢 主函数的实现(test.c) game.c的实现 game.h的实现 铁汁们~今天给大家分享一篇三子棋以及N子棋的实现,来吧 ...

最新文章

  1. 无线分类新写法,是不是很吊@!
  2. [译] Lenses:可组合函数式编程的 Getter 和 Setter(第十九部分)
  3. egg.js连接mysql数据库遇到的问题
  4. 3D模型“换皮肤”有多简单?也就一句话的事
  5. DbHelperSQL 判断数据库表结构公用方法
  6. 全国独家首测 腾讯QQ 2011 Beta1体验
  7. linux局部变量特殊字符替换,变量,全局变量,环境变量,特殊符号、管道符命令:cut、sort、uniq、wc、tee、tr、sp...
  8. PASTE Splay
  9. [USACO19JAN,Platinum] Redistricting
  10. jQuery Mobile中列表listview(ol、ul)的data-*选项
  11. Django实战(21):使用内置的Amin管理用户
  12. WSL离线安装到任意目录
  13. 数组排序使得数组负数在正数左边且按照原来的顺序
  14. 函数参数缺少const导致so无法加载
  15. \r\n的来历与用法
  16. 消息队列(MQ)之生产者-消费者 | 一文搞定
  17. 别再自己抠图了,Python教你一招弄完
  18. flutter comsumer局部刷新的问题
  19. 【Seaborn】组合图表、多子图的实现
  20. 9.ESP32--ADC

热门文章

  1. 计算机二级系统班C语言讲义,计算机二级C语言讲义8
  2. ORB-SLAM2从理论到代码实现(十二):Frame类
  3. java poi 读取 word图片_Java Poi 根据文字内容 插入 word 图片-Go语言中文社区
  4. Debian11.2安装Python3.10.5
  5. php iphone壁纸,iphone 壁纸尺寸 PHP 图像尺寸调整代码
  6. java 甘特图_Java报表软件--甘特图(Gantt chart)深度解析
  7. SQL Server 变更数据捕获(CDC)
  8. 品优购注册页html
  9. 【C语言-嵌入式】‘a0x7f‘代表什么意思?
  10. 关于crnn中的ctc