目录
一、 摘要
二、 文件配置
三、 功能实现
1 开始游戏界面
2 游戏内容game()
2.1 初始化棋盘为空格
2.2打印棋盘
2.3 玩家下棋以及电脑下棋
2.4 判断输赢
四、游戏代码
学习了C语言的分支结构、循环结构、数组、函数后,我们将知识融会贯通来实现一个三字棋小游戏吧。
好的代码习惯从C语言就开始,以后我们到公司做项目的时候,需要维护自己的代码段,所以我们今天的代码就分别放在三个文件:test.c、game.c、game.h中。test.c源文件主要用来测试整个小游戏;game.c源文件主要用来完成小游戏各功能的实现;game.h头文件中则用来包含所有的库函数并声明game.c中的函数。这样一来,代码的可读性提高了,同时方便后期调试与维护。
我们先一步步展示各功能,最后展示整个项目:
void menu()
{printf("********************************n");printf("********* 1. play ************n");printf("********* 0. exit ************n");printf("********************************n");
}
int main()
{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;
}
我们定义了一个菜单函数,同时在主函数里开始运行,运用switch语句,输入1则进入游戏,输入0则退出游戏,输入其他数字则重新输入,同时我们想:玩一把不过瘾想要继续玩怎么办?用循环结构就好了,我们选择do-while语句先执行后判断,由input控制循环,如果选择了0那正好不符合while的条件退出循环。
#define ROW 3
#define COL 3
void game()
{char board[ROW][COL] = { 0 };//初始化棋盘Initboard(board,ROW,COL);//打印棋盘Displayboard(board,ROW,COL);
}
玩三字棋,棋盘首先是空的,而且要打印出来让玩家看到,那么我们就需要先实现初始化棋盘和打印棋盘。棋盘是3*3的,所以我们很容易想到用二维数组来定义棋盘:board[3][3]
我们用宏定义常量ROW(行)为3,定义常量COL(列)也为3,这样方便后续程序升级为五子棋等更大棋盘的游戏。
void Initboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}}
}
我们想打印一个这样的棋盘,行列间都有间隔,看起来舒服。
void Displayboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("n");//打印分割线___if (i < row){for (int j = 0; j < col; j++){printf("___");if (j < col - 1){printf("|");}}printf("n");}}
}
玩家下棋和电脑下棋的顺序可以在game函数里设置,这边分别实现两个函数玩家下棋和电脑下棋:
1)玩家下棋(*)
玩家下棋只需要在二维数组board[3][3]中设置值即可,我们让玩家输入下棋的坐标x和y分别表示第x行和第x列。
玩家下棋必须在限定的棋盘范围内下棋,三字棋的棋盘为3*3,二维数组中行和列下标是从0-2,那么为了玩家着想,玩家输入的x和y的范围是1-3,那么程序里就让board[x-1][y-1]='*' ,正确下完这步棋就退出循环,否则提示重新落子。
正确落子的两个判定:
格子里没下过棋,即board[x-1][y-1]= ' '
落子的范围在棋盘内,即1<= x,y <= ROW,COL
void Playermove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家下棋n");while (1){printf("输入坐标x y,请落子:>n");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");}}//坐标错误elseprintf("坐标错误,请重新输入n");}
}
2)电脑下棋(#)
电脑随机下棋,即电脑输入的坐标x和y是随机的,那么我们要运用到生成随机数的三个函数:
int rand(void) void srand(unsigned int seed) time_t time(time_t* timer)
#include<stdlib.h>
#include<time.h>srand((unsigned int)time(NULL));
x=rand()%ROW;
y=rand()%COL;
rand函数会在0-32787中随机生成一个值,虽然每次调用的值随机,但是每次调试程序的值是固定的,也就是第一把电脑怎么落子,后面几把电脑也怎么落子,没有做到完全随机。
rand函数每次都会调用srand函数,让srand函数为其确定随机数的起始值,而srand函数的接收类型是unsigned int类型,所以srand函数如果接收一个固定的值,比如srand(1)、srand(243)等,会让rand函数每次都生成固定的随机数,这也是为什么如果rand函数没有做到完全随机的原因。所以我们要人为地让srand函数接收不同的数,达到rand函数每次都生成随机数的目的。
这时就用到time函数,时间是时刻变化的,time函数接收time_t类型的指针(可以是空指针NULL),返回的类型time_t,而srand函数的接收类型是unsigned int,所以我们用一个强制类型转换,并设置time的接收是空指针NULL即可。
x=rand()%ROW的意思是每次电脑输入的x坐标在0 - ROW-1的范围内
y=rand()%COL的意思是每次电脑输入的y坐标在0 - COL-1的范围内
完成了随机下棋的实现,剩下的步骤和玩家下棋是一致的,只不过电脑是不需要提示越界或者会落在下过棋的地方:
void Computermove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;srand((unsigned int)time(NULL));printf("电脑下棋:>n");while (1){x = rand() % row;//x的范围在0-row-1y = rand() % col;//y的范围在0-col-1if (board[x][y] == ' ')//没下过棋的地方{board[x][y] = '#';break;}}
}
完善一下game函数:
void game()
{char board[ROW][COL] = { 0 };//打印棋盘Initboard(board,ROW,COL);//下棋Displayboard(board,ROW,COL);while (1){//玩家先下Playermove(board, ROW, COL);Displayboard(board, ROW, COL);//判断输赢,出结果就breakbreak;//电脑后下Computermove(board, ROW, COL);Displayboard(board, ROW, COL);//判断输赢,出结果就breakbreak;}//判断哪方赢
}
玩家先下或者电脑先下可以由我们人为设置,玩家下完或者电脑下完都判断一下是否出结果,出结果然后跳出循环,然后在循环外判断哪方赢,于是我们继续实现一下判断的部分。
C语言阶段我们做过的判断函数包括判断素数、判断闰年函数等,返回类型一般设为int,返回值一般为1或者0。我们可以采用同样的思路,对不同的结果返回不同的值。一把三字棋结束的条件有三种:玩家赢、电脑赢或者平局,如果没结束那就继续下棋,一共是四个判断。
我们将函数的返回类型设为char:
玩家赢,返回值设为: '*'
电脑赢,返回值设为:'#'
平局,返回值设为:'Q'
继续,返回值设为:'C'
1)三行中其中一行均是*号或者#号
for (int i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}
注:如果满足if语句,说明有一方赢了,玩家赢则返回'*',电脑赢则返回'#',那直接返回二维数组的值即可
2)三列中其中一列均是*号或者#号
for (int i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}
3)对角线均是*号或者#号
//左对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') {return board[0][0];}
//右对角线
else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0] &&
board[0][2] != ' ')){return board[0][2];}
4)平局判断棋盘是否已经下满了
int Isfull(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;//下满了
}if (Isfull(board, col, row) == 1)
{return 'Q';
}
整合成判断输赢函数:
char Iswin(char board[ROW][COL], int row, int col)
{//行赢for (int i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2]
&& board[i][0] != ' '){return board[i][0];}}//列赢for (int i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i]
&& board[0][i] != ' '){return board[0][i];}}//对角线赢if (board[0][0] == board[1][1] && board[1][1] == board[2][2]
&& board[0][0] != ' ') {return board[0][0];}else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0]
&& board[0][2] != ' ')){return board[0][2];}//平局if (Isfull(board, col, row) == 1){return 'Q';}//继续return 'C';
}
将判断输赢函数放入游戏主体函数game中:
void game()
{char board[ROW][COL] = { 0 };char ret = 0;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')//ret等于C时继续游戏break;//电脑后下Computermove(board, ROW, COL);Displayboard(board, ROW, COL);//判断输赢ret = Iswin(board, ROW, COL);if (ret != 'C')//ret等于C时继续游戏break;}if (ret == '*')printf("玩家赢了n");else if (ret == '#')printf("电脑赢了n");else if(ret == 'Q')printf("平局n");
}
test.c:
#include "game.h"
void menu()
{printf("********************************n");printf("********* 1. play ************n");printf("********* 0. exit ************n");printf("********************************n");
}
void game()
{char board[ROW][COL] = { 0 };char ret = 0;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')//ret等于C时继续游戏break;//电脑后下Computermove(board, ROW, COL);Displayboard(board, ROW, COL);//判断输赢ret = Iswin(board, ROW, COL);if (ret != 'C')//ret等于C时继续游戏break;}if (ret == '*')printf("玩家赢了n");else if (ret == '#')printf("电脑赢了n");else if(ret == 'Q')printf("平局n");
}
int main()
{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;
}
game.c:
#include "game.h"//初始化棋盘为空格
void Initboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}}
}//打印棋盘
void Displayboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("n");//打印分割线if (i < row){for (int 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");while (1){printf("输入坐标x y,请落子:>n");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");}}//坐标错误elseprintf("坐标错误,请重新输入n");}
}//电脑随机下棋
void Computermove(char board[ROW][COL], int row, int col)
{srand((unsigned int)time(NULL));int x = 0;int y = 0;printf("电脑下棋:>n");while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'
char Iswin(char board[ROW][COL], int row, int col)
{//行赢for (int i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2]
&& board[i][0] != ' '){return board[i][0];}}//列赢for (int i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i]
&& board[0][i] != ' '){return board[0][i];}}//对角线赢if (board[0][0] == board[1][1] && board[1][1] == board[2][2]
&& board[0][0] != ' ') {return board[0][0];}else if ((board[0][2] == board[1][1] && board[1][1] == board[2][0]
&& board[0][2] != ' ')){return board[0][2];}//平局if (Isfull(board, col, row) == 1){return 'Q';}//继续return 'C';
}
game.h:
#pragma once
#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);
//平局判断棋盘是否满
int Isfull(char board[ROW][COL], int row, int col);
本文发布于:2024-01-28 23:49:23,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170645696611185.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |