Factorio Space-Exploration終盤のアルコスフィアバランサー解説とやりこみ
最近、日本語でいくつかアルコスフィアバランサーの解説を読んだので、自分でもまとめておきたくなりました。
私がSpace-Exploration modを気に入っている理由の一つ、アルコスフィア関連のレシピ。ゴリ押し、時間をかける、既存のやり方の延長などではどうにもならなくて、頭を使わないといけないところが好きです。あと隠し要素のアレのパズルも。とにかく、ノーヒントで解くことを強くおすすめします。
対象読者
Factorioプレイヤーで、Space-Explorationをプレイし、アルコスフィアバランサーを自力で構築済みであること。その上で、他の人がどうやったかに興味がある方が、対象読者と考えます。私が構築したシステムの効率 ( spm / 使用アルコスフィア数、この記事で特に断らず単に効率と書いた場合、これを指すと考えてください ) は現時点で世界一の筈なので、そういうやりこみ視点で興味がある方も是非読んでみてください。
生涯にわたってSpace-ExplorationをプレイすることはないだろうがFactorioやSpace-Explorationについて興味がある方については、読むことを止めはしません。しかし、プレイしていることを前提にした文なので、分かりづらい部分が多いと思います。雰囲気だけ掴みたい場合にどうぞ。
上記に当てはまらない方は、ここで読むのを止めておくことをおすすめします。
アルコスフィアバランサー概説
どう解くか、そして解いたものをどうfactorioで実装するか、この2ステップになるはずです。
どう解くか
皆さん、次のいずれかで解いているはずです。過不足を調整する方法、もしくは逆変換を行う方法です。私は後者を選びました。
実装
いずれの方法で解いた場合でも、主に回路を用いた実装になります。他のどんなmodでもこのように回路の活用を要求されることはなく、やりがいがあったと思います。一応、回路不使用でも実装は可能なようです。そこそこの作り込みで済ませることもできますし、ひたすら効率を求めて作り込むこともできます。
私の解き方
初めはパッと思いつく過不足を調整する方法にしようと思ったのですが、パズルが思いの外面倒そうだったので、数学で解いたほうが楽だろうと考え、逆変換を行う方法を用いることにしました。
線形方程式
逆変換を求める方法です。folding1~8、inversionA,Bの計10種の変換を結合して行列bとします。要素8の、アルコスフィア逆変換ベクトルx、要素10の、逆変換を行うために10種の変換をそれぞれ何回ずつ行うかというベクトルc(解)。これらを用いた方程式は次のようになります。
bc=x
ムーア・ペンローズ逆行列
cを求めたいので、両辺にbの逆行列を左から掛けるのですが、初歩的な(高校数学で習うような)方法では逆行列の計算ができません。ムーア・ペンローズ逆行列を計算します。リンク先はほとんど理解する必要ありません。計算ソフトのライブラリを使用して逆行列を計算するだけです。計算には無料なのでRを使用しました。
Rで計算
Naquium Tesseractの2番目のレシピの場合です。Rでこのように計算します。逆行列はginv()によって計算され、解cが得られました。
> x <- c(1,1,1,0,0,-1,-1,-1)
>
> library(MASS)
> a <- c(-1,1,0,-1,0,0,0,1,1,-1,
+ 1,-1,-1,0,0,0,1,0,1,-1,
+ 0,1,-1,1,0,-1,0,0,-1,1,
+ 1,0,1,-1,-1,0,0,0,-1,1,
+ 0,0,0,1,-1,1,0,-1,1,-1,
+ 0,0,1,0,1,-1,-1,0,1,-1,
+ 0,-1,0,0,0,1,-1,1,-1,1,
+ -1,0,0,0,1,0,1,-1,-1,1
+ )
> b <- t(matrix(a,nrow=10))
> c <- ginv(b) %*% x
>
>
> b
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] -1 1 0 -1 0 0 0 1 1 -1
[2,] 1 -1 -1 0 0 0 1 0 1 -1
[3,] 0 1 -1 1 0 -1 0 0 -1 1
[4,] 1 0 1 -1 -1 0 0 0 -1 1
[5,] 0 0 0 1 -1 1 0 -1 1 -1
[6,] 0 0 1 0 1 -1 -1 0 1 -1
[7,] 0 -1 0 0 0 1 -1 1 -1 1
[8,] -1 0 0 0 1 0 1 -1 -1 1
>
> c
[,1]
[1,] 0.250
[2,] 0.500
[3,] -0.625
[4,] -0.125
[5,] -0.500
[6,] -0.250
[7,] 0.375
[8,] 0.375
[9,] 0.125
[10,] -0.125
解cの調整
しかし、解cは扱いやすいように調整することができます。cに任意の自然数を掛けることで、完全な逆変換を得るために複数回のxをまとめて処理する、という視点でcを調整できます。
また、アルコスフィアの変換は、3つのグループに分けることができます。folding1,2,5,6、folding3,4,7,8、inversionA,Bです。そして、各グループ内において、それぞれn回ずつ実行することは何も実行しないことと等価です。
これらをを考慮し、cに4を乗じ、さらにfolding1,2,5,6を+2、folding3,4,7,8を+5/2、inversionA,Bを+1/2調整(これらは各グループの最小値が0になるように加算)した結果、Naquium Tesseractの2番目のレシピ4回分の逆変換を行う解は、folding1を3回、folding2を4回、…、inversionAを1回、inveresionBを0回行う、であることがわかりました。
> round (c*4 + 2 * c(1,1,0,0,1,1,0,0,0,0) + 5/2 * c(0,0,1,1,0,0,1,1,0,0) + 1/2 * c(0,0,0,0,0,0,0,0,1,1) )
[,1]
[1,] 3
[2,] 4
[3,] 0
[4,] 2
[5,] 0
[6,] 1
[7,] 4
[8,] 4
[9,] 1
[10,] 0
私の実装
現時点でsaveは14k時間を超えています。アルコスフィアの使用効率やUPS効率を上げるため、何回か作り直してきましたが、現在のもの(最後の方に画像を添付)が恐らく最終形です。これ以上がんばってもおそらく効率は1割上がるかどうかでしょう。下のツイートは、ゲームクリア前の最初の実装です。ゲームクリアまでなら問題ないですが、無限研究に入りspmを上げようとすると処理速度の問題が出ます。確か100spmくらいで限界が来ました。
以降、現在の実装の要点を書いていきます。
どちらのレシピが実行されたかの判定
アルコスフィアを触媒とするすべてのレシピは、ランダムで2種のうちいずれかを実行します。どちらのレシピが実行されたかは、排出されるアルコスフィアを回路を用いて測定することで判定できます。その判定結果を元に、必要な逆変換を行います。
これは、逆変換を行う方法を採用したほとんどすべての人が行っているはずです。
大きなチェスト
多種アイテムを高速にやり取りするため、物理的にサイズが大きいチェストを使用したくなります。チートmodを使用していない場合、Warehouse ( 6*6, 512 slot )、Cargo landing pad ( 9*9, 610 slot )、Cargo rocket silo ( 10*10, 500 slot )が候補になります。
まず単純明快な話として、slot数は少ない方がUPS効率がいいです。それなりのインパクトがあります。そして、siloは最も物理サイズが大きくて実装がしやすいのですが、アイテムの入出に伴う追加の計算が非常に多いので、UPSを意識するケースでは乱用しないことが望ましいです。padも同様ですが、siloよりはだいぶマシのようです。一方、Warehouseは追加の計算はありませんが、6*6では隣接可能な組立機の数が少なすぎます。総合的に考えた結果、私はCargo landing padを使用しています。
変換の相殺
前述の通り、アルコスフィアの変換は、3つのグループに分けることができ、また、それぞれn回ずつ実行することは何も実行しないことと等価です。この考えを用いて、トータルの変換数を減らすことができます。特にinversionは、foldingの10倍処理時間がかかり、その間アルコスフィアが拘束され効率が悪くなりますから、相殺の効果が高くなります。
相殺するために、ある程度のfoldingやinversionを溜めておき、相殺可能な場合は相殺し、相殺しきれないfoldingやinversionの数がしきい値を超えた場合、実際に処理を行うようにしました。ただし、溜めすぎると変換待ちのアルコスフィアが多くなり効率が悪くなるので、そのあたりの加減が必要になります。
逆変換のグループ化
変換の相殺を最大限行うためには、すべて(T3の4種、wormhole、naq tesseract/proc)の逆変換を一つのシステムで行うのが良いのですが、色々な制約があるため、私は変換の相殺効果がある程度見込めるグループで分割しました。つまり、T3の4種(コストの大きいinversionを大幅に相殺できる)、wormhole(これ自体がシンプルで単体で最大効率にできる)、naq tesseract、naq procとnaq procの材料となるtesseract(ζ以外が補完関係にありやや変換の相殺が見込める)の4グループです。
逆変換の分割
変換待ちが多い=効率悪化です。例えば、Naquium Tesseract2番目のレシピは4回セットできれいな逆変換が得られますが、実装の段階では4回をまとめて処理する必要はありません。1,2,3,4回目それぞれの変換をデザインし、4回目が終わった時点で帳尻が合うようにします。
組立機内に滞留するアルコスフィア削減
組立機は材料となるアイテムを多めに入れることができます。ほとんどの場合気にならない仕様ですが、アルコスフィア数をシビアに管理したい場合は制御が必要になります。一つのアイテムが作成されたら、それに必要なアルコスフィアを一式だけ要求する処理を行うことで、組立機内に滞留するアルコスフィア数を、動作に支障がない範囲で最小になるようにしています。
インサータの共用
アルコスフィアは8種ありますが、物理的な配置の制約で、一つの(フィルタ)インサータで2種類のアルコスフィアを移動させる必要がある場合があります。いずれかの種類が偏って移動待ちにならないよう制御しています。例えば、一つのインサータでλとξを移動させている場合、λ10とξ2の移動待ちがあるならば、待ち数が多いλを優先的に移動させています。
チェスト間の過不足調整
チェスト間は、4本ずつのインサータを用いて双方向にアルコスフィアを移動させています。値が+だったら正方向へ、-だったら反対方向へ、という具合です。それぞれのインサータにアルコスフィア2種を割り当てていますので、前述の優先機能も実装してあります。
全体の処理の流れ
大まかには次のようになります。実行されたレシピの測定と必要な変換(foldingやinversionを何回するか)の通知をリアルタイムに実行。変換の通知はメモリ1に書き込まれます。次にバッチで(定期的に)変換の相殺としきい値を超えた変換の実行指示をシーケンシャルに実行しメモリ1を更新。変換の実行指示はメモリ2に書き込まれます。メモリ2の内容に従ってインサータが動作し、動作した結果でメモリ2を更新します。
効率の世界記録
986 spheres / 1,358 spm = 0.726 spheres/spm。これが私の世界記録です。前述の通り、逆変換を求める方法を用いています。ついでに言っておくと、1,358spmと(現時点で)14k時間というのも世界一のやりこみです。
1,120 spheres / 1,350 spm = 0.830 spheres/spm。EarendelのDiscordで紹介された次点の他の方の記録です。解き方は過不足を調整する方法を用いており、wormholeを除くすべての処理を、226spm毎に一つのシステムで行っています。かなり作り込んでいるはずです。
逆変換を求める方法、過不足を調整する方法、どちらがより効率の面で優れているかと言うのは明らかではなく、どちらも実装を突き詰めれば差はあまり無いんじゃないかとは思ってます。カッチリ作り込める余地がある分、逆変換のほうがいいのかなあ?その分回路が複雑になりますが。