分类:Tech

“斗地主”残局的对抗搜索算法

“斗地主”残局的对抗搜索算法

Adversarial Search Algorithm on Chinese Poker Game

许久未打开手机斗地主,前日登录发现新增“残局”模式,便思考尝试编程给出解法。搜索网络上相关资料较少,去重后仅找到两个简单的Python实现,其一仅能判断必胜策略的存在性,另一给出了低效的简单实现,且牌型的支持不够完整,对于一个简单残局的运算耗时五分钟,相比下本文的C++多线程实现仅耗时数秒且复用对象减少内存消耗。

对抗搜索 Adversarial Search

        斗地主残局双方明牌,玩家作为地主方先出。完全信息,有限步数(手牌数有限,打完结束),符合策梅洛定理,且显然没有平局,双方必有一方有必胜策略。至于如何暴力搜索,此处非常符合“对抗搜索”的应用范围,即MinMax算法。某本书的一部分介绍得很清晰,很有帮助。

        放在双人斗地主的场景中来说,这意味着在每一次出牌时,玩家都会选择打出对自己最有利的一手牌,打出对对方最不利的一手牌。而这是一个零和博弈,每种出牌最终都会导致一个二选一的结果——地主赢(我们认为该节点得分为1)或农民赢(得分-1)。地主轮将努力最大化分值,从众多分支中挑分值最大的一个,并将其作为当前节点的分值;相应的,农民轮将从众多分支中挑分值最小的作为当前节点的分值。显然,地主要想有必胜策略,根节点得分需要为1 。

        至此,该问题已可以完全地用MinMax算法表述出来并简单地得到解决框架:状态为地主、农民手牌;地主/农民步骤函数根据状态计算出后续可能的状态(出牌型);一方手牌为空时该节点为叶子结点,得到结果分值;获取分值函数递归计算节点分值。借用资料中伪代码阐释:

MinMax算法伪代码

        至此,判断必胜策略的存在性问题已得到理论解决。关于保存步骤以供回溯,我选择在Action(s)函数中顺便构建状态树作为一个搜索时的副作用。当求得根节点分值的同时状态树已构建完成。

实现

        细节请参考文末附带的源码,以下为实现中粗略的一些要点。

树结构设计(Node)

  • layer 当前节点深度,根节点为0
  • score 当前节点分值,默认为0
  • move 上一步牌型
  • lord 当前地主手牌
  • farmer 当前农民手牌
  • children 子节点(们)
  • parent 父节点

        其中所有非标量对象均为指向堆上对象的指针。结构体包含一个析构函数,用以析构children指向的堆上的一个std::vector<Node*>对象。

对象复用

        斗地主可能出牌策略的规模在N!级别,考虑双人游戏,规模可达N!M!级别。若独立创建对象,极其容易栈溢出、占满内存。因此我实现了两个对象池,有效缓解了空间压力,分别用以储存出牌牌型、手牌。

牌型池

  • std::unordered_map
  • 牌型组成的vector(sorted)作为Key,boost::hash_range作为自定义hash
  • shared_mutex线程安全

        牌型池的效果应是最明显的,因为全局牌型总量在第一层便应被固定了,此后只减不增。复用后全局牌型对象一般维持在20~30个。

手牌池

  • std::unordered_map
  • std::vector<uint8_t>作为Key(后附解释),复用牌型池的hash
  • shared_mutex线程安全

Key uint8_t 算法:手牌对象储存结构为std::map,key为牌面大小,value为该牌数量。牌面大小数值为3~18(出于方便计算顺子的缘故,中间有空缺),而牌数最多支持两副,每张牌最多八张,为1~8 。故uint8_t高五位储存牌面,低3位储存数量。

手牌池的设计修改了很多次,最终采用了这个方法。由于决策树不深(最大深度应为两者牌数相加M+N),vector不会很大。使用后再未出现过内存不足、栈溢出甚至蓝屏的情况,最大内存使用量目前在10GB左右,一般在1GB左右。

