N子棋(外加双人对战)详解!推荐!!!

news/2024/7/8 2:20:44

文章目录

  • 准备工作
    • 创建菜单
      • 进入游戏
        • 初始化棋盘、打印棋盘
          • 玩家下棋、电脑下棋、生成随机数
            • 判断输赢

大家好!时隔多天,我终于写博客了,真的是开心!这一次带来的是N子棋有双人对战和单人下棋,请认真看下去,我会竭尽所能讲清楚整个思路!如果还有疑问的话,我们可以进行探讨!
首先给大家展示代码:

这是test.c:

#define _CRT_SECURE_NO_WARNINGS


#include"game.h"


void game()
{
	char board[ROW][COL];
	char ret = 0;
	init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	while (1)
	{
		player1_move(board, ROW, COL);
		print_board(board, ROW, COL);
		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("玩家1赢了!\n");
	else if (ret == '#')
		printf("电脑赢了!\n");
	else if (ret == 'P')
		printf("平局!\n");
}

void menu()
{
	printf("    1. play    \n");
	printf("    0. exit    \n");
	printf("    please enter:");
}

void test()
{	
	srand((unsigned int) time(NULL));
	int i = 0;
	do
	{
		menu();
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			game();
			break;
		case 0:
			printf("    quit game\n");
			break;
		default:
			printf("    please enter again!\n");
			break;
		}
	} while (i);
}



int main()
{
	test();
	return 0;
}

这是game.c:

#define _CRT_SECURE_NO_WARNINGS

#include"game.h"

void init_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] = ' ';
		}
	}
}

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]);
			if (j < col - 1)
				printf("|");
			
		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
		}
		printf("\n");
	}
}

void player1_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家1请下棋:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x - 1 < row && y >= 1 && y - 1 < col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("已被占用!");
			}
		}
		else
		{
			printf("非法输入!");
		}
	}
}

void computer_move(char board[ROW][COL], int row, int col)
{
	int x = rand() % 3;
	int y = rand() % 3;
	while (1)
	{
		printf("电脑请下棋:");
		scanf("%d %d", &x, &y);
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
}

static int  is_full(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++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}


char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')//
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[i][j - 1];
	}
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[j][i] == board[j - 1][i] && board[j - 1][i] != ' ')
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[j - 1][i];
	}
	int flag = 0;
	for (i = 1; i < row; i++)
	{
		
		if (board[i - 1][i - 1] == board[i][i] && board[i - 1][i - 1] != ' ')
			flag++;
		if (flag == KEY - 1)
			return board[i][i];
	}
	flag = 0;
	int j = col - 1;
	for (i = 1; i < row; i++)
	{
		
		if (board[i][j - 1] == board[i - 1][j] && board[i - 1][j] != ' ')
		{
			flag++;
			j--;
		}
		if (flag == KEY - 1)
			return board[i][0];
	}
	int ret = is_full(board, ROW, COL);
	if (ret)
		return 'P';
		return 'C';
}


这是game.h:

#pragma once

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

#define ROW 10
#define COL 10

#define KEY 5

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

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

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

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

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

准备工作

在进行设计一个游戏前,我们要思考游戏分为什么部分 ,根据模块逐个进行编程,并且写完一部分就要进行调试,看是否出错!

我们可以从简单入手,先设计一个三子棋,然后再进行扩展。

先创建文件,创建一个test.c 文件作为主函数的部分,然后创建游戏文件game.c 文件作为游戏主体的部分,最后创建一个game.h 文件作为声明函数的文件,如图:
注意:这里可以将<stdio.h>头文件放在game.h中,然后再test.c 和game.c 中引用game.h 文件,#include"stdio.h"。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建菜单

当创建完文件之后,就可以进行写代码了。首先进入一个游戏,映入眼帘的是菜单,玩还是不玩?所以先可以创建菜单了。

void menu()//菜单说明
{
	printf("    1. play    \n");
	printf("    0. exit    \n");
	printf("    please enter:");
}

