首先,什么是Factorio?

《异星工厂》(英语:Factorio)为Wube Software所开发的一套冒险沙盒游戏。发布有Microsoft Windows、OS X、Linux平台,2016年于Steam发布。

u1s1,其实我没玩过这游戏 ,之前看到一朋友在写这个游戏的脚本我闲得没事干也要了份数据尝试写了个简易版本的 。这个游戏往简单的说类似于我的世界合成方块,比如想合成一个下界合金剑需要钻石剑和下界合金碎锭,合成钻石剑又需要钻石+木棍...总之就如此一层一层的往下分解直到分解到最小资源单元1

对于这个游戏,我们的目的是写一个脚本工具使用户能通过输入想生成的物资以及数量输出合成的具体步骤。因为合成结构是一层一层往下的,所以不难想到用递归(recursion)来写,所以很快啊,先用python把算法撸出来。

import json
import pprint

data = dict(json.load(open("data.json", 'rb')))


def get_ing(item):
    steps = []
    helper(item, steps)
    return steps


def helper(item, steps):
    if not len(data[item]):
        return
    ingredient = data[item][0]['ingredients']
    steps.append(ingredient)
    for i in ingredient:
        return helper(i['name'], steps)

pprint.pprint(get_ing('speed-module'))

为了能把工具发布到网上,我还写了个PHP版本的

function echo_ing($item)
{
    global $data;
    global $id;
    global $amount;
    if (!empty($data[$item])) {
        $ingredient = $data[$item][0]['ingredients'];
        echo "<i>Parent: " . $item . "</i><br><br>";
        foreach ($ingredient as $ing) {
            if (empty($data[$ing['name']])) echo "*";
            echo "<b>" . $ing['name'] . "</b>: " . intval($ing['amount']) * $amount . "<br>";
            echo_ing($ing['name']);
        }
    }
}

现在脚本已经知道合成所需要的材料,但为了方便用户使用,我们还得想个办法把合成的结构以及层级显示出来。

在递归中有很多种方式能够获取到每个材料所处的层级,比如可以在loop前后加个定位的玩意儿。我这里是通过判断材料是否属于同一个Parent来分辨是否为一个层级,再配合<div>标签和css里的margin-left就能实现简易的树状结构显示了,代码如下:

$id = 0;
$cur_parent = NAN;

function echo_ing($item)
{
    global $data;
    global $id;
    global $cur_parent;
    global $amount;
    if (!empty($data[$item])) {
        $ingredient = $data[$item][0]['ingredients'];
        echo "<div id=" . $id++ . " style='margin-left: " . ($cur_parent == $item || $id == 1 ? 0 : 50) . "'>";
        //echo "<i>Parent: " . $item . "</i><br><br>";
        foreach ($ingredient as $ing) {
            if (empty($data[$ing['name']])) echo "*";
            echo "<b>" . $ing['name'] . "</b>: " . intval($ing['amount']) * $amount . "<br>";
            echo_ing($ing['name']);
        }
        if ($cur_parent != $item) echo '</div>';
    }
}

DEMO

Source Code: TwinIsland/Factorio-Calculator


  1. 比如我的世界里的原木