剪枝

        由于决策树是一颗深度有限,但广度扩展较广的树,因此保留MinMax算法的递归结构,对栈压力较小。出于效率考虑,设法对其进行剪枝。考虑到应用场景为双人明牌斗地主,玩家(地主)先出,进行如下剪枝:

  • 对于某一次出牌产生的节点,若进行该行动的玩家行动后手牌为空,则该节点作为其父节点的唯一子节点也是叶子结点并立即返回上一层递归(当能一次出完牌时,没有理由出其他牌);
  • 对玩家(地主)而言,对于对方每一次出牌,玩家只需知道唯一一个有必胜策略的应对方式即可。因此遍历玩家可能的策略时,若子节点分值不为1则删除(见LumberJack节)子树,若子节点分值为1则该子树为其父节点的唯一子树,并立即break并删除所有其他子节点。这能使问题规模下降到最乐观情况下M!(此处配合另一处细节,见其他优化节);
  • 对农民的非叶子节点不应予以剪枝。

多线程

        尝试使用多线程充分利用计算资源,加速计算。对于这一本质上类似深度优先搜索的问题,采用了较为简单的“划分问题子空间”的方法。又考虑到需控制线程数量以免导致性能下降,故选取农民的第一步可能的出牌作为子空间划分点。选择一层划分的优点在于在“Reduce”最终获得的结果时,由于使用了std::future,在前面获得了确认分值的结果时,迭代可以直接break并返回上一层递归调用,而由后台进程继续构建其他尚未构建完成的子树(此处再次涉及到其他优化一节的设计)。

        多线程后计算中四核八逻辑处理器CPU可以跑满。相应计算时长降低到原1/4到1/8 。

LumberJack

        之前在剪枝一节中提到了玩家决策过程中删除非必要子树。此过程删除的子树数量较多、大小较大,采用了递归算法删除;于搜索过程中删除较为耗时,且删除子树行为本身不对搜索过程产生副作用,因此想到开后台线程删除;然而直接开线程挤占计算线程的资源,更拖慢了效率。于是构建了一个“伐木工”类,实现了一个“多生产者,单消费者”的模型。将欲删除的子树的根节点丢到任务队列,由该单线程循环获取任务并进行删除,有效降低了计算资源挤占,提高了速度。基本实现如下:

  • std::queue 任务队列
  • std::mutex + std::condition_variable 保障线程安全
  • 公开的AddTask函数,为线程安全的queue的push函数wrapper
  • 永续循环(想不到代替死循环的词了,想起了”永续年金”……)的Worker函数

其他优化

        最后一个出于提高剪枝效率考虑的设计在GetAllSolution(获取所有可能的出牌牌型)函数上。剪枝中提前返回的逻辑在最差情况下事实上是无法降低时间复杂度的,只能事后诸葛地降低空间复杂度。如何尽量避免最差情况呢。我尝试在获取出牌牌型时将长牌型(如顺子、连对)的搜索结果放置于前,短牌型(如单牌、对子)放置于后,使得遍历搜索结果时先尽量多出牌,使得先遍历的树深度、广度都较小,也较为偏向人类思考方式(先想着多出长牌型),提高剪枝的优化效果。

代码

https://github.com/Whotakesmyname/ChinesePokerGame

代码已托管于Github,并提供Windows下64位预编译的Release,欢迎Issue/Fork/Star。由于是个人第一个较完整的C++项目,代码可能较脏,欢迎指正。

之前有“Triggered a Breakpoint”Bug出现(Release版本下表现为闪退),但未能找到原因,修改了一些实现后再未出现过。

编译时请注意:该程序使用了boost库。

效率与资源占用

环境:

  • CPU:Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz
  • 内存:DDR3 24G

运行时中等问题内存占用1G以下,2秒以下解出;偶现高复杂度问题(手牌多,单牌多;欢乐斗地主专家级前38关中出现2-3次)需要约10G内存,耗时30秒-1分钟。

站点、MYSQL跨服务器迁移及申请泛域名SSL证书并向HTTPS迁移

站点、MYSQL跨服务器迁移及申请泛域名SSL证书并向HTTPS迁移

花了一个通宵完成了个人站点、博客、数据库的迁移并且全站到CDN、对象存储都上了HTTPS。然而找性价比高的服务商花了一个月。贫穷是原罪。