void test()
{	
	int i = 0;//进行选择
	do
	{
		menu();//进行打印菜单
		scanf("%d", &i);
		switch (i)
		{
		case 1://选择1进行游戏
			game();//游戏主体部分
			break;
		case 0://选择0退出游戏
			printf("    quit game\n");
			break;
		default://选择其它数字就进行报错
			printf("    please enter again!\n");
			break;
		}
	} while (i);//为0跳出循环,退出游戏
}



int main()
{
	test();//测试部分
	return 0;
}
//这里用到do while 语句很合适,进入游戏,不管你玩不玩,游戏界面是一定
//要显示的,体现了do while 语句的先执行一次的特点!

进入游戏

那么创建完菜单之后,进行选择,选择1进入游戏。接下来进行游戏主体部分,我们把游戏中的各种函数定义放在game.c 中,放在test.c 中会显得臃肿,函数的声明放在game.h 中。

void game()//游戏主体
{
//那么创建一个棋盘变量。棋盘分为行列,所以我们可以用二维数组来作为棋盘,
//ROW代表行,COL代表列,我们进行宏定义ROW为3,COL为3,如下图:

	char board[ROW][COL];
}

宏定义ROW ,COL 为3,这样宏定义很方便,想要改变棋盘的大小,只要改变这里就行了,其它不用改变!在这里插入图片描述

初始化棋盘、打印棋盘

当我们进入游戏的时候,我们看到应该是棋盘,并且没有下棋的棋盘.如下图:

void game()//游戏主体
{//在这里调用函数,在game.c 中定义函数.
	char board[ROW][COL];//棋盘大小,ROW为行,COL为列
	init_board(board, ROW, COL);//初始化棋盘
	print_board(board, ROW, COL);//打印棋盘
}

我们要思考:如何设计一个棋盘?如何去初始化棋盘,让棋盘每一个位置都是空格?下图是一个模板:
在这里插入图片描述

初始化棋盘:我们直接用双层循环进行每个元素赋值为空格就行,如下图:

//记得要在game.h中声明该函数!
void init_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] = ' ';//每个元素赋予空格
		}
	}
}

打印棋盘:我们可以将这个图案分为两个部分:

在这里插入图片描述

我们可以观察:无横线的部分中空格是有三个空格,因为下面有三个横线,那我们可以写双重循环,内层循环写无横线的部分,循环三列,外层循环写三行.如下图:

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");
	}
}

这样打印结果就是如下:
在这里插入图片描述

第一个问题:我们可以看到在第三列不需要竖杠,只需要打印小于COL - 1 的列数,所以用一个if语句来执行,如果小于COL就打印竖杠,否则不打印!***
第二个问题:我们看到缺少了横线与竖杠,所以我们可以在内层循环结束后,进行打印横线与竖杠,但是最后一行不需要打印,所以要进行判断行小于ROW - 1 。***
所以解决途径如下:

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]);//打印三个部分,中间放字符
			if (j < col - 1)//不打印最后一个竖杠
				printf("|");//打印竖杠,成为棋盘的一部分呢
			
		}
		printf("\n");
		if (i < row - 1)//到了最后一行就不打印横线
		{
			for (j = 0; j < col; j++)//循环3次,打印竖杠
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
		}
		printf("\n");
	}
}

那么初始化棋盘,打印棋盘就完成了。

玩家下棋、电脑下棋、生成随机数

既然棋盘已经做完了,那么接下来就是下棋了。下棋分为玩家和电脑下棋。

玩家下棋:作为一个玩家,我们可以输入坐标在棋盘上显示符号,玩家输入坐标是大于等于1的,所以存入数组的时候要进行减一。

规则:输入坐标。首先判断坐标是否合法,什么是合法?合法就是要在棋盘的大小范围之内!然后判断坐标的位置是否为空格?意思就是这个坐标不能有棋子,有棋子就代表被占用了,不能下棋!这两个规则遵守了,就可以进行设计了!如下图:

