Screeps 第一周小结

从2月18日购买screeps至今已经有近一周了,写些东西备忘。

当初听说有这样的编程游戏还激动了好一阵子,可惜我太菜,犹豫了好久才下的单。

为了玩screeps,寒假还特意学了点js。还好js的语法与c差不多。

(顺便一提,js的箭头函数和弱变量类型是真的舒服,但也经常会有些奇怪的操作,总之很迷)

Picture from Johnson

人生第一次把api文档啃得那么仔细,为了建个能跑的脚本还反复过了好几遍的教程。

几天后的版本便能自动挖矿、升级、修路、刷墙了。

还在我的家(E17N28)击败了第一个侵略者,并收获了它的遗产。

甚至拓展了第二间room,开启了外矿之路。

感觉还是挺自豪的……

直到有人拆了我隔壁邻居的家,强占了他的room。

一看rcl等级,才3,不过如此——我都上5了。

碰巧敌人的防御creep是个憨憨。

这仇,必须得报。

进攻废了点功夫,不过,我还是占领了第三间room。

敌人被我赶跑,缩在自己老巢。

(有一说一,那个老巢地势真的好,易守难攻,我当初咋就没看见呢……E17N29)


夜深了,

我心满意足地睡觉去了……

第二天醒来,

发现家没了。

。。。

顿时人比前一天抽胡桃专武时歪了天空枪还难受……

。。。

好吧,一样难受。。。

我的家啊。。。


赶紧调录像,发现是我代码的一个逻辑bug。

当占领的room里的creep不断被干掉时,我的家会不断刷新creep。

导致自己把自己饿死了……

事前也想到过这种情况,但没想到的是,紧急搬运能量的creep也会由于能量不够,造不出来……

明明storage里还有300K的能量啊……

如果发现了这个问题,,

如果昨晚没为了进攻隔壁而把自家刷了好久的wall改建成rampart,,

如果睡前给新room开个安全模式,,

如果之前记得设置了自动安全模式打开机制,,

如果当时没贪、没懒,,

如果……


一个小bug或许短时间不会暴露出来,但一连串的小bug能拆了一个家。

这或许正是这个游戏的挑战之处。

毕竟coding一时爽,一直coding一直爽,debug火葬场。

总结教训:

在没有足够把握时,还是默默刷墙吧。

我的编程技巧暂时还支撑不起这个游戏。

这个寒假暂时退坑了。

厚积,薄发。

回顾2020 展望2021

终日乾乾,夕惕若厉

第一次选考

国科大冬令营 物之道 北方的冬天

疫情 停课 腾讯课堂 知乎

王裔平 铭校

作文素材 英语好词 apple的笔记

数海漫游 数学网课 模拟卷

汽车 公路 逆风而行 高楼蝼蚁

英语练字 5楼教室 乐正绫 地铁工地 远方

天命

憨憨的 傻不拉叽的 脸 手 颈 毕业了

租借女友 裸考的物理 迟到的高考

三一 鄞中 上海 复旦

国科大 分别 家 宿舍

孤月 大学生

深秋 落叶 初雪 寒风 卷

深夜 教学楼 操场 球

教室 寝室 食堂

消愁

原神 安柏 刻晴 胡桃

跨年 人类一败涂地


Flag

1. 11点前不打游戏,11点后不吃东西

2. 自习去教学楼或图书馆

3. 1点半前必须上床,睡前刷牙,睡时锁手机

4. 最晚10点起床,必须吃早餐

5. 不要活在过去的影子之中,学会反省,学会思考

0. 终日乾乾,夕惕若厉。自律,慎独,不自欺。


贪吃蛇 – 100行版本

简介

高一时受学校图形计算器上原装贪吃蛇程序启发而写的C++小游戏

高三时整理压缩至100行

代码