最终找到的是腾讯云的服务,发现还有学生体验名额?果断买了一年……独立1C2G1M¥10/M还要什么自行车,配上¥3/M的乞丐版独立MYSQL数据库虽然种种功能都不对我开放但我好歹把MYSQL请了出去。

记正题。新服务器为了省心采用了著名的LNMP安装包,时下最新1.5稳定版。单作客户端无需安装MYSQL,使用PHP7.2。下载安装时间都稍长,建议在tmux或screen等辅助下进行以便(ssh session)断线重连。静态站点迁移就是想办法复制文件夹到新目的地。Wordpress站点也并无太大差别,大可放心迁移。

数据库迁移稍显麻烦。腾讯云提供了数据迁移功能奈何乞丐版无法使用。phpMyadmin提供的导入选项文件不超过2M属实鸡肋。最终采用在原始主机上使用mysqldump命令序列化指定数据库为sql文件,再连接远程数据库source进去的方法实现。需要注意的是为了避免编码问题,尽管查看了dump下来的sql文件包含了创建同名数据库语句,但我仍事先手动建立了utf8编码数据库,use之后进行的source。虽然结果可能没有什么差别。

之后远程连接数据库为Wordpress建立一个账户,只对目标数据库grant所有权限。在Wordpress目录下wp-config中修改database host、database username和database password(这几个变量好像叫这个名字……总之进去一看就认出来了)。需要说明的是这里的host测试下是可以带端口的,即ip:port格式。

回到LNMP设置。接下来配置Nginx及申请泛域名证书并上HTTPS。泛域名证书属实昂贵,但开源界提供了应该是全球唯一的一个乞丐之选,Let’s Encrypt。唯一的缺点是有效期仅三个月,我刚申请完导入到腾讯云证书管理它就提示我“即将过期”……不过无妨,申请过程基本实现了全自动化,可以自动续期。

我拥有darkray.cn域名,目前公开使用的二级域名有blog.darkray.cn、wx***.darkray.cn(API用途)、www。思路是除去API不动,blog单指向博客,其他包括一级域名全部解析到个人主页上去,且除API,其余全部使用泛域名一张证书,也方便管理。那么流程是首先给泛域名申请证书,之后将证书放在blog上使用。

尝试了LNMP在新建虚拟主机(vhost add)时是不能申请泛域名证书的。

    1. 首先需要参考LNMP.org关于申请Let’s Encrypt泛域名证书的说明,获取你域名DNS服务商的API密钥,并按说明export到环境中。腾讯的是DNSPod+。必须使用lnmp dnsssl [DNS服务商简称如dp]命令先为泛域名申请证书,该命令似乎同时会添加虚拟主机。主域名darkray.cn,其他域名*.darkray.cn。申请完成后nginx配置也应完成,可以自行修改Nginx vhost conf添加301http强制跳转规则。

  1. 之后使用lnmp vhost add添加其他虚拟主机,SSL证书一步选择自行添加证书,证书应填写fullchain.cer路径,密钥为domain.key的路径。设置完成后同样可自行修改conf添加HTTP301跳转HTTPS规则。

All done.

VS Code Latex-Workshop中Texcount无法运行的解决方案

VS Code Latex-Workshop中Texcount无法运行的解决方案

有一段时间之前遇到的问题了,但今天在另一台电脑重装Tex工具集又遇到了一时间有些忘了,记下来免得以后再忘。

Texlive2017 + VS Code + Latex-Workshop

Workshop中有一项统计字数的功能,事实调用Texcount实现,然而和Texlive2017配合使用出现问题,提示大概是@INC中没有找到Win32:ANSI模块。

查阅了外网资料,追踪了Texlive中整个的调用链,安装了Active Perl……最后似乎这是TexCount中一个不必须的调动,类似于……一个Bug?总之在之后的版本中被修复了。

解决方案:

在TexCount官方地址http://app.uio.no/ifi/texcount/download.html下载最新脚本,至Texlive2017中texcount.pl脚本的位置覆盖原脚本即可。

Linux服务器中代理的使用

Linux服务器中代理的使用