void player1_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)//只有坐标合法并且正确才能跳出循环,否则继续输入坐标
	{
		printf("玩家1请下棋:");
		scanf("%d %d", &x, &y);//坐标一定要大于等于1
		if (x >= 1 && x - 1 < row && y >= 1 && y - 1 < col)//坐标合法的条件
		{
			if (board[x - 1][y - 1] == ' ')//坐标减一才能对应数组中的元素
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("已被占用!");//不是空格就说明
			}
		}
		else
		{
			printf("非法输入!");//坐标不合法就说明
		}
	}
}

电脑下棋:电脑下棋不需要那么麻烦,所以只需要生成的随机数作为坐标,然后判断是否被占用,不被占用就可以赋予符号并且跳出循环!

生成随机数:我之前在写猜数字游戏的时候讲了随机数的一些知识,不了解可以去看看,这是链接http://t.csdn.cn/IgYyi。把随机数当成坐标,但是随机数很随机,很可能不合法,所以我们可以%3,那么得到的结果只能小于3,就可以作为随机数了。

void computer_move(char board[ROW][COL], int row, int col)
{
	int x = rand() % 3;//srand可以放在void test()中,因为只需要生成一次就可以了!
	int y = rand() % 3;//记得引用头文件#include<stdlib.h>,放在game.h中。
	while (1{
		printf("电脑请下棋:";
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

玩家下一个棋,是不是要打印一下棋盘,因为不打印棋盘,就不知道下了什么棋,所以要打印棋盘;电脑也是如此,如果电脑下完不显示,玩家就不能根据形势来下棋获得胜利了。

void game()//游戏主体
{
	char board[ROW][COL];//棋盘大小,ROW为行,COL为列
	char ret = 0;
	init_board(board, ROW, COL);//初始化棋盘
	print_board(board, ROW, COL);//打印棋盘
	while (1)//这里用到for循环是因为玩家和电脑下棋,总不可能下一次棋就结束了吧!
			//待会会讲到如何跳出循环
	{
		player1_move(board, ROW, COL);//玩家1下棋
		print_board(board, ROW, COL);
		computer_move(board, ROW, COL);//电脑下棋
		print_board(board, ROW, COL);
	}
}

当然这个电脑是有点人工智障的,它不会赌棋,让电脑赢反而成为了一种难度。

判断输赢

来到了我们的结束阶段了!
有三种情况:赢、平局、游戏继续。所以我们可以写一个判断输赢的函数,返回值为字符型。

返回值为C,则游戏继续;返回值为*,则跳出循环,并输出玩家赢了;返回值为#,则跳出循环,并输出电脑赢了;返回值为P,则跳出循环,并输出平局。

void game()//游戏主体
{
	char board[ROW][COL];//棋盘大小,ROW为行,COL为列
	char ret = 0;
	init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	while (1)
	{
		player1_move(board, ROW, COL);//玩家1下棋
		print_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);//判断是否赢了的函数
		if (ret != 'C')//返回值只要不是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("玩家1赢了!\n");
	else if (ret == '#')
		printf("电脑赢了!\n");
	else if (ret == 'P')
		printf("平局!\n");
}

赢有四种方式:行、列、对角线、另一条对角线

第一种:行的判断!我们只需要判断同一行的每个元素相同就行了,当然不能等于空格!所以如下:

char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{//连续两个数相等并且不等于空格
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')
				flag++;//作为标志
			if (flag == KEY - 1)//KEY代表玩什么棋
				break;
		}
		if (flag == KEY - 1)//假如为三子棋,flag只要为2就可以赢了!,三个连成一线要判断两次
			return board[i][j - 1];
	}
}

第二种:列的判断!列的判断类似于行的判断。列不变化,行在变化。如下:

char is_win(char board[ROW][COL], int row, int col)
{
	//行的判断
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')//
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)//假如为三子棋,flag只要为2就可以赢了!,三个连成一线要判断两次
			return board[i][j - 1];
	}

	//列的判断
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[j][i] == board[j - 1][i] && board[j - 1][i] != ' ')
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[j - 1][i];
	}

第三种:对角线!对角线是有规律的,其中一个是坐标相同,另一个是行列变化1。
先讲一个对角线:如下图:

