【C语言】三子棋----详解

news2024/9/23 23:34:03

目录

前言

 一、游戏规则

二、创建文件

1.test.c文件

😄菜单函数的实现

 😄main函数的实现

😄game游戏函数的实现

 2.game.c文件

😄书写初始化棋盘的函数:

😄书写打印棋盘的函数

😄书写玩家下棋的函数(玩家下棋用“ * ”)

😄书写电脑下棋的函数(电脑下棋用“ # ”)

😄书写判断棋盘是否下满的函数

😄书写判断输赢的函数

3.game.h文件

😄需要使用的头文件 :

😄定义棋盘的行列:

 使用宏定义的好处:

 😄初始化棋盘:

😄打印棋盘:

😄玩家下棋:

😄电脑下棋:

😄判断输赢:

 😄判断棋盘是否下满:

 三、总代码

四、效果展示

 结语


前言

本篇文章是通过C语言来实现三子棋小游戏,主要用到的是数组和函数的知识,是对前面这些知识的灵活运用和巩固,下面我们来进行详细讲解具体步骤。

 一、游戏规则

三子棋游戏是在一个3X3的网格棋盘上进行的,开始时默认玩家先下棋,电脑后下棋。当三个相同的棋子先连成一条直线(行,列,对角线均可)的玩家获胜,若最终棋盘下满都未分出胜负,则判定为平局。

二、创建文件

根据三子棋游戏需要,我们将其分为game.h \ game.c \ test.c 三个文件来写,game.h文件用来定义棋盘的行和列以及添加各种头文件,声明各种函数;game.c文件用来书写游戏的实现过程,即棋盘的初始化,打印,玩家下棋,电脑下棋以及判断输赢的内容;test.c文件则用来打印游戏菜单,以及game函数的实现。

1.test.c文件

 为了实现三子棋首先我们需要有游戏菜单,其次我们需要通过主函数实现对菜单的选择,即输入1,开始游戏,输入0,退出游戏,输入其它,打印输入错误并且让玩家重新输入,这里我们通过while循环来实现游戏的持续进行,用switch语句来实现菜单的选择,最后在此文件中设计实现游戏(game)函数。

😄菜单函数的实现

void menu()
{
	printf("\t\t\t\t\t\n");
	printf("************************\n");
	printf("*********1.play*********\n");
	printf("*********0.exit*********\n");
	printf("************************\n");
}

打印结果:

 😄main函数的实现

int main()
{
	srand((unsigned int)time(NULL));//设置随机数的生成起点
	int input=0;
	do 
	{
		menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);
	return 0;
}

创建一个input的变量,用do while循环实现菜单的打印和选项的选择,当input输入为0时,打印一次菜单,并打印“退出游戏”后,退出循环并且停止程序。通过switch语言,对输入不同的input值进行判断和对应输入的功能实现。

打印结果:

这里较难的是game函数的实现,下面我们来详细讲解。

😄game游戏函数的实现

当玩家输入1选择开始游戏时,调用game()函数,此函数的功能包括:1.创建棋盘并初始化棋盘           2.打印棋盘           3.玩家下棋            4.电脑下棋            5.判断游戏输赢 

void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 }; 
	//初始化棋盘的函数
	InitBoard(board,ROW,COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	while (1)
	{
		//玩家下棋的函数
		PlayerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
		//电脑下棋的函数
		ComputerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL); 
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
	DisplayBoard(board, ROW, COL);
}

规定: 

 //玩家赢 - ‘*’
//电脑赢 - ‘#’
//平局 - ‘Q’
//继续 - ‘C’

通过 while循环实现玩家和电脑的对弈,利用if else语句判断游戏结束还是终止,上述只有游戏继续时不会跳出循环,即当 IsWin()函数返回值不是‘C’时,玩家和电脑继续对弈,否则跳出循环,接着通过 IsWin()函数的返回值来判断打印什么结果,如果返回值是‘ * ’,则打印”玩家赢“,如果返回  ‘ # ’,则打印”电脑赢“,否则打印”平局“。

打印结果:  

    

这里game函数内各个函数的实现在接下的game.c文件中有具体的讲解。

 2.game.c文件

😄书写初始化棋盘的函数:

void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
}

因为是对棋盘初始化,所以需要一个3*3的二维数组以及表示棋盘的行与列两个int类型的变量作为函数的形参。通过for循环将棋盘初始化为空,即初始化为‘ ’(空格)。

