戻る

天下統一2PUS/相克の果て 疑似乱数Report - かねやんの部屋


はじめに

PC98x1版「天下統一II」+「天下統一IIパワアップセット」およびWindows版「天下統一 相克の果て」の疑似乱数の法則について調査した資料です。


配布ファイル

ソフトウェアが分からない人には全く意味不明の文章だと思うので、そういう方は配布プログラムのみお持ち帰り下さい。
↓ページの下の方


疑似乱数列の位置

疑似乱数の位置は、セーブデータではSYSDAT.BINの最初を0byteとしてから0x24B byteの位置2byte、メモリ上では、98版は文字列「Dec」の後ろに2byte程ダミーがあってその後ろの4byte、Windows版は「scanf : floating point formats not linked」の文字列の最後の「d」から17byteほど後ろから4byteのようである。ここをバイナリエディタやメモリエディタで変えると違うことが発生する。(Windowsでメモリを覗くには、タスクマネージャから右クリック→ダンプファイルの作成で作成したダンプファイルをバイナリエディタで見るのが手っ取り早い。)

どのように見つけるかは、セーブしたり俸禄を上げた前後で値が変更されている箇所バイナリエディタ等で発見して、変更箇所を総当たりで上書き変更した後、隠居などさせて見つける。PC98ゲームならメモリがたかだか1MB程度なのでそれ程困難ではない。(乱数列固定のゲームはそれ程多くないが。)
Windows版にしても、武将データなどの近くにある上に、98版で調査済みだったので苦労はなかった(セーブデータ2byte分と同じ値を探して、俸禄加増して変わっている箇所はすぐに発見できた)。

エミュレータ等で動作させている場合はメモリダンプが可能だったりする。実機で動いている場合はメモリにアクセスするのが困難な場合がある。WindowsNT系だと制限が多いというか、プロセスダンプするとよく強制終了になる。


疑似乱数列の系列

メモリ上の4byteをC言語(C言語のは以下省略)のunsignd long(インテル8086系なのでリトルエンディアン)型に当てはめて変数nとすると、1度疑似乱数を発生させると、n×A+Bの処理がされてオーバーフロー分は削除して4byte分の新しい乱数になるようだ。(このような疑似乱数の手法は線形合同法と呼ばれていて、単純で高速なアルゴリズムとして知られている。)
A:214013(PC98版)/22695477(Windows版)、B:2531011(PC98版)/1(Windows版)

static unsigned long n;

short pseudorandom_numbers() {
    n=n*214013+2531011;
    return (short)((n>>16)&7ffff);
}

↑上のようなコードと同等な処理があるはずだが、メモリ上で214013や2531011の数値を発見することはできなかった。
最初n=0なら、次は((0×214013+2531011) mod 4294967296)で2531011、
n=1なら次は((1×214013+2531011) mod 4294967296)で2745024となる。
(4294967296=232で手計算ではオーバーフロー分を手動で削除する必要がある、CPUの中では勝手に削除される)
後ろの内容を見れば分かるのだが、ゲーム内ではこのうち上位2bit目〜16bit目までしか使わないようだ。

ひとつ前の乱数値を取得するには、98版では(n-2531011)×(-1179438763)のオーバーフロー分を削除すればOKのようだ(→[214013,4294967296(=232)]について拡張ユークリッド法を適応すると-117943876を求めることができるということを今回知った)。
ちなみにWindows版では(n-1)*690295837のオーバーフロー分を削除すればOK。
疑似乱数の種、発生手順、逆方向の発生手順を見つけておくことは、乱数列固定なゲームを解析するうえで非常に重要のようだ。


セーブ時の疑似乱数列

セーブするときは、1度疑似乱数を発生させて、上位16bit分だけに取り出し、最上位を0で削除して、セーブデータに書き込み、書き込んだ値が新しい疑似乱数に記憶される。
short pseudorandom_save() {
    n=n*214013+2531011;
    n=n>>16;
    n=n&0x7fff;
    return (short)n;
}