char is_win(char board[ROW][COL], int row, int col)
{   //行的判断
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')//
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)//假如为三子棋,flag只要为2就可以赢了!,三个连成一线要判断两次
			return board[i][j - 1];
	}
	//列的判断
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[j][i] == board[j - 1][i] && board[j - 1][i] != ' ')
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[j - 1][i];
	}
	//对角线的判断
	int flag = 0;//这个flag放在里面就会重新定义为0,这样flag最大只能为1了,不能为2!
	for (i = 1; i < row; i++)
	{//flag在里面的话,会重新初始化为0,最大为1,不会返回符号,就没有
	//这个对角线很方便,横纵坐标都相同。
		if (board[i - 1][i - 1] == board[i][i] && board[i - 1][i - 1] != ' ')
			flag++;
		if (flag == KEY - 1)
			return board[i][i];
	}

第四种:另一种对角线!另一种对角线有两种方式:1. 右上到左下。2. 左下到右上。
我是第一种方式,如下:

char is_win(char board[ROW][COL], int row, int col)
{	//行的判断
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')//
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)//假如为三子棋,flag只要为2就可以赢了!,三个连成一线要判断两次
			return board[i][j - 1];
	}
	//列的判断
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[j][i] == board[j - 1][i] && board[j - 1][i] != ' ')
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[j - 1][i];
	}
	//对角线的判断
	int flag = 0;//这个flag放在里面就会重新定义为0,这样flag最大只能为1了,不能为2!
	for (i = 1; i < row; i++)
	{
		
		if (board[i - 1][i - 1] == board[i][i] && board[i - 1][i - 1] != ' ')
			flag++;
		if (flag == KEY - 1)
			return board[i][i];
	}
	//另一个对角线
	flag = 0;//这个跟上面的一样
	int j = col - 1;//j如果放在里面的话就发生其它位置的元素对比,不符合对角线原则
	for (i = 1; i < row; i++)
	{//j如果放在里面的话,进行第二次循环时,i = 2, j - 1 = 1,坐标2 1不符合对角线原则
		
		if (board[i][j - 1] == board[i - 1][j] && board[i - 1][j] != ' ')
		{
			flag++;
			j--;
		}
		if (flag == KEY - 1)
			return board[i][0];
	}

赢的方式判断完了,就要判断平局了,我们把这函数就放在is_win函数中,因为这个平局函数就是为is_win函数服务的,所以不用在game.h中声明了。

static int  is_full(char board[ROW][COL], int row, int col)
{//赋予static意思是只能在game.c 文件中看到,其它文件看不到,这个函数只是为is_win函数服务的,
 //所以没必要在game.h中进行声明。
	int i = 0;//这个函数返回值为整型,只要有一个为空格,就返回0,在is_win函数中设计一个if语句
			 //如果is_full函数返回值为真,就返回P,否则不执行。
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[i][j - 1] == board[i][j] && board[i][j - 1] != ' ')//
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)//假如为三子棋,flag只要为2就可以赢了!,三个连成一线要判断两次
			return board[i][j - 1];
	}
	for (i = 0; i < row; i++)
	{
		int j = 0;
		int flag = 0;
		for (j = 1; j < col; j++)
		{
			if (board[j][i] == board[j - 1][i] && board[j - 1][i] != ' ')
				flag++;
			if (flag == KEY - 1)
				break;
		}
		if (flag == KEY - 1)
			return board[j - 1][i];
	}
	int flag = 0;//这个flag放在里面就会重新定义为0,这样flag最大只能为1了,不能为2!
	for (i = 1; i < row; i++)
	{
		
		if (board[i - 1][i - 1] == board[i][i] && board[i - 1][i - 1] != ' ')
			flag++;
		if (flag == KEY - 1)
			return board[i][i];
	}
	flag = 0;//这个flag也是一样。
	int j = col - 1;//j如果放在里面的话就发生其它位置的元素对比,不符合对角线原则
	for (i = 1; i < row; i++)
	{
		
		if (board[i][j - 1] == board[i - 1][j] && board[i - 1][j] != ' ')
		{
			flag++;
			j--;
		}
		if (flag == KEY - 1)
			return board[i][0];
	}
	int ret = is_full(board, ROW, COL);//判断平局函数
	if (ret)
		return 'P';//为真就返回P,平局
	return 'C';//上面情况都不符合,那么游戏只能继续
}