😄书写打印棋盘的函数

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//打印数据
		//printf(" %c | %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");
		//打印分割信息
		/*printf("---|---|---\n");*/
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

 这里为了提高代码的复用性我们尽量通过形参row和col的值来判断打印棋盘数据和分割信息‘--4-’和‘|’。这里我们将第一行的 %c | %c | %c 和第二行的 _ _ _ | _ _ _ | _ _ _看成一组,当外面for循环的i=0时,先打印 %c | %c | %c 再打印 _ _ _ | _ _ _ | _ _ _ 。

打印结果:

😄书写玩家下棋的函数(玩家下棋用“ * ”)

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");
	while (1)
	{
		printf("请输入坐标:>");
		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] = '*';
					break;
			}
			else
			{
				printf("坐标被占用,不能下棋,请选择其他位置\n");
			}
		}
		else
		{
			printf("坐标非法输入,请重新输入\n");
		}
	}
}

 注意:

我们知道在写代码时第一个位置的坐标是(0,0),但是在玩家眼里第一个位置的坐标是(1,1),所以玩家输入坐标下棋的(x,y)实际上是程序的(x-1,y-1)位置。

接下来可能会遇到以下问题,但是不要慌我会一一解答👀

👀玩家输入的下棋位置不在棋盘上怎么办?

通过 if  else语句判断玩家下棋的坐标是否正确,若输入正确则在玩家输入的位置落下棋子,若不正确,则在屏幕上打印“坐标非法输入,请重新输入”,提醒玩家重新输入正确坐标。

👀玩家输入的下棋位置被占用怎么办?

下棋位置被占用的前提是玩家输入的坐标是正确的,所以此时需要在判断下棋位置是否正确的 if else语句中再使用一个 if else语句来判断输入的坐标是否被占用:如果该坐标上棋盘对应的数据是 ‘ ’(空格),则该位置可以下棋,若不是空格,则位置打印“坐标被占用,不能下棋,请选择其他位置”。利用while循环语句可再次输入正确的未被占用的坐标。

打印结果:

 

😄书写电脑下棋的函数(电脑下棋用“ # ”)

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;//生成0-2的随机数
		y = rand() % col;//0-2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

 这里也会遇到一些问题,但是不要慌我也会一一解答👀

👀电脑如何随机输入坐标来进行下棋

这里我们需要对使用srand()函数来随机设置坐标。

//test.c
srand((unsigned int)time(NULL));//设置随机数的生成起点

 在使用rand()函数时我们需要在主函数中调用此函数,利用时间戳来设置随机值。具体使用方法可以参考我的上一篇博客《猜数字游戏》四、1、产生随机数函数 http://t.csdn.cn/oigPl

👀电脑如何控制输入坐标的合法性

x = rand() % row;//生成0-2的随机数
y = rand() % col;//生成0-2的随机数

利用rand()生成随机数取row或者col的模就可以得到0—2之间的数,如此可以控制电脑输入的坐标在3*3的棋盘上。

👀电脑如何处理坐标被占用的情况

 利用while循环来判断电脑输入的坐标上对应的数据是否为‘  ’(空格),如果是,则下入棋子,如果不是,就一直循环直到输入的坐标不被占用,此时需要在下棋的代码后加上break跳出循环。

打印结果:

😄书写判断棋盘是否下满的函数

//棋盘满了 返回1;不满 返回0
int IsFull(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就是0,所以我们要将函数的返回类型定义为int类型,因为是对棋盘进行判断所以需要棋盘(二维数组)以及行(整型)与列(整型)的形参,然后我们通过for循环来判断棋盘上各个坐标位置上的数据是否为‘  ’(空格),如果有坐标位置上的数据为空格,则棋盘没满,返回0,如果没有,则棋盘满了,返回1。 

😄书写判断输赢的函数

char IsWin(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][1] != ' ')
		{
			return board[i][1];
		}
	}
	//列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}
	//对角线
	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 (IsFull(board, ROW, COL))
	{
		return 'Q';
	}
	//如果上面的情况都不满足,则游戏继续
	return 'C';
}

通过for循环和 if else语句来判断游戏的输赢,一共有以下四种情况,因为下棋的棋子是一个字符型的数据,所以我们规定:

1.玩家赢        返回‘ * ’

2.电脑赢        返回‘ # ’

