大家好呀!👋这个是付青云同学的博客,是一名大一在校生哦!😁😁
目前一直在学习C语言。🐸
写博客是为了来记录我的学习过程,同时也希望通过博客能够帮助到需要帮助的人。
如果我的博客可以帮助到你,不妨给我一个关注哦😁
首先看动图演示
三子棋
这里使用的编译环境是VS2022
导语
小时候我们应该都玩过三子棋这个游戏吧,记得那时候,我经常会去河边找几颗小石子,然后带到学校操场画一个三子棋盘,跟几个同学玩三子棋游戏,玩得还不亦乐乎😁。
但规则其实很简单:
在一个
9
∗
9
9*9
9∗9的棋盘里,每人放一个子,当己方或对方的棋子横向、竖向或斜向连成一条线时,该玩家获胜。
而现在,我们在手机上就可以玩到这个游戏,因此学了几个月的C语言的我突发奇想:是不是也可以用C语言来实现这个游戏呢?答案是:当然能。
那现在我们就一起开始吧!😉
思路
玩三子棋,我们首先是要有棋子和棋盘的对吧,那如何制作呢?
- 先定义一个二维数组。我们将坐标输入这个二维数组中:将玩家棋子定为*,将电脑棋子定为#。
- 有了棋子之后,我们就要将棋盘制作(初始化)出来。
- 在玩家或电脑下完棋后要将下完的棋盘打印出来
有了棋子和棋盘之后,就可以正常下棋了,但是棋不可能就这样一直下下去对吧。
有这样几个游戏状态:玩家获胜/电脑获胜/平局/继续游戏。
所以我们就需要编写一个函数来判断游戏状态
思路有了,但是实现这个思路有这几个困难:
- 如何初始化棋盘
- 玩家如何下棋
- 电脑如何下棋(电脑简单和困难模式)
- 如何打印下好的棋盘
- 如何判断游戏状态
那,现在我们就来解决这些问题吧!
代码实现
制作一个菜单
自定义一个菜单函数,可以选择游戏模式
void menu()//菜单函数
{
printf("************************************\n");
printf("******** 1、开始(简单) *********\n");
printf("******** 2、开始(困难) *********\n");
printf("******** 0、结束 *********\n");
printf("***********************************\n");
}
int main()
{
//三子棋项目
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)//使用switch我们可以更加灵活的选择
{
case 1://简单模式
{
break;
}
case 2://困难模式
{
break;
}
case 0:
{
printf("结束\n");
break;
}
default:
{
printf("输入错误,重新输入\n");
break;
}
}
} while (input);
return 0;
}
}
定义棋盘大小
我们一般利用#define定义符号来方便修改参数
#define ROW 3
#define COL 3
初始化棋盘
定义一个二维数组,将数组中的元素设为空格
void IBoard(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] = ' ';
}
}
}
char board[ROW][COL] = { 0 };
IBoard(board, ROW, COL);
打印棋盘
我们打印出来的棋盘应该是这样的:
我们可以将这个棋盘拆分开来看:
分两行打印,一行打印空格+数组元素+|,另一行打印—|—|—
但是这样的话就只能打印3行3列了,显得不够通用
所以我们可以先打印空格+数组元素+空格,再打印|,换行打印—,再打印|
以下为代码:
void CBoard(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]);
if (j < col - 1)//两边没有|
{
printf("|");
}
}
if (i < row - 1)
{
printf("\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)//两边没有|
{
printf("|");
}
}
}
printf("\n");
}
}
电脑输入
简单电脑的输入
要实现电脑的输入,我们可以利用一个函数rand函数,这个函数的作用是输出一个随机数,但是这个函数输出的随机数是一个假随机数,详情可以看rand函数
因此我们需要再使用srand函数来使rand函数输出一个真随机数
如下:
void CmperEasy(char board[ROW][COL], int row, int col)
{
printf("电脑输入\n");
while (1)
{
//生成随机坐标
int x = rand() % row;//生成0 ~ row-1之间的随机数
int y = rand() % col;
if (board[x][y] ==' ')
{
board[x][y] = '#';
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));//时间戳
CmperEasy(board,row, col);
return 0;
}
困难电脑的输入
在这里,我的方法是将所有可能获胜的下法全部穷举出来,然后再堵的,如果有更好的方法希望可以告诉我,代码如下:
void CmperHard(char board[ROW][COL], int row, int col)
{
printf("电脑输入\n");
//判断第一行
if ((board[0][0] == ' ' && board[0][1] == '*' && board[0][2] == '*') || (board[0][0] == ' ' && board[0][1] == '#' && board[0][2] == '#'))
{
board[0][0] = '#';
}
else if ((board[0][0] == '*' && board[0][1] == ' ' && board[0][2] == '*') || (board[0][0] == '#' && board[0][1] == ' ' && board[0][2] == '#'))
{
board[0][1] = '#';
}
else if ((board[0][0] == '*' && board[0][1] == '*' && board[0][2] == ' ') || (board[0][0] == '#' && board[0][1] == '#' && board[0][2] == ' '))
{
board[0][2] = '#';
}
//判断第二行
else if ((board[1][0] == ' ' && board[1][1] == '*' && board[1][2] == '*') || (board[1][0] == ' ' && board[1][1] == '#' && board[1][2] == '#'))
{
board[1][0] = '#';
}
else if ((board[1][0] == '*' && board[1][1] == ' ' && board[1][2] == '*') || (board[1][0] == '#' && board[1][1] == ' ' && board[1][2] == '#'))
{
board[1][1] = '#';
}
else if ((board[1][0] == '*' && board[1][1] == '*' && board[1][2] == ' ') || (board[1][0] == '#' && board[1][1] == '#' && board[1][2] == ' '))
{
board[1][2] = '#';
}
//判断第三行
else if (board[2][0] == ' ' && board[2][1] == '*' && board[2][2] == '*' || board[2][0] == ' ' && board[2][1] == '#' && board[2][2] == '#')
{
board[2][0] = '#';
}
else if (board[2][0] == '*' && board[2][1] == ' ' && board[2][2] == '*' || board[2][0] == '#' && board[2][1] == ' ' && board[2][2] == '#')
{
board[2][1] = '#';
}
else if (board[2][0] == '*' && board[2][1] == '*' && board[2][2] == ' ' || board[2][0] == '#' && board[2][1] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断第一列
else if (board[0][0] == ' ' && board[1][0] == '*' && board[2][0] == '*' || board[0][0] == ' ' && board[1][0] == '#' && board[2][0] == '#')
{
board[0][0] = '#';
}
else if (board[0][0] == '*' && board[1][0] == ' ' && board[2][0] == '*' || board[0][0] == '#' && board[1][0] == ' ' && board[2][0] == '#')
{
board[1][0] = '#';
}
else if (board[0][0] == '*' && board[1][0] == '*' && board[2][0] == ' ' || board[0][0] == '#' && board[1][0] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
}
//判断第二列
else if (board[0][1] == ' ' && board[1][1] == '*' && board[2][1] == '*' || board[0][1] == ' ' && board[1][1] == '#' && board[2][1] == '#')
{
board[0][1] = '#';
}
else if (board[0][1] == '*' && board[1][1] == ' ' && board[2][1] == '*' || board[0][1] == '#' && board[1][1] == ' ' && board[2][1] == '#')
{
board[1][1] = '#';
}
else if (board[0][1] == '*' && board[1][1] == '*' && board[2][1] == ' ' || board[0][1] == '#' && board[1][1] == '#' && board[2][1] == ' ')
{
board[2][1] = '#';
}
//判断第三列
else if (board[0][2] == ' ' && board[1][2] == '*' && board[2][2] == '*' || board[0][2] == ' ' && board[1][2] == '#' && board[2][2] == '#')
{
board[0][2] = '#';
}
else if (board[0][2] == '*' && board[1][2] == ' ' && board[2][2] == '*' || board[0][2] == '#' && board[1][2] == ' ' && board[2][2] == '#')
{
board[1][2] = '#';
}
else if (board[0][2] == '*' && board[1][2] == '*' && board[2][2] == ' ' || board[0][2] == '#' && board[1][2] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断左对角线
else if (board[0][0] == ' ' && board[1][1] == '*' && board[2][2] == '*' || board[0][0] == ' ' && board[1][1] == '#' && board[2][2] == '#')
{
board[0][0] = '#';
}
else if (board[0][0] == '*' && board[1][1] == ' ' && board[2][2] == '*' || board[0][0] == '#' && board[1][1] == ' ' && board[2][2] == '#')
{
board[1][1] = '#';
}
else if (board[0][0] == '*' && board[1][1] == '*' && board[2][2] == ' ' || board[0][0] == '#' && board[1][1] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断右对角线
else if (board[0][2] == ' ' && board[1][1] == '*' && board[2][0] == '*' || board[0][2] == ' ' && board[1][1] == '#' && board[2][0] == '#')
{
board[0][2] = '#';
}
else if (board[0][2] == '*' && board[1][1] == ' ' && board[2][0] == '*' || board[0][2] == '#' && board[1][1] == ' ' && board[2][0] == '#')
{
board[1][1] = '#';
}
else if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == ' ' || board[0][2] == '#' && board[1][1] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
}
else if (board[1][1] != '*' && board[1][1] != '#')
{
board[1][1] = '#';
}
else
{
CmperEasy(board, ROW, COL);
}
}
判断游戏状态
我们可以自定义一个函数,玩家玩家胜利输出*号,电脑胜利输出#号,平局输出“P”,游戏继续输出“J”。
在这里,我们设置玩家和电脑胜利输出的都是他们输入的数,可以让代码更加通用,而不必要再写一个函数来额外判断玩家或者电脑的的游戏状态了。
代码如下:
char Winer(char board[ROW][COL], int row, int col)
{
int i = 0;
int ret = 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][0];
}
}
//判断列
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];
}
ret = IsFull(board, row, col);
if (ret == 1)
{
return 'P';
}
return 'J';
}
另外,我们还需要写一个判断棋盘是否满了(平局)的函数
代码如下:
int IsFull(char broad[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (broad[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
更多的细节(所有代码)
写到这里,我们的三子棋代码就写得差不多了。
补一点细节,将所有的代码整理一下。
所有代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>//rand函数srand函数所需标头
#include <windows.h>//system函数所需标头
#define ROW 3
#define COL 3
void menu()//菜单
{
printf("************************************\n");
printf("******** 1、开始(简单) *********\n");
printf("******** 2、开始(困难) *********\n");
printf("******** 0、结束 *********\n");
printf("***********************************\n");
}
void IBoard(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 CBoard(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]);
if (j < col - 1)
{
printf("|");
}
}
if (i < row - 1)
{
printf("\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
void PlayerBoard(char board[ROW][COL], int row, int col)//玩家下棋
{
int x = 0;
int y = 0;
while (1)
{
printf("输入坐标:>");
scanf("%d %d", &x, &y);
if (x <= row && x > 0 && y <= col && y > 0)
{
if (board[x - 1][y - 1] == ' ')//x和y都减1是为了方便输入
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,重新输入\n");
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
}
void CmperEasy(char board[ROW][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;
}
}
}
void CmperHard(char board[ROW][COL], int row, int col)//困难电脑
{
printf("电脑输入\n");
//判断第一行
if ((board[0][0] == ' ' && board[0][1] == '*' && board[0][2] == '*') || (board[0][0] == ' ' && board[0][1] == '#' && board[0][2] == '#'))
{
board[0][0] = '#';
}
else if ((board[0][0] == '*' && board[0][1] == ' ' && board[0][2] == '*') || (board[0][0] == '#' && board[0][1] == ' ' && board[0][2] == '#'))
{
board[0][1] = '#';
}
else if ((board[0][0] == '*' && board[0][1] == '*' && board[0][2] == ' ') || (board[0][0] == '#' && board[0][1] == '#' && board[0][2] == ' '))
{
board[0][2] = '#';
}
//判断第二行
else if ((board[1][0] == ' ' && board[1][1] == '*' && board[1][2] == '*') || (board[1][0] == ' ' && board[1][1] == '#' && board[1][2] == '#'))
{
board[1][0] = '#';
}
else if ((board[1][0] == '*' && board[1][1] == ' ' && board[1][2] == '*') || (board[1][0] == '#' && board[1][1] == ' ' && board[1][2] == '#'))
{
board[1][1] = '#';
}
else if ((board[1][0] == '*' && board[1][1] == '*' && board[1][2] == ' ') || (board[1][0] == '#' && board[1][1] == '#' && board[1][2] == ' '))
{
board[1][2] = '#';
}
//判断第三行
else if (board[2][0] == ' ' && board[2][1] == '*' && board[2][2] == '*' || board[2][0] == ' ' && board[2][1] == '#' && board[2][2] == '#')
{
board[2][0] = '#';
}
else if (board[2][0] == '*' && board[2][1] == ' ' && board[2][2] == '*' || board[2][0] == '#' && board[2][1] == ' ' && board[2][2] == '#')
{
board[2][1] = '#';
}
else if (board[2][0] == '*' && board[2][1] == '*' && board[2][2] == ' ' || board[2][0] == '#' && board[2][1] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断第一列
else if (board[0][0] == ' ' && board[1][0] == '*' && board[2][0] == '*' || board[0][0] == ' ' && board[1][0] == '#' && board[2][0] == '#')
{
board[0][0] = '#';
}
else if (board[0][0] == '*' && board[1][0] == ' ' && board[2][0] == '*' || board[0][0] == '#' && board[1][0] == ' ' && board[2][0] == '#')
{
board[1][0] = '#';
}
else if (board[0][0] == '*' && board[1][0] == '*' && board[2][0] == ' ' || board[0][0] == '#' && board[1][0] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
}
//判断第二列
else if (board[0][1] == ' ' && board[1][1] == '*' && board[2][1] == '*' || board[0][1] == ' ' && board[1][1] == '#' && board[2][1] == '#')
{
board[0][1] = '#';
}
else if (board[0][1] == '*' && board[1][1] == ' ' && board[2][1] == '*' || board[0][1] == '#' && board[1][1] == ' ' && board[2][1] == '#')
{
board[1][1] = '#';
}
else if (board[0][1] == '*' && board[1][1] == '*' && board[2][1] == ' ' || board[0][1] == '#' && board[1][1] == '#' && board[2][1] == ' ')
{
board[2][1] = '#';
}
//判断第三列
else if (board[0][2] == ' ' && board[1][2] == '*' && board[2][2] == '*' || board[0][2] == ' ' && board[1][2] == '#' && board[2][2] == '#')
{
board[0][2] = '#';
}
else if (board[0][2] == '*' && board[1][2] == ' ' && board[2][2] == '*' || board[0][2] == '#' && board[1][2] == ' ' && board[2][2] == '#')
{
board[1][2] = '#';
}
else if (board[0][2] == '*' && board[1][2] == '*' && board[2][2] == ' ' || board[0][2] == '#' && board[1][2] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断左对角线
else if (board[0][0] == ' ' && board[1][1] == '*' && board[2][2] == '*' || board[0][0] == ' ' && board[1][1] == '#' && board[2][2] == '#')
{
board[0][0] = '#';
}
else if (board[0][0] == '*' && board[1][1] == ' ' && board[2][2] == '*' || board[0][0] == '#' && board[1][1] == ' ' && board[2][2] == '#')
{
board[1][1] = '#';
}
else if (board[0][0] == '*' && board[1][1] == '*' && board[2][2] == ' ' || board[0][0] == '#' && board[1][1] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
}
//判断右对角线
else if (board[0][2] == ' ' && board[1][1] == '*' && board[2][0] == '*' || board[0][2] == ' ' && board[1][1] == '#' && board[2][0] == '#')
{
board[0][2] = '#';
}
else if (board[0][2] == '*' && board[1][1] == ' ' && board[2][0] == '*' || board[0][2] == '#' && board[1][1] == ' ' && board[2][0] == '#')
{
board[1][1] = '#';
}
else if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == ' ' || board[0][2] == '#' && board[1][1] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
}
else if (board[1][1] != '*' && board[1][1] != '#')
{
board[1][1] = '#';
}
else
{
CmperEasy(board, ROW, COL);
}
}
int IsFull(char broad[ROW][COL], int row, int col)//判断棋盘是否满了
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (broad[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char Winer(char board[ROW][COL], int row, int col)//判断游戏状态
{
int i = 0;
int ret = 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][0];
}
}
//判断列
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];
}
ret = IsFull(board, row, col);
if (ret == 1)
{
return 'P';
}
return 'J';
}
void game(int n)
{
char t = 0;
//初始化棋盘
char board[ROW][COL] = { 0 };
IBoard(board, ROW, COL);
//打印棋盘
CBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerBoard(board, ROW, COL);
CBoard(board, ROW, COL);
system("cls");//清屏
//判断玩家胜利
t = Winer(board, ROW, COL);
if (t != 'J')
{
break;
}
//电脑下棋
switch (n)
{
case 1:
{
CmperEasy(board, ROW, COL);
CBoard(board, ROW, COL);
break;
}
case 2:
{
CmperHard(board, ROW, COL);
CBoard(board, ROW, COL);
break;
}
}
//判断电脑胜利
t = Winer(board, ROW, COL);
if (t != 'J')
{
break;
}
}
//判断其他状态
if (t == '*')
{
CBoard(board, ROW, COL);
printf("游戏结束,玩家胜利^_^\n");
}
else if (t == '#')
{
CBoard(board, ROW, COL);
printf("游戏结束,电脑胜利~_~\n");
}
else
{
CBoard(board, ROW, COL);
printf("游戏结束,平局\n");
}
printf("再来一局\n");
}
int main()//主函数
{
//三子棋项目
srand((unsigned int)time(NULL));//时间戳
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");//清屏,更加美观
switch (input)
{
case 1:
{
game(input);
break;
}
case 2:
{
game(input);
break;
}
case 0:
{
printf("结束\n");
break;
}
default:
{
printf("输入错误,重新输入\n");
break;
}
}
} while (input);
return 0;
}
结语
到这里,三子棋小游戏的代码就写完了,若代码中有不足之处,望大佬指正😁。
最后,花了一个下午写的博客,要个三连不过分吧😁。