てくね のバックアップ(No.7)
ここに書いてあるのは全部推測で、事実とは異なる場合があります
鵜呑みにしないでください
以前から気になっていた隊移動についても調べる
隊移動に関する不思議な挙動をあげていく
- 挙動1:同一ターンに何回隊移動させても、派遣位置は1回目の隊移動と2回目の隊移動以外の位置にはならない
3回目の隊移動の派遣位置は1回目の隊移動の派遣位置と同じ、4回目の隊移動の派遣位置は2回目の隊移動の派遣位置と同じ
5回目の隊移動の派遣位置は1回目の隊移動の派遣位置と同じ、6回目の隊移動の派遣位置は2回目の隊移動の派遣位置と同じ
...... 以下ループ - 挙動2:飛行・海上のユニットと海中のユニットを別の隊にして、同一ターンに同一の島にそれぞれ派遣すると、海中のユニットは(敵・味方問わず)飛行・海上のユニットの下に派遣される
上記の挙動が説明できるような隊移動のアルゴリズムを推測
艦隊1:飛行・海上ユニット
艦隊2:海中ユニット
挙動1の発生原理
- 1回目の隊移動
乱数によって艦隊1の派遣位置を(X1,Y1)に決定
艦隊1を(X1,Y1)に派遣 - 2回目の隊移動
乱数によって艦隊1の派遣位置を(X1,Y1)に決定
(X1,Y1)には既に艦隊1がいるため派遣不可
再度乱数によって艦隊1の派遣位置を(X2,Y2)に決定
艦隊1を(X2,Y2)に派遣 - 3回目の隊移動
乱数によって艦隊1の派遣位置を(X1,Y1)に決定
2回目の隊移動で艦隊1は(X1,Y1)から(X2,Y2)に移動したため、(X1,Y1)に派遣可能
艦隊1を(X1,Y1)に派遣 - 4回目の隊移動
……以下ループ
挙動2の発生原理
- 艦隊1の隊移動
乱数によって艦隊1の派遣位置を(X1,Y1)に決定
艦隊1を(X1,Y1)に派遣 - 艦隊2の隊移動
乱数によって艦隊2の派遣位置を(X1,Y1)に決定
(X1,Y1)には既に艦隊1がいるが、海中階層では派遣可能
艦隊2を(X1,Y1)に派遣
乱数の発生について、仮説を立てる
仮説1
隊移動する際に乱数の初期化が行われている
隊移動
↓
乱数初期化
↓
乱数による派遣位置決定
仮説2
あらかじめ乱数によって派遣位置と順番を決めておき、隊移動する際は順番通りに決められた位置に派遣する
乱数発生
↓
乱数による派遣位置配列作成
隊移動
↓
派遣位置配列を参照
↓
派遣位置決定
仮説1と仮説2の違い
もし仮説1であれば、擬似乱数のseed値を特定すると乱数調整が可能になる
乱数調整ができると……
- 派遣位置を自由に決められる
- 掘削数量1で必ず油田が見つかる(高速掘削でも同様)
- 残骸売却で必ずクリスタルが見つかる(どのクリスタルを発見するかも決められる)
- 全ての災害を操れる(敵の艦隊に隕石を落とす等)
仮説2であれば、擬似乱数のseed値を特定すると
- 派遣位置が事前に分かる
前回同様、ソースコードを読む
ターン消費無しの隊移動はhakojoy独自の改造
↓
通常の隊移動のソースコードから推測
hako-turn.cgiに関数moveFleetを発見
# 艦隊移動 my($tx, $ty, $tLv); foreach $i (0..$tIsland->{'pnum'}) { $tx = $tIsland->{'rpx'}[$i]; $ty = $tIsland->{'rpy'}[$i]; $tLv = $tLandValue->[$tx][$ty];
pnum,rpx,rpyの定義を探す
hako-main.cgiに関数makeRandomIslandPointArray?を発見
# (0,0)から(size - 1, size - 1)までの数字が一回づつ出てくるように # $pnum($pointNumber)(@rpx, @rpy)を設定 sub makeRandomIslandPointArray { my($island) = @_;
undef $island->{'rpx'}; undef $island->{'rpy'}; my(@rpx, @rpy, $map, @x, @y, $xsize, $ysize, $pnum); $map = $island->{'map'}; @x = @{$map->{'x'}}; @y = @{$map->{'y'}}; $xsize = @x; $ysize = @y; $pnum = $xsize * $ysize;
my($x); # 初期値 @rpx = (@x) x $ysize; foreach $y (@y) { push(@rpy, ($y) x $xsize); }
# シャッフル my($i, $j); for ($i = $pnum; --$i; ) { $j = int(rand($i+1)); next if($i == $j); @rpx[$i,$j] = @rpx[$j,$i]; @rpy[$i,$j] = @rpy[$j,$i]; }
$island->{'pnum'} = $pnum - 1; $island->{'rpx'} = \@rpx; $island->{'rpy'} = \@rpy; }
再び関数moveFleetを読む
……関数makeRandomIslandPointArray?の呼び出しは無し
関数makeRandomIslandPointArray?の呼び出されている箇所を探す
hako-turn.cgiの関数turnMainで発見
# 座標配列を作る foreach $i (0..$islandNumber) { $island = $Hislands[$order[$i]]; makeRandomIslandPointArray($island); }
更新の最初に、島ごとに座標配列を作っている
この後、コマンドチェックが入るので仮説2が正しいと推測
seed値の特定
hako-main.cgiで発見
# 乱数の初期化 srand(time() ^ ($$ + ($$ << 15)));
hako-main.cgiが実行される時間は決まっているため、一見するとseed値の特定は可能そうだが......
特殊変数$$はプロセスIDの値を持つため、seed値の推測は不可能
乱数を使って悪さはできない
どんな事ができるか
- 隊移動の派遣位置をループさせない
このぐらいしか思いつかない
意見や指摘
参照回数 531