一、内容介绍
本文内容是实现一个初阶版的三子棋游戏,玩法和正常的三子棋玩法相同,玩家和电脑轮流落子,任意一方优先三个棋子连成直线就算获胜。
二、基本流程
在实现三子棋游戏之前,我们先来看看实现这个游戏的逻辑:
1.建立一个游戏菜单。
2.创建和初始化棋盘。
3.打印棋盘。
4.玩家落子并打印棋盘(输入坐标)用 '*'表示玩家落子。
5.判断胜负(判断玩家是否获胜?获胜则直接游戏结束否则继续进行)。
6.电脑落子并打印棋盘(随机落子)用 ‘#’表示电脑落子。
7.判断胜负(电脑是否获胜?获胜则直接游戏结束否则继续进行)。
8.若和棋则回到 步骤2 继续执行。
三、实现步骤
1.菜单界面
#include<stdio.h>
menu()
{
printf("**************************************\n");
printf("*********** 三子棋游戏!**************\n");
printf("**************************************\n");
printf("*********** 1.开始游戏 ***************\n");
printf("*********** 0.退出游戏 ***************\n");
printf("**************************************\n");
}
void test()
{
int input = 0;
//此处用到了do while循环,玩家可以反复进行选择来进行下一步操作;
do {
menu();
printf("请选择>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("三子棋游戏\n");
//game();此地方为游戏实现的模块,将在后面的内容中实现,在此我们先测试一下主体的逻辑;
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
运行结果如下图:
可以看出,游戏的主体逻辑没有什么问题,接着我们实现后面的内容。
2.创建棋盘
我们在game()函数中定义一个3行3列的二维数组,用来存放棋盘中的数据,元素类型为char。因为在后面的内容中频繁的使用到了行和列这两个数据,为了提高代码的可读性以及后续对数据的修改,我们使用了宏定义。
#define ROW 3 //行
#define COL 3 //列
char board[ROW][COL] //棋盘数组
3.棋盘初始化
在下棋时,要保证棋盘最开始是空的。所以我们用空格字符来初始化棋盘。
void InitBoard(int 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] = ' ';
}
}
}
4.打印棋盘
当我们初始化棋盘之后,我们就打印出棋盘看看效果。
void DisplayBoard(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++)
{
printf("%c", board[i][j]);
}
printf("\n");
}
}
运行结果如下图:
屏幕上并没有显示棋盘,所以注意,在这里并不是没有把棋盘打印出来,而是为我们在初始化棋盘的时候是用的空格字符,每个数组元素之间也没有任何区分,所以打印出来的效果就是一片空白区域。对此我们给棋盘做一些小小的改动,让棋盘看起来更加直观。
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)
{
for (j =0; j < col; j++) //分割行的打印
{
printf("---");
if (j < col - 1) //分割线“ | ”的打印
{
printf("|");
}
}
printf("\n");
}
}
}
运行结果如下图:
这样我们的棋盘就弄好了,以上代码可以通过修改宏定义的行和列的值来实现任意数量的行和列的棋盘。例如,实现8行8列的棋盘:
#define ROW 8
#define COL 8
5.玩家落子
玩家落子时注意事项:
1.玩家落子需要在棋盘范围内。
2.玩家要在棋盘上空的地方落子。
3.如果输入的坐标不满足要重新输入。
void player_move(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 >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标被占用,请重新输入\n");
}
}
else
{
printf("输入非法,重新输入\n");
}
}
}
6.电脑落子
电脑随机落子,'#’表示电脑落子。
因为电脑是随机落子,所以我们需要产生一个随机坐标,所以我们需要一个随机值。
电脑落子注意事项:
1.要在主函数中使用srand((unsigned int)time(NULL)),将时间戳作为随机数的起点(头文件:#include <time.h>),确保得到的行列坐标是真随机。
2.在函数中使用rand()函数产生随机坐标(头文件:#include <stdlib.h>),还要确保坐标在棋盘范围内
3.要在棋盘上空的地方下棋。
void Computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成0到2的数
y = rand() % col;//生成0到2的数
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
7.判断胜负
什么情况游戏就结束了?分为以下几种:
玩家获胜—> ‘*’
电脑获胜 —> ‘#’
平局 —> ‘Q’
继续 —> ‘C’
int Is_ful(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char Is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][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];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//判断平局
if (Is_ful(board,ROW,COL)==1)
{
return 'Q';
}
return 'C';
}
四、完整代码实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
menu()
{
printf("**************************************\n");
printf("*********** 三子棋游戏!**************\n");
printf("**************************************\n");
printf("*********** 1.开始游戏 ***************\n");
printf("*********** 0.退出游戏 ***************\n");
printf("**************************************\n");
}
//初始化棋盘为全空格
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)
{
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)
{
for (j =0; j < col; j++) //分割行的打印
{
printf("---");
if (j < col - 1) //分割线“ | ”的打印
{
printf("|");
}
}
printf("\n");
}
}
}
//玩家落子
void player_move(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 >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标被占用,请重新输入\n");
}
}
else
{
printf("输入非法,重新输入\n");
}
}
}
//电脑落子
void Computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成0到2的数
y = rand() % col;//生成0到2的数
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//平局判断
int Is_ful(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断输赢
char Is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][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];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//判断平局
if (Is_ful(board,ROW,COL)==1)
{
return 'Q';
}
return 'C';
}
void game()
{
char ret = 0;
//存放棋盘数据
char board[ROW][COL] = { 0 };
//初始化棋盘为全空格
InitBoard(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{ //玩家落子
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret=Is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑落子
Computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret=Is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢!\n");
}
else if (ret == '#')
{
printf("电脑赢!\n");
}
else
{
printf("平局\n");
}
DisplayBoard(board, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int )time(NULL));
do {
menu();
printf("请选择>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//此地方为游戏实现的模块,将在后面的内容中实现,在此我们先测试一下主体的逻辑;
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
五、多文件形式
为了便于小伙伴们观看,博主将以上的内容都放在了一个源文件下进行的,然而在现实开发的过程当中,需要很多人共同完成一个项目, 所以每个人就会分配不同的模块来进行实现,于是就有多文件的这种形式,使用多文件的形式可以将整个程序拆分开来,比方说分为头文件、函数文件、主函数文件。当然如果有需要的话,还可以继续细分。
博主在这里就创建了3个文件,分别是test.c文件、game.c文件以及game.h文件
game.h是用来放各个函数的声明部分,game.c是各个函数的代码的实现,test.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 player_move(char board[ROW][COL], int row, int col);
//电脑落子
void Computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char Is_win(char board[ROW][COL], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS
#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)
//{
// int i = 0;
// int j = 0;
// for (i = 0; i < row; i++)
// {
// for (j = 0; j < col; j++)
// {
// printf("%c", board[i][j]);
// }
// printf("\n");
// }
//}
//打印棋盘
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)
{
for (j =0; j < col; j++) //分割行的打印
{
printf("---");
if (j < col - 1) //分割线“ | ”的打印
{
printf("|");
}
}
printf("\n");
}
}
}
//玩家落子
void player_move(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 >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标被占用,请重新输入\n");
}
}
else
{
printf("输入非法,重新输入\n");
}
}
}
//电脑落子
void Computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成0到2的数
y = rand() % col;//生成0到2的数
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//平局判断
int Is_ful(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断输赢
char Is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][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];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//判断平局
if (Is_ful(board,ROW,COL)==1)
{
return 'Q';
}
return 'C';
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
menu()
{
printf("**************************************\n");
printf("*********** 三子棋游戏!**************\n");
printf("**************************************\n");
printf("*********** 1.开始游戏 ***************\n");
printf("*********** 0.退出游戏 ***************\n");
printf("**************************************\n");
}
void game()
{
char ret = 0;
//存放棋盘数据
char board[ROW][COL] = { 0 };
//初始化棋盘为全空格
InitBoard(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{ //玩家落子
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret=Is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑落子
Computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret=Is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢!\n");
}
else if (ret == '#')
{
printf("电脑赢!\n");
}
else
{
printf("平局\n");
}
DisplayBoard(board, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int )time(NULL));
do {
menu();
printf("请选择>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//此地方为游戏实现的模块,将在后面的内容中实现,在此我们先测试一下主体的逻辑;
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
以上就是这篇文章的内容,如果这篇文章对你有所帮助,那就给博主点点赞吧!