好了,这个N子棋就讲完了,我们可以在game.h中改变ROW,COL的大小,进而改变棋盘的大小;改变KEY的大小,进而决定玩什么棋,都由你决定!

双人对战只需要把电脑下棋的代码换成玩家的代码即可,然后改变一些名称,就大工完成了。

如果这个文章对你有所帮助的话,请你点个赞,谢谢!!!
^ _ ^

位卑未敢忘忧国,事定犹须待阖棺。—陆游《病起书怀》

上善若水


http://www.niftyadmin.cn/n/15338.html

相关文章

Vue | 有关Vue2路由知识点的一些总结,以及Vue3路由做出了哪些调整?

目录 Vue2: 1. 路由&#xff1a; 2. 路由规则&#xff1a; 3. 实现切换&#xff08;active-class可配置高亮样式&#xff09; 4. 指定展示位置 5. 路由的query参数 6. params传参&#xff1a; 7. 多级路由 8. 路由的props配置 9. 的replace属性 10. 编…

UE在TextRender上显示中文文本

文章目录 1.实现目标2.实现过程2.1 添加字体2.2 创建字体材质2.3 将字体应用到TextRender3.参考资料1.实现目标 UE的UMG可以正常支持中文,但是TextRender并不支持中文,因此需要添加本地离线中文字体库,使TextRender显示中文。 2.实现过程 2.1 添加字体 (1)选择User Int…

C++经典题目

目录 P62 3.6 求圆周长面积 P80 3 华氏转摄氏 P80 10 分段函数 P81 21 数列求和 P82 24 打印图形 P229 6 长方体体积 P384 4 printArea 题目来源于C程序设计&#xff08;第4版&#xff09; P62 3.6 求圆周长面积 设圆半径r1.5&#xff0c;圆柱高h3&#xff0c;求圆周长…

Java_笔记_多态_包_final_权限修饰符_代码块

封装&#xff1a;对象代表什么&#xff0c;就得封装对应的数据&#xff0c;并提供数据对应的行为。 一、多态&#xff1a;对象的多种形态。同类型的对象&#xff0c;表现出的不同形态。 1.多态的表现形式&#xff1a;父类类型 对象名称 子类对象; 学生形态 对象 Student s …

Unity Cg着色器开发教程

Unity Cg着色器开发教程 学习在 Unity 中对图形管道进行编程&#xff0c;以便为游戏对象创建独特的视觉表面 课程英文名&#xff1a;Shader Development from Scratch for Unity with Cg 此视频教程共2.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c…

StarRocks技术内幕 | 打造一款强大成熟的数据库有多难?

作者&#xff1a;康凯森&#xff0c;StarRocks PMC&#xff0c;负责查询方向的研发&#xff08;本文转自其个人博客“编程小梦”&#xff09; 从 2015 年开始&#xff0c;我在美团先后维护和研发过 Apache HBase、Apache Kylin、Apache Druid 和 Apache Doris&#xff0c;对大…

全面上新!阿里 2023 版(Java 岗)面试突击手册,Github 已标星 37K

程序员面试背八股&#xff0c;几乎已经是互联网不可逆的一个形式了。自从面试**八股文火了之后&#xff0c;网上出现了不少 Java 相关的面试题&#xff0c;很多朋友盲目收集背诵&#xff0c;**但网上大部分的面试题&#xff0c;大多存在这几个问题&#xff1a;第一&#xff0c;…

Python对json的操作总结

Json简介&#xff1a;Json&#xff0c;全名 JavaScript Object Notation&#xff0c;是一种轻量级的数据交换格式。Json最广泛的应用是作为AJAX中web服务器和客户端的通讯的数据格式。现在也常用于http请求中&#xff0c;所以对json的各种学习&#xff0c;是自然而然的事情。 J…