本文不提供任何流量代理资源抑或获取代理资源的方法,以下所述仅为解决一个异常问题的技术方案。

起因

是因为博客中想加入Goole Analytics,一搜WordPress插件库正好有个插件专门做这个,毕竟使用插件才是WordPress的风格嘛(其实就是懒了)(但是插件应该能保持文件间的低耦合性,功能也较为丰富,也是真的方便)。然而之后使用谷歌账户授权给该APP时却一直出错无法完成,错误信息是一个curl.php文件中访问了一个无法访问的ipv6地址,神秘的

** * 2404:6800:4012::200d * **

错误日志如下:

Last Error: 2017-12-18 16:14:49: Deconf_IO_Exception: Failed to connect to 2404:6800:4012::200d: Network is unreachable in /home/www/blog.darkray.cn/wp-content/plugins/google-analytics-dashboard-for-wp/tools/src/Deconf/IO/Curl.php:126
Stack trace:

0 /home/www/blog.darkray.cn/wp-content/plugins/google-analytics-dashboard-for-wp/tools/src/Deconf/IO/Abstract.php(136): Deconf_IO_Curl->executeRequest(Object(Deconf_Http_Request))

1 /home/www/blog.darkray.cn/wp-content/plugins/google-analytics-dashboard-for-wp/tools/src/Deconf/Auth/OAuth2.php(112): Deconf_IO_Abstract->makeRequest(Object(Deconf_Http_Request))

2 /home/www/blog.darkray.cn/wp-content/plugins/google-analytics-dashboard-for-wp/tools/src/Deconf/Client.php(128): Deconf_Auth_OAuth2->authenticate(‘4/AABwnP1NCe1pS…’, false)

3 /home/www/blog.darkray.cn/wp-content/plugins/google-analytics-dashboard-for-wp/admin/settings.php(1126): Deconf_Client->authenticate(‘4/AABwnP1NCe1pS…’)

4 /home/www/blog.darkray.cn/wp-includes/class-wp-hook.php(286): GADWP_Settings::general_settings(”)

5 /home/www/blog.darkray.cn/wp-includes/class-wp-hook.php(310): WP_Hook->apply_filters(”, Array)

6 /home/www/blog.darkray.cn/wp-includes/plugin.php(453): WP_Hook->do_action(Array)

7 /home/www/blog.darkray.cn/wp-admin/admin.php(224): do_action(‘toplevel_page_g…’)

8 {main}

看插件的评论,一色的外国友人表示“很好” “很赞”,没有问题反馈,大概就知道了问题出在哪儿了。接下来的若干小时便在处理如何让服务器“走向世界”这件事上了。因此本文还是以此为题比较合适。

服务器托管于腾讯云上,途中还不抱希望地提交了工单,也许奇迹发生会得到暂时的海外线路。

没有这种奇迹。不过工程师两点多的一通电话着实惊到了我。夜班辛苦。

需求

首先如同文首声明,本文没有代理资源,而你需要一个以解决该问题。

  • 一条代理渠道 一个稳定可访问的海外服务器 => 一条代理渠道;
  • 因为该插件访问地址大概率是HTTPS的,此处HTTP代理难以满足需求;
  • 本文使用shadowsocks代理实现,它本质上是SOCKS5代理,实现于OSI模型会话层,因此对上层协议不敏感。连接稳定,性能良好。但其连接安全性不佳,不适用于保密要求高的场景。

请咨询相关技术人员获取更多帮助。

环境

  • CentOS 7
  • 腾讯云单核1M带宽
  • Nginx + PHP7 + WordPress + Google Analytics for WP

方案

绕了若干圈不知从何说起。其实说起来又很简单,不过是修改插件源码+使用ss代理。

首先腾讯工程师和自己都测了,log中的那个ipv6地址是不存在的。但搜索和一些google.com的地址相似。自行大致确认被DNS污染了。(腾讯云的工单就结束掉了)

Shadowsocks

网络上能找到的大多都在介绍Windows如何使用代理,其次是教学如何搭建代理服务器,少有如何Linux使用代理。

  1. 安装shadowsocks(python版本此处足矣),需要先安装pip,可以通过安装python一并获得

