9*9乘法表编累了吧,杨辉三角编累了吧我们知道那些很枯燥,但谁也架不住一上来就写那些吧,为了让我们小白学C语言不枯燥,我们今天实现一个小游戏的编程:
185行代码带你一步一步理解并实现三子棋游戏!!!
废话不多说先上效果图
我们初学程序需要了解什么程序的运行时如何运行的,要实现一个目标我们首先得一步一步分开走.确定小的目标
比如我们这个三子棋程序我们得先确定程序的大体流程是什么再来编写,而不是上来就开搞,这样是很难的
首先我先贴出来程序的大体框架,一条一条写出来便于大家理解
如果你看不懂没关系,我来一步一步讲解
首先我们要编写三子棋,那么我们得定义一个棋局的大小吧
我们先在预编译阶段定义了一个 3*3也就是就宫格的棋局大小
代码如下
#define m_row 3 //棋盘大小控制
#define m_col 3
char chess[m_row][m_col]; //定义棋盘数组
写在程序的开头为了方便我们任意函数随时来调用他
好,那么我们完成了定义操作就要开始写主函数了!
在主函数里我们要完成什么操作呢? 我们得完成模式的选择!由上图我们也看出来了
而怎么进行模式选择呢
靠的就是我们的菜单函数!
我们进入菜单函数之后需要返回一个键盘输入的值来进行我们的模式选择(好吧其实就只有一种而已)
在这里我附上主程序和菜单函数的代码
代码如下
//菜单函数
int menu () {
int chooise;
printf("-------------------\n");
printf("-----1.开始游戏----\n");
printf("-----2.退出游戏----\n");
printf("-------------------\n");
printf("请输入你的选择:");
scanf("%d",&chooise);
return chooise;
}
//主函数
int main() {
//定义一个选择函数来接收菜单函数的返回值
int choose;
while(1) {
choose = menu ();
//选择函数为1 开始游戏
if(choose == 1) {
game();
}
else if(choose == 2){
break;
}
else {
printf("你的输入有误,请重新输入!\n");
continue;
}
}
return 0;
}
好写在这里我们就可以运行一下这个程序了,哦我们还没有定义geme()函数我们可以先注释掉看一下效果图
好,到这里我们的主函数就写完了,接下来就要写游戏函数了
我们要思考,在游戏函数函数里我们需要完成什么
首先我们要完成我们的初始化棋盘!
完成之后我们得输出棋盘吧
之后呢完成玩家落子
玩家落完自就电脑落子了??不对我们还得进行胜负的检查!有胜负就跳出
如果没有我们才可以让电脑落子
电脑落完子之后我们再次检查胜负
如果没有产生产生胜负我们需要再打印棋盘回到第一步的操作,我这样说可能不太理解再次附上我们的流程图后半部分
如果没有看懂就想象一下我们平时下棋的场景,结合实际效果更好一点!先贴出我们的游戏代码函数
游戏函数代码
void game() {
//定义一个检查数组字符,如果改变说明有胜负产生!
char winner=' ';
initchess();
while(1) {
//输出棋盘
outputchess();
//玩家落子
playermove();
//winner接受一下检查函数返回来的值
winner = checkwinner();
//进行判断,如果不是空格跳出判断
if(winner!= ' ') {
break;
}
//电脑落子
computermove();
//winner接受一下检查函数返回来的值
winner = checkwinner();
//进行判断,如果不是空格跳出判断
if(winner!= ' ') {
break;
}
}
//跳出循环说明胜者或者和棋产生判断
outputchess();
if(winner== 'x'){
printf("玩家获胜!\n");
}
else if(winner== 'o'){
printf("电脑获胜!\n");
}
else if(winner== 'q') {
printf("和棋!\n");
}
else
printf("代码出BUG了!\n");
}
如果看不懂没关系我们接着往下一一细说,让你理解这个代码
我们进入函数之后得初始化棋盘
注意我们在游戏进入之后初始一次就可以了
剩下的函数我们写在while(1)循环里面
接着我们就要打印棋盘了,先放出代码理解
代码如下
void outputchess() {
int row;
for(row = 0;row<m_row;row++) {
printf("| %c | %c | %c |\n",
chess[row][0],chess[row][1],chess[row][2]);
if(row!=m_row-1) //加这一行是让他少输出一个行间隔线可以,最后一行多输出一个行线很丑,仅仅是美观而已
printf("|----|----|----|\n");
}
}
我们直接一排一排打印出我们3个数组,我们不需要遍历数组,因为这样我们每个数组中间的 ‘|’ 没办法打印
接下来玩家落子就简单了 我们用字符’x’来实现玩家落子的符号
玩家落子之后并不是执行检查胜负那样简单我们还需要进行合法性的判断,判断是否输出越界,或者被占用了!
具体看程序代码段
代码如下
//玩家落子
void playermove(){
int row = 0,col = 0;
while(1) {
printf("请输入你的行和列:\n");
scanf("%d,%d",&row,&col);
//对玩家输入坐标判断
if(row<0||row>=m_row||col<0||col>=m_col) {
printf("输入的坐标不合法!重新输入!\n");
continue;
}
//如果不是一个空格那表示被占用
if(chess[row][col]!=' ') {
printf("输入的坐标被占用!重新输入!\n");
//如果不是一个空格那表示被占用结束这次循环
continue;
}
//玩家落子用'x'表示
chess[row][col] = 'x';
break;
}
printf("玩家落子完毕!\n");
}
接下来就是检查胜负了
检查胜负函数得有一个返回值,所以我们需要在game()第一行定义一个字符winner = ’ '初始值为 ’ ‘(空格),来接受检查函数的返回值,
而我们也是靠winner里面的字符(如果我们的winner的初始值被改变了)才可以判断胜负或者和棋.
那么我们怎么下棋才会胜利呢
1.横行练成了一条线
2.竖行连成了一条线
3,对角线连城一条线(注意有两个对角线)
这3个条件分开来判断,并返回我们判断胜负条件成立的棋局上的字符传回给 geme()里面的winner
想一想还有那种情况没判断呢???
对,那就是和棋,和棋条件是什么呢,是不是棋盘满了但是没分出胜负啊!
那么我们还需要一个判断和棋的函数
如果这四个条件都没一个成立那说明我们没分出胜负那就继续下!
返回一个’ '(空格) winner 的值没有改变!
代码如下
int isfull(){
int row,col;
for(row = 0;row<m_row;row++) {
for(col = 0;col<m_col;col++)
//如果棋盘有一个为空格说明未满
if(chess[row][col] == ' ')
return 0;
}
//棋盘满了输出1
return 1;
}
//返回了一个字符函数 返回棋盘的字符来确定谁是赢家
char checkwinner() {
int row,col;
//检查行是否连为一条线
for(row = 0;row<m_row;row++){
if(chess[row][0]==chess[row][1]
&&chess[row][0]==chess[row][2]) {
return chess[row][0];
}
}
//检查列是否连为一条线
for(col = 0;col<m_col;col++){
if(chess[0][col]==chess[1][col]
&&chess[0][col]==chess[2][col]){
return chess[0][col];
}
}
//检查对角线
if(chess[0][0]==chess[1][1]
&&chess[0][0]==chess[2][2]) {
return chess[0][0];
}
//检查另外一条对角线
if(chess[0][2]==chess[1][1]
&&chess[0][2]==chess[2][0]) {
return chess[0][2];
}
//除了这些还有棋盘满了,但是没有分出胜负
//所以设立一个检查棋盘满的函数
if(isfull()){
//棋盘满了返回'q'
return 'q';
}
//如果都不满足的话说明棋盘未满,且未分出胜负
return ' ';
}
在判断完成之后如果没结束那么就到电脑下棋了,同样也得进行占用问题的判断
我们用随机种子机制来让电脑随机落子(意味着我们的电脑是在乱下棋的没有算法)
void computermove(){
int row,col;
printf("电脑落子!\n");
while(1){
row = rand()%3;
col = rand()%3;
//如果被占用了重新下
if(chess[row][col]!=' ')
continue;
chess[row][col] = 'o';
printf("电脑落子完毕!\n");
break;
}
}
在game ()也就是我们的游戏主程序中走到玩家落子这里还得进行胜负的判断,检查胜负(和上面的检查函数一样)
如果我们的winner字符发生了改变那就跳出
写到这里我们的程序也就写完了,我们先分段理解各自模块该干的事情,然后穿起来来实现整个游戏函数
值得注意的是我们的winner 字符 是一个很重要的字符,他需要接受我们检查函数返回来值,如果改变了那意味着我们有
胜负的产生,所以我们必须附一个初始值来进行判定,这样说可能不理解,我们放出整个程序代码便于你来理解,如果有不懂的可以留言交流!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include <time.h>
#define m_row 3 //棋盘大小控制
#define m_col 3
char chess[m_row][m_col]; //定义棋盘数组
//菜单函数
int menu () {
int chooise;
printf("-------------------\n");
printf("-----1.开始游戏----\n");
printf("-----2.退出游戏----\n");
printf("-------------------\n");
printf("请输入你的选择:");
scanf("%d",&chooise);
return chooise;
}
//初始化棋盘,每个数组都输出为空格
void initchess() {
int row,col;
for(row = 0;row<m_row;row++) {
for(col = 0;col<m_col;col++)
chess[row][col] =' ';
}
//随机数生成,让电脑随机生成棋子
srand((unsigned int)time(NULL));
}
//输出棋盘
void outputchess() {
int row;
for(row = 0;row<m_row;row++) {
printf("| %c | %c | %c |\n",
chess[row][0],chess[row][1],chess[row][2]);
if(row!=m_row-1)
printf("|----|----|----|\n");
}
}
//玩家落子
void playermove(){
int row = 0,col = 0;
while(1) {
printf("请输入你的行和列:\n");
scanf("%d,%d",&row,&col);
//对玩家输入坐标判断
if(row<0||row>=m_row||col<0||col>=m_col) {
printf("输入的坐标不合法!重新输入!\n");
continue;
}
//如果不是一个空格那表示被占用
if(chess[row][col]!=' ') {
printf("输入的坐标被占用!重新输入!\n");
//如果不是一个空格那表示被占用结束这次循环
continue;
}
//玩家落子用'x'表示
chess[row][col] = 'x';
break;
}
printf("玩家落子完毕!\n");
}
//检查棋盘满的函数
int isfull(){
int row,col;
for(row = 0;row<m_row;row++) {
for(col = 0;col<m_col;col++)
//如果棋盘有一个为空格说明未满
if(chess[row][col] == ' ')
return 0;
}
//棋盘满了输出1
return 1;
}
//返回了一个字符函数 返回棋盘的字符来确定谁是赢家
char checkwinner() {
int row,col;
//检查行是否连为一条线
for(row = 0;row<m_row;row++){
if(chess[row][0]==chess[row][1]
&&chess[row][0]==chess[row][2]) {
return chess[row][0];
}
}
//检查列是否连为一条线
for(col = 0;col<m_col;col++){
if(chess[0][col]==chess[1][col]
&&chess[0][col]==chess[2][col]){
return chess[0][col];
}
}
//检查对角线
if(chess[0][0]==chess[1][1]
&&chess[0][0]==chess[2][2]) {
return chess[0][0];
}
//检查另外一条对角线
if(chess[0][2]==chess[1][1]
&&chess[0][2]==chess[2][0]) {
return chess[0][2];
}
//除了这些还有棋盘满了,但是没有分出胜负
//所以设立一个检查棋盘满的函数
if(isfull()){
//棋盘满了返回'q'
return 'q';
}
//如果都不满足的话说明棋盘未满,且未分出胜负
return ' ';
}
//电脑落子
void computermove(){
int row,col;
printf("电脑落子!\n");
while(1){
row = rand()%3;
col = rand()%3;
//如果被占用了重新下
if(chess[row][col]!=' ')
continue;
chess[row][col] = 'o';
printf("电脑落子完毕!\n");
break;
}
}
//'x'代表玩家
//'o'代表电脑
//'q'代表和棋
void game() {
//定义一个检查数组字符,如果改变说明有胜负产生!
char winner=' ';
initchess();
while(1) {
//输出棋盘
outputchess();
//玩家落子
playermove();
//winner接受一下检查函数返回来的值
winner = checkwinner();
//进行判断,如果不是空格跳出判断
if(winner!= ' ') {
break;
}
//电脑落子
computermove();
//winner接受一下检查函数返回来的值
winner = checkwinner();
//进行判断,如果不是空格跳出判断
if(winner!= ' ') {
break;
}
}
//跳出循环说明胜者或者和棋产生判断
outputchess();
if(winner== 'x'){
printf("玩家获胜!\n");
}
else if(winner== 'o'){
printf("电脑获胜!\n");
}
else if(winner== 'q') {
printf("和棋!\n");
}
else
printf("代码出BUG了!\n");
}
//主函数
int main() {
//定义一个选择函数来接收菜单函数的返回值
int choose;
while(1) {
choose = menu ();
//选择函数为1 开始游戏
if(choose == 1) {
game();
}
else if(choose == 2){
break;
}
else {
printf("你的输入有误,请重新输入!\n");
continue;
}
}
return 0;
}