3.平局            返回‘Q ’

4.继续            返回‘C’

当函数任意一行或者任意一列或则任意对角线为相同的数据连成一条直线时,返回‘ * ’或‘ # ’,这里有一个小细节:我们在返回时可以不用判断返回何值,直接返回这个数据,因为玩家赢时棋盘上的这三个数据是‘ * ’,电脑赢时这三个数据是‘ # ’。

当棋盘下满了,函数 IsFull()返回值为1,否则为0,通过 if else语句,则可以判断当棋盘下满了,则没有人赢,此时为平局,返回‘Q’。最终如果以上情况都不满足,则继续游戏,返回‘C’。

3.game.h文件

😄需要使用的头文件 :

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

😄定义棋盘的行列:

#define ROW 3
#define COL 3

 使用宏定义的好处:

1.宏定义可以用一个有意义的名称来代替复杂的表达式或常量,使代码更具可读性。它还可以提高代码的维护性,因为如果需要修改某个值,只需修改宏定义的地方而不是整个代码中的多个地方。这样在三子棋基础上,只需改变宏定义的值,就可以实现多子棋的效果。

2.宏定义可以定义一段重复使用的代码,使得代码更具可重用性。通过使用宏定义,可以在程序中多次调用同一段代码,减少代码的冗余,提高代码的复用性。

3.宏定义是在预处理阶段处理的,它会将宏定义的部分直接替换为相应的内容。这样可以避免了函数调用的开销,提高了程序的执行效率

 😄初始化棋盘:

void InitBoard(char board[ROW][COL], int row, int col);

😄打印棋盘:

void DisplayBoard(char board[ROW][COL], int row, int col); 

😄玩家下棋:

void PlayerMove(char board[ROW][COL], int row, int col);

😄电脑下棋:

void ComputerMove(char board[ROW][COL], int row, int col);

😄判断输赢:

//
//玩家赢 - ‘*’
//电脑赢 - ‘#’
//平局 - ‘Q’
//继续 - ‘C’
//
char IsWin(char board[ROW][COL],int  row,int  col);

 😄判断棋盘是否下满:

int IsFull(char board[ROW][COL], int row, int col);

 三、总代码

注意:此代码分为三个部分的代码

(一)game.h文件

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 3
#define COL 3

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

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

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

//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);

//
//玩家赢 - ‘*’
//电脑赢 - ‘#’
//平局 - ‘Q’
//继续 - ‘C’
//判断游戏输赢的函数
char IsWin(char board[ROW][COL],int  row,int  col);

//判断棋盘是否下满
int IsFull(char board[ROW][COL], int row, int col);

(二)game.c文件

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
}

void DisplayBoard(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]);
			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[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");
	while (1)
	{
		printf("请输入坐标:>");
		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] = '*';
					break;
			}
			else
			{
				printf("坐标被占用,不能下棋,请选择其他位置\n");
			}
		}
		else
		{
			printf("坐标非法输入,请重新输入\n");
		}
	}
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;//生成0-2的随机数
		y = rand() % col;//生成0-2的随机数
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

//棋盘满了 返回1;不满 返回0
int IsFull(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;
}

char IsWin(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][1] != ' ')
		{
			return board[i][1];
		}
	}
	//列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}
	//对角线
	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 (IsFull(board, ROW, COL))
	{
		return 'Q';
	}
	//如果上面的情况都不满足,则游戏继续
	return 'C';
}

(三)test.c文件 

#define _CRT_SECURE_NO_WARNINGS 1
//test.c测试游戏的逻辑
//game.c游戏代码实现
//game.h游戏代码声明(函数声明等)

#include"game.h"
void menu()
{
	printf("\t\t\t\t\t\n");
	printf("************************\n");
	printf("*********1.play*********\n");
	printf("*********0.exit*********\n");
	printf("************************\n");
}

void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 }; 
	//初始化棋盘的函数
	InitBoard(board,ROW,COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	while (1)
	{
		//玩家下棋的函数
		PlayerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
		//电脑下棋的函数
		ComputerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL); 
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
	DisplayBoard(board, ROW, COL);
}


int main()
{
	srand((unsigned int)time(NULL));//设置随机数的生成起点
	int input=0;
	do 
	{
		menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);
	return 0;
}

四、效果展示

 结语

这里博主使用的编译器是Visual Studio 2022

