标题: 英杰传:用GB4改变随机数的原理, 感谢孝直的算法解说
性别:未知-离线 SkyGrasper
(FX-550)


Rank: 4
组别 校尉
级别 忠义校尉
功绩 27
帖子 234
编号 419858
注册 2011-4-4


发表于 2011-12-13 23:33 资料 文集 短消息 只看该作者
英杰传:用GB4改变随机数的原理

这个事情挑战的前辈们不写,分析程序的也不写,那我就抛块砖,抛块砖...
其实费劲SL过的都知道,但是没打过的还真就未必知道

----------------------------------------------------------------------------------------------------------

多年以前,随着英杰传n99登上20大关,对玩家的细心和耐心要求越来越高
各关的打法变得精细繁复,战场上犯点错误也变得不可忽视了
于是GB4被用来做战斗中的存档(当然GB4能做很多事,但这就是另外的话题了)

初衷是防错,但GB4本身就是带来了一个SL的机能,于是用GB4做SL改变随机事件提高成绩(增加反击、烧火失败等)就成了大家的选择
然而大家很快发现,由于英杰传的随机数系统是程序内递推的伪随机数,读同一个GB4档后什么都不会变
只有改变我军的行动顺序或内容,需要的随机事件才可能变化

即使是这样的SL,也展现了不小的威力
不过也有很多人认为“只要无限SL下去,什么结果都能SL出来,也就起到了补丁的效果,至少能接近补丁”
其实不是这样的:某些项目上用GB4可以接近补丁,但是大多数时候会差很远,除非无数次地全军撤退重新初始化随机数序列
在此就简述一下用GB4做SL的原理,这里讲的是从经验中总结并回到实战验证的,有些细节可能不准确,希望分析程序的几位从底层程序给点支持和补充
(感谢孝直的算法解说)

----------------------------------------------------------------------------------------------------------

英杰传在开始每一关以及全军撤退时,会初始化随机数
在之后的全战中使用的所有随机数,都是由这第一个随机数确定性地递推出来的
每次产生需要随机数的事件,如天气、恢复、混乱及其恢复、反击、策略成败及其伤害值等,就会用掉相应的随机数;下次随机事件就用掉序列里下一个随机数

比如焦热,先计算伤害(不论后面是否命中都要算)用掉一个随机数,再计算命中用掉一个随机数,无论敌我,用一次焦热就是两个随机数
又比如假情报只判定一次是否混乱,消耗一个随机数;援助只计算一次援助量,消耗一个随机数
而大援助需要计算所有涉及的人的援助量,就是涉及几个人消耗几个随机数
其他的如决定天气、恢复兵力、降低士气时判断是否混乱、回合初判定是否从混乱恢复,都消耗一个随机数,具体的可以参考龙吟的程序分析

GB4的SL能改变的,就是通过采取不同的行动/顺序,让需要SL的随机事件换一个随机数
大体上分两类:我方回合和敌方回合

----------------------------------------------------------------------------------------------------------

我方回合的随机事件SL,典型的就是烧火
打比方说,魏延和其他9人出场,这9人都是普通兵种/军乐/运输
在某回合初,魏延有花五烧了,那么怎样尽可能多失败呢?

假设这时的随机数序列是r1,r2,r3,.......
注意,不回去改变上回合行动的话,这个随机数序列就是不变的
如果魏延第一个行动烧花五,那么决定各人是否失败的随机数就是r2,r4,r6,r8,r10

如果我们不满意这个结果,OK,让马谡激励一次消耗一个随机数,魏延第二个行动烧
这下,决定成败的随机数就变成了r3,r5,r7,r9,r11,结果就可能不同了(注意,仅仅是可能)

当然我们可以让更多人在魏延前面行动,换取不同的随机数组
但是遗憾的是并没有那么多变数
一方面其他人不损失经验的话就是一人消耗一个随机数,只有10种不同的随机数组
另一方面这些随机数组中的随机数可能部分重合,比如魏延第一个行动,和前面已经消耗两个随机数,就有r4,r6,r8,r10四个随机数重合

