前言
Hello!友友们,前边我们已经学习了C语言的基础知识,但单纯的理论和简单的代码演示是无法真正做到巩固所学的知识的,那么今天我将会带领大家,根据之前所学的知识,来写一个三子棋小游戏。
目录
前言
总体框架设计
多文件创建分装
各个功能模块化实现
棋盘初始化
棋盘打印
玩家下棋
电脑下棋
结果判断
平局
游戏逻辑的安排
总结
总体框架设计
在玩游戏时,我们在进入游戏都会有菜单选项,选择开始游戏,推出游戏等这些指令,说到选择,那么我们可以依据我们所学的循环和分支语句来先完成基本框架的设计。
首先我们进入游戏都是先显示选项,做出选择,并且在玩游戏时玩一局,还想玩怎么办(想一想我们前边的知识哪种结构符合先进入游戏出现菜单再循环这一需求)那肯定是do…while的循环结构更符合,那么我们就先使用函数来打印输出一个菜单选项
int main() {
do {
menu();//菜单
} while ();
return 0;
}
既然以及有了菜单提示,接下来就是玩家进行选择,这时就用到了我们的选择分支语句switch语句;
int main() {
int input = 0;
do {
menu();
printf("请输入:>\n");
scanf("%d", &input);
switch (input) {
case 1:
game();//游戏实现模块,后续通过函数模块化实现
break;
case 0:
printf("退出游戏:>\n");
break;
default:
printf("输入有误,请重新输入:>\n");
break;
}
} while (input);
return 0;
}
这样就使用do…while和switch语句基本实现了游戏框架的构建。那么接下来最重要的就是game()游戏模块的实现。当然也不能忘了我们的菜单提示;
void menu() {
printf("***************************\n");
printf("******* 1.play **********\n");
printf("******* 0.exit **********\n");
printf("***************************\n");
}
这里我们可以先把game()换成打印玩游戏。这里我们先测试一下程序运行是否正常,再进行下一步(对于功能复杂较多的程序我们都可以是写一点测试一点,这样更便于我们找到错误)。
多文件创建分装
当然根据之前的方法,我将程序分装到多文件,.h文件用于声明函数,test.c文件用于程序设计,game.c文件用于函数定义。
注意:函数的定义和声明是不同的(详细请看函数那期内容)
函数声明
void Initboard(board);//初始化棋盘
函数定义
void Initboard(char board[ROW][COL]) {
}
具体文件创建如下:
各个功能模块化实现
棋盘初始化
三子棋,我们需要在棋盘中输入要下的位置,相当于是一个三乘三的数组(这里我们就用到了二维数组的知识),那么游戏开始前需要我们先对棋盘初始化(使数组中的元素都为空格),那么就是数组初始化赋值(只用循环遍历每一个元素并赋予空格就ok了)。
void Initboard(char board[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
board[i][j] = ' ';
}
}
}
既然初始化已经完成,那么下棋总不能光秃秃没有棋盘,接下来就是棋盘的打印。
棋盘打印
要打印一个三乘三的棋盘不难,这里可直接打印棋盘,也可以选择使用循环的方式打印棋盘(单纯打印棋盘相对简单这里就不再演示),但是为了巩固我们所学知识,本文将会对使用循环的方式打印棋盘做讲解。
void DisPlayBoard(char board[ROW][COL]) {//ROW 和COL是为了便于修改定义的标识符常量为3
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {//为了实现 %c | %c | %c 的打印
printf(" %c ", board[i][j]);
if (j < COL - 1) {//为了不让最后一个|打印
printf("|");
}
}
printf("\n");//打印一行及时换行
if (i < ROW - 1) {//控制---|---|---打印次数为两次
for (int i = 0; i < COL; i++) {//为了打印---|---|---
printf("---");
if (i < COL - 1) {
printf("|");
}
}
}
printf("\n");// | |
} //---|---|---为一个整体循环
}
游戏开始棋盘已经打印完成,那么接下来就是玩家下棋和电脑下棋
玩家下棋
玩家下棋首先就是判断下的位置是否越界,其次就是判断所下位置是否为空,当输入不合法就要提重新输入,直到输入合法为止,这里就形成了一个循环结构。当然玩游戏的人可能不知道数组下标从0开始。根据以上几点对程序进行设计。
void PlayerMove(char board[ROW][COL]) {
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
while (1) {
printf("请输入要下的位置坐标>:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL) {
if (board[x - 1][y - 1] != ' ') {
printf("该位置已被占有,请重新选择:>\n");
}
else {
board[x - 1][y - 1] = '*';
break;
}
}
else {
printf("输入不合法,请重新输入>:\n");
}
}
}
玩家下棋之后就是电脑下棋
电脑下棋
电脑下棋目前我们所学的知识不足以实现电脑下棋智能化,但是我们可以通过生成随机数的方式,让电脑下棋。
电脑下棋就简单的多,让他生成随机数并判断所下位置是否为空,不为空就一直循环,直到落子成功。
void ComputerMove(char board[ROW][COL]) {
printf("电脑下>:\n");
while (1) { //注意引用头文件stdlib.h 和 time.h
int x = rand() % ROW;//rand与srand搭配使用来实现真正的随机这里srand加在了主函数里
int y = rand() % COL;//随机数与COL和ROW求余结果在(0~COL-1)之间
if (board[x][y] == ' ') {
board[x][y] = '#';
break;
}
}
}
结果判断
下棋肯定需要判断结果,是电脑赢还是玩家赢,或者是平局。
赢需要三个连续的位置有相同的棋子,那无非就是行,列以及对角线这几种情况。
char IsWin(char board[ROW][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];//返回连成三个的字符
}
//列赢
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];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {
return board[0][2];
}
//平局
if (IsFull(board) == 1) {
return 'p';
}
//继续
return 'c';
}
平局
最后就是判定平局,平局的规则:没有一方获胜,并且没有位置可以落子。这一步也是非常简单,只需遍历每一个数组元素,并判断是否为空就可以了。
int IsFull(char board[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (board[i][j] == ' ') {
return 0;
}
}
}
return 1;
}
以上便是游戏模块各个函数的定义与实现,接下来就是游戏逻辑安排。
游戏逻辑的安排
以上我们已实现初始化棋盘,打印棋盘,玩家下棋,电脑下棋,结果判断,接下来就要对这几个功能进行合理安排,以确保游戏运行正常。
首先我们初始化棋盘,并打印棋盘提示玩家落子,接下来是玩家落子,电脑落子,每次落子之后都需要判断输赢,并且落子是一个循环的过程。
void game() {
char board[ROW][COL];
Initboard(board);
//打印棋盘
DisPlayBoard(board);
while (1) {
PlayerMove(board);
DisPlayBoard(board);
//判断输赢
if (IsWin(board) != 'c') {
break;//判定出输赢及时跳出循环
}
ComputerMove(board);
DisPlayBoard(board);
if (IsWin(board) != 'c') {
break;
}
}
if (IsWin(board) == '*') {
printf("玩家获胜!\n");
}
else if (IsWin(board) == '#') {
printf("电脑获胜!\n");
}
else if(IsWin(board)=='p') {
printf("平局!\n");
}
}
好了我们游戏设计与安排以及完成,下面我将完整代码附在下边
头文件:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void Initboard(board);//初始化棋盘
void DisPlayBoard(board);//打印棋盘
void PlayerMove(board);//玩家下棋
void ComputerMove(board);//电脑下棋
int IsFull(board);//判断棋盘是否满
char IsWin(board);//判断输赢
函数定义文件:
#include"game.h"
void Initboard(char board[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
board[i][j] = ' ';
}
}
}
void DisPlayBoard(char board[ROW][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 - 1) {
for (int i = 0; i < COL; i++) {
printf("---");
if (i < COL - 1) {
printf("|");
}
}
}
printf("\n");
}
}
void PlayerMove(char board[ROW][COL]) {
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
while (1) {
printf("请输入要下的位置坐标>:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL) {
if (board[x - 1][y - 1] != ' ') {
printf("该位置已被占有,请重新选择:>\n");
}
else {
board[x - 1][y - 1] = '*';
break;
}
}
else {
printf("输入不合法,请重新输入>:\n");
}
}
}
void ComputerMove(char board[ROW][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]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (board[i][j] == ' ') {
return 0;
}
}
}
return 1;
}
char IsWin(char board[ROW][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];
}
//列赢
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];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {
return board[0][2];
}
//平局
if (IsFull(board) == 1) {
return 'p';
}
//继续
return 'c';
}
游戏框架:
#include"game.h"
void menu() {
printf("***************************\n");
printf("******* 1.play **********\n");
printf("******* 0.exit **********\n");
printf("***************************\n");
}
void game() {
char board[ROW][COL];
Initboard(board);
//打印棋盘
DisPlayBoard(board);
while (1) {
PlayerMove(board);
DisPlayBoard(board);
//判断输赢
if (IsWin(board) != 'c') {
break;
}
ComputerMove(board);
DisPlayBoard(board);
if (IsWin(board) != 'c') {
break;
}
}
if (IsWin(board) == '*') {
printf("玩家获胜!\n");
}
else if (IsWin(board) == '#') {
printf("电脑获胜!\n");
}
else if(IsWin(board)=='p') {
printf("平局!\n");
}
}
int main() {
int input = 0;
srand((unsigned int)time(NULL));
do {
menu();
printf("请输入:>\n");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏:>\n");
break;
default:
printf("输入有误,请重新输入:>\n");
break;
}
} while (input);
return 0;
}
总结
以上就是今天要讲的内容,本文使用我们所学的C语言知识对小游戏——三子棋的实现,希望能够更好巩固前边所学的知识。好的本期内容到此结束,感谢阅读!