↑多分こんな感じの処理がされている。returnされた値を保存する。
n=0なら、2531011(16進数0x00269EC3)の0x0026の部分を取り出して0x7FFFとの論理和0x0026(10進数38)をファイルに保存する。エディタで見るとリトルエンディアンなのでSYSDAT.BINのオフセット0x24Bが「00 00」から「26 00」に変化しているはずだ。

ゲームプレイで注意したいのは、Windows版でセーブデータの乱数が「0」になってしまった場合は、何度セーブしても「0」のままで変化がない。98版にしても何度セーブを繰り返しても同じパターンの繰り返しということはよくあることである。


俸禄加増時の忠誠度変化

俸禄加増時の疑似乱数メモリの変動を調べてみると、1回疑似乱数を利用しているようだ。
忠誠は最低で1.0、最大で3.0ほど上昇する。

私の予想では、INT(INT(n/65536)/(65536/2/21))+10 (×0.1)
(nは符号なしの次の疑似乱数、INT関数はその数を超えない最大の整数)
となった。

以下がPC98版で2回俸禄加増して調査した結果と予想。
疑似乱数(保存)の値をセーブデータに書き込めば再現できるはずだ。

疑似乱数(保存)次の疑似乱数次の次の疑似乱数1回目の上昇(×0.1)2回目の上昇(×0.1)
10進数16進数符号なし10進数符号あり10進数16進数符号なし10進数符号あり10進数16進数
000002531011253101100269EC35059088585059088581E278E7A10101414
10001274502427450240029E2C03357800067-937167229C823F68310102121
10000A46711414671141004746A53255017172-1039950124C2039ED410102020
16001059552195955219005ADE933186495242-1108472054BDEE0F0A10102020
32002093794279379427008F1E63157211433015721143305DB48F9A10102525
1280080299246752992467501C89D434757634504757634501C5B92FA10101414
25601005731833957318339036A9BC34456180424456180421A8F977A10101414
38401808471200384712003050C9A4341547263441547263418C39BFA10101414
44801C0984088359840883505DD99832547883578-174708371897DD9E3A10101313
46401D01018330431018330430611D95393350266693350266637A41ECA10101919
46601D21022610691022610690618614D2342317788-19526495088B9CEEDC10101111
46701D3102475082102475082061BA54A899241701899241701359956E511111818
46801D4102689095102689095061EE9473751132910-543834386DF95BEEE11112525
47201D8103545147103545147062BF93B2273795858-202117143887875F1211111111
48001E0105257251105257251064619233614089050-680878246D76A9F5A11112424
512020011210566711210566706AE98C338532722638532722616F7A07A11111313
93403A62024191532024191530C10ABD1129257454412925745444D0B1F5011112222
93503A72026331662026331660C13EFCE4144465753-150501543F707875911112929
94003AC2037032312037032310C2443BF1224052614122405261448F58F8611112121
94203AE2041312572041312570C2ACBB92632867736-16620995609CEE5F9811111414
94303AF2043452702043452700C2E0FB61189791649118979164946EAC7A111112121
94403B02045592832045592830C3153B34041682858-253284438F0E72FAA12122828
94503B12047732962047732960C3497B02598606771-16963605259AE397B312121414
95003B62058433612058433610C44EBA13973160928-321806368ECD19FE012122727
102404002216803232216803230D3692C32647455942647455940FC7B27A12121212
4096100087912825987912825934666EC33836223098-458744198E4A81E7A18182626
85812185183897656418389765646D9C8E344155687975-139279321F7B2C42727272929

大体の値が変わる間隔は推測できる。
上記のみでは、うまく式を導くことができなかったので、下がメモリ上の疑似乱数の種を変化させての追加再調査。
疑似乱数(メモリ上)次の疑似乱数上昇(×0.1)
10進数16進数符号なし10進数符号あり10進数16進数
123769777249C5C4EC4192731135-102236161F9E7FFFF2929
582590090378F6414192731136-102236160F9E800003030
3887973612E7BDC4EC4294967295-1FFFFFFFF3030
2708534849A170F64100000000001010
4206604601912C4EC65535655350000FFFF1010
3536188993D2C5F6416553665536000100001010
3070936300B70AC4EC1023016951023016950618FFFF1010
189149753770BDF641102301696102301696061900001111
14262448445502C4EC2045378552045378550C30FFFF1111
2468060810EB5F6412045378562045378560C3100001212
4076520684F2FAC4EC3067740153067740151248FFFF1212
2897081921ACADF641306774016306774016124900001212
609207532244FC4EC3068395513068395511249FFFF1212
3724736065DE02F641306839552306839552124A00001313

