三子棋(C 语言)

目录

  • 一、游戏设计的整体思路
  • 二、各个步骤的代码实现
    • 1. 菜单及循环选择的实现
    • 2. 棋盘的初始化和显示
    • 3. 轮流下棋及结果判断实现
    • 4. 结果判断实现
  • 三、所有代码
  • 四、总结

一、游戏设计的整体思路

(1)提供一个菜单让玩家选择人机对战、玩家对战或者退出游戏,且一局结束以后还可以继续选择直到退出。
(2)使用一个 3*3 二维数组来表示一个棋盘,存放双方的落子情况并进行显示。且显示时使用一些符号进行分隔让棋盘更加合理。
(3)初始棋盘应为空,然后提示先手方下棋,要对先手方落子位置进行判断(是否合法,是否该位置已经落子),最后先手方下棋完毕后应检查棋局状态(获胜、平局或继续);同理后手方下棋。
(4)若平局或者任意一方获胜则结束对局,显示结果。

本次代码使用多文件形式,一共有三个文件,一个头文件包含各种声明,一个 .c 文件进行测试,一个 .c 文件实现函数功能。
在这里插入图片描述

二、各个步骤的代码实现

1. 菜单及循环选择的实现

(1)主函数代码的实现

// 头文件
#include <stdio.h>
#include "Tic_tac_toe.h"

int main()
{
	// 所需变量
	int select = 0;
	// 选择
	do
	{
		// 菜单
		menu();
		// 选择
		scanf("%d", &select);
		// 判断
		switch (select)
		{
		case 1 :  // 人机对战
			PVE();
			break;
		case 2 :
			PVP();  // 玩家对战
			break;
		case 0 :
			printf("游戏结束!\n");
			break;
		}
	} while (select);

	return 0;
}

(2)头文件中的声明

// 菜单
void menu();

(3)函数实现

// 菜单
void menu()
{
	printf("**************************************\n");
	printf("**********      1. PVE      **********\n");
	printf("**********      2. PVP      **********\n");
	printf("**********      0. exit     **********\n");
	printf("**************************************\n");
}

(4)运行效果如下
在这里插入图片描述

2. 棋盘的初始化和显示

棋盘的初始化和显示分别设计为两个函数 —— InitBoard()、PrintBoard()。首先,需要在主函数创建棋盘,且大小使用符号常量,方便替换。然后把棋盘的信息传入人机对战和玩家对战函数中,并在头文件和实现文件中进行相应的声明和定义。

(1)主函数创建棋盘

int main()
{
	// 所需变量
	int select = 0;
	char board[ROW][COL] = { 0 };  // 创建棋盘
	//...
}

(2)头文件进行相应声明

// 初始化棋盘
void InitBoard(char board[][COL], int row, int col);

// 打印棋盘
void PrintBoard(char board[][COL], int row, int col);

// 人机对战模式
void PVE(char board[][COL], int row, int col);

// 玩家对战模式
void PVP(char board[][COL], int row, int col);

(3)实现文件进行定义

// 初始化棋盘
void InitBoard(char board[][COL], int row, int col)
{
	int i;
	for (i = 0; i < row; ++i)
	{
		int j;
		for (j = 0; j < col; ++j)
			board[i][j] = ' ';
	}
}

// 打印棋盘
void PrintBoard(char board[][COL], int row, int col)
{
	// 打印棋盘时,需要适当添加符号分隔
	int i;
	for (i = 0; i < row; ++i)
	{
		int j;
		for (j = 0; j < col; ++j)
			printf(" ---");
		// 下一行
		printf("\n");
		for (j = 0; j < col; ++j)
			printf("| %c ", board[i][j]);
		// 补齐改行分隔
		printf("|");
		// 下一行
		printf("\n");
	}
	// 补齐最后一行分隔
	for (i = 0; i < col; ++i)
		printf(" ---");
	
	printf("\n");
}

