当前位置:网站首页>C语言实现五子棋游戏
C语言实现五子棋游戏
2022-07-27 21:16:00 【7昂7.】
五子棋的实现
一、实现的目的和意义
1、巩固和加深对c语言知识的理解
2、学会使用编译器的各种调试
3、提高解决实际问题的能力
二、实现内容描述
实现简单的人人对战五子棋,此设计用的是C语言去实现
三、实现原理
采用二位数组保存棋盘信息,棋盘上面的任何一个位置,里头
可以放三个信息:
1、空
2、用户1的落子
3、用户2的落子
下棋就是在二维数组种找对应的空位置,进行落子,落完之后立
即就要判断落子位置是否有五字连珠,从而判断谁数输谁赢。每
走一次棋会有四种情况:
*用户1赢
*用户2赢
*平局(这里说的平局是棋盘被占满的情况)
*没有出结果 意思就是时此用户没赢 下个用继续去下棋
四、实现模块五子棋实现分为三大模块
文件名 作用
five_chress.h 五子棋的函数声明,头文件声明等
five_chress.c 五子棋函数接口的实现
main.c 五子棋函数测试功能
五、模块代码分析
1、five_chress.h
#pragma once
#include <stdio.h>
#include <string.h>
#include<Windows.h>
#define ROW 10//数组号行号 按需求调整
#define COL 10//数组列数 按需求调整
#define PLAYER1 1//玩家编号,默认棋盘数据是0,玩家1落子,该位置被改成1
#define PLAYER2 2//玩家编号,默认棋盘数据是0,玩家2落子,该位置被改成2
#define NEXT 0//游戏继续
#define PLAYER1_WIN 1//玩家1赢
#define PLAYER2_WIN 2//玩家2赢
#define DRAW 3//平局
enum Dir{
LEFT,
RIGHT,
UP,
DOWN,
LEFT_UP,
LEFT_DOWN,
RIGHT_UP,
RIGHT_DOWN
};//用枚举去表示4个方向,上下,左右,左上右下,右上左下,统计用户当前棋子四个方向的棋数是否为大于等于5
void Menu();//实现菜单
void Game();//构建游戏入口Game()函数
2、five_chress.c
```c
在这里插入代码片#include "five_chress.h"
int x = 0;
int y = 0;
void Menu()
{
printf("############################\n");
printf("## 1. Play 0. Exit ##\n");
printf("############################\n");
printf("Please Select# ");
}
//按照x,y作为起点,按照特定的方向,求连续相对的最大格式
int ChessCount(int board[][COL], int row, int col, enum Dir d)
{
int _x = x - 1; //从1
int _y = y - 1; //从1
int count = 0;
while (1){
switch (d){
case LEFT://从当前位置向左移动统计 横坐标不变 纵坐标变了 所以是y--
_y--;
break;
case RIGHT://从当前位置向右移动统计 横坐标不变 纵坐标变了 所以是_y++
_y++;
break;
case UP://从当前位置向上移动统计 纵坐标不变 横坐标变了 所以是_x--
_x--;
break;
case DOWN://从当前位置向下移动统计 纵坐标不变 横坐标变了 所以是_x++
_x++;
break;
case LEFT_UP://从当前位置向左上移动统计 纵,横变都变了 所以是_x--,_y--
_x--, _y--;
break;
case LEFT_DOWN://从当前位置左下移动统计 纵,横坐标都变了 所以是_x++,_y--
_x++, _y--;
break;
case RIGHT_UP://从当前位置右上移动统计 纵,横坐标都变了 所以是_x--,_y++-
_x--, _y++;
break;
case RIGHT_DOWN://从当前位置右下移动统计 纵,横坐标都变了 所以是_x++,_y++
_x++, _y++;
break;
default:
//Do Nothing
break;
}
if (_x < 0 || _x > row - 1 || _y < 0 || _y > col - 1){
break;/表示越界了就停止
}
//合法
if (board[x - 1][y - 1] == board[_x][_y]){
count++;//统计从旧位置出发统计和他一样的个数
}
else{
break;//如果碰到不一样的就终止循环
}
}
return count;//返回统计个数
}
//4种情况
//NEXT:表明要继续
//PLAYER1_WIN: 用户1赢了
//PLAYER2_WIN:用户2赢了
//DRAW: 平局
int IsOver(int board[][COL], int row, int col)
{
int count1 = ChessCount(board, row, col, LEFT) + ChessCount(board, row, col, RIGHT) + 1; //?
int count2 = ChessCount(board, row, col, UP) + ChessCount(board, row, col, DOWN) + 1; //?
int count3 = ChessCount(board, row, col, LEFT_UP) + ChessCount(board, row, col, RIGHT_DOWN) + 1; //?
int count4 = ChessCount(board, row, col, LEFT_DOWN) + ChessCount(board, row, col, RIGHT_UP) + 1; //?
if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5){
//有五子连珠
//一定有人赢
//x, y
if (board[x - 1][y - 1] == PLAYER1){
return PLAYER1_WIN;
}
else{
return PLAYER2_WIN;
}
}
int i = 0;
for (; i < row; i++){
int j = 0;
for (; j < col; j++){
if (board[i][j] == 0){
return NEXT;//当前位置还没有被填写棋盘不满 当前用户没有赢返回next 让下个用户继续下
}
}
}
return DRAW;//最后一种情况棋盘满了 为平局
}
void ShowBoard(int board[][COL], int row, int col)
{
//printf("\e[1;1H\e[2J");这是linux环境下用的清屏
//讲数组内容,进行可视化
system("cls");//vs环境下用的清屏
int i = 0;
for (i=1; i <= col; i++){
printf("%3d", i);
}
printf("\n");
for (i = 0; i < row; i++){
int j = 0;
printf("%2d",i + 1 );
for (; j < col; j++){
if (board[i][j] == 0){
printf(" . ");
}
else if (board[i][j] == PLAYER1){
printf(" x ");
}
else{
printf (" y ");
}
}
printf("\n");
}
}
void PlayerMove(int board[][COL], int row, int col, int who)
{
while (1){
printf("Player[%d] Please Enter Your Pos# ", who);
scanf("%d %d", &x, &y);
if (x < 1 || x > row || y < 1 || y > col){
printf("Pos Is Not Right!\n");
continue;
}
else if (board[x - 1][y - 1] != 0){
printf("Pos Is Occupied!\n");
continue;
}
else{
//合法性,去重
board[x - 1][y - 1] = who;
break;
}
}
}
void Game()
{
int board[ROW][COL];
memset(board, 0, sizeof(board));
int result = NEXT;
do{
ShowBoard(board, ROW, COL);//显示棋盘
PlayerMove(board, ROW, COL, PLAYER1);//Player1先走
result = IsOver(board, ROW, COL);//判断游戏是否结束
if (NEXT != result){
break;//如果返回值不等于NEXT就跳出循环 说明当前用户赢了或者平局 如果=NEXT 下个用户继续下
}
ShowBoard(board, ROW, COL);//同上
PlayerMove(board, ROW, COL, PLAYER2);
result = IsOver(board, ROW, COL);
if (NEXT != result){
break;
}
} while (1);
//p1 win, p2 win, draw
switch (result){
case PLAYER1_WIN:
ShowBoard(board, ROW, COL);
printf("恭喜用户1,你已经赢了!\n");
break;
case PLAYER2_WIN:
printf("恭喜用户2,你已经赢了!\n");
break;
case DRAW:
printf("平局\n");
break;
default:
//do nothing!
break;
}
}
分析:
我们要先构建游戏入口void game()函数在里面构建上层本
调用框架 例如一开始初始化数组把每个位置都置为0,然后
构建调用框架:
1、我们要保存二位数组并可视化 就要构建ShowBoard函数;
2、之后 我们要让用户下棋 就要构建PlayerMove()函数
3、第一个用户下完之后就要立马判断当前用户是否赢,
因为落子和判定是强相关的 这时候要构建 IsOver()函数
如果此用户没赢 那二个用户继续下。
当我们这些函数逻辑都明确好的时候 就用分而治之思想 ,
实现他们的功能。
* 1、ShowBoard()函数里面我用到了一个c语言里面的清屏函数
printf(“cls”);引上头文件window.h,这个的作用是在固定
地方刷新视图,把上次的视图清理掉 ,显示当前位置视图。
后面就打印视图的内容。用户一和用户二可以用字符表示,
也可以用圆圈图案表示这个图案可以在网上找复制一下就可
*2、 Playermove()函数让用户下棋,里面先考虑它的合法性 ,
不能越界和重复,再然后用我们在five_chrsss.h文件定义
宏来赋值 ,赋完之后再终止循环。
*3、 Isover()函数里面是让我们判断谁输谁赢 换句话游戏是否
结束。游戏结束标志是分为四种情况。用户一赢,用户二赢,
平局,继续。前两种情况则需要判断从当前位置出发 沿四个
方向当前用户棋的个数是否为大于等于5,在判断一下是哪个
用户的棋 就返回哪个用户。 而这判断需要在构建并调用Chre
ssCount()函数去统计当前用户的个数是否大于等于5,有4个
方向,例如上和下为一个方向,左和右为一个方向,左上和
右下为一个方向,右上和左下为一个方向,分别各自相加之后
在加上1就是当前的棋,如果满足这个4个方向大于等于5的一个
条件,我们就能知道一定有人赢,否则在继续判断周围是否有
空位置,有则返回NEXT让下个用户继续下,没有则返回平局
*ChressCoun()函数具体分析请看代码块
这些函数实现完之后再在Game()函数里面来个Switch循环,
来结收宏 去打印谁赢 还是平局。
三、main.c
在这里插入代码片#include "five_chress.h"
int main()
{
int quit = 0;
int select = 0;
while (!quit){
Menu();
scanf("%d", &select);
switch (select){
case 1:
Game();
break;
case 0:
quit = 1;
printf("ByeBye!\n");
break;
default:
printf("Enter Error, Try Again!\n");
break;
}
}
return 0;
}
main函数作为测试入口,相比较里面的逻辑是很简单的,创建一个菜单函数和调用一个Game函数,再增添点其他的内容。
六、实现结果


七、总结
实现五子棋给我最大的体会是应用比理论学习难得多,首先要逻辑清楚,也会涉及到各种实际问题,但是加深了我对知识的理解和运用,也知道了只有多练习 多写代码才能更好的提升编程技术。同时我也学到了实现一个复杂的项目时,先去构建一个框架,一个清晰的逻辑。再去逐个击破每个问题,要学会用分而治之的思想去解决问题。
边栏推荐
- Redis distributed lock
- Introduction to several common usage scenarios of message queue
- 尚硅谷尚品项目汇笔记(一)
- Realize today's news website based on native JS
- Why does redis cluster use reverse proxy? Just read this one
- Xss.haozi.me practice customs clearance
- (12) 51 Single Chip Microcomputer -- use DS18B20 to measure the outdoor temperature in Gongjiang West
- UE4官方AEC蓝图案例课程学习笔记
- 【zer0pts CTF 2022】 Anti-Fermat
- 测试类中的断言机制
猜你喜欢

Key points of data management

File & recursion 14.1

尚硅谷尚品项目汇笔记(一)
![[GWCTF 2019]BabyRSA1](/img/31/6727fd04be13ddd6bd46969fe2c50f.png)
[GWCTF 2019]BabyRSA1

QT with OpenGL (shadow mapping)

Latex中如何加粗字体 & 如何打出圆圈序号

Why does redis cluster use reverse proxy? Just read this one

蚁剑常见报错
![[December Haikou] the 6th International Conference on ships, marine and Maritime Engineering in 2022 (naome 2022)](/img/a4/041268aadd5d8ff493b52ead9c5e79.png)
[December Haikou] the 6th International Conference on ships, marine and Maritime Engineering in 2022 (naome 2022)

Put cloudflare on the website (take Tencent cloud as an example)
随机推荐
JS提升:JS中的数组扁平化问题
J9 Digital Science Popularization: how does the double consensus of Sui network work?
2022/7/26
Edit the copy and paste judgment problem (bug?), WYSIWYG display symbol problem feedback.
Legendary Internet Setup tutorial with graphic explanation - GOM engine
MQTT----mqtt.fx客户端软件
MapReduce (III)
Sort sort
BUUCTF-RSA
Why do I need to wait for 2msl?
【zer0pts CTF 2022】 Anti-Fermat
(十二)51单片机----用DS18B20浅测一下工(江)西的室外温度
Reduce error demonstration
Put cloudflare on the website (take Tencent cloud as an example)
Your list is too laggy? These four optimizations can make your list silky smooth
How to use C WinForm to copy files and display progress
29.学习Highcharts 使用百分比的堆叠柱形图
【开发教程11】疯壳·ARM功能手机-定时器实验教程
BUUCTF-RSA roll
BUUCTF-[BJDCTF2020]RSA1