----------------------------------------------------------------------------------------------------------

敌方回合的随机事件SL,典型的就是反击
打比方说,赵何一个人反击三个敌人
由于反击发生在敌方回合,敌人的行动顺序是固定的,如果我军本回合结束时消耗掉相同个数的随机数,是否发生反击的结果就不会改变

这实际上经常意味着刘备需要休息或者用焦热/焦热书,以经验为代价换取赵何可能更多的反击
但是刘备自己也只能让随机数序列的消耗多一个或者少一个,多两次机会
如果有更多的人可以牺牲经验的话,就可能再多点选择
不过和上面的烧火例子一样地,这里也有不同随机数组部分内容重合的问题

在有些情况下可以有一些变通方案。
比如可以用假情报混乱掉一个敌人,那么判定反击前这个敌人的混乱恢复会消耗一个随机数,进而判定赵何反击时的三个随机数就比原来各后移一位了
这样可以不损失经验,但是对策略补给和兵力补给要求高,很受限制

----------------------------------------------------------------------------------------------------------

实战中还有一些小技巧,不过基本的情况就是如此
如果是一次SL个别随机事件,比如单点反击,就比较容易
但是一次SL多个随机事件,比如要求赵何三次都反击而且下回合下雨,或者要魏延烧花五时至少失败四个,就对多个随机数同时提出了要求,变得非常困难
即使没学过概率,从常识来讲也容易接受

而更严峻的一个现实是,靠GB4的SL,随机数可调整的余地太小了
比如单人烧火,其他人能给你调出来的就是那十几种可能的随机数组,还大量重合
多人烧火复杂一些,SL的效果平均到每个人就更小了
而敌军回合的所有事件都决定于不能大幅改变的回合结束时状态(一次性而且选择余地有限),SL多点反击就是个噩梦

GB4的SL就是这样一个有力但是很局限的手段
代替补丁?如果全军撤退无数次的话,是可以的,否则都被那个固定的随机数序列限制住了
这家伙边际效益递减很厉害的,你对它要求得越多,它对你越吝啬

[ 本帖最后由 SkyGrasper 于 2011-12-28 22:18 编辑 ]


顶部
性别:未知-离线 edmund_liyc

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 仁勇校尉
功绩 2
帖子 172
编号 332186
注册 2009-7-31


发表于 2011-12-13 23:40 资料 短消息 只看该作者
辛苦了,頂一個,深以為然


顶部
性别:男-离线 阿尔法孝直
(雀力日进)

闽国公
遂安军节度使
★★★★★★

Rank: 19Rank: 19Rank: 19Rank: 19
柱国(正二品) 轩辕春秋年度最佳(游戏人生区)
组别 节度使
级别 卫将军
好贴 2
功绩 1796
帖子 6037
编号 19070
注册 2004-10-16
家族 轩辕雀党


发表于 2011-12-13 23:46 资料 个人空间 短消息 只看该作者 QQ
随机数算法,适用于英杰传系列的所有游戏:

设A为32位(即4字节,范围0~4294967295)随机种子,计算

B=1103515245 * A+12345

此时B应该是一个64位(即8字节)整数,取B的低32位填回A作为下一次随机数运算的种子,即

A=B MOD 4294967296

最后的随机数是:

RANDOM=(新的A/65536) MOD 32768

如果需要0~N-1之间的随机整数,那就计算 RANDOM MOD N
顶部
性别:未知-离线 SkyGrasper
(FX-550)


Rank: 4
组别 校尉
级别 忠义校尉
功绩 27
帖子 234
编号 419858
注册 2011-4-4


发表于 2011-12-13 23:52 资料 文集 短消息 只看该作者
回复 #3 阿尔法孝直 的帖子

那就是说,我顶楼推测的
“开始战斗初始化一个随机数,后面的随机数都由其确定性地推出”
是对的了

放心了...没误导人......
多谢多谢
顶部
性别:未知-离线 edmund_liyc

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 仁勇校尉
功绩 2
帖子 172
编号 332186
注册 2009-7-31