値が切り替わるポイントを特定できた。同じ値になる区間が65536×1560の場合と65536×1561の場合があることが確認できる。下位16bitは使用していないようだ。上位16bitは0〜216-1の範囲を取りえ、忠誠上昇は10〜30の範囲であることから予測して、216/(2×21)が1560.39くらいになるので2bit目から16bit目までを21分割して、最上位1bitは捨てているようだ。
サンプルが少ないので、間違いがあれば自由にご指摘下さい。

これでセーブを何回行えば、効率よく忠誠が上がるか、予測できるはずだ。

↓予測プログラムはページ下の方


隠居

再登場フラグOFFの場合、6回疑似乱数を使うようだ。シナリオを変えても再登場する武将のID、年齢、寿命、忠誠、再登場の有無は変化しなかった。(予想より1回多く使用している)
保存された疑似乱数が、7937〜10022、17971〜20056、28005〜30091の場合、跡継ぎが登場しないようだ。また、跡継ぎが登場しない場合、疑似乱数は1回の使用だけである。(→最初に使われる疑似乱数は再登場の有無判定)
再登場フラグがONの場合、武将のID、年齢、寿命、忠誠が変化した。(→2番目に使われる疑似乱数は武将のID)
とりあえず、最初の調査の結果。IDや忠誠は法則性はあるもの、予想を立てるのが困難。寿命に至っては、まったく予想が立たない。(データはPC98版)

