我破解了那个“男娘程度测试”的算法!高一技术宅的逆向工程实录?️

skl 发布于 2026-02-25 37 次阅读


我破解了那个“男娘程度测试”的算法!高一技术宅的逆向工程实录?️

兄弟们,今天刷手机的时候,看到一个贼沙雕的网站——“年度男娘程度总结器”。输入昵称就能测你的男娘指数,从D级钢铁直男到SSS级萌力爆表,分分钟给你贴标签。

作为一个光荣的高一技术宅,我第一反应不是笑,而是:这玩意儿到底怎么算的???

第一步:观察现象

我试了几个名字:

昵称 得分 等级
skl 12 D级男娘
SKL 51 A级男娘
SKLQT 96 SSS级男娘
SKLQTA 57 A级男娘

等等,这里有个诡异的点:SKL和skl差这么多?? 而且SKLQT 96分,加个A反而掉到57分,这特么不科学啊!

更关键的是,网站下面写着一行小字:“相同的昵称会得到相同的结果”。这句话直接给我指明了方向——这不是随机数,也不是数据库里存的,而是纯纯的确定性算法,输入字符串,输出0-100的分数。

第二步:大胆假设

作为一个看过几本黑客小说的高一学生,我立马想到了:这八成是哈希函数! 就像我的世界种子一样,把字符串转成固定数字。

哈希函数的特征:

· 同一个输入永远得到同一个输出
· 输入稍微变化,输出剧烈变化(比如SKL和SKLQTA)
· 理论上均匀分布在0-100之间

但是,哈希函数的结果通常很大(比如2^32),怎么映射到0-100?取模运算呗! hash(name) % 101,完美得到0-100的整数。

第三步:猜算法

问题是,它用的啥哈希?我试了几个常见算法:

  1. ASCII码求和:skl(115+107+108=330) mod 101 = 27,但实际是12,排除
  2. 加权求和:类似 h = (h * 31 + char) & 0xFFFFFFFF —— 等等,这特么不就是Java的String.hashCode() 吗?

Java的hashCode算法是公开的:

h = 0
for each char in string:
    h = h * 31 + char (用int存,溢出自动截断)
返回h(int,可能负数)

这个31是有讲究的(质数,减少碰撞)。而且用int存,溢出了就变成负数,取绝对值再模101,正好得到0-100!

第四步:动手验证

我掏出手机计算器,手算一下"abc":

· a=97 → h=97
· b=98 → h=97*31+98 = 3105
· c=99 → h=310531+99 = 96354
96354 mod 101 = 96354 - 101954 = 96354 - 96354 = 0,得0分!

再算"SKL":

· S=83, K=75, L=76
· 83 → 83
· 83*31+75 = 2648
· 264831+76 = 82164
82164 mod 101 = 82164 - 101813 = 82164 - 82113 = 51分!和截图一致!

最后试"d":

· d=100
· 直接100 mod 101 = 100分!SSS级男娘诞生!

我手都抖了,赶紧在网站输入"d",屏幕直接跳出100分,SSS级萌力爆表!老子的高中信息技术课没白上啊!

第五步:完整破解

所以这个网站的代码大概长这样(Python版):

def get_score(name):
    h = 0
    for ch in name:
        h = (h * 31 + ord(ch)) & 0xFFFFFFFF  # 模拟Java的int溢出
    # Java的hashCode返回的是有符号int,转成32位有符号整数
    if h > 0x7FFFFFFF:
        h -= 0x100000000
    score = abs(h) % 101
    return score

# 等级划分
def get_level(score):
    if score <= 20: return "D级男娘"
    elif score <= 40: return "C级男娘"
    elif score <= 60: return "B级男娘"
    elif score <= 80: return "A级男娘"
    else: return "SSS级男娘"

注意那个& 0xFFFFFFFF和后面的负数处理,完美模拟Java int的溢出。这也是为什么有些长名字会突然分数暴跌——因为溢出了变成负数,取绝对值后模101,分布完全变了。

第六步:为什么英文多分数高?

因为英文字母ASCII在65-122,汉字Unicode动不动几千,加权求和后很容易溢出变成负数,取绝对值后均匀分布在0-100。所以不是英文分数高,是汉字更容易溢出导致分布更随机。你输个“龘”(三个龙),ASCII直接炸裂,说不定给你个0分钢铁直男。

第七步:终极验证

我写了个小脚本,遍历所有小写字母:

· 'a'=97 → 97 mod 101 = 97分(SSS级)
· 'b'=98 → 98分(SSS级)
· 'c'=99 → 99分(SSS级)
· 'd'=100 → 100分(SSS级)
· 'e'=101 → 101 mod 101 = 0分(D级)

从'e'开始直接掉到0分!太搞笑了,一个字母之差,从SSS级萌神变成钢铁直男,这算法简直是个傲娇!

写在最后

所以兄弟们,这个所谓的“男娘程度测试”就是个披着娱乐外衣的哈希函数。你的得分跟你的真实属性没半毛钱关系,完全取决于你名字的ASCII码和Java那个坑爹的31乘法。

不过话说回来,这种小网站确实挺有意思的,几分钟就让我过了一把逆向工程的瘾。下次看到这种测试,你就可以装逼地说:“这玩意儿就是Java hashCode mod 101,输入‘d’直接满分,不信你试试!”

最后温馨提示:千万别拿你喜欢的女生的名字去测,万一测出个D级钢铁直男,你就尴尬了。?


(附:想自己验证的,去 https://nanniang-1tw.pages.dev/ 输入“d”,截图打我脸)