发表于 2011-12-13 23:59 资料 短消息 只看该作者
想起一項觀察,求孝直解說
單挑後會否重設隨機種子?
顶部
性别:男-离线 阿尔法孝直
(雀力日进)

闽国公
遂安军节度使
★★★★★★

Rank: 19Rank: 19Rank: 19Rank: 19
柱国(正二品) 轩辕春秋年度最佳(游戏人生区)
组别 节度使
级别 卫将军
好贴 2
功绩 1796
帖子 6037
编号 19070
注册 2004-10-16
家族 轩辕雀党


发表于 2011-12-14 00:13 资料 个人空间 短消息 只看该作者 QQ
回复 #5 edmund_liyc 的帖子

这个还真不知道。。找不到单挑部分的代码。
顶部
性别:未知-离线 edmund_liyc

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 仁勇校尉
功绩 2
帖子 172
编号 332186
注册 2009-7-31


发表于 2011-12-14 00:22 资料 短消息 只看该作者
回复 #6 阿尔法孝直 的帖子

噢,無論如何,謝謝

觀察實際內容是:經不完全測試,兗州單挑張郃後的策略效果,跟同一回合單挑前的行動基本不相關,因而推論隨機種子已重設

[ 本帖最后由 edmund_liyc 于 2011-12-14 00:59 编辑 ]
顶部
性别:未知-离线 SkyGrasper
(FX-550)


Rank: 4
组别 校尉
级别 忠义校尉
功绩 27
帖子 234
编号 419858
注册 2011-4-4


发表于 2011-12-14 00:22 资料 文集 短消息 只看该作者
回复 #5 edmund_liyc 的帖子

实验结果呢?

比如在兖州赵云单挑前存一个档
挑完用一个援助/激励/牵制
试几次看数值变不变

--------------------------------------------
ft,发出来发现同时已经发出来实验结果了......

[ 本帖最后由 SkyGrasper 于 2011-12-14 00:23 编辑 ]
顶部
性别:未知-离线 edmund_liyc

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 仁勇校尉
功绩 2
帖子 172
编号 332186
注册 2009-7-31


发表于 2011-12-14 00:58 资料 短消息 只看该作者
回复 #7 edmund_liyc 的帖子

特意找來當時的進度再測試,確認單挑沒有涉及隨機數重設,謹為樓上錯誤陳述致歉
或許當時搞混了其他變化導致錯誤印象,orz
顶部
性别:未知-离线 likelove

Rank: 2Rank: 2
组别 百姓
级别 破贼校尉
功绩 1
帖子 52
编号 56074
注册 2005-12-27


发表于 2011-12-15 21:24 资料 短消息 只看该作者
随机数在计算时,种子是更新回去的。理论上玩家只能通过保留变化,影响后续的随机数计算序列。
这是随机数计算的过程,RandA,RandB保留上次计算结果,每次计算都要更新:

seg001:3DA0 _sub_Rand00     proc far                ; CODE XREF: _sub_RandAX+7P
seg001:3DA0                 push    41C6h
seg001:3DA3                 push    4E6Dh
seg001:3DA6                 push    ds:_word_RandB
seg001:3DAA                 push    ds:_word_RandA
seg001:3DAE                 call    __aFlmul
seg001:3DB3                 add     ax, 3039h
seg001:3DB6                 adc     dx, 0
seg001:3DB9                 mov     ds:_word_RandA, ax
seg001:3DBC                 mov     ds:_word_RandB, dx
seg001:3DC0                 mov     ax, dx
seg001:3DC2                 and     ah, 7Fh
seg001:3DC5                 retf
seg001:3DC5 _sub_Rand00     endp

顶部
性别:男-离线 阿尔法孝直
(雀力日进)

闽国公
遂安军节度使
★★★★★★

Rank: 19Rank: 19Rank: 19Rank: 19
柱国(正二品) 轩辕春秋年度最佳(游戏人生区)
组别 节度使
级别 卫将军
好贴 2
功绩 1796
帖子 6037
编号 19070
注册 2004-10-16
家族 轩辕雀党