疑似乱数(保存)次の疑似乱数(Hex)ID年齢寿命忠誠
02531011269EC3241313868
1274502429E2C0577226674
229590372D26BD913336780
33173050306ABA224234286
4338706333AEB7560354392
5360107636F2B4896257098
638150893A36B1208374654
13531318051129C511335596
145527193545699847235651
155741206579A96159355758
1659552195ADE93495255864
2170252846B3284126206494
2272392976E76814623140100
23745331071BA7E798216855
2565731833936A9BC3212225351
1122242653597E76999D275244191
37027948071372F5FCB615613660100
12127-16971006349AD84CA679375980
6872147322834757CFAE3B365195493
224795183619421EE59356708294955
79091695159828650A1614521265356
2586612432239734A1A17A56961958100
18970-232609675F222A875----
29218196059554974DC505D----
2991621099766237DC3B02F----
32195-16972550469AD5F17A705275771
6869147258630857C5E244381275175
224695162218121EC4EB74421206296
78761688097399649E5277700266358
25758122011056948B968E9260215052
18617-308156264EDA1E898----
280651713838560662719E0----
2615113042176784DBCC84E168265957
19900-33577585FDFFA58F----
32255-16844142669B99E0C6378215681
706515145328565A45EFF86792341100
2310965319013226EEE3F4350184781
996621353845697F4761F9----
32583-16142180029FC8FCEE982385896
8136174374077967EF5F6B----
266071401807606538DE2F6757184390
2138928508777210FE181C159243475
435093348756137A3E3C9104215782
14243-1244249126B5D643DA161285858
13782-1342909119AFF4D541965226796
12276-16652126979CBEDEE7974214172
735815772386655E02C089790185155
2406685800057333240CBD258334864
13092-1490578089A7279557626184461
10023-21473839868001854E955364973
1274502429E2C0577226674
4111305544AC8248700183863
172393412472584CBF669264999
6001309388117CDF7BB45335063
1997429914972199FFB5C288256784
6559140624227853D18DE6704267168
2145729964065611DC2750471264282
45729809984473A78D92F943215562
14968-1089089701BF15CF5B992347452
16149-836340348CE267584363304978
20006-10892207FF59CC51----
32601-1610365768A003C4B8884345653
8195175636754668B00ABA----
268001443112115560424B347225596
22020420129975190AACB7136246055
6410137435434151EAFBA5833226275
20970195416325BA5D105734364564
2981640503764262D4FD450345079
977320940800607CD1203C----
31953-174904619297BFAC50316286071
607913035160384DB21386246335592
19890-35717715FDDEFDAD----
32222-16914766959B2E1D29558216683
6958149163346558E88539579376058
22760578499595227B340B885336990
8827189162376270BFE352----
28863188462093470550886----
2875718619355566EFAE1C4----
2841017876730456A8DB9D5----
2727715451963165C19D31C522234154
235777533482162CE72E78873217385
11495-183235685092C8740E790265893
480810315055153D7B866B341357076
15739-924085678C8EB9252889204472
18667-297455614EE453002----
282291748936692683EA7F4----
266861418714633548FDE09668194063
2164734030312614489D16802385171
51921113686507426181EB298216677
16993-655713376D8EA9BA0204336085
227625789276212281BC05534354651
8833189290784070D37B40----
2888318889011947096584A----
2882218758464016FCF2501----
2862318332578146D454B56----
27973169414936464FAAAF4827334674
25850123979976549E5D7D5442243853
18917-243952364F1759514----
29045192357130072A75E64----
293511989059278768EA2CE----
30350-2092109031834CF319512306666
844183157983AEAC4DF82347675
279460048333323CAA605727357159
916219633181177505DB65----
2995721187511567E4993B4----
32329-16685773049C8B87E8658284774
730715663240025D5C3522442263100
239008224744153105F6AF821234370
12549-1606787148A03A5FB4511185258
825017681382616963A615----
269791481420442584CAE9A779355068
22604545113567207DC5DF710325254
831717824771326A3E714C----
2719815282892895B17D809610224481
23319698132862299CA97E230285589
10652-2012769809880791EF261354692
20554423277261A5D62AE314383781
67491446904748563E03AC11185356
2207843254272919C81409161375653
660014150168115457716B140347163
215913283183981391BDBE424275885
50091074522128400BE810270266681
16395-783693150D149CAA248335152
208091609602329980EE89282047100
24565281469391F7AE1FB861305584
8058172704776566F0A855----
263521347234291504D29F397185661
2055710702895666121DC252333790
163335201424014FB4FA0905374452
5371115199483444AA0BD263461100
17578-530515771E060F8C591325491
246729876924513ADEFDA330204196
15070-1067260375C062E629436257463
16482-765074019D265E59D598215873
21093221739924D377B9464377151
33837265369902B4E131E933384488
11086-19198881678D90D4D9628265592

上記では分からないので、まずは跡継ぎのありなし判定を詳細調査。
疑似乱数(メモリ上)次の疑似乱数跡継ぎ
符号あり10進数16進数符号あり10進数16進数
793600001F001700938179656241C3あり
793700001F011701152192656585C0なし
100220000272621473692977FFE4151なし
1002300002727-21473839868001854Eあり
1797000004632-446622675E561142Dあり
1797100004633-446408662E564582Aなし
2005600004E58-191557FFFD13BBなし
2005700004E5922456000057B8あり
2800400006D641700783767655FE697あり
2800500006D65170099778065632A94なし
300910000758B21474288987FFF2A22なし
300920000758C-214732438580026E1Fあり
-1586432447A170F641000000000あり
-2070100756849CC4EC17009868796562FFFFあり
10454277773E4FF641170098688065630000なし
174048996467BDC4EC21474836477FFFFFFFなし
5610512012170F641-214748364880000000あり
77382892049CC4EC-446496769E562FFFFあり
-1102055871BE4FF641-446496768E5630000なし
-406993684E7BDC4EC-1FFFFFFFFなし

次の疑似乱数の上位16bit分から最上位ビットを除いた部分が、0x6563より大きい場合は跡継ぎなしとなるようだ。
どうでもいいことだが、跡継ぎなしの場合は俸禄加増の効果が大きくなることになる。