// 人机对战模式
void PVE(char board[][COL], int row, int col)
{
	printf("\n人机对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
}

// 玩家对战模式
void PVP(char board[][COL], int row, int col)
{
	printf("\n玩家对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
}

运行效果如下:
在这里插入图片描述

3. 轮流下棋及结果判断实现

这里假设人机对战时,玩家使用符号 ‘#’,机器人使用符号 ‘*’;玩家对战时,一号玩家使用符号 ‘#’,二号玩家使用符号 ‘*’。玩家下棋和机器人下棋分别使用两个函数 —— PMove() 和 EMove()。PMove() 函数需要使用一个额外的变量判断是 1 号玩家下棋,还是 2 号玩家下棋。

判断结果函数 is_win() 需要判断每行是否相同、每列是否相同,倘若其中有一个实现,则有一方获胜,倘若没有则需要使用函数 is_full() 判断棋盘是否已满,若满则平局,否则继续。is_full() 函数也可以直接实现在 is_win() 函数内部。

(1)头文件函数声明

// 玩家下棋
void PMove(char board[][COL], int row, int col, int who);

// 机器人下棋
void EMove(char board[][COL], int row, int col);

// 判断是否获胜
void is_win(char board[][COL], int row, int col);

(2)实现文件函数定义

// 玩家下棋
void PMove(char board[][COL], int row, int col, char who)
{
	// 所需变量
	int x, y;
	do
	{
		// 输入坐标
		printf("玩家下棋(输入坐标中间用空格隔开):\n");
		scanf("%d %d", &x, &y);
		// 判断合法性
		if ((x < 0 || x > row || y < 0 || y > col) || board[x - 1][y - 1] != ' ')
		{
			printf("坐标非法,请重新输入!\n");
		}
		else
		{
			board[x - 1][y - 1] = who;
			break;
		}

	} while (1);
}

// 机器人下棋
void EMove(char board[][COL], int row, int col)
{
	// 机器人是随机下棋的,这里就要获取随机数了
	// 需要包含头文件 stdlib.h 和 time.h 
	// 设置随机数种子
	srand((unsigned)time(0));
	printf("电脑下棋:\n");
	while (1)
	{
		int x = rand() % row;  // 0 - row - 1
		int y = rand() % col;  // 0 - col - 1
		if (board[x][y] == ' ')
		{
			board[x][y] = '*';
			break;
		}
	}
}

// 判断是否获胜
char is_win(char board[][COL], int row, int col)
{
	// 判断每行
	int r = 1;
	int i;
	for (i = 0; i < row; ++i)
	{
		// 重置判断符号
		r = 1;
		// 若首字符为空则下一行
		if (board[i][0] == ' ')
			continue;
		// 判断改行
		int j;
		for (j = 1; j < col; ++j)
		{
			r *= (board[i][j - 1] == board[i][j]);
			// 判断
			if (!r)
				break;
		}
		if (r)
			return board[i][0];
	}

	// 判断每列
	int c = 1;
	int j;
	for (j = 0; j < col; ++j)
	{
		// 重置判断符号
		c = 1;
		// 首字符为空则下一列
		if (board[0][j] == ' ')
			continue;
		// 判断该列
		int i;
		for (i = 1; i < row; ++i)
		{
			c *= (board[i - 1][j] == board[i][j]);
			// 判断
			if (!c)
				break;
		}
		if (c)
			return board[0][j];
	}

	// 判断对角线
	int d = 1;
	if (board[0][0] != ' ')
	{
		for (i = 1; i < row; ++i)
		{
			d *= (board[i - 1][i - 1] == board[i][i]);
			// 判断
			if (!d)
				break;
		}
		if (d)
			return board[0][0];
	}

	if (board[0][col] != ' ')
	{
		d = 1;
		for (i = 1; i < row; ++i)
		{
			d *= (board[i - 1][col - i + 1] == board[i][col - i]);
			// 判断
			if (!d)
				break;
		}
		if (d)
			return board[0][col];
	}

	// 判断棋盘是否已满
	int full = 1;
	for (i = 0; i < row; ++i)
	{
		for (j = 0; j < col; ++j)
		{
			if (board[i][j] == ' ')
			{
				// 未满
				return 'C';
			}
		}
	}
	// 已满
	return 'D';

}

上述代码中 is_win() 函数中所使用的是通用判断方法,即使改变了符号常量 ROW 和 COL 的值也可以是判断。(如果实在理解不了,可以只当 3*3 的特殊情况来实现判断,当然,也可能是我的代码写的不好)。

(3)程序运行结果:
这里值展示人机对战的三种结果:

玩家获胜:
在这里插入图片描述

电脑获胜:
在这里插入图片描述

平均:
在这里插入图片描述

4. 结果判断实现

该代码直接放在了函数 PMove() 和函数 EMove() 中,也可以单独写一个函数。

(1)实现文件函数定义

// 人机对战模式
void PVE(char board[][COL], int row, int col)
{
	printf("\n人机对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
	// 开始下棋
	int ret = 0;
	do
	{
		// 玩家下棋
		PMove(board, row, col, '#');
		// 显示棋盘
		PrintBoard(board, row, col);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
		// 机器人下棋
		EMove(board, row, col);
		// 显示棋盘
		PrintBoard(board, row, col);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
	} while (1);
	// 判断最终结果
	if (ret == '#')
		printf("玩家获胜!\n");
	else if (ret == '*')
		printf("电脑获胜!\n");
	else
		printf("平局!\n");
}

// 玩家对战模式
void PVP(char board[][COL], int row, int col)
{
	printf("\n玩家对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
	// 开始下棋
	int ret = 0;
	do
	{
		// 玩家 1 号下棋
		PMove(board, row, col, '#');
		// 显示棋盘
		PrintBoard(board, col, row);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
		// 玩家 2 号下棋
		PMove(board, row, col, '*');
		// 显示棋盘
		PrintBoard(board, col, row);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
	} while (1);
	// 判断最终结果
	if (ret == '#')
		printf("玩家 1 号获胜!\n");
	else if (ret == '*')
		printf("玩家 2 号获胜!\n");
	else
		printf("平局!\n");
}

(2)演示结果
在上一次演示结果中已经体现。

三、所有代码

分三个文件,分别是头文件 Tic_tac_toe.h,测试文件 test.c,和函数实现文件 Tic_tac_toe.c。

(1)Tic_tac_toe.h

// 常量声明
#define ROW 3
#define COL 3

// 函数声明

// 菜单
void menu();

// 初始化棋盘
void InitBoard(char board[][COL], int row, int col);

// 打印棋盘
void PrintBoard(char board[][COL], int row, int col);

// 玩家下棋
void PMove(char board[][COL], int row, int col, char who);

// 机器人下棋
void EMove(char board[][COL], int row, int col);

// 判断是否获胜
char is_win(char board[][COL], int row, int col);

// 人机对战模式
void PVE(char board[][COL], int row, int col);

// 玩家对战模式
void PVP(char board[][COL], int row, int col);

(2)test.c

// 头文件
#include <stdio.h>
#include "Tic_tac_toe.h"

int main()
{
	// 所需变量
	int select = 0;
	char board[ROW][COL] = { 0 };
	// 选择
	do
	{
		// 菜单
		menu();
		// 选择
		scanf("%d", &select);
		// 判断
		switch (select)
		{
		case 1 :  // 人机对战
			PVE(board, ROW, COL);
			break;
		case 2 :
			PVP(board, ROW, COL);  // 玩家对战
			break;
		case 0 :
			printf("游戏结束!\n");
			break;
		default :
			printf("选择错误请重新选择!\n");
			break;
		}
	} while (select);

	return 0;
}

(3)Tic_tac_toe.c

// 头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "Tic_tac_toe.h"

// 函数定义

// 菜单
void menu()
{
	printf("**************************************\n");
	printf("**********      1. PVE      **********\n");
	printf("**********      2. PVP      **********\n");
	printf("**********      0. exit     **********\n");
	printf("**************************************\n");
}

// 初始化棋盘
void InitBoard(char board[][COL], int row, int col)
{
	int i;
	for (i = 0; i < row; ++i)
	{
		int j;
		for (j = 0; j < col; ++j)
			board[i][j] = ' ';
	}
}

// 打印棋盘
void PrintBoard(char board[][COL], int row, int col)
{
	// 打印棋盘时,需要适当添加符号分隔
	int i;
	for (i = 0; i < row; ++i)
	{
		int j;
		for (j = 0; j < col; ++j)
			printf(" ---");
		// 下一行
		printf("\n");
		for (j = 0; j < col; ++j)
			printf("| %c ", board[i][j]);
		// 补齐改行分隔
		printf("|");
		// 下一行
		printf("\n");
	}
	// 补齐最后一行分隔
	for (i = 0; i < col; ++i)
		printf(" ---");
	
	printf("\n");
}

// 玩家下棋
void PMove(char board[][COL], int row, int col, char who)
{
	// 所需变量
	int x, y;
	do
	{
		// 输入坐标
		printf("玩家下棋(输入坐标中间用空格隔开):\n");
		scanf("%d %d", &x, &y);
		// 判断合法性
		if ((x < 0 || x > row || y < 0 || y > col) || board[x - 1][y - 1] != ' ')
		{
			printf("坐标非法,请重新输入!\n");
		}
		else
		{
			board[x - 1][y - 1] = who;
			break;
		}

	} while (1);
}

// 机器人下棋
void EMove(char board[][COL], int row, int col)
{
	// 机器人是随机下棋的,这里就要获取随机数了
	// 需要包含头文件 stdlib.h 和 time.h 
	// 设置随机数种子
	srand((unsigned)time(0));
	printf("电脑下棋:\n");
	while (1)
	{
		int x = rand() % row;  // 0 - row - 1
		int y = rand() % col;  // 0 - col - 1
		if (board[x][y] == ' ')
		{
			board[x][y] = '*';
			break;
		}
	}
}

// 判断是否获胜
char is_win(char board[][COL], int row, int col)
{
	// 判断每行
	int r = 1;
	int i;
	for (i = 0; i < row; ++i)
	{
		// 重置判断符号
		r = 1;
		// 若首字符为空则下一行
		if (board[i][0] == ' ')
			continue;
		// 判断改行
		int j;
		for (j = 1; j < col; ++j)
		{
			r *= (board[i][j - 1] == board[i][j]);
			// 判断
			if (!r)
				break;
		}
		if (r)
			return board[i][0];
	}

	// 判断每列
	int c = 1;
	int j;
	for (j = 0; j < col; ++j)
	{
		// 重置判断符号
		c = 1;
		// 首字符为空则下一列
		if (board[0][j] == ' ')
			continue;
		// 判断该列
		int i;
		for (i = 1; i < row; ++i)
		{
			c *= (board[i - 1][j] == board[i][j]);
			// 判断
			if (!c)
				break;
		}
		if (c)
			return board[0][j];
	}

	// 判断对角线
	int d = 1;
	if (board[0][0] != ' ')
	{
		for (i = 1; i < row; ++i)
		{
			d *= (board[i - 1][i - 1] == board[i][i]);
			// 判断
			if (!d)
				break;
		}
		if (d)
			return board[0][0];
	}

	if (board[0][col] != ' ')
	{
		d = 1;
		for (i = 1; i < row; ++i)
		{
			d *= (board[i - 1][col - i + 1] == board[i][col - i]);
			// 判断
			if (!d)
				break;
		}
		if (d)
			return board[0][col];
	}

	// 判断棋盘是否已满
	int full = 1;
	for (i = 0; i < row; ++i)
	{
		for (j = 0; j < col; ++j)
		{
			if (board[i][j] == ' ')
			{
				// 未满
				return 'C';
			}
		}
	}
	// 已满
	return 'D';

}


// 人机对战模式
void PVE(char board[][COL], int row, int col)
{
	printf("\n人机对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
	// 开始下棋
	int ret = 0;
	do
	{
		// 玩家下棋
		PMove(board, row, col, '#');
		// 显示棋盘
		PrintBoard(board, row, col);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
		// 机器人下棋
		EMove(board, row, col);
		// 显示棋盘
		PrintBoard(board, row, col);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
	} while (1);
	// 判断最终结果
	if (ret == '#')
		printf("玩家获胜!\n");
	else if (ret == '*')
		printf("电脑获胜!\n");
	else
		printf("平局!\n");
}

// 玩家对战模式
void PVP(char board[][COL], int row, int col)
{
	printf("\n玩家对战:\n");
	// 初始化棋盘
	InitBoard(board, row, col);
	// 显示棋盘
	PrintBoard(board, row, col);
	// 开始下棋
	int ret = 0;
	do
	{
		// 玩家 1 号下棋
		PMove(board, row, col, '#');
		// 显示棋盘
		PrintBoard(board, col, row);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
		// 玩家 2 号下棋
		PMove(board, row, col, '*');
		// 显示棋盘
		PrintBoard(board, col, row);
		// 判断
		ret = is_win(board, row, col);
		if (ret != 'C')
			break;
	} while (1);
	// 判断最终结果
	if (ret == '#')
		printf("玩家 1 号获胜!\n");
	else if (ret == '*')
		printf("玩家 2 号获胜!\n");
	else
		printf("平局!\n");
}

四、总结

本次三子棋的代码编写总体来说还可以,基本上都实现了上述功能,其中的某些代码本人均是根据符号常量来编写的,也就是即使符号常量改变,本代码依旧可以实现。当然,本人水平有限,有的地方看不懂可能是本人代码写的太烂,这里先道个歉。

当然代码还有很多可以提升的地方,比如优化棋盘,可以使用鼠标来下棋,提升电脑的水平等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891359.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大厂面试真题-组合和聚合的区别是什么

组合和聚合比较类似&#xff0c;二者都表示整体和部分之间的关系。 聚合关系的特点是&#xff1a;整体由部分构成&#xff0c;但是整体和部分之间并不是强依赖的关系&#xff0c;而是弱依 赖的关系&#xff0c;也就是说&#xff0c;即使整体不存在了&#xff0c;部分仍然存在…

Zabbix监控vCenter虚拟机

1. vcenter上配置snmp agent 如果配置 vCenter Server Appliance SNMP 代理以用于轮询,则它可以侦听和响应来自 SNMP 管理客户端系统的请求,如 GET、GETNEXT 和 GETBULK 请求. 使用root身份进入vcenter命令行,开启snmp代理 Command> snmp.enable Command> snmp.set…

正则表达式 | Python、Julia 和 Shell 语法详解

正则表达式在网页爬虫、脚本编写等众多任务中都有重要的应用。为了系统梳理其语法&#xff0c;以及 Python、Julia 和 Shell 中与正则表达式相关的工具&#xff0c;本篇将进行详细介绍。 相关学习资源&#xff1a;编程胶囊。 基础语法 通用语法 在大多数支持正则表达式的语…

24/10/14 视觉笔记 图像拼接融合

图像拼接分为四步 1.特征点提取 2.特征点匹配 3.仿射矩阵计算 4.图像拼接与融合 1.特征提取 找到图像中具有显著性信息点&#xff0c;并计算该点的特征表达 def detectAndDescrible(img):#构建STFT特征检测器sift cv2.SIFT_create()#特征提取kps,features sift.detectA…

3-3 AUTOSAR RTE 对SR Port的实现

返回总目录->返回总目录<- 目录 一、前言 二、显式访问 三、隐式访问 四、队列调用(Queued) 五、无效数据元素 一、前言 RTE作为SWC和BSW之间的通信机构,支持Sender-Receiver方式实现ECU内及ECU间的通信。 对于Sender-Receiver Port支持三种模式: 显式访问:若…

京东零售数据湖应用与实践

作者&#xff1a;陈洪健&#xff1a;京东零售大数据架构师&#xff0c;深耕大数据 10 年&#xff0c;2019 年加入京东&#xff0c;主要负责 OLAP 优化、大数据传输工具生态、流批一体、SRE 建设。 当前企业数据处理广泛采用 Lambda 架构。Lambda 架构的优点是保证了数据的完整性…

LeetCode|70.爬楼梯

这道题很像斐波那契数列&#xff0c;但是初始值不同&#xff0c;也有动态规划的解法&#xff0c;但是一开始我想到的是递归写法。现在我们站在第n阶台阶&#xff0c;那么&#xff0c;我们上一步就有两种可能&#xff1a;1、我们从第n-1阶台阶走一步上来的&#xff1b;2、我们从…

弹出“xinput1_3.dll文件缺失”的错误要怎么处理?一键修复xinput1_3.dll

当你尝试打开游戏或应用时&#xff0c;如果弹出“xinput1_3.dll文件缺失”的错误&#xff0c;请记得及时处理。这个文件是DirectX中用于处理游戏控制器输入的关键组件。这个问题可以通过几个简单的步骤轻松解决。本指南将教你如何快速恢复或替换丢失的xinput1_3.dll文件&#x…

免费Excel工作表同类数据合并工具

下载地址&#xff1a;https://pan.quark.cn/s/81b1aeb45e4c 在 Excel 表格里&#xff0c;当我们试图手动将多行同类数据合并为一行时&#xff0c;会遭遇诸多棘手的困难以及繁杂的操作流程。在确定哪些数据属于可合并的同类数据时&#xff0c;单纯依靠人工进行对比&#xff0c;极…

SQL数据库刷题sql_day33(连续3次为球队得分的球员名单)

描述 两支篮球队进行了激烈的比赛&#xff0c;比分交替上升。比赛结束后&#xff0c;你有一个两队分数的明细表&#xff08;名称为“分数表”&#xff09;。 表中记录了球队、球员号码、球员姓名、得分分数及得分时间。现在球队要对比赛中表现突出的球员进行奖励。 问题&#x…

用最短长度的绳子把整个花园围起来

给定一个数组 trees&#xff0c;其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来&#xff0c;因为绳子很贵。只有把 所有的树都围起来&#xff0c;花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输入: points […

MySQL 的数据类型

1.整数类型 1.1 tinyint tinyint 为小整数类型&#xff0c;存储空间为1个字节&#xff08;8位&#xff09;&#xff0c;有符号范围-128 ~ 127&#xff0c;无符号范围 0 ~ 255,此类型通常在数据库中表示类型的字段&#xff0c;如某一字段 type 表示学科,其中 “type1” 表示语文…

实战篇:(二)React 创建项目并连接 MySQL 后台的实战教程

React 创建项目并连接 MySQL 后台的实战教程 一、项目概述 本篇博客将介绍如何使用 React 搭建前端项目&#xff0c;并通过 Node.js 和 MySQL 实现简单的后台数据连接。通过这个项目&#xff0c;你将掌握从前端到后端数据库的基础开发流程&#xff0c;适合初学者或正在项目实…

中国各大一线及二线省会城市程序员收入大比拼,看看你所在的城市的统计是否准确

在中国&#xff0c;程序员的收入因城市、经验、学历等因素而有所不同。本文将对一线及二线省会城市的程序员收入进行详细比较&#xff0c;帮助大家了解各地的薪资水平。 一线城市程序员收入 上海 上海作为中国的经济中心&#xff0c;程序员收入最高。根据最新数据&#xff…

新生编程入门的方式探讨

关于如何编程入门&#xff0c;这是一个很好的问题。在上大学之前&#xff0c;并没有怎么接触电脑的我&#xff0c;也许可以谈一谈。 还记得在高中的时候&#xff0c;因为很多同学去网吧玩电脑打游戏&#xff0c;被学校开除&#xff0c;老师谆谆教诲大家不要去网吧&#xff0c;所…

Word粘贴时出现“文件未找到:MathPage.WLL”的解决方案

解决方案 一、首先确定自己电脑的位数&#xff08;这里默认大家的电脑都是64位&#xff09;二、右击MathType桌面图标&#xff0c;点击“打开文件所在位置”&#xff0c;然后分别找到MathPage.WLL三、把这个文件复制到该目录下&#xff1a;C:\Program Files\Microsoft Office\r…

SQLAlchemy入门:详细介绍SQLAlchemy的安装、配置及基本使用方法

SQLAlchemy是一个流行的Python SQL工具包和对象关系映射&#xff08;ORM&#xff09;框架&#xff0c;它为开发人员提供了一种高效、灵活的方式来与数据库进行交互。本文将详细介绍SQLAlchemy的安装、配置及基本使用方法&#xff0c;并通过代码示例和案例分析&#xff0c;帮助新…

SSL---SSL certificate problem

0 Preface/Foreword 0.1 SSL certificate problem 开发过程中&#xff0c;gitlab-runner连接gitlab时候出现SSL 证书问题。 场景&#xff1a;公司的gitlab runner服务器引入了SSL证书&#xff0c;每年都会主动更新一次。当前的gitlab-runner运行在PC机器上&#xff0c;但是g…

论文翻译 | OpenICL: An Open-Source Framework for In-context Learning

摘要 近年来&#xff0c;上下文学习&#xff08;In-context Learning&#xff0c;ICL&#xff09;越来越受到关注&#xff0c;并已成为大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;评估的新范式。与传统微调方法不同&#xff0c;ICL无需更新任何参…

如何用好 CloudFlare 的速率限制防御攻击

最近也不知道咋回事儿,群里好多站长都反映被CC 攻击了。有人说依旧是 PCDN 干的,但明月感觉不像,因为有几个站长被 CC 攻击都是各种动态请求(这里的动态请求指的是.php 文件的请求)。经常被攻击的站长们都知道,WordPress /Typecho 这类动态博客系统最怕的就是这种动态请求…