🚩纸上得来终觉浅, 绝知此事要躬行。
🌟主页:June-Frost
🚀专栏:C语言
🔥该篇将结合之前的知识来实现 三子棋游戏。
目录:
- 🌟思路框架:
- 测试
- 游戏
- 🌟测试部分函数实现
- 🌟游戏部分函数实现
- 🌟完整的代码:
- ❤️ 结语
🌟思路框架:
测试
通过迭代保证每次玩完游戏后可以再来一局或者退出。
游戏
博主将会对上图每一个板块进行函数实现。
🌟测试部分函数实现
- 选择是否玩游戏
该板块的循环部分将会使用do while 循环来实现(保证一开始可以选择,运行完游戏部分后还可以继续选择)。
#include"game.h"
int main()
{
int input = 0;
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);
return 0;
}
🌟游戏部分函数实现
在玩三子棋游戏中,每一步棋下完之后的状态需要保存,即需要数据的保存,所以可以创建一个3X3的数组,之后的数据操作就可以针对数组进行操作。
- 菜单
void menu()
{
printf("**************************\n");
printf("********* 1.play *********\n");
printf("********* 0.exit *********\n");
printf("**************************\n");
}
- 初始化棋盘
定义一个 3X3 数组后,我们将数组的元素都赋为 空格,这样就可以保证打印出来的效果是空的棋盘。
void BoardInit(char board[][Col], int row, int col)
{
//遍历数组将每个元素赋为 空格
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
- 打印棋盘
需要产生的效果:
实现上述的效果,只需要两步拆解:
1.
将这样的棋盘首先分为三部分,每一个部分由数据部分和分割线部分构成,分割线部分在最后一部分没有(只需要加一个限制条件即可)int i = 0; for (i = 0; i < row; i++) { //打印数据 printf("\n");//打印后换行 //打印分割线 if (i < row - 1)//保证最后一部分不打印分割线 { } printf("\n");//打印后换行 }
每个部分内部又可以划分为三部分,与第一次拆解逻辑一摸一样,注意第三部分没有 | 即可
void DisplayBoard(char board[][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)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
- 玩家下棋:
这里需要注意 检查玩家输入的坐标是否合法,以及该坐标下是否已经有棋子。而且,在写条件的时候,需要代入玩家视角,输入区间为 1 —— 3,但访问区间为 0——2 。
void PlayerMove(char board[][Col], int row, int col)
{
printf("玩家下棋:\n");
printf("请输入下棋的坐标,中间使用空格:>");
while (1)
{
int x = 0;
int y = 0;
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] = 'X';//落子
break;
}
else
{
printf("该位置已有棋子,请重新输入:>");
}
}
else
{
printf("输入非法,请重新输入:>");
}
}
}
- 电脑下棋
这里需要使用伪随机数,并且直接将范围锁定在 0——2,可以直接访问数组元素。完成该功能只需要判断 坐标下是否有棋子,若有棋子,则重新生成随机数。若要了解随机数,可以参考——随机数 。
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] = 'O';
break;
}
}
}
- 判断输赢
只需要从4种方向遍历数组,有符合获胜条件的直接返回数组元素,如果没有获胜,则需要判断是否棋盘已满(平局),除此之外就是未完成该局,继续下棋。
所以返回值 有四种情况:
电脑赢 —— 返回 ‘O’
玩家赢 —— 返回 ‘X’
平局 —— 返回 ‘P’
继续 —— 返回 ‘C’
int IsFull(char board[][Col], int row, int col)//判断是否已满,已满返回1
{
//遍历
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 IsWin(char board[][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][0] != ' ')
{
return board[i][0];
}
}
//从左至右遍历
for (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[1][1];
}
//左下至右上
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' ')
{
return board[1][1];
}
//平局
if (IsFull(board,row,col))
{
return 'P';
}
return 'C';
}
- 游戏逻辑部分
我们已经有了所有的功能函数,按照思路框架直接写出来即可。
void game()
{
char board[Row][Col] = { 0 };
BoardInit(board, Row, Col);
DisplayBoard(board, Row, Col);
//先手判断
//假设玩家先手
void(*Fir)(char board[][Col], int, int) = PlayerMove;
void(*Sec)(char board[][Col], int, int) = ComputerMove;
int flag = rand()%2; //1——玩家先手,0——电脑先手
if (flag == 0)
{
printf("电脑先手\n");
Fir = ComputerMove;
Sec = PlayerMove;
}
else
{
printf("玩家先手\n");
}
//
char ret = 0;
while (1)
{
Fir(board, Row, Col);
DisplayBoard(board, Row, Col);
ret = IsWin(board, Row, Col);
if (ret != 'C')
break;
Sec(board, Row, Col);
DisplayBoard(board, Row, Col);
ret = IsWin(board, Row, Col);
if (ret != 'C')
break;
}
if (ret == 'X')
{
printf("玩家获胜\n");
}
else if (ret == 'O')
{
printf("电脑获胜\n");
}
else
{
printf("平局\n");
}
}
首先假设玩家是先手,如果flag =1,则照旧进行,如果flag = 0,就直接交换先后手。
🌟完整的代码:
test.c :
请记得设置随机数起点srand。
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//起点
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);
return 0;
}
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Row 3
#define Col 3
//菜单
void menu();
//游戏(逻辑)
void game();
//初始化棋盘
void BoardInit(char board[][Col], int row, int col);
//打印棋盘
void DisplayBoard(char board[][Col], int row, int col);
//玩家下棋
void PlayerMove(char board[][Col], int row, int col);
//电脑下棋
void ComputerMove(char board[][Col], int row, int col);
//判断输赢
char IsWin(char board[][Col], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("**************************\n");
printf("********* 1.play *********\n");
printf("********* 0.exit *********\n");
printf("**************************\n");
}
void BoardInit(char board[][Col], int row, int col)
{
//遍历数组将每个元素赋为 空格
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(char board[][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)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
void PlayerMove(char board[][Col], int row, int col)
{
printf("玩家下棋:\n");
printf("请输入下棋的坐标,中间使用空格:>");
while (1)
{
int x = 0;
int y = 0;
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] = 'X';//落子
break;
}
else
{
printf("该位置已有棋子,请重新输入:>");
}
}
else
{
printf("输入非法,请重新输入:>");
}
}
}
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] = 'O';
break;
}
}
}
int IsFull(char board[][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 IsWin(char board[][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][0] != ' ')
{
return board[i][0];
}
}
//从左至右遍历
for (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[1][1];
}
//左下至右上
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' ')
{
return board[1][1];
}
//平局
if (IsFull(board,row,col))
{
return 'P';
}
return 'C';
}
void game()
{
char board[Row][Col] = { 0 };
BoardInit(board, Row, Col);
DisplayBoard(board, Row, Col);
//先手判断
//假设玩家先手
void(*Fir)(char board[][Col], int, int) = PlayerMove;
void(*Sec)(char board[][Col], int, int) = ComputerMove;
int flag = rand()%2; //1——玩家先手,0——电脑先手
if (flag == 0)
{
printf("电脑先手\n");
Fir = ComputerMove;
Sec = PlayerMove;
}
else
{
printf("玩家先手\n");
}
//
char ret = 0;
while (1)
{
Fir(board, Row, Col);
DisplayBoard(board, Row, Col);
ret = IsWin(board, Row, Col);
if (ret != 'C')
break;
Sec(board, Row, Col);
DisplayBoard(board, Row, Col);
ret = IsWin(board, Row, Col);
if (ret != 'C')
break;
}
if (ret == 'X')
{
printf("玩家获胜\n");
}
else if (ret == 'O')
{
printf("电脑获胜\n");
}
else
{
printf("平局\n");
}
}
❤️ 结语
文章到这里就结束了,如果对你有帮助,你的点赞将会是我的最大动力,如果大家有什么问题或者不同的见解,欢迎大家的留言~