• C语言实现五子棋游戏


    五子棋的实现

    一、实现的目的和意义

    1、巩固和加深对c语言知识的理解
    2、学会使用编译器的各种调试
    3、提高解决实际问题的能力

    二、实现内容描述

    实现简单的人人对战五子棋,此设计用的是C语言去实现

    三、实现原理

    采用二位数组保存棋盘信息,棋盘上面的任何一个位置,里头
    可以放三个信息:
    1、空
    2、用户1的落子
    3、用户2的落子
    下棋就是在二维数组种找对应的空位置,进行落子,落完之后立
    即就要判断落子位置是否有五字连珠,从而判断谁数输谁赢。每
    走一次棋会有四种情况:
    *用户1赢
    *用户2赢
    *平局(这里说的平局是棋盘被占满的情况)
    *没有出结果 意思就是时此用户没赢 下个用继续去下棋

    四、实现模块五子棋实现分为三大模块

         文件名                       作用
        five_chress.h       五子棋的函数声明,头文件声明等
        five_chress.c       五子棋函数接口的实现
        main.c              五子棋函数测试功能
    
    • 1
    • 2
    • 3
    • 4
    五、模块代码分析

    1、five_chress.h

       #pragma once
        #include 
        #include 
        #include
        #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()函数      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190

    分析:
    我们要先构建游戏入口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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    main函数作为测试入口,相比较里面的逻辑是很简单的,创建一个菜单函数和调用一个Game函数,再增添点其他的内容。

    六、实现结果

    在这里插入图片描述

    在这里插入图片描述

    七、总结

    实现五子棋给我最大的体会是应用比理论学习难得多,首先要逻辑清楚,也会涉及到各种实际问题,但是加深了我对知识的理解和运用,也知道了只有多练习 多写代码才能更好的提升编程技术。同时我也学到了实现一个复杂的项目时,先去构建一个框架,一个清晰的逻辑。再去逐个击破每个问题,要学会用分而治之的思想去解决问题。

  • 相关阅读:
    第02章 Tableau连接数据源
    QT读取Excel表格内容到Table Widget
    CCF CSP认证 历年题目自练 Day20
    JAVA集合
    uniCloud开发公众号:五、开通/配置/初始化uniPush2.0
    docker保存镜像、打包tar、加载tar镜像
    如何学习RISC-V
    用最少的代码模拟gRPC四种消息交换模式
    spark知识点总结(1)
    Java安全之CC2
  • 原文地址:https://blog.csdn.net/m0_59292239/article/details/126020950