見出し画像

このウツロパズルには必勝法がある(謎解きに関するネタバレあり)

※本記事は「ウツロマユ」の謎解きに関するネタバレが含まれます(ストーリーに関するネタバレは含まれておりません)

 近年、欧州サッカーに匹敵する市場規模に迫りつつあると噂されるeスポーツ「ウツロマユ RTA」ですが、その中で大きなタイムロスの原因となっているのが、仏間にあるパズル(通称:ウツロパズル)です。

 要は、4 つの円盤を回転させて、中心を「緑→青→赤→黒」(緑が上)に揃えるゲームですが、頭がこんがらがってミスをしがちです。

 しかし、RTA においては 1 秒でもタイムを縮めたい。どうにかならないものか……。

秋山「このゲームには必勝法がある」
「!?」
秋山「マス目は 12 通り、有効なコマは区別のある 4 種類」
秋山「つまり、ありえる状態数は $${_{12} P _4 = 11,880}$$ 通り」
秋山「回転の処理を考えても高々 $${10^6}$$ オーダー」
秋山「通るんだよ、全探索が。1秒足らずで」

 という訳で、プログラムで全探索します。以下は C++ による実装です。

// include やマクロの類は省略

string clockwise(string s, int start)
{
    swap(s[start], s[start + 4]);
    swap(s[start + 4], s[start + 5]);
    swap(s[start + 5], s[start + 1]);
    return s;
}

string counter_clockwise(string s, int start)
{
    swap(s[start], s[start + 1]);
    swap(s[start + 1], s[start + 5]);
    swap(s[start + 5], s[start + 4]);
    return s;
}

int main()
{
    map<string, int> mp;
    queue<string> q;
    vector<int> starts = {1, 4, 6, 9};
    string s = "x..x.GB..KR.x..x";
    mp[s] = 0;
    q.push(s);
    while (q.size())
    {
        string now = q.front();
        q.pop();
        for (int start : starts)
        {
            string cw = clockwise(now, start);
            if (!mp.count(cw))
            {
                mp[cw] = mp[now] + 1;
                q.push(cw);
            }
            string ccw = counter_clockwise(now, start);
            if (!mp.count(ccw))
            {
                mp[ccw] = mp[now] + 1;
                q.push(ccw);
            }
        }
    }
}

 アルゴリズム的に表現すると、「x..x.GB..KR.x..x」という文字列の並び替え(ただし x は固定)をノードとした幅優先探索です。

 もちろん、このままではなんのこっちゃという感じだと思うので、わかりやすく図示した結果を以下に示します。

結果

 詰将棋にならって、$${x}$$ 手詰という形で表記します。

1 手詰(8 種類)

1 手詰の一覧

 完成形から 1 つずらしたものは全て 1 手詰になります。以下のような「へ」の字になっている形です。「へ」の字になっている時はリーチだと覚えましょう。ただし、色の並びが違う場合は注意です。

2 手詰(44 種類)

2 手詰の一覧

 ちょっと量が多いですが、以上の形が 2 手詰です。選択肢が多いのに、ここを外すと大きなロスが出ます。麻雀でいえば一向聴、いわば一番実力が出る部分ですね。「ウツロマユ RTA のプロ走者は 2 手詰を外さない」とは良く言われるところです。

その他解析

(※1/14 追記 最初に載せた解析にミスがあり、この項目の結論を修正しました。その時は最悪手は 10 手詰であると述べましたが、正しくは 9 手詰になります)

 $${x}$$ 手詰と対応する盤面の種類 $${n}$$ は以下の表の通りになります。

 一番、状態数が多いのは 6 手詰の時で、4072 通りになります。また、一番完成形から遠いのは 9 手詰です。言い方を変えれば、ウツロパズルはどのような極悪な配置でも、必ず 9 手以内に完成させられると言えます。

 ちなみに、以下がそのような最悪配置(16 種類)です。走っている時にこれを引き当てたら最悪です。

9 手詰の一覧

おまけ:将来の夢(?)

 アルゴリズム的には完全に解析完了したので、RTA 走者向けに、このパズルを訓練する Web アプリ(最短経路以外の選択肢を選んだら強制ゲームオーバー)でも作ろうかと思いましたが、UI の実装がめんどくさそう&ホスティング(もしかして DB も?)を確保するのにも料金がかかるかも、ということで、優先順位はそこまで高くないです。

 極めて限られた需要だと思いますが、実現して欲しいという方がいたら……気長に待ってください。すいません。

おまけ:現実的な攻略法

 ちなみに、私が実際に走る時は、以下のような配置にすることを実質なゴールにしています。

 左上から時計回りに「緑、黒、青、赤」ですね。それぞれのコマ同士を離すようにしていけば、それほど難しくありません。

 後は、黒→青→赤を中心に寄せて、緑黒を時計回りに回転させれば完成するという、簡単な 4 手詰になります。

 まあ、このレベルの攻略法だと、もっとマシな戦略をすでに実践しとるわ! という走者も多いと思いますが、何かの参考になれば。


この記事が気に入ったらサポートをしてみませんか?