三子棋游戏是一个趣味且富有挑战性的游戏,它可以帮助我们提高逻辑思维和决策能力。通过编写这个游戏,我们不仅学习了如何在C语言中实现一个简单的游戏,还了解了一些常见的编程概念和技巧,例如数组、循环、条件语句等等。希望本博客的内容对你有所帮助,并激发你对C语言编程和游戏开发的兴趣。通过不断学习和实践,相信你可以在编程的道路上越走越远,创造出更加出色和有趣的作品。如果你有任何问题或建议,欢迎在评论区留言与我分享。祝愿你在编程的旅程中取得巨大的成功!

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iSCSI磁盘配置

iSCSI磁盘简要描述 iSCSI&#xff08;Internet Small Computer System Interface&#xff09;&#xff0c;Internet小型计算机系统接口&#xff0c;又称为IP-SAN&#xff0c;是一种基于因特网及SCSI-3协议下的存储技术。 iSCSI 可以与任意类型的 SCSI 设备进行通信。对于一个…

【阿里巴巴1688API接口开发系列】数据采集获取,封装接口可加高并发,大数据中心项目

首先以1688商品数据为例 item_get-获得1688商品详情 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;注册Key和secret接入secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_…

Kafka request.log中RequestQueueTimeMs、LocalTimeMs、RemoteTimeMs、ThrottleTimeMs、含义

Kafka request.log中RequestQueueTimeMs、LocalTimeMs、RemoteTimeMs、ThrottleTimeMs、含义 要理解各个延时项的含义&#xff0c;必须从Kafka收到TCP请求、处理请求到返回TCP包整个流程开始梳理 RequestQueueTimeMs Processor 执行processNewResponses() 方法&#xff0c;不…

DPWWN1靶场详解

DPWWN1靶场详解 首先还是nmap -sP 192.168.102.0/24扫描到ip地址&#xff0c;然后对这个ip进行一个单独的扫描&#xff0c;发现这个靶场有一个mysql数据库&#xff0c;猜测可能会用到sql注入&#xff0c;但是没用到。 ip登陆到网页发现并没有什么可利用的 唯一的切入点也就数…

【Docker】Docker之镜像上传(阿里云镜像仓库)

注册阿里云镜像仓库 登录阿里云 登录成功后&#xff0c;搜索docker镜像 点击立即开通 创建个人实例 创建镜像仓库 点击下一步之后&#xff0c;可以选择代码源&#xff0c;本文选择的是本地仓库 镜像仓库创建成功&#xff0c;根据对应操作命令实现想要的功能&#xff0c;如上传镜…

Java 动态规划 剑指 Offer 47. 礼物的最大价值

代码展示&#xff1a; class Solution {public int maxValue(int[][] grid) {int mgrid.length;int ngrid[0].length;//创建dp数组int[][]dpnew int[m1][n1];//填充数组for(int i1;i<m;i){for(int j1;j<n;j){dp[i][j]Math.max(dp[i-1][j],dp[i][j-1])grid[i-1][j-1];}}r…

LLM模型微调方法总结

文章目录 Freeze方法P-tuning方法prefix-tuningPrompt TuningP-tuning v1P-tuning v2 Lora方法Qlora方法 在现在这大规模语言模型&#xff08;LLM&#xff09;盛行的时代&#xff0c;由于模型参数和显卡配置的因素&#xff0c;预训练基本是大公司或者高校可以完成的事情&#x…

SpringBoot+Prometheus+Grafana 监控面板(项目配置方式【入侵】)

SpringBootPrometheusGrafana 监控面板 提示&#xff1a;本文使用SpringBoot 简单样例&#xff0c;介绍基础配置和使用方法 包含内容&#xff1a;Docker、SpringBoot、Maven、 Prometheus、Grafana等 提示&#xff1a;本文包含官网内容介绍&#xff0c;具体更项目的学习&#x…

怎么学习Web框架和库相关知识?

学习Web框架和库相关知识可以帮助你构建高效、可扩展和安全的Web应用程序。以下是一些学习Web框架和库的方法和步骤&#xff1a; 确定学习目标&#xff1a; 明确你想学习的Web框架或库&#xff0c;例如常用的PHP框架&#xff08;如Laravel、Symfony&#xff09;或JavaScript库…

香橙派4和树莓派4B构建K8S集群实践之八: TiDB

