shapezで自動工場(MAM)を作ろう

しばらく積んでいた「shapez」というゲームを遊びました。

とりあえずクリアしたので、クリアのための攻略法と考え方について紹介します。
あくまで私のクリア手法であることをご了承ください。

shapezとは

Steam:shapez
Steam:shapez
shapezは無限のマップ内で様々な"形"を資源とし、段々と複雑になっていく形の作成や合成の自動化を目指して工場を構築するゲームです。

shapez(シェイプズらしい)は工場づくりゲームの一種です。フィールドから素材を採掘し、要求されている図形を構築、HUBという場所に運ぶことが目的になっています。
同様のゲームで最も有名なのはFactorioだと思います。ですがshapezはFactorioにないいくつかの特徴を持っています。

  • 敵がいない
  • 資源が無限
  • 機械も無限
  • 先が短い
  • ソースコードが公開されている

shapezの世界には敵がおらず、偶発的に工場を破壊されるというイベントは起きません(Factorioだと多足の生物が破壊しに来る)。資源は枯渇しませんし、機械の配置数にも最初から制限がないため、純粋に工場作成を自分のペースで楽しむことができます。

あと「先が短い」という部分がかなりいい点かなと思います。Factorioは無限に時間が溶け、生活を脅かす可能性がありますが、shapezは比較的コンパクトに収まっています。shapezの最終クリアは自動工場の作成で、私はそこまでだいたい45時間くらいで終わりました。

またこのゲームはSteamでの有料配信ですが、OSS版も存在しています。Webから遊ぶこともできます。ソースコードからアルゴリズムを確認できるので攻略がしやすいですね。

GitHub - tobspr-games/shapez-community-edition: The community edition of shapez, maintained by community contributors!
GitHub - tobspr-games/shapez-community-edition: The community edition of shapez, maintained by community contributors!
The community edition of shapez, maintained by community contributors! - tobspr-games/shapez-community-edition

ゲーム内容

ゲームのフィールドは2次元の無限に広い空間で、中心にHUBが存在しています。このHUBには納品すべき図形の形が表示されており、フィールド上の部品を集めて組み合わせ、その図形を作って指定数納品することが目標です。

HUB

工場でできる操作は大まかに4つに分類できます。

  • 運ぶ
    • 採掘・コンベアでの運搬・分岐・合流
  • 切断する・組み立てる・回転させる
    • 図形の切断・図形の組み合わせ・積み上げ・回転
  • 着色する
    • 色素の混色・図形への着色
  • 回路による自動化
    • コンベア操作・論理回路の構築・図形の解析

これらを組み合わせ、指定の図形をがんばって作ります。

レベル1~26までは基本的に決められた図形を一定数作ることが目標となります。このあたりではレベルが上がるごとに使える部品が増えていきます。
一方、レベル27からは「フリープレイ」モードが開始されます。ランダムな図形がお題として出され、それを一定速度で納品することがクリア条件に変化します。
いちいちお題となる図形を見て、それを組み立てる工場を作るのは面倒ですよね。そこで登場する概念が「全自動工場(Make Anything Machine, MAM)」です。
フリープレイモードに突入する頃には回路部品が使えるようになっています。回路はHUBからお題を信号として処理することができるため、これを使って図形の解析・工場の操作を行うことで図形ごとに合った図形を生産する工場を作ることができるようになるのです。

作ろう、MAM

MAMを作る前に、注意しておくべきことがあります。今回作るMAMはあくまでフリープレイモードをクリアするためのもので、shapezで作ることのできるすべての図形をさばけるわけではありません。例えばLevel 20の形状は、単純な組み立てでは実現できない形状であるため作ることができません。後述のようにフリープレイでは出てくる形状がある程度制限されているため、このような難しい図形を対象外とすることで難易度を下げています。全ての図形を作れる工場は別にTMAM(True MAM)と呼ばれ、幾人かが作っているようです。

フリープレイモードの解析

