並列駅の回路制御
前回の記事で搬入駅の回路についてあまり詳しく書かなかった&不完全だったので、今回は複数の列車をうまく制御するための回路をどう考えて組んだかについて書きます。
Q.回路は必要?
A.生産ラインを繋ぐ上では不要です。回路によってできることは、大抵は効率化だけかと思います。
例えば、以下のやつです。
したがって、一応動くけどもうちょっと思い通り動いてほしいな~、というときに回路を使って解決します。
問題を設定・洗練する
とりあえず問題設定
論理回路は難しいので、最初にやりたいことを明確にしたほうがいいと思います。
以下の具体例を考えます。
画像のような複数並列させた搬入駅において、次のことを実現させたいとします。(もう実装済みだけど)
- 鉄板が足りていない駅に優先的に列車が入るようにする。
列車の行き先の操作には、信号を赤にする他に、駅の有効/無効を制御する方法があります。これを使ってもう少し具体的にすると、
- 鉄板が不足している駅のみを有効にし、十分な駅を無効にする。
となります。
しかし前回の記事でも書いた通り、このまま実装してしまうと、全駅のバッファが十分になるとすべての駅が無効になってしまい、機能しなくなります。したがって、さらに条件を追加します。
- 鉄板が不足している駅のみを有効にし、十分な駅を無効にする。
- すべての駅が無効となるとき、すべての駅を有効にする。
ここまでは前回書きました。
バグから仕様変更する
しかししかし、この回路を組んで動かしてみて気づいたのですが、
- 鉄板が不足している駅すべてに列車が停まっており、列車の停まっていないすべての駅に十分な鉄板があってその駅が無効化されているとき、新しい列車が使用中の駅に侵入しようとしてしまう。
- 列車が駅に進入している途中で、(他駅の鉄板が消費されて足りなくなり、有効/無効が切り替わるなどして)向かっている駅が突然無効化されてデッドロックが起きる。
という2つの欠陥がありました。特に2つ目の欠陥は致命的です。1の欠陥は使用中の駅を無効にすることで、2の欠陥は列車が進入中の(信号が緑でない)ときにその駅を有効にすることで解決できそうです。よって最終的には要件を以下のようにします。条件は上から優先されます。
- すべての駅が無効化されようとするとき、すべての駅を有効化する。
- 以下のいずれかを満たすとき、駅を無効化する。
・列車が停車している
・鉄板が足りていてかつ信号が緑である(侵入中の列車が存在しない)
式を立てる
ここからは、いわゆるブール代数で立式します。今回エンティティから拾う欲しい情報は以下の項目です。n個の駅を想定します。
- k番目の駅への信号が緑であること(緑[k]とします)
- k番目の駅の鉄板が足りていること(足[k])
- k番目の駅に列車が停車していること(T[k])*1
k番目の駅を有効にすることをX[k]とすると、X[k]は以下の式で表されます。式変形の際は各式をひとつの算術回路か条件回路で表現できる程度に分解します。("<"とか"≧"は不等号?ではなく二項演算子です。)
これをもとに実際に駅を作ってテストしてみます。
実装してみた。
駅の数は4つ、鉄板不足の条件を鉄板200枚未満に設定してみました。右から2、4番の駅に225枚の鉄板を入れたので、駅が無効になっているのが分かると思います。(駅のライトが黄色ではなく赤色になっています。)
次の画像の通り列車を一本自動で走らせてみたところ、1番の駅に入り、1番の駅が無効になりました。
もう一本走らせると、予定では3番の駅に入って3番も無効化され、これによりすべての駅が無効になろうとするのですべての駅が有効となります。次の画像で確認しましょう。
たしかにすべての駅に黄色いランプが点いています。次にさらに列車を走らせ、2番への進入中に4番の鉄板を減らしてみます。以前であれば2番の駅が進入中に無効となり、デッドロックが起こっていましたが、改善されてるかな?
画像では2番の駅のブロックが予約済みになっているため、信号が黄色になり、駅が有効になっているのが分かります。これでデッドロックも起こらなさそうです。よかった。
現在僕の工場は全部この回路を使って動かしていますが、今のところデッドロックは起こっていません。
まとめ
Factorioの基本アイテムはデフォルトでとても優秀なアルゴリズムで動いているので、そのままでも十分使えると思います。ただ、生産性や効率性を限界まで追求するためには、回路による制御は必要不可欠です。
ぼくもやっと最近触り出したばかりなので、こういうところに回路をこう使えば便利などといった知恵があればまた記事にすると思います。次回の内容はなににしようかな。
*1:二値ではなく列車のID(正の整数)で代用しています。