目录 1. 说明 2. 准备工作 3. 安装 3.1 参考TiDB官方 v1.5安装说明 3.2 准备存储类 3.3 创建crd 3.4 执行operator 3.5 创建cluster/dashboard/monitor容器组 3.6 装好后的容器状况 3.7 设置访问入口(Ingress & Port) 4. 遇到的问题 5. 参考 1. 说明 建立TiDB…

Mongo可视化工具studio 3t无限试用

文章目录 前言一、下载二、使用步骤1.下载后,无脑下一步安装好2.开始无限试用 总结 前言 mongodb可以说是比较流行的nosql数据库了,它灵活多变的存储,为项目中后续可能的变更提供了极大的便利性,工欲善其事必先利其器,今天推荐一款mongo的可视化工具: studio 3t 一、下载 各版…

Linux驱动进阶(一)——设备驱动中的并发控制

文章目录 前言并发与竞争原子变量操作原子变量操作原子整型操作原子位操作 自旋锁自旋锁概述自旋锁的使用自旋锁的使用注意事项 信号量信号量概述信号量的实现信号量的使用自旋锁与信号量的对比 完成量完成量概述完成量的实现完成量的使用 小结 前言 现代操作系统有三大特征&a…

华为云流水线CodeArts Pipeline怎么样?能实现哪些功能?

华为云流水线服务CodeArts Pipeline&#xff0c;旨在提升编排体验&#xff0c;开放插件平台&#xff0c;并提供标准化的DevOps企业治理模型&#xff0c;将华为公司内的优秀研发实践赋能给伙伴和客户。 灵活编排、高效调度 开放流水线插件 内置企业DevOps研发治理模型 体验通…

Mysql常见的集群方案

一&#xff0c;MySQL Replication MySQL Replication 是官方提供的主从同步方案&#xff0c;用于将一个 MySQL 的实例同步到另一个实例中。Replication 为保证数据安全做了重要的保证&#xff0c;是目前运用最广的 MySQL 容灾方案。Replication 用两个或以上的实例搭建了 MySQ…

driftingblues3靶机详解

driftingblues3靶机复盘 打完这个靶机后发现自己最近一段时间进步了很多&#xff0c;并且有了一些自己的思想。 这里扫除来一个22和80端口&#xff0c;大概率是要用到ssh远程登陆的。 扫描ip的同时扫描了一下目录&#xff0c;发现扫描出来很多目录&#xff0c;这里我还很窃喜&…

linux中miniconda的重装问题

linux中miniconda的重装问题Linux安装condaconda使用yaml创建虚拟环境 注意问题&#xff1a; 安装minconda时&#xff1a; 安装好之后&#xff0c;把别人的环境直接复制到自己的‘miniconda3/envs’下&#xff0c;再修改该文件的拥有者和群组 source .bashrc 重新激活 问题…

虚幻引擎程序化资源生成框架PCG 之 UPCGBlueprintElement源码笔记(一)

UPCGBlueprintElement是PCGGraph中自定义节点的基类&#xff0c;但官方目前还没有给出详细的文档&#xff0c;所以从源代码里找点答案。 文章目录 可覆盖函数&#xff08;Override Functions&#xff09;Excute 和 Excute with ContextLoop Body函数和Loop函数Point Loop Body和…

LabVIEW-通过子VI实现组合数

一、题目 已知组合数 请根据这一计算规则&#xff0c;封装设计子程序&#xff0c;实现的计算&#xff0c;并编写测试程序验证子VI设计的正确性。 二、过程 设置数值输入控件的“属性”-“数据输入”-“最小值”为1&#xff0c;当输入值为0时强制转换为1。在程序框图界面放置…

更新换代IDEA和插件啦

1.背景介绍 在2019年的时候接触到IDEA了&#xff0c;本站也先后学习了IDEA的相关知识&#xff0c;当时一直到3个月前也一直都使用的是IDEA2018.2的版本&#xff0c;常用的各种插件也都是基于这个版本应用的不亦乐乎。期间也有在自己的电脑中体验过2021的版本&#xff0c;但是办…

顺序容器Primer

顺序容器在以下方面都有不同的性能折衷&#xff1a; 1.像容器中添加和删除元素的代价&#xff1b; 2.非顺序访问容器中元素的代价&#xff1b; 原因&#xff1a;容器的存储要么采用数组型&#xff0c;要么链式存储&#xff0c;前者导致不能随机添加删除&#xff0c;后者不能…