//By Eric Jin 2018     编译后切换至英文  a左d右w上s下       使用了Sleep() _kbhit() _getch() system("cls")等
#include <iostream> 
#include <sstream>
#include <string>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
std::string o(int i)//4左6右8上2下
{
	if (i == 0) return "  ";
	else if (i == 1) return "# ";
	else if (i == 3) return "$ ";
	else return "* ";
}
void drawmap(int h, int l, int maptest[100][100])//绘图
{
	std::stringstream ss;
	for (int i = 1; i <= h; i++)
	{
		for (int j = 1; j <= l; j++) ss << o(maptest[i][j]);
		ss << std::endl;
	}
	std::string out = ss.str();
	system("cls");
	std::cout << out;
}
void findfood(int maptest[100][100], int& foodx, int& foody, int h, int l)//出食物
{
	for (;;)
	{
		srand((int)time(0));
		foodx = rand() % h + 1, foody = rand() % l + 1;
		if (maptest[foodx][foody] == 0) break;
	}
}
int gamein()
{
	int speed, h = 20, l = 30, tail = 6, maptest[100][100], x = h / 2, y = l / 2, tx = h / 2, ty = l / 2 - tail, foodx, foody, dir = 6, tdir = 6, food = 0;
	bool skip = 0;
	std::cout << "Speed (100-slow 50-medium 10-fast):" << std::endl;
	std::cin >> speed;
	Sleep(500);
	system("cls");
	for (int i = 1; i <= h; i++)//设置边界
	{
		for (int j = 1; j <= l; j++)
		{
			maptest[i][j] = 0;
			if (i == 1 || i == h) maptest[i][j] = 1;
		}
		maptest[i][1] = 1, maptest[i][l] = 1;
	}
	for (int i = ty + 1; i <= y; i++) maptest[x][i] = 6;
	findfood(maptest, foodx, foody, h, l);
	maptest[foodx][foody] = 3;
	drawmap(h, l, maptest);
	for (;;)
	{
		maptest[x][y] = dir;
		x = (dir == 2) ? (x + 1) : (dir == 8 ? x - 1 : x), y = (dir == 6) ? (y + 1) : (dir == 4 ? y - 1 : y);
		if (maptest[x][y] == 0 || maptest[x][y] == 3) maptest[x][y] = dir;
		else
		{
			std::cout << std::endl << "You died." << std::endl << "Score: " << food << std::endl << "Speed: " << speed << std::endl;
			std::cout << "0:exit" << std::endl;
			std::cout << "1:new game" << std::endl;
			char in1 = _getch();
			std::cout << std::endl;
			if (in1 == '0') return 0;
			else return gamein();
		}
		if (skip == 0)
			tx = (tdir == 2) ? (tx + 1) : (tdir == 8 ? tx - 1 : tx), ty = (tdir == 6) ? (ty + 1) : (tdir == 4 ? ty - 1 : ty), tdir = maptest[tx][ty];
		else skip = 0;
		maptest[tx][ty] = 0;
		drawmap(h, l, maptest);
		std::cout << "Score: " << food << std::endl << "Speed: " << speed << std::endl;
		Sleep(speed);
		if (_kbhit() != 0)
		{
			int in = _getch();
			if (in == 97 && dir != 4 && dir != 6) dir = 4;
			if (in == 115 && dir != 2 && dir != 8) dir = 2;
			if (in == 119 && dir != 2 && dir != 8) dir = 8;
			if (in == 100 && dir != 4 && dir != 6) dir = 6;
		}
		if (x == foodx && y == foody)
		{
			food++;
			findfood(maptest, foodx, foody, h, l);
			maptest[foodx][foody] = 3;
			skip = 1;
		}
	}
}
int main()
{
	return gamein();
}

图片

五子棋 – 人机对战

简介

高一时第一次接触了C++,心血来潮编了几个诸如推箱子、贪吃蛇、俄罗斯方块的小游戏。

觉得不过瘾,碰巧那会儿班里流行五子棋,便着手于编一个人机对战程序。

碍于编程知识不足,算法只用了判断、循环。借助easyx的图形库,它有了图形界面。

最终版本经调查测试,实力优于初学者,并能与中等水平者相抗衡。