MAMに必要な条件を調べるため、まずはフリープレイモードで出てくる形状がどのようなものなのか、確認しましょう。
OSSなのでソースコードからアルゴリズムを確認できちゃいます。
フリープレイモードにおける図形の生成は、hub_goals.jsのcomputeFreeplayShape関数に書かれています。

shapez-community-edition/src/js/game/hub_goals.js at 7814c3a15a1239ea9232fe9b9ee8077ee0d31265 · tobspr-games/shapez-community-edition
shapez-community-edition/src/js/game/hub_goals.js at 7814c3a15a1239ea9232fe9b9ee8077ee0d31265 · tobspr-games/shapez-community-edition
The community edition of shapez, maintained by community contributors! - tobspr-games/shapez-community-edition

引数に渡されているlevel(this.levelも同)は表示上のレベルと同じ数値です。

レイヤ数

最初に図形のレイヤ数を決めています。

1
2
3
4
5
6
7
8
const layerCount = clamp(this.level / 25, 2, 4);
// ...
let layers = [];
// ...
for (let i = 0; i < layerCount; ++i) {
// ...
layers.push(layer);
}

clamp関数は最大最小で挟んでいるだけです。

shapez-community-edition/src/js/core/utils.js at 7814c3a15a1239ea9232fe9b9ee8077ee0d31265 · tobspr-games/shapez-community-edition
shapez-community-edition/src/js/core/utils.js at 7814c3a15a1239ea9232fe9b9ee8077ee0d31265 · tobspr-games/shapez-community-edition
The community edition of shapez, maintained by community contributors! - tobspr-games/shapez-community-edition

上のコードを整理すると、レベルとレイヤー数の関係は以下のようにわかります。

レベル 27 <= level < 51 51 <= level < 76 76 <= level
レイヤー数 2 3 4

色の種類

次に色の種類を決めます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
generateRandomColorSet(rng, allowUncolored = false) {
const colorWheel = [
enumColors.red,
enumColors.yellow,
enumColors.green,
enumColors.cyan,
enumColors.blue,
enumColors.purple,
enumColors.red,
enumColors.yellow,
];

const universalColors = [enumColors.white];
if (allowUncolored) {
universalColors.push(enumColors.uncolored);
}
const index = rng.nextIntRange(0, colorWheel.length - 2);
const pickedColors = colorWheel.slice(index, index + 3);
pickedColors.push(rng.choice(universalColors));
return pickedColors;
}
// ...
const colors = this.generateRandomColorSet(rng, level > 35);

図形に使われる色の種類はgenerateRandomColorSet関数から得られます。rngは乱数生成器です。
実行する事に異なる4色が選ばれるようになっています。

  • levelが35以下の場合:
    • カラーホイール8色のうち連続する3色 + 白
  • levelが35より大きい場合:
    • カラーホイール8色のうち連続する3色 + (白 or 無色)

図形の配置

次は使用する図形の種類と配置方法を決めます。見た目的な綺麗さを重視しているのか、ランダムな配置ではなく対称的な配置となるように調整されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
let pickedSymmetry = null; // pairs of quadrants that must be the same
let availableShapes = [enumSubShape.rect, enumSubShape.circle, enumSubShape.star];
if (rng.next() < 0.5) {
pickedSymmetry = [
// radial symmetry
[0, 2],
[1, 3],
];
availableShapes.push(enumSubShape.windmill); // windmill looks good only in radial symmetry
} else {
const symmetries = [
[
// horizontal axis
[0, 3],
[1, 2],
],
[
// vertical axis
[0, 1],
[2, 3],
],
[
// diagonal axis
[0, 2],
[1],
[3],
],
[
// other diagonal axis
[1, 3],
[0],
[2],
],
];
pickedSymmetry = rng.choice(symmetries);
}

ここではavailableShapesとpickedSymmetryに値を入れています。
pickedSymmetryは配列の配列の形状で、ちょっと構造が分かりにくいのですが、同じ図形が入る位置を指定しています。数字は右上から時計回りに振られた図形の位置を示しており、同じ配列にある位置には同じ図形が入ります。50%の確率で点対称の図形になり、それ以外のパターンは各12.5%の確率で現れます。

