前言
用写小游戏的方式,可以更快,更高效且有趣地学习C语言!!!
一、游戏的设计思路
1.游戏模式
2.设计模块
二、分层说明
1.game.h文件
1.1 在此文件中,我们对其它需要在此游戏中实现的功能所对应的函数库进行了包含
//头文件包含 #include<stdio.h> #include<stdlib.h> #include<time.h>
这样做的好处在于,当我们需要同时使用stdio.h、stdlib.h和time.h时,不用再到每个文件中进行文件包含,我们只需写一句#include"game.h"就行,如在test.c文件中进行文件包含。
1.2 进行符号定义
为什么需要符号定义呢?这是因为我们这里的符号ROW,COL对应了二维字符数组的大小,如果当我们想改变该字符数组的大小时,只需在改动game.h文件中的ROW和COL的值,就可以改变在此游戏中,所对应的字符数组大小,不用再一个一个数字去修改。
//符号定义 #define ROW 3 #define COL 3
1.3 函数声明
在game.h文件中进行函数声明后,在其他.c文件中想用调用在game.h声明过的函数,只需要将game.h进行一个文件包含就行了。如:#include"game.h"
//函数声明 //初始化二维字符数组 void InitBoard(char[][COL], int, int); //展示棋盘 void DisplayBoard(char[][COL], int, int); //玩家下棋 void PlayerMove(char[][COL], int, int); //电脑下棋 void ComputerMove(char[][COL], int, int); //判断输赢 char IsWin(char[][COL], int, int);
2.game.c文件
在此文件中,主要是编辑了一些关于棋局实现,玩家下棋,电脑下棋,棋局展示代码等等。
2.1 对二维字符数组进行初始化
void InitBoard(char board[ROW][COL], int row, int col) { int i, j; for (i = 0;i < row;i++) { for (j = 0;j < col;j++) { board[i][j] = ' '; } } }
2.2 展示棋盘
void DisplayBoard(char board[][COL], int row, int col) { int i, j; 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"); } } }
2.3 玩家下棋
void PlayerMove(char board[][COL], int row, int col) { //定义一个坐标x,y int x = 0, 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"); } } }
2.4 电脑下棋
void ComputerMove(char board[][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; } } }
这其中的rand()%row,rand()%col,体现了电脑下棋的随机性,在这里我没有设计“让电脑看起来聪明点”的算法,我们初学者先能让电脑走起来就行了。
2.5 判断棋局是否为满
int IsFull(char board[][COL], int row, int col) { int i, j; for (i = 0;i < row;i++) { for (j = 0;j < col;j++) { if (board[i][j] == ' ') return 0; } } return 1; }
2.6 判断是否赢了
char IsWin(char board[][COL], int row, int col) { int i; //横向三个连一起为赢 for (i = 0; i < row; i++) { // board[i][1] != ' ' :如果三格都是空的,那也是不行的 if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ') { //电脑赢返回# //玩家赢返回* return board[i][0]; } } //竖向三个连一起为赢 for (i = 0;i < col; i++) { if (board[0][i] == board[1][i] && board[2][i] == board[1][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]; } else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') { return board[1][1]; } //判断平局 //判断棋局是否为满(1为满,0为非满) if (IsFull(board, row, col) == 1) { return 'Q'; } return 'C'; }
3.test.c文件
3.1 main函数
游戏的主要流程步骤,在main函数中体现出来,在main函数中,不断的调用其他函数从而来实现游戏功能。在test.c文件中,还主要编辑了菜单函数menu和游戏函数game
3.2 menu函数
void menu() { printf("*************************\n"); printf("*****开始游戏输入:1*****\n"); printf("*****结束游戏输入:0*****\n"); printf("*************************\n"); }
3.3 game函数
void game() { //对棋局进行初始化——用二维数组 char board[ROW][COL]; //对棋局进行初始化 InitBoard(board, ROW, COL); //展示棋局,本质是打印二维数组的内容 DisplayBoard(board, ROW, COL); //ret判断谁赢的变量 char ret = 0; //玩家和电脑下棋 while (1) { //玩家下棋 PlayerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); /* ret的值为Q:平局 —— 游戏结束 ret的值为*:玩家赢 —— 游戏结束 ret的值为#:电脑赢 —— 游戏结束 ret的值为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"); } else if(ret == '#') { printf("电脑胜利!\n"); } else { printf("平局!\n"); } }
我们在game函数中,还调用了game.c文件中的函数,从而丰富了我们的游戏功能。这种分模块设计思想,也是以后在工作中设计一个项目的一个中心思想。
三、完整代码展示
1.test.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void menu() { printf("*************************\n"); printf("*****开始游戏输入:1*****\n"); printf("*****结束游戏输入:0*****\n"); printf("*************************\n"); } void game() { //对棋局进行初始化——用二维数组 char board[ROW][COL]; //对棋局进行初始化 InitBoard(board, ROW, COL); //展示棋局,本质是打印二维数组的内容 DisplayBoard(board, ROW, COL); //ret判断谁赢的变量 char ret = 0; //玩家和电脑下棋 while (1) { //玩家下棋 PlayerMove(board, ROW, COL); DisplayBoard(board, ROW, COL); /* ret的值为Q:平局 —— 游戏结束 ret的值为*:玩家赢 —— 游戏结束 ret的值为#:电脑赢 —— 游戏结束 ret的值为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"); } else if(ret == '#') { printf("电脑胜利!\n"); } else { printf("平局!\n"); } } int main() { //input 用来接受用户的开始游戏的指令 int input; srand((unsigned int)time(NULL)); do{ menu(); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("游戏结束\n"); break; default: printf("输入的数据有误,请重新输入!\n"); } //input为0是跳出循环,游戏结束;input为1或者非零数时,游戏继续 } while (input); return 0; }
2.game.h文件
#define _CRT_SECURE_NO_WARNINGS 1 //头文件包含 #include<stdio.h> #include<stdlib.h> #include<time.h> //符号定义 #define ROW 3 #define COL 3 //函数声明 //初始化二维字符数组 void InitBoard(char[][COL], int, int); //展示棋盘 void DisplayBoard(char[][COL], int, int); //玩家下棋 void PlayerMove(char[][COL], int, int); //电脑下棋 void ComputerMove(char[][COL], int, int); //判断输赢 char IsWin(char[][COL], int, int);
3.game.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" //对二维字符数组进行初始化 void InitBoard(char board[ROW][COL], int row, int col) { int i, j; for (i = 0;i < row;i++) { for (j = 0;j < col;j++) { board[i][j] = ' '; } } } //展示棋盘 void DisplayBoard(char board[][COL], int row, int col) { int i, j; 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[][COL], int row, int col) { //定义一个坐标x,y int x = 0, 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"); } } } //电脑下棋 void ComputerMove(char board[][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[][COL], int row, int col) { int i, j; for (i = 0;i < row;i++) { for (j = 0;j < col;j++) { if (board[i][j] == ' ') return 0; } } return 1; } //判断是否赢了 char IsWin(char board[][COL], int row, int col) { int i; //横向三个连一起为赢 for (i = 0; i < row; i++) { // board[i][1] != ' ' :如果三格都是空的,那也是不行的 if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ') { //电脑赢返回# //玩家赢返回* return board[i][0]; } } //竖向三个连一起为赢 for (i = 0;i < col; i++) { if (board[0][i] == board[1][i] && board[2][i] == board[1][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]; } else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') { return board[1][1]; } //判断平局 //判断棋局是否为满(1为满,0为非满) if (IsFull(board, row, col) == 1) { return 'Q'; } return 'C'; }
四、游戏效果图
哈哈哈,看到这里不容易哇!第一次写这种游戏代码思路,不足之处,请多多指教。
大家觉得有趣,就点一波关注呗,以后还会继续更新好玩的内容!