LoginSignup
1
1

JavaScriptでかの有名な水の移し替えパズルを解く【幅優先探索】

Last updated at Posted at 2024-01-05

元ネタ

問題

水が5L入る容器と3L入る容器がある、この2つの容器だけを使って、
4Lの水を量るにはどうすれば良いですか?
水はいくらでも使えるものとします。

ソース

function 水を捨てる_3L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const result = {
        new容器3Lの容量: 0,
        new容器5Lの容量: 容器5Lの容量
    }
    if (need操作テキスト) {
        result.操作テキスト = "3L容器を空っぽにした。  ";
    }
    return result;
}
function 水を捨てる_5L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const result = {
        new容器3Lの容量: 容器3Lの容量,
        new容器5Lの容量: 0
    }
    if (need操作テキスト) {
        result.操作テキスト = "5L容器を空っぽにした。  ";
    }
    return result;
}
function 水を入れる_3L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const result = {
        new容器3Lの容量: 3,
        new容器5Lの容量: 容器5Lの容量
    }
    if (need操作テキスト) {
        result.操作テキスト = "3L容器を満タンにした。  ";
    }
    return result;
}
function 水を入れる_5L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const result = {
        new容器3Lの容量: 容器3Lの容量,
        new容器5Lの容量: 5
    }
    if (need操作テキスト) {
        result.操作テキスト = "5L容器を満タンにした。  ";
    }
    return result;
}
function 水を移す_3Lから5L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const 移動する容量 = Math.min(容器3Lの容量, 5 - 容器5Lの容量);
    const result = {
        new容器3Lの容量: 容器3Lの容量 - 移動する容量,
        new容器5Lの容量: 容器5Lの容量 + 移動する容量
    }
    if (need操作テキスト) {
        result.操作テキスト = "3L容器から5L容器へ注いだ。";
    }
    return result;
}
function 水を移す_5Lから3L(容器3Lの容量, 容器5Lの容量, need操作テキスト = false) {
    const 移動する容量 = Math.min(3 - 容器3Lの容量, 容器5Lの容量);
    const result = {
        new容器3Lの容量: 容器3Lの容量 + 移動する容量,
        new容器5Lの容量: 容器5Lの容量 - 移動する容量
    }
    if (need操作テキスト) {
        result.操作テキスト = "5L容器から3L容器へ注いだ。";
    }
    return result;
}

const 操作一覧 = [
    水を捨てる_3L, 水を捨てる_5L,
    水を入れる_3L, 水を入れる_5L,
    水を移す_3Lから5L, 水を移す_5Lから3L
];

const キュー = [];
キュー.push({
    容器3Lの容量: 0,
    容器5Lの容量: 0,
    操作手順: []
});

let 答えの操作手順 = undefined;
loop:
while (true) {
    const {容器3Lの容量, 容器5Lの容量, 操作手順} = キュー.shift();
    for (const 操作 of 操作一覧) {
        const {new容器3Lの容量, new容器5Lの容量} = 操作(容器3Lの容量, 容器5Lの容量);
        if (容器3Lの容量 === new容器3Lの容量 && 容器5Lの容量 === new容器5Lの容量) {
            continue;
        }
        const new操作手順 = [...操作手順];
        new操作手順.push(操作);
        if (new容器5Lの容量 === 4) {
            答えの操作手順 = new操作手順;
            break loop;
        }
        キュー.push({
            容器3Lの容量: new容器3Lの容量,
            容器5Lの容量: new容器5Lの容量,
            操作手順: new操作手順
        });
    }
}

let 容器3Lの容量 = 0;
let 容器5Lの容量 = 0;
for (let i = 0; i < 答えの操作手順.length; i++) {
    const 操作 = 答えの操作手順[i];
    const {new容器3Lの容量, new容器5Lの容量, 操作テキスト} = 操作(容器3Lの容量, 容器5Lの容量, true);
    console.log(`${i + 1}: ${操作テキスト}【3L容器: ${new容器3Lの容量}L, 5L容器: ${new容器5Lの容量}L】`);
    容器3Lの容量 = new容器3Lの容量;
    容器5Lの容量 = new容器5Lの容量;
}

実行結果

1: 5L容器を満タンにした。  【3L容器: 0L, 5L容器: 5L】
2: 5L容器から3L容器へ注いだ。【3L容器: 3L, 5L容器: 2L】
3: 3L容器を空っぽにした。  【3L容器: 0L, 5L容器: 2L】
4: 5L容器から3L容器へ注いだ。【3L容器: 2L, 5L容器: 0L】
5: 5L容器を満タンにした。  【3L容器: 2L, 5L容器: 5L】
6: 5L容器から3L容器へ注いだ。【3L容器: 3L, 5L容器: 4L】

別の方法

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1