– pip的安装教程很多;
pip install shadowsocks 即可。

  1. 包中分成几个部分,其中用的最多的是ssserver,其次有一个sslocal,是客户端。

  2. 编辑一个json配置文件可以省去之后在终端中手书n条参数。示例如下:

{
"server": "xxx.xxx.xxx.xxx",
"server_port":12919,
"local_address": "127.0.0.1",
"local_port":1080,
"password":"xxxxxxxxx",
"timeout":300,
"method":"xxx",
"fast_open": false,
"workers": 1
}

以上配置替换xxx为拥有的代理资源的对应配置后即可保存使用。JSON不支持注释,故在此注释:

  • server: 远程代理服务器ipv4地址(ipv6支持未知);
  • server_port: 远程代理服务器端口;
  • local_address: 本地代理端口,python版本无法做到全局代理,将监听本地地址的端口(local_port)并通过SOCKS5转发接受到的所有流量;
  • local_port: 见local_address;
  • password: 代理服务器密码,该密码似乎也被用于加密通讯流量。固定的约定密码不具有前向安全性以及对于一些购买公用代理服务器资源的人来说……根本没有安全性可言;
  • timeout: 连接超时,建议不要更改;
  • method: 加密方法,如rc4-md5,与代理服务器配置保持一致;
  • fast_open: 一种用于加速TCP连接提高效率的新(协议?提案?proposal?),大意是在TCP三次握手中加入数据传输。未尝试开启,且仅插件本身的连接对效率要求并不是很大,较新版本Linux中可以尝试开启;
  • workers: 猜测是指工作线程数?没有注意到更详细的解释,就不要随意更改了。
  1. 之后使用sslocal命令运行,命令的详细帮助可以sslocal -h。网上大多数是使用nohup,但个人觉得命令中已经提供了后台运行指令,就使用自带参数方法较好。
sslocal -c 上一步配置文件路径 --pid-file 指定pid-file保存位置 --log-file 指定日志文件保存位置 -d start

Google Analytics for WP 插件修改

先把插件修好。

error_log很清楚了,插件目录下Curl.php出错了。该文件处在Google Analytics插件目录下,应该是该插件专用的一个工具,不影响WordPress其他模块,因此直接暴力修改源文件。

但为了之后的方便,代理配置我们将写在全局环境变量中,以便未来随时更改本地代理地址或有一天不再需要代理的时候关了它。

打开Curl.php——你可以直接在服务器使用Vi(m)编辑也可以下载到本地编辑后上传覆盖——定位至约120行处有如下代码:

$this->client->getLogger()->debug(
'cURL request',
array(
'url' => $request->getUrl(),
'method' => $request->getRequestMethod(),
'headers' => $requestHeaders,
'body' => $request->getPostBody()
)
);
// 本注释在源文件中不存在,是为了提示下一步代码的插入位置而添加
$response = curl_exec($curl);
if ($response === false) {
$error = curl_error($curl);
$code = curl_errno($curl);
$map = $this->client->getClassConfig('Deconf_IO_Exception', 'retry_map');

$this->client->getLogger()->error('cURL ' . $error);
throw new Deconf_IO_Exception($error, $code, null, $map);
}

在两个代码块中上示注释位置插入以下代码

// Read proxy settings from env
$curl_proxy = getenv('php_curl_proxy');
if (isset($curl_proxy)) {
curl_setopt($curl, CURLOPT_PROXY, $curl_proxy);
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
}

上述代码片段设定了代理类型为SOCKS5,shadowsocks以外的代理方案请自行修改

保存/替换/覆盖。注意之后使用list检查文件权限,与同目录下其他文件权限保持一致。如果这难倒了你,请在该目录下执行以下命令sudo chmod 777 Curl.php

接下来须添加环境变量。编辑/etc/profile文件,在末尾添加以下代码:

export php_curl_proxy=‘127.0.0.1:1080’

修改后保存,然后重启php服务

service php-fpm restart

检查该插件,应该已经可以正常使用。

终端中curl命令的代理

curl命令自带代理参数,普通代理参数为-x。