疑似乱数の種(メモリ上)次の次の疑似乱数武将ID
符号なし10進数Hex符号なし10進数Hex
5925551003882AD60000000000
3930621085EA48849D2097151001FFFFF0
3400018646CAA82AD62097152002000001

とりあえず、2つ次の疑似乱数上位2bit目から11bit目までが武将IDになるようだ。また、再登場フラグが立っていれば、次の疑似乱数から同じ論理で取り出すようだ。

乱数の種(HEX/メモリ上)3つ次(符号あり)Hex年齢
777C254F00000000018
54330B621023016950618FFFF18
8DA1254F1023016960619000019
506B0B622045378550C30FFFF19
C3473F3C2045378570C31000120
BE0E0B6221474836477FFFFFFF38
F77C254F-21474836488000000018
3E0E0B62-1FFFFFFFF38

年齢は、3つ次の疑似乱数上位16bitから最上位を取り除いて、21分割しているようだ。
(年齢は18〜38の範囲)
年齢が38から1減るにつれて1%ずつ能力は劣化する。

次は寿命。細かい調査は省略して、4つ次のと5つ次の2つの疑似乱数を使用していて、それぞれ上位16bitから最上位を取り除いて、26分割しているようだ。2つの疑似乱数を足して30を足す処理のようだ。2つの疑似乱数の使用により30や80付近の分布が薄くなるようにしているようだ。
(寿命は30〜80の範囲)
忠誠は6つ次の疑似乱数上位16bitから最上位を取り除いて、51分割しているようだ。
(忠誠は5.0〜10.0の範囲)

以上で、何回セーブすれば優秀な隠居武将を手に入れることができるか分かるはずだ。

↓予測プログラムはページ下の方


引抜と楽市楽座

4人軍団で引抜を行って失敗すると、10〜22回ほど疑似乱数を使用するようだ。4人軍団での楽市楽座は10回ほど疑似乱数を使用する。
3人軍団での引抜だと8〜17回使用、2人軍団での引抜だと6〜12回使用、1人軍団での引抜だと4〜7回使用する。

4人軍団での楽市楽座では3〜6回目の疑似乱数の数値が半分以下なら各武将の能力がアップするのではないかと思われる。
同様に4人軍団で単独武将を引き抜く場合も3〜6回目の疑似乱数の数値が半分以下なら各武将の能力がアップするのではないかと思われる。

楽市楽座では1回目と2回目の疑似乱数を使って町上昇値が、引抜では1回目の疑似乱数で忠誠低下、2回目の疑似乱数で引抜成否が決定されているようだ。
4人軍団で4人軍団の武将を引抜失敗の場合は3〜6回目、7〜10回目、11〜14回目、15〜18回目の疑似乱数で能力アップ判定を行うようだ。軍団長なら3回目、7回目、11回目、15回目でそれぞれ判定し、半分以下なら能力が上昇するようだ(最大4回能力が上昇)。
4人軍団で1人の武将の引抜に成功した場合は、3回目の疑似乱数で忠誠度が決定され、4〜7回目の疑似乱数で能力上昇が判定されるようだ(1回のみ)。
その後4回疑似乱数の判定があって忠誠度の低下が判定されているようだ。疑似乱数値が半分以下ならアウト。

引抜失敗で敵が4人軍団の場合、最大0.4上昇、3人軍団の場合は最大0.3上昇、2人軍団の場合は最大0.2上昇、1人軍団の場合は最大0.1上昇となる。期待値はその半分。
引抜成功と楽市楽座では、最大0.1上昇で、確率は50%。
(軍団長を引き抜き成功した場合は最大で0.1×敵軍団人数分上がるようだ)
能力を鍛えたいのなら4人軍団で4人軍団の(忠誠が高い)武将に引抜をかけて失敗したほうが効率的と言える。
ちなみに相手が4人軍団の独立勢力であれば引き抜きづらいので中盤以降も効率的に鍛えることができるが、あまり意味はない。

↓予測プログラムはページ下の方


使者派遣