发表于 2011-12-16 19:08 资料 个人空间 短消息 只看该作者 QQ
_word_RandA和_word_RandB其实是由一个dword数拆成的两个word数(因为这是16位汇编),且
_word_RandB是高字,_word_RandA是低字。

16位汇编的伪随机数算法


sub_20D00 proc far
push    41C6h
push    4E6Dh
push    word_40F72      ; word_RandomH
push    word_40F70      ; word_RandomL
call    __aFlmul
add     ax, 3039h
adc     dx, 0
mov     word_40F70, ax
mov     word_40F72, dx  ; dx:ax=dword_Random
mov     ax, dx
and     ah, 7Fh
retf
sub_20D00 endp


和32位汇编的伪随机数算法


sub_4472FC proc near
mov     eax, dword_453B20
imul    eax, 41C64E6Dh
add     eax, 3039h
mov     dword_453B20, eax
and     eax, 7FFF0000h
shr     eax, 10h
retn
sub_4472FC endp


应该是等效的。

[ 本帖最后由 阿尔法孝直 于 2011-12-16 19:16 编辑 ]
顶部
性别:未知-离线 likelove

Rank: 2Rank: 2
组别 百姓
级别 破贼校尉
功绩 1
帖子 52
编号 56074
注册 2005-12-27


发表于 2011-12-28 08:52 资料 短消息 只看该作者


QUOTE:
原帖由 阿尔法孝直 于 2011-12-16 19:08 发表
_word_RandA和_word_RandB其实是由一个dword数拆成的两个word数(因为这是16位汇编),且
_word_RandB是高字,_word_RandA是低字。

16位汇编的伪随机数算法
sub_20D00 proc far
push    41C6h
push    4 ...

想起来freecell随机数的一个小BUG,因为它是调用系统DLL中那段代码,就是你所说的32位那段,其中有And和SHR操作,导致随机数不会超过0xFFFF,所以后面直到1000000的牌局只能手动选。
顶部
性别:未知-离线 edmund_liyc

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 仁勇校尉
功绩 2
帖子 172
编号 332186
注册 2009-7-31


发表于 2011-12-30 01:23 资料 短消息 只看该作者
遲來的挑錯,嘿

QUOTE:
由于反击发生在敌方回合,敌人的行动顺序是固定的,如果我军本回合结束时消耗掉相同个数的随机数,是否发生反击的结果就不会改变

敵軍每個可能行動都會算一次行動價值的,所以引用部分只有敵軍所有可能行動都不涉及隨機數才成立

如果先行動敵軍有策略可用,即使其實際行動是打人,單是改變我軍在其觸及範圍內的站位,同一回合後續反擊結果仍有可能變動
顶部
性别:未知-离线 SkyGrasper
(FX-550)


Rank: 4
组别 校尉
级别 忠义校尉
功绩 27
帖子 234
编号 419858
注册 2011-4-4


发表于 2011-12-30 11:37 资料 文集 短消息 只看该作者
回复 #13 edmund_liyc 的帖子

嗯,同意,谢谢
顶楼只是一个简化例,实际打的时侯有很多情况会影响用的随机数

比如你说的敌人AI决策时用掉的随机数
比如士气低敌人受到伤害判定陷入混乱的随机数
比如对混乱敌人烧火失败,判定混乱恢复的随机数
......

这样的情况太多,有经验的话一看就明白,但是没经验的可能就要绕进去了
而它们都可以看作顶楼提到的简化情况的变体
所以我在顶楼省略了这些,而是说“实战中还有一些小技巧,不过基本的情况就是如此”

[ 本帖最后由 SkyGrasper 于 2011-12-30 11:39 编辑 ]
顶部

正在浏览此帖的会员 - 共 1 人在线




当前时区 GMT+8, 现在时间是 2025-3-16 01:53
京ICP备2023018092号 轩辕春秋 2003-2023 www.xycq.org.cn

Powered by Discuz! 5.0.0 2001-2006 Comsenz Inc.
Processed in 0.011974 second(s), 8 queries , Gzip enabled

清除 Cookies - 联系我们 - 轩辕春秋 - Archiver - WAP