网络有若干教程介绍使用Privoxy搭建http/https代理,再次监听本地端口8118并转发至shadowsocks代理1080端口。雷同的教程中有些命令有误需要修改,并且若只是偶尔使用的话,并无再次进行本地代理的必要。以下是curl内置的代理参数

curl --socks5-hostname 127.0.0.1:1080 www.google.com

命令中网站仅作示例参考

其中参数必须如此写是因为–socks5选项的域名解析似乎仍是在本地完成的,遇到如此例所示存在DNS污染,选项–socks5或-s或-x会因得不到正确的ip地址而无法正确获得内容。

正因为设置系统默认环境变量 ALL_PROXYhttp_proxyhttps_proxy 没有指明DNS的解析位置,此处需要一劳永逸的代理设置则需要Privoxy,它提供了DNS解析位置的配置。在配置文件(./configure时我加了prefix选项,我的配置文件在/usr/local/privoxy/etc/config)中搜索forward-socks5,在大约1336行处删除注释,改成如下配置即可

# To chain Privoxy and Tor, both running on the same system, you
# would use something like:
#
forward-socks5 / 127.0.0.1:1080 .
#
# Note that if you got Tor through one of the bundles, you may
# have to change the port from 9050 to 9150 (or even another
# one). For details, please check the documentation on the Tor
# website.

网上一些博文表示要使用forward-socks5t选项,但我认为socks5选项更佳,t似乎是为Tor做了一些调整,而socks5选项明确表示了DNS解析是在远程代理服务器发起的。

保存配置后执行

privoxy 配置文件位置

便已启动Privoxy,默认运行在8118端口。你可以直接curl -x 127.0.0.1:8118 www.google.com测试是否成功代理。

也可以在环境变量中添加变量http_proxy和https_proxy,之后直接curl www.google.com便可。

永久为所有用户添加环境变量必须在/etc/profile文件末尾以export命令添加(如修改Google Analytics for WP插件最后编辑/etc/profile时所做的那样),否则当前shell中export的环境变量在shell结束后将一同销毁。


后台进程太多,可以考虑使用supervisor管理一下。

改变WordPress在系统中的文件路径

改变WordPress在系统中的文件路径

改变WordPress目录

配置好Nginx后遇到500错误,Error信息显示

Failed opening required Unknown … include_path=’.:/usr/share/pear:/usr/share/php’

解决方案先放前面吧

我的部分原因是使用了Wordfence,其他插件可能存在其他地方需要修改,请自寻。

  1. 在WordPress目录下:
    • .user.ini中寻找到一处旧路径记录,替换为新的;
    • wordfence-waf.php中寻找到两处旧路径记录,替换为新的;
  2. 登陆MySQL数据库,找到WordPress所属数据库的option表,有一到两处旧域名记录,替换为新的域名

叨叨

因为建设个人主页的想法,原先www域名下的此博客需要让出这个域名,转到现今的
访问域名的更改通过Nginx配置修改主机名便简单完成。但之后弹出500错误。Display_error发现是在某一未知的php文件中require了原有路径的文件。然而可能由于某种缓存机制的原因,该php文件只显示为Unkonwn,并无法知道文件位置。
所以我把全部文件打包压缩了下下来了用WebStorm作为项目打开然后全局搜索原路径名……
然后发现博客显示不正常,跳转链接也有问题;于是想到了去数据库看一看。
命令行mysql难以显示储存的复杂的数据,需要一个客户端界面。
Navicat确实UI好看,也挺好用,主要是UI好看,免费试用15天,自带简中。

秋季创意者更新(1709)后的移动热点失效问题

秋季创意者更新(1709)后的移动热点失效问题

Windows 10 Mobile Hotspot doesn’t Work after Fall Creator Update 1709

先把解决方法放在最前