風車の形は点対称の場合のみに使うように設定されます。

各レイヤの図形の決定

次に今まで決定した情報をもとにして、各レイヤの図形を作っていきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for (let j = 0; j < pickedSymmetry.length; ++j) {
const group = pickedSymmetry[j];
const shape = randomShape();
const color = randomColor();
for (let k = 0; k < group.length; ++k) {
const quad = group[k];
layer[quad] = {
subShape: shape,
color,
};
}
}

// Sometimes they actually are missing *two* ones!
// Make sure at max only one layer is missing it though, otherwise we could
// create an uncreateable shape
if (level > 75 && rng.next() > 0.95 && !anyIsMissingTwo) {
layer[rng.nextIntRange(0, 4)] = null;
anyIsMissingTwo = true;
}

layers.push(layer);

前半部分ではpickedSymmetryのそれぞれの枠に図形を当てはめていきます。制約内のランダムな図形と色を取り出し、同じ図形になる部分には同じ図形を入れます。

後半部分では欠けの設定が行われます。レベルが76以上の場合、4つのレイヤのうち1つのレイヤーの1つの図形が欠ける可能性があります。
逆に言えばそれ以上欠けることはありません。全てのレイヤで3つ以上の図形が存在する場合、Level 20の図形のような小細工は不要であり、ただ各レイヤの図形を作ってそれらを重ねれば指定の図形を構築できます。

工場の全体設計

さて、フリープレイで出てくる図形がわかったので、工場に必要な機能を決定することができます。
以下のように機能をモジュールとして組み合わせます。

実際に作ったのが以下の工場です。

今回私はコンパクトさと運搬効率性を意識して設計しました。
shapezをやっていて最終的にボトルネックになってくるのがベルトコンベアの容量です。加工ラインを並べていくと材料の運搬が間に合わなくなり、全体としての稼働効率が落ちてしまいます。そのため、この工場ではなるべく材料の絶対運搬量を減らすこと、各ラインの速度を計算して無駄なスタックが発生しないようにすることで運搬の効率化を進めています。

図形解析

HUBから得た図形情報を解析し、色生成・染色・組み立て・積み重ね機能に必要な情報を供給するモジュールです。

レイヤー生成

レイヤーごとに図形を独立に作るモジュールです。図形は4分割のそれぞれについて形状選択と染色を行い、組み合わせて1つの図形にします。これを4つ並列に作ることで4レイヤーに対応します。

色生成

それぞれの図形について、必要な色を生成するモジュールです。3つの原色を受け取り、モジュール内で必要に応じて混色するようになっています。人によっては全ての色を別の場所で作って必要な色を取り出す形式のものを作りますが、運搬効率性の観点からモジュール内での混色形式を採用しました。

染色

色生成から流れてきた色で指定された図形に色を塗るモジュールです。4つの図形(丸・四角・星・風車)から指定の図形のみを取り出す機構も内包しています。色生成と染色のモジュールは各レイヤ生成で4つずつ使われます。

組み立て

4つの染色された図形片をあわせて一つの図形を作るモジュールです。

積み重ね

最大4つのレイヤーを積み重ねるモジュールです。

ストレージ

作成した図形を一時的に貯蔵し、自動的に放出するモジュールです。
フリープレイのレベルクリアの条件は、時間あたりの供給図形数です。これは一定時間その供給速度を達成すればよいので、しばらく作った図形を貯めておいて一気に放出して条件をクリアさせます。
自動でレベルをクリアしてもらいたかったので、貯蔵と放出も自動化しています。

各モジュールの詳細については後ほど別記事で紹介しています。

終わり

とりあえず作った工場を放置していたらレベル142まで上がりました。ちゃんと動作しているようです。

みなさんもshapezで気ままな工場長生活を送ってみてはいかがでしょうか。

Share on X now! | Share on Facebook now! | Share on Linkedin now!

shapezで自動工場(MAM)を作ろう
https://fastriver.dev/2024/11/30/shapez-mam-overview/
著者
Hayakawa Yuki
作成日
2024年11月30日
著作権