• 你真的明白井字棋整个过程吗


    前沿

    井字棋其实也叫三子棋,但是我们这边叫井字棋。废话不多少 ,直接开整
    首先我们要创建三个文件:
    image.png
    test.c——是测试的逻辑,写出来之后能让你把整个游戏制作思路表现出来。
    game.h
    game.c ——是游戏的实现,具体写代码的地方。

    简单的运行流程

    首先我们先在test.c中写主函数:

    int main()
    {
    	test();
    		return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后我们可以在test()函数中写出主要运行流程

    1.打印菜单

    先在test()函数中增加menu()——用来打印菜

    void test()
    {
    	do
    	{
    		menu();
    	} while ();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    做一个简单的菜单表示

    void menu()
    {
    	printf("***************************\n");
    	printf("********   1. play   ******\n");
    	printf("********   0. eixt   ******\n");
    	printf("***************************\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这样就把菜单表示出来了

    2.对菜单选项进行表示

    void test()
    {
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择:>");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			printf("井字棋\n");
    			break;
    		case 0:
    			printf("退出游戏\n");
    			break;
    		default:
    			printf("选择错误\n");
    			break;
    		}
    	} while (1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    不多废话,直接运行起来看看效果
    image.png
    这个整个框架就搭建起来了,但是我们输入1:玩游戏,只出现井字棋。这是不够的哦。
    image.png 这样才算是进入了游戏门槛了。

    3. 对游戏棋盘进行表示

    所以我们单独打印一个中文数字是不行的,那就再加一个函数game();
    首先我们存储数据,是需要一个3*3的数组。

    我们初始化一下棋盘为全空格,与上图相对应

    void game()			
    {
    	char board[3][3];
    	init_board(board, 3, 3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样我们就需要在game.h——文件中引用
    并且不局限于三子棋,可以五子棋,甚至n子棋了。
    这是因为我们数组的行与列是可以无限延伸的

    #pragma once
    
    #define ROW 3
    #define COL 3
    
    • 1
    • 2
    • 3
    • 4

    这里大写ROW 代表行 COL 代表列 后面的数字你写多少就表示多少哦
    所以我们在game()函数中就让ROW COL 替换 3 3

    void game()
    {
    	char board[ROW][COL];
    	init_board(board, ROW, COL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    同时我们也要在game.h头文件中表示

    #pragma once
    
    #define ROW 3
    #define COL 3
    
    • 1
    • 2
    • 3
    • 4
    初始化棋盘

    我们首先在game.h中声明函数
    //初始化棋盘
    void init_board(char board[ROW][COL], int row, int col);

    后面具体操作就要在game.c中操作了

    void intit_board(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++)
    		{
    			board[i][j] = ' ';
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    小插曲:因为我们是三个文件同时写的,且都要引用头文件game.h
    所以我们就把其他需要引用的东西写在头文件中,这样就简单明了了

    打印棋盘

    初始化之后,我们要表示出来,就要打印了,这些具体操作就放在game.c中写了
    同时其他两个文件,也要表示表示,你懂的,哈哈

    void print_board(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]);
    		}
    		printf("\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里我们使用了两个循环,是为了行与列都打印出来。
    image.png
    我们这个打印似乎缺少点什么了,我们的边界呢?所以是要优化一下的

    void print_board(char board[ROW][COL], int row, int col)
    {
    	int i = 0;
    	for (i = 0; i < row; i++)
    	{
    		printf(" %c | %c | \n", board[i][0], board[i][1], board[i][2]);
    		if (i < row - 1)
    			printf("---|---|---\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
       来运行一波
    
    • 1

    在这里插入图片描述

    这个不就可以了呀, 但是如果要玩五子棋呢?
    简单因为我们有变量 ROW COL 直接在头文件换数字不就可以了

    在这里插入图片描述

    看看这个是啥玩意,五子棋不像三子棋,三子棋不像井字棋
    这就露出鸡脚了吧! 所以为了追求完美还是要继续优化

    void print_board(char board[ROW][COL], int row, int col)
    {
    	int i = 0;
    	for (i = 0; i < row; i++)
    	{
    		//printf(" %c | %c | \n", board[i][0], board[i][1], board[i][2]);
    		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)
    		{
    			//printf("---|---|---\n");
    			for (j = 0; j < col; j++)
    			{
    				printf("---");
    				if (j < col - 1)
    					printf("|");
    			}
    			printf("\n");
    		}
    	}
    }
    
    • 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

    我们是依据这个个循环打印的哦在这里插入图片描述

    玩家&电脑操作

    现在所有的外部环境,背景都安排好了。就真的该上手操作了
    同样在game.h和test.c中记得申明哦 废话不多说 开整

    void player_move(char board[ROW][COL], int row, int col)
    {
    	printf("玩家下棋\n");
    	while (1)
    	{
    		printf("请输入要下棋的坐标:>");
    		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] = '*';
    			}
    			else
    			{
    				printf("该坐标被占用,请重新输入\n");
    			}
    		}
    		else
    		{
    			printf("坐标非法\n");
    		}
    	}
    }
    
    • 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


    在这里是不是脑瓜子嗡嗡的,所以这听我娓娓道来
    首先我们要输入坐标,但是坐标要在范围内,否则就非法访问了
    然后我们进入门槛后,再判断你输入的位置是不是已经有棋子在那里了
    没有的话就直接坐标替换了


    接下来就是电脑操作了
    电脑下棋,随机生成坐标,只要坐标没有被占用,就下棋

    void computer_move(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;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这就完成一个小任务
    这里的rand()是随机函数,还有时间戳(NULL),所以我们就要添加一些东西了

    image.png 更加精确

    判断输赢

    接下来总不能一直玩下去吧,我们还要判断输赢吧
    判断输赢
    判断输赢的代码要告诉我:电脑赢了?玩家赢了?平局?游戏继续?
    电脑赢:#
    玩家赢:*
    平局:Q
    游戏继续:C
    我们先在test.c中把整体判断框架搞出来

    		//判断输赢
    		ret = is_win(board, ROW, COL);
    		if (ret != 'C')
    		{
    			break;
    		}
    		computer_move(board, ROW, COL);
    		print_board(board, ROW, COL);
    		//判断输赢
    ret = is_win(board, ROW, COL);
    		if (ret != 'C')
    		{
    			break;
    		}
    	}
    	if (ret == '*')
    		printf("电脑赢了\n");
    	else if (ret == '#')
    		printf("玩家赢了\n");
    	else if (ret == 'Q')
    		printf("平局\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    然后再对is_win函数在game.c中进行具体运行

    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][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[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_full(board, row, col) == 1)
    	{
    		return 'Q';
    	}
    	//继续
    	//没有玩家或者电脑赢,也没有平局,游戏继续
    	return 'C';
    }
    
    • 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


    在这里玩家和电脑循环下棋,每下一步就需要is_win()函数进行判断
    三行,三列,对角线是否有同棋
    或者平局(棋盘填满)
    这里我们就又又又要写一个is_full()函数了

    static int is_full(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++)
    		{
    			if (board[i][j] == ' ');
    			{
    				return 0;
    			}
    		}
    	}
    	return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    我希望is_full()这个函数只是为了支持is_win()函数的,只是在is_win()函数内部使用
    就没有必要在头文件中申明了。
    这就可以把它给隐藏起来了,那就需要 static 把那个函数放在静态库中了。
    只要我不给你game.c文件 就你看着头文件是不可能想到这个的哦
    结尾:我也是边学,边写,搞了半天。
    希望后面的学习,更加熟练,更加通畅,效率更高。
    这么长时间居然连如何使用编译器都不清楚。
    连小叮当的任意门都做不到

    仍需继续努力

    守得云开见月明

  • 相关阅读:
    pgbouncer 使用
    iText实战--Table、cell 和 page event
    VUE&Element
    视频监控系统/视频汇聚平台EasyCVR如何反向代理进行后端保活?
    读书笔记:彼得·德鲁克《认识管理》第8章 战略规划:企业家技能
    TikTok Shop美国本土店VS跨境店,如何选择?有何区别?
    大数据集群中部署Hive
    理解Hash表
    类型转换(2)
    【CNN-SVM回归预测】基于CNN-SVM实现数据回归预测附matlab代码
  • 原文地址:https://blog.csdn.net/m0_73920510/article/details/127825911