能力上昇がよくわからない。稀に当主の政治が上がるようだ。
4人軍団で行うと疑似乱数を11回使用、1人軍団で行うと疑似乱数を5回使用する。
最初の疑似乱数で友好の上昇幅が決まる。

乱数の種(HEX/メモリ上)次の乱数(Hex)政治上昇
A170F641013.39
2.75
E7BDC4ECFFFFFFFF13.34
2.72
67BDC4EC7FFFFFFF13.34
2.72
E170F6414000000013.36
2.73
01B2F641673A000013.34
47FFC4EC6739FFFF13.35
D215F6414211000013.35
1862C4EC4210FFFF13.36
0262F641252A000013.36
48AFC4EC2529FFFF13.37
9299F6411085000013.37
D8E6C4EC1084FFFF13.38
E170F6410422000013.38
E170F6410421FFFF13.39

(4…19.4%)、5…29.0%、6…22.6%、7…16.1%、8…9.7%、(9…3.2%)
疑似乱数値が低いほど友好が上昇するが、間隔が一定でなく、高い数値が出にくい。
友好は、低い確率で大きく上昇する。

2つ目の疑似乱数は、不戦同盟を申し込んでくるかの判定に使用されるのではないかと思われる。
→値が大きいと、不戦同盟を申し込まれないようだ。

3つ目の疑似乱数から軍団人数分だけ、政治上昇判定が入る。
3つ次の乱数(Hex)軍団長政治上昇
7FFFFFFF0
600000000
5FFFFFFF1
000000001

実行軍団の武将政治は、3/4の確率で0.1上昇する。

最後に使用する疑似乱数で当主の政治上昇判定を行う。
?次の乱数(Hex)当主の政治上昇
7FFFFFFF0
200000000
1FFFFFFF1
000000001

当主の政治は、1/4の確率で0.1上昇する。

↓予測プログラムはページ下の方


明や南蛮の書物渡来

渡来確率は各季節毎に1/2
特定の国に来る確率は1/68(68:国の数)
政治上昇幅は0.1〜0.5のようだ。


攻城戦

包囲すると疑似乱数を1回使用する。ターン終了時に軍団数分だけ戦意低下判定で疑似乱数を使用する。
内応時は、成功判定、計略対象(城 or 兵糧)判定、低下判定(1〜2回)、包囲兵糧判定で、疑似乱数4〜5回に軍団数分だけ戦意低下判定で疑似乱数を使用する。

内応成功率
智謀成功率
20.081%
10.041%
0.021%

内応成功時は、40%で兵糧、40%で城Lv、20%で両方低下となる。
兵糧は10〜20の範囲、城Lvは1〜4の範囲で均等に分布するようになっているようだ。

メモリ上の疑似乱数が分かれば、何回か包囲して内応等、効率よく内応を使うことができる。
↓予測プログラムはページ下の方


その他

その他の疑似乱数使用箇所は未調査です。
軍団長解任時の忠誠低下などは簡単に調べることができそうだが、使用用途があまりない。
そろそろ疲れてきた。もし、機会があれば。


セーブデータを覗き見る

天下統一2PUS/相克のセーブデータをExcel(マクロ)で閲覧 Ver.1.8
セーブデータエディタなんかも出回ってますが、つい作ってしまいました。当主のリハビリや外交成否の確認などに便利かも。
俸禄加増、楽市・引抜失敗での能力上昇、隠居の予測機能をつけてみました。Windows版の予測にも追加対応しました。何回セーブした後に俸禄増加、楽市、引抜をしかけると効率よく能力上昇が起こるかが分かります。また、何回俸禄加増(軍団長解任、相克の果ての場合は俸禄加増のキャンセルでも可)して、何回セーブすると、よい隠居武将が出てくるかが分かるようになります。
使者派遣の予想も追加しました。
使用により、性格が変わってしまったなど、いかなる事態が発生しても責任は持てません。ご利用は計画的に。
というか、誰かもっと調べて予測機能つけてくれないかな?(^_^;)

意見のある方、謎を解明した方、間違いの指摘などはこちらから⇒



2016/05/29 かねやん
2018/01/21 Last update