Solution First for the Impatient Ones

  • Win+X, A -> Open PowerShell 打开PowerShell;
  • netsh advfirewall reset -> Reset Win Firewall config 重置防火墙配置;
  • Win+X, M -> 打开设备管理器;
  • Menu ‘查看(V)’ – ‘显示隐藏的设备(W)’;
  • 网络适配器/Network Adapters, delet/删除 ‘Microsoft Wi-Fi Direct Virtual Adapter #n’ until there remains only one adapter without ‘#n’;
  • End. Check if Mobile Hotspot can work, and it worked for me.
  • If this doesn’t work, restart PC | 不行试试重启;
  • If that doesn’t work, check whether following services are running | 还不行,检查以下服务是否开启:
    • Wired AutoConfig
    • WLAN AutoConfig
    • Extensible Authentication Protocol
  • If all above doesn’t work, the following sotfware should work | 如果这还不行,下面这个软件管用,免费版广告多了点,良好简体中文界面:
  • Connectify
  • I swear that’s not an ad | 这绝不是广告。

胡侃

Useless Words

自从11月初被强行重启安装了秋季创意者更新1709(我当时还在团战啊!)后,这个问题就困扰着我。之后发现并不止我一个,周围同学的电脑同样更新至1709后无法打开移动热点了。

百度搜索过后11月初已经有一个网站以此为标题了,然而其中内容似乎只是把以前的老文章抄袭了一遍,讲述了如何使用命令行打开Hostednetwork。尝试之后并不管用。以太网属性中设置共享网络连接,确定时整个网络连接窗口会“未响应”。之后这个问题便搁置了很久,直到一个月后的现在。

拖到了自己实在无法忍受没有热点的生活。更新强迫症看着手机上一堆更新提示却在白天难以更新,便重新拾起了这个问题。重新百度搜索,发现提出问题的人更多了,知乎上有了一些答案但……看起来并不觉得可行。抱着希望尝试着在谷歌上搜索。关键词还想了我一会儿……不过谷歌的结果令人振奋,外国社区的有效结果/活跃度比国内的高多了(毕竟Win还是人家的东西)。终于了解了知乎有答案表示重置防火墙配置的来源,这是国外主流意见并且似乎对很多人有效。然而并不对我有效,但重置防火墙后情况确实改善了——共享网络连接设置应用时不再“未响应”,移动热点也不再永无止境地旋转下去——它会告诉我“我们无法设置热点”。并且它能解决某几个服务进程(忘了名字了)长时间高CPU占用率的问题。

沿着Reddit该办法来源的链接指向了一些微软社区的帖子。其中似乎找到了重置防火墙方法的最初来源。回帖询问方案提出的层主是怎么想到这个方法的还是不小心按到的;层主表示这个方法是在他搜了一天谷歌后看到Win8.1类似问题当初的解决方案,尝试的。打开了若干网页,忘了是在Reddit还是在微软论坛看到有一层表示在设备管理器中删除隐藏的除了Microsoft Wifi Direct Virtual Adapter除了不带#号的所有Adapter。当时并不以为意。毕竟……这个解决办法有些不合逻辑……那几号适配器不应该是平等的吗……为什么不删了其他几号……为什么不删光让它重建(也许能自动重建?)。事到如今走投无路只好一试。试了之后其实是想让Hostednetwork连上网的,因为之前即使能够设置连接共享了但Hostednetwork还是连不上网,也无法开启DHCP。并没有用。在国外网站上看到个类似国内“WIFI共享大师”的软件,想着也许外国的会干净点,便下下来用了,可行。值得一提的是,软件官网还特地发了一篇声明,表示Fall Update 1709过后的大批量热点无法使用事件是Win API引起的,并且软件加急修正了推出Beta新版以供下载,欢迎使用

然而外国的月亮并不见得圆……广告弹窗开关一下热点各弹两遍。而且似乎是由于C#开发的原因(这是一种……感受,味道,C#软件的味道……然我并不确认)有着……一种似乎是C#独特的卡……这段可能是我无知了莫喷

无意点了一下系统设置开启热点……它就开了。

所以以上提供的方法并不保证解决问题……只是我估计的生效的操作步骤。还有没提到的一些我认为无关的步骤包括

  • 多次开关了Hostednetwork并最终还是打开的;
  • 建立了网桥后断开了;
  • 修改了无线网络的用户名和密码;
  • n次重启;
  • ……

这教会我们什么。

Windows故障是真的博大精深(玄学)啊……

现在的我和十年前的我在处理Windows系统故障这方面……可能只是长进在多认得了一些洋文而已。