(反正我被他阴了好多次,不知是该笑还是该哭(▼皿▼#) )

基本思路

敌方每下一子,就在一个计数的矩阵里自己那格的四周(横竖撇捺四个方向,正负各延伸四格)加上个数值。这个加上的数值随与敌方所下子的距离而变。

不妨命名一个点的累积值为,下子使周围改变的效果为

己方下的子同理,但所给的是反向的(即所增加的值为负值)。

用四个矩阵分别记录来自四个方向的和相应积累的,互不干扰。

最终己方落子的判断依据来源于所有方向的绝对值的总和,取绝对值的总和最大的点落子。

算法原理很简单,说白了就是赋值再取极值的贪心算法,但至于怎么赋值还是有点讲究的。

初始版本里采用了1-1-1-1赋值法(就是那个加上的值不随与上一落子的距离而变),并且没有加入四方向绝对值相加的机制,导致算法的最终行为很玄学

它居然自动解锁了八卦阵技能,在连活三都不会防的情况下。(⊙_⊙)

升级版本采用了4-3-2-1赋值法,并延续到了最终版本。至此,它学会了如何防双三、三四等局面。

最终版本里又加入了遇四就堵的功能,但已经丧失了初始版本“两仪生四象,四象生八卦”的睿智。

废话讲完了,下面是代码

代码

#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "winspool")
#pragma comment(lib, "comdlg32")
#pragma comment(lib, "advapi32")
#pragma comment(lib, "shell32")
#pragma comment(lib, "ole32")
#pragma comment(lib, "oleaut32")
#pragma comment(lib, "uuid")
#pragma comment(lib, "odbc32")
#pragma comment(lib, "odbccp32")
#include <graphics.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>

int plotform(int x)
{
	return 25 * (x - 1) + 15;
}

int storgeform(int x)
{
	return (x - 15) / 25 + 1;
}

class whom
{
public:
	int value;//1 or -1
	COLORREF color;//BLACK or WHITE
};

void changeplayer(whom& whom)
{
	whom.value = whom.value*(-1);
	if (whom.value == 1)
		whom.color = BLACK;
	else
		whom.color = WHITE;
}

void drawmap(int map[][20])
{
	int xwidth = 480, ywidth = 480;
	initgraph(xwidth, ywidth);
	setbkcolor(YELLOW);
	cleardevice();
	setlinecolor(LIGHTGRAY);
	for (int i = 15; i <= ywidth - 15; i = i + 25)
		line(15, i, xwidth - 15, i);
	for (int j = 15; j <= xwidth - 15; j = j + 25)
		line(j, 15, j, xwidth - 15);
	setfillcolor(LIGHTGRAY);
	for (int i = 4; i <= 16; i = i + 6)//both i & j are storgeform
	{
		for (int j = 4; j <= 16; j = j + 6)
		{
			solidcircle(plotform(i), plotform(j), 5);
		}
	}
}

void human(int& x, int& y, int&xq, int& yq, whom& whom, int map[][20])//both x & y are storgeform 
{
	MOUSEMSG a;
	do
	{
		do
		{
			a = GetMouseMsg();
		} while (a.mkLButton == 1);
		do
		{
			a = GetMouseMsg();
		} while (a.mkLButton == 0);
		xq = x;
		yq = y;
		x = round(((double)a.x - 15) / 25) + 1;
		y = round(((double)a.y - 15) / 25) + 1;
		/*if (getpixel(plotform(x),plotform(y)) == LIGHTGRAY)
			break;*/
		if (map[x][y] == 0)
			break;
	} while (1);
}

void record(int x, int y, whom whom, int map[][20], int maprecord[][20][20])//for robot
{
	for (int i = 1; i <= 4; i++)
	{
		int dx, dy;
		switch (i)
		{
		case 1:dx = 1, dy = 0; break;
		case 2:dx = 0, dy = 1; break;
		case 3:dx = 1, dy = -1; break;
		case 4:dx = 1, dy = 1; break;
		}
		for (int j = -4; j <= 4; j++)
		{
			if (1 <= x + dx * j&&x + dx * j <= 19 && 1 <= y + dy * j&&y + dy * j <= 19 && map[x + dx * j][y + dy * j] == 0)
			{
				maprecord[i][x + dx * j][y + dy * j] = maprecord[i][x + dx * j][y + dy * j] + whom.value*abs(5 - abs(j));
			}
		}
	}
}

void chong4(int x, int y,whom whom, int map[][20],int coordinate[3])//map[x][y]==whom.value
{
	for (int i = 1; i <= 4; i++)
	{
		int dx, dy;
		switch (i)
		{
		case 1:dx = 1, dy = 0; break;
		case 2:dx = 0, dy = 1; break;
		case 3:dx = 1, dy = -1; break;
		case 4:dx = 1, dy = 1; break;
		}
		int m = 0, n = 0, skip = 0;
		coordinate[0] = 0;
		coordinate[1] = -1;
		coordinate[2] = -1;
		for (int j = 1;; j++)
		{
			if (x + j * dx < 1 || x + j * dx>19 || y + j * dy < 1 || y + j * dy>19)
				break;
			if (map[x + j * dx][y + j * dy] == whom.value)
			{
				m = m + 1;
				if (skip > 0)
					skip++;
			}
			else if (skip == 0 && map[x + j * dx][y + j * dy] == 0)
			{
				skip = 1;
				coordinate[1] = x + j * dx;
				coordinate[2] = y + j * dy;
			}
			else if (skip > 1)
			{
				coordinate[0] = 1;
				break;
			}
			else
				break;
		}
		if (coordinate[0] == 1)
			skip = 1;
		else
			skip = 0;
		for (int j = -1;; j--)
		{
			if (x + j * dx < 1 || x + j * dx>19 || y + j * dy < 1 || y + j * dy>19)
				break;
			if (map[x + j * dx][y + j * dy] == whom.value)
			{
				n = n + 1;
				if (skip > 0)
					skip++;
			}
			else if (skip == 0 && map[x + j * dx][y + j * dy] == 0)
			{
				skip = 1;
				coordinate[1] = x + j * dx;
				coordinate[2] = y + j * dy;
			}
			else if (skip > 1)
			{
				coordinate[0] = 1;
				break;
			}
			else
				break;
		}
		if (m + n >= 3&&coordinate[1]!=-1)
		{
			coordinate[0] = 2;
			settextcolor(whom.value == 1 ? RED : BLUE);//used for debug
			outtextxy(plotform(coordinate[1]), plotform(coordinate[2]), 'x');
			return;
		}
	}
}

void robot(int& x, int& y, int& xq, int& yq, whom& whom, int map[][20], int maprecord[][20][20])//both x & y are storgeform 
{
	int max = -1;
	changeplayer(whom);
	record(x, y, whom, map, maprecord);
	changeplayer(whom);

	int coordinate[3];
	chong4(xq, yq, whom, map, coordinate);
	if (coordinate[0] == 2)
	{
		xq = x;
		yq = y;
		x = coordinate[1];
		y = coordinate[2];
		record(x, y, whom, map, maprecord);
		return;
	}
	changeplayer(whom);
	chong4(x, y, whom, map, coordinate);
	if (coordinate[0] == 2)
	{
		xq = x;
		yq = y;
		x = coordinate[1];
		y = coordinate[2];
		changeplayer(whom);
		record(x, y, whom, map, maprecord);
		return;
	}
	changeplayer(whom);

	for (int i = 1; i <= 19; i++)
	{
		for (int j = 1; j <= 19; j++)
		{
			if (map[i][j] == 0)
			{
				int potential[5];
				for (int p = 1; p <= 4; p++)
				{
					potential[p] = maprecord[p][i][j];
					if (abs(potential[p]) >= 5)
						potential[p] = potential[p] * 2;
					if (abs(potential[p]) >= 18)
						potential[p] = potential[p] * 2;
				}
				int all = abs(potential[1]) + abs(potential[2]) + abs(potential[3]) + abs(potential[4]);
				if (all > max)
				{
					max = all;
					xq = x;
					yq = y;
					x = i;
					y = j;
				}
				if (all == max && rand()%100 <= 60)
				{
					max = all;
					xq = x;
					yq = y;
					x = i;
					y = j;
				}
			}
		}
	}
	record(x, y, whom, map, maprecord);
}

void drawpiece(int x, int y, whom& whom, int map[][20])//both x & y are storgeform 
{
	setfillcolor(whom.color);
	solidcircle(plotform(x), plotform(y), 10);
	map[x][y] = whom.value;
	changeplayer(whom);
}

int main()
{
	int map[20][20] = { 0 };
	int maprecord[5][20][20] = { 0 };
	whom whom;
	whom.color = BLACK;
	whom.value = 1;
	int x, y, xq, yq;
	drawmap(map);
	do
	{
		if (whom.value == 1)
			human(x, y,xq,yq, whom, map);
		else
			robot(x, y, xq, yq, whom, map, maprecord);
		drawpiece(x, y, whom, map);
	} while (1);
	_getch();
	closegraph();
}

图片

LNMP环境下,利用Nginx反代Wikipedia

前记

之前一直使用ShadowsocksR代理网络,但是这需要安装软件,还是很麻烦的。

考虑到访问外网的主要需求为维基百科,所以就着手于制作一个维基镜像站。

了解到一共有两种方法,分别为通过Kiwix访问本地存储的ZIM文件通过Nginx反代wikipedia.org

前者不仅时效性差还需要占用大量空间,对于我寒酸的服务器来说是个大问题,因此采用了第二个方案。

特别感谢Johnson的指点、网上大佬们的教程,才有了如今这个维基镜像站。

准备

  1. 一台港澳台或国外的VPS
  2. Linux系统(笔者使用的是Ubuntu 18.04 LTS
  3. LNMP环境(笔者使用的是LNMP 1.6,安装详见LNMP官网

教程

1. 为已安装的LNMP编译ngx_http_substitutions_filter_module模块

下载ngx_http_substitutions_filter_module模块

cd /root
git clone "https://github.com/yaoweibin/ngx_http_substitutions_filter_module.git"

编辑lnmp.conf文件

vim /root/lnmp1.6/lnmp.conf

Nginx_Modules_Options一项后的单引号间添加 --add-module=/root/ngx_http_substitutions_filter_module

查看Nginx版本号

nginx -V

安装ngx_http_substitutions_filter_module模块

cd /root/lnmp1.6
./upgrade.sh

选择Update Nginx

Current Nginx Version中输入你当前的Nginx版本号

不停回车即可

编译结束时,输入nginx -V检查编译

你将看到--add-module=/root/ngx_http_substitutions_filter_module

2.添加vhost

确保相关域名已添加至你的DNS解析服务商

以本站为例,分别为:

wiki.ericdrive.ml

*.wiki.ericdrive.ml

实际使用的为:

wiki.ericdrive.ml

lang.wiki.ericdrive.ml

lang.m.wiki.ericdrive.ml

up.wiki.ericdrive.ml

注意:

ericdrive.ml替换成你自己的域名

lang替换为你希望添加的维基语言,如enzh分别对应英文中文维基,下同

新建配置文件

lnmp vhost add

依次添加

wiki.ericdrive.ml
lang.wiki.ericdrive.ml
lang.m.wiki.ericdrive.ml
up.wiki.ericdrive.ml

路径默认即可

n直到出现Add SSL Certificate (y/n) 一项,选y

1: Use your Own SSL Certificate and Key 
2: Use Let's Encrypt to create SSL Certificate and Key 
Enter 1 or 2:

然后填2

完成配置即可

3.编辑配置文件

配置wiki.ericdrive.ml.conf

vim /usr/local/nginx/conf/vhost/wiki.ericdrive.ml.conf

用以下代码覆盖原文件

注意:

ericdrive.ml替换成你自己的域名

server {
    server_name up.wiki.ericdrive.ml;
    listen 80;
    listen 443 ssl http2;
    resolver 8.8.8.8;
#    resolver 127.0.0.1 valid=30s;

    ssl_certificate /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/fullchain.cer;
    ssl_certificate_key /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/wiki.ericdrive.ml.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
    ssl_session_cache builtin:1000 shared:SSL:10m;
    # openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
    ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
    
    if ($http_x_forwarded_proto = 'http')
    {
        return 301 $server_name$request_uri;
    }

    location / {
        proxy_pass https://upload.wikimedia.org;
        proxy_cookie_domain upload.wikimedia.org up.wiki.ericdrive.ml;
        proxy_buffering off;
        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header referer "https://upload.wikimedia.org$request_uri";
    }
}

server {
    server_name  wiki.ericdrive.ml;
    listen 80;
    listen 443 ssl http2;
    resolver 8.8.8.8;

    ssl_certificate /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/fullchain.cer;
    ssl_certificate_key /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/wiki.ericdrive.ml.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
    ssl_session_cache builtin:1000 shared:SSL:10m;
    # openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
    ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
    
    if ($http_x_forwarded_proto = 'http')
    {
        return 301 $server_name$request_uri;
    }

    location / {
        proxy_pass https://www.wikipedia.org;
        proxy_buffering off;

        proxy_redirect https://www.wikipedia.org/ http://wiki.ericdrive.ml/;
        proxy_cookie_domain www.wikipedia.org wiki.ericdrive.ml;
        proxy_redirect ~^https://([\w\.]+).wikipedia.org/(.*?)$ http://$1.wiki.ericdrive.ml/$2;

        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header Accept-Encoding '';
        proxy_set_header referer "https://$proxy_host$request_uri";

        subs_filter_types text/css text/xml text/javascript application/javascript application/json;
        subs_filter .wikipedia.org .wiki.ericdrive.ml;
        subs_filter //wikipedia.org //wiki.ericdrive.ml;
        subs_filter upload.wikimedia.org up.wiki.ericdrive.ml;
    }
}

server {
    server_name  ~^(?<subdomain>[^.]+)\.wiki\.ericdrive\.ml$;
    listen 80;
    listen 443 ssl http2;
    resolver 8.8.8.8;

    ssl_certificate /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/fullchain.cer;
    ssl_certificate_key /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/wiki.ericdrive.ml.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
    ssl_session_cache builtin:1000 shared:SSL:10m;
    # openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
    ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
    
    if ($http_x_forwarded_proto = 'http')
    {
        return 301 $subdomain.wiki.ericdrive.ml$request_uri;
    }

    location / {
        proxy_pass https://$subdomain.wikipedia.org;
        proxy_buffering off;

        proxy_redirect https://$subdomain.wikipedia.org/ http://$subdomain.wiki.ericdrive.ml/;
        proxy_redirect https://$subdomain.m.wikipedia.org/ http://$subdomain.m.wiki.ericdrive.ml/;
        proxy_cookie_domain $subdomain.wikipedia.org $subdomain.wiki.ericdrive.ml;
        proxy_redirect ~^https://([\w\.]+).wikipedia.org/(.*?)$ http://$1.wiki.ericdrive.ml/$2;

        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header Accept-Encoding ''; 
        proxy_set_header referer "https://$proxy_host$request_uri";

        subs_filter_types text/css text/xml text/javascript application/javascript application/json;
        subs_filter .wikipedia.org .wiki.ericdrive.ml;
        subs_filter //wikipedia.org //wiki.ericdrive.ml;
        subs_filter 'https://([^.]+).wiki' 'http://$1.wiki' igr; 
        subs_filter upload.wikimedia.org up.wiki.ericdrive.ml;
    }
}

server {
    server_name ~^(?<subdomain>[^.]+)\.m\.wiki\.ericdrive\.ml$;
    listen 80;
    listen 443 ssl http2;
    resolver 8.8.8.8;

    ssl_certificate /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/fullchain.cer;
    ssl_certificate_key /usr/local/nginx/conf/ssl/wiki.ericdrive.ml/wiki.ericdrive.ml.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
    ssl_session_cache builtin:1000 shared:SSL:10m;
    # openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
    ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
    
    if ($http_x_forwarded_proto = 'http')
    {
        return 301 $subdomain.m.wiki.ericdrive.ml$request_uri;
    }

    location / {
        proxy_pass https://$subdomain.m.wikipedia.org;
        proxy_buffering off;

        proxy_redirect https://$subdomain.m.wikipedia.org/ http://$subdomain.m.wiki.ericdrive.ml/;
        proxy_cookie_domain $subdomain.m.wikipedia.org $subdomain.m.wiki.ericdrive.ml;

        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header Accept-Encoding ''; 
        proxy_set_header referer "https://$proxy_host$request_uri";

        subs_filter_types text/css text/xml text/javascript application/javascript application/json;
        subs_filter .wikipedia.org .wiki.ericdrive.ml;
        subs_filter //wikipedia.org //wiki.ericdrive.ml;
        subs_filter 'https://([^.]+).m.wiki' 'http://$1.m.wiki' igr; 
        subs_filter upload.wikimedia.org up.wiki.ericdrive.ml;
    }
}

4.重启Nginx

lnmp nginx restart