最近遊んでいる工場建造ゲーム Satisfactoryで少し疑問に思うことがあったので、今回はVBAを使って検証してみた。
ゲームを題材にしてはいるものの、この記事で伝えたいことはクラスモジュールの有用性なので、ゲーム自体に興味ない方も是非ご一読いただければ幸いである。
前提の説明
このゲームではコンベアスプリッターという機材を使ってベルトコンベアを分岐させ、複数のマシンに資源を送り込むことができる。
スプリッターは資源の分配レートを指定できない為、出力経路が2本なら単純に2分割、3本なら3分割される仕組みである。
この時に使用する分岐メソッドは2タイプあり、1つはLoad Balancing Method、もう1つはOverflow Methodである。
実際のゲーム画面で説明するとこんな感じ。
モデル化したものがこちらである。
Load Balancing Methodの方は最初から資源が等配分されるのに対し、Overflow MethodはInputに近い順から配分が大きくなる。
Overflowメソッドで受け取れる資源は次のようになる。
No | 受け取れる資源の量 |
マシン1 | 半分 |
マシン2 | 半分の半分 |
マシン3 | 半分の半分の半分 |
マシン4 | 残り |
一見、後方のマシンの生産性が低いように思えるが、マシン1には生産効率を超えて資源が入るので稼働を続けると貯めきれなくなった分が溢れて資源を受け取れなくなる。そうすると受け取れなかった分は次のマシンに回されていくので、同じ資源を与えた場合のトータルの生産性はLoad Balancing Methodに追いつくとされている。(立ち上がりのアドバンテージによって総生産数の差は埋まらないが、このゲームではマシンは延々と動き続けるので総生産数はどのみち∞。重要なのは生産効率である。)
Overflowメソッドの場合、同じパターンで何台でも繋げられるので拡張性に優れている。
疑問:本当に生産効率は変わらないのか
稼働から一定時間が経過すると2つのメソッドの生産性はイコールになるということだが、本当にそうなのか心配になった。
生産性がイコールになるという説明は頭では理解できる。しかし直感的には資源が常に等分されるLoad Balancingの方が生産性に優れているような気がするのだ。
大規模な工場を建造する場合は失敗するとかなりの時間を失うため、ここでこの疑問をばっちり解消しておきたい。
VBAで検証:設計編
今回Load Balancingメソッドについては特に検証はしない。
資源が等しく配分される以上、検証するまでもなく全マシンの生産性は最初から最大である。
検証するのはOverflowメソッドの生産性である。
コンベアスプリッターとマシンで共通して使えるノードクラスを考え、次のプロパティを実装することにした。
プロパティはパブリック変数として簡易に実装する。
変数名 | 型 | 説明 |
Storage | Double | 格納できる資源の上限数 |
Store | Double | 実際に格納されている資源の数 |
Consume | Double | 1チックごとに消費する資源の数 |
Product | Long | 生産された製品の数 |
NextNodes | Collection | 資源の送出先ノード |
スプリッターの場合はConsumeは0、資源の上限数は現状コンベアベルトMk.5の運搬スピードが780 Item/minなので780する。NextNodesには次のスプリッターノードとマシンノードを登録する。
マシンの場合はConsumeが90、資源の上限数は500とし、NextNodesは何も登録しない。
また、マシンの挙動としてStoreがConsumeよりも大きい場合、1チックごとにStoreからConsumeを差し引いて、代わりにProductが1増える仕組みとした。
ちなみにスプリッターも内部的には同じ挙動をするが、Consumeは0なのでStoreは減らず、単にProductだけが増え続ける。スプリッターのProduct数に意味はないが、わざわざ増やさない処理を書くのも面倒だったので単に無視することにした。
VBAで検証:コーディング
まずはクラスモジュールを挿入し、オブジェクト名をNodeとして次のコードを張り付ける。
Option Explicit Public Storage As Double Public Store As Double Public Consume As Double Public Product As Long Public NextNodes As Collection Public Sub Tick() Dim n As Node If Store > Consume Then Store = Store - Consume Product = Product + 1 End If Dim cnt As Integer cnt = NextNodes.Count For Each n In NextNodes Dim ret As Double ret = n.TryReceive(Store / cnt) Store = Store - (Store / cnt) Store = Store + ret cnt = cnt - 1 Next End Sub Public Function TryReceive(amount As Double) As Double Store = Store + amount Dim ret As Double If Storage < Store Then ret = Store - Storage Store = Storage Else ret = 0 End If TryReceive = ret End Function Private Sub Class_Initialize() Set NextNodes = New Collection End Sub
次に標準モジュールのコード。
Sub OverflowProductivityCheck() Const NUMBER_OF_TICKS = 100 Dim splitter(1 To 4) As Node Dim machine(1 To 4) As Node Dim i As Long For i = 1 To 4 Set splitter(i) = New Node splitter(i).Storage = 780 splitter(i).Consume = 0 Set machine(i) = New Node machine(i).Storage = 500 machine(i).Consume = 90 Next For i = 1 To 4 splitter(i).NextNodes.Add machine(i) If i < 4 Then splitter(i).NextNodes.Add splitter(i + 1) End If Next Dim j As Integer For i = 1 To NUMBER_OF_TICKS splitter(1).TryReceive 360 For j = 1 To 4 splitter(j).Tick machine(j).Tick Next Next For i = 1 To 4 Debug.Print machine(i).Product Next End Sub
OverflowProductivityCheckプロシージャはNUMBER_OF_TICKSで指定された回数分時間を進めて、マシンごとの累計プロダクト数を出力する。
NUMBER_OF_TICKSを変えて何度か試してみたところ、Tick回数ごとの累計プロダクト数は以下のようになった。
↓マシン/Tick回数→ | 5 | 10 | 50 | 100 | 10000 |
マシン1 | 5 | 10 | 50 | 1000 | 10000 |
マシン2 | 4 | 9 | 49 | 99 | 9999 |
マシン3 | 2 | 6 | 45 | 95 | 9995 |
マシン4 | 2 | 6 | 45 | 95 | 9995 |
この実験で、累計プロダクト数は立ち上がり時の効率による影響を受けているものの、生産性は確かにLoad Balancing Methodに追いつくということが分かった。
終わりに
本当はクラスなんて作らなくても数学的に解けないか、あるいはExcelの機能で簡単に解けないかということも考えていたのだが、結局私は文系思考から抜け出せていない為、ロジックを言語で記述すること(つまりプログラミング)で実験することにした。
私の中に最近、ロジックを式で完結に表記するのが理系、言葉で順序だてて説明するのが文系というイメージがある。そう考えると、プログラミングは文系最強の道具なのではないかと思う。
さて、今回は頭で考えてもなかなか払拭できない疑問を晴らすためにクラスモジュールを使って実際の構造を再現して実行してみた。
頭の中に描いたモデルを実際にプログラミングで使える道具にしてしまうのがクラスモジュールの強みである。
特にデータ構造を作ったとき、各ノードは何らかの機能を持っていることが普通のなので、クラスを用いることでそうしたモデルを直感的に扱うことができるようになる。
クラスなんて使わなくてもVBAは書けるので全く覚える必要はないという意見も耳にするが、それは頭の良い人が言ってることなので真に受けないほうが良い。
絵を描く天才が、直線引くのに定規なんて要ります?鉛筆だけで十分でしょと言ってるのと同じ。
私は凡人である。凡人には強力なツールが必要だ。さもなければすぐに頭がこんがらがってしまい、難しい問題に太刀打ちできない。
皆さんも凡人である。天才はこんなブログ読んでない。多分。
クラスモジュールは凡人にこそおススメしたい、VBA最強の整理整頓ツールである。
以上。