17-8 廃坑から覗く闇③

解説動画

解答コード

// アイテム番号の連想配列
let dic_item178: { [key: string]: number } = {
    "support": 17,    // 補助支柱(オークの原木)
    "trapdoor": 656,  // 暗渠のふた(トラップドア)
    "slab": 262302    // 暗渠のふた(ハーフブロック)
};

// 反対方向の連想配列
let dic_opposite: { [key: number]: number } = {
    [RIGHT]: LEFT,      // 右の反対は左
    [LEFT]: RIGHT,      // 左の反対は右
    [UP]: DOWN,         // 上の反対は下
    [DOWN]: UP,         // 下の反対は上
    [FORWARD]: BACK,    // 前の反対は後ろ
    [BACK]: FORWARD     // 後ろの反対は前
};

// エリア番号の連想配列
let dic_areaId178: { [key: string]: number } = {
    "farmlandArea": 1, // 畑エリア
    "floorArea": 2     // 床エリア
};

// 各エリアのブロック番号を記録する二次元配列
let arr_areaBlocks178: number[][] = [
    [],  // 畑エリアのブロック配列
    []   // 床エリアのブロック配列
];

// エリア状態
let dic_areaStatus178: { [key: string]: number } = {
    "areaId": 0,                      // エリア番号(初期状態は未指定:0)
    "maxRow": 6,                      // 行の最大値
    "maxCol": 8,                      // 列の最大値
    "positiveRowDirection": FORWARD,  // 行の順方向
    "positiveColDirection": RIGHT     // 列の順方向
};

// エージェント状態
let dic_agentStatus178: { [key: string]: number } = {
    "row": 0,                         // 現在の行位置
    "col": 0,                         // 現在の列位置
    "moveDirection": RIGHT            // 移動する方向
};

// エージェントを移動する関数
function move178(agentStatus: { [key: string]: number }, areaStatus: { [key: string]: number }) {
    // エージェントの現在の位置と移動方向を取得します
    let row = agentStatus["row"];                     // エージェントの現在の行位置
    let col = agentStatus["col"];                     // エージェントの現在の列位置
    let moveDirection = agentStatus["moveDirection"]; // エージェントの移動方向

    // 列の順方向を取得します
    let positiveColDirection = areaStatus["positiveColDirection"];
    // 列の逆方向を取得します
    let negativeColDirection = dic_opposite[positiveColDirection];

    // 方向転換が必要かどうかを判定します
    let shouldTurn = false;

    // エージェントが列を順方向に進んでいて、エリアの列の最後にいる場合は、方向転換が必要です
    if (moveDirection == positiveColDirection && col == areaStatus["maxCol"]) {
        shouldTurn = true;
    }
    // エージェントが列を逆方向に進んでいて、エリアの列の最初にいる場合は、方向転換が必要です
    if (moveDirection == negativeColDirection && col == 0) {
        shouldTurn = true;
    }

    // 移動を続けるかどうかを判定します
    let shouldContinue = true;

    // エージェントがエリアの行の最後にいる場合
    if (row == areaStatus["maxRow"]) {
        // かつ、方向転換が必要の場合は、移動してもエリア外に出てしまうので、ここで移動を終了します
        if (shouldTurn) {
            shouldContinue = false;
        }
    }

    // 移動終了の場合は、false を返して終了します
    if (shouldContinue == false) {
        return false;
    }

    // エージェントを移動します
    if (shouldTurn) {
        // 方向転換をする場合の移動方法

        // 行を移動します
        agent.move(areaStatus["positiveRowDirection"], 1);
        row += 1;
        // エージェントが移動する向きを反対にします
        moveDirection = dic_opposite[moveDirection];
    } else {
        // 方向転換をしない場合の移動方法

        // 列を移動します
        agent.move(moveDirection, 1);
        if (moveDirection == positiveColDirection) {
            // 列の順方向へ移動する場合はエージェントの列位置に 1 を加えます
            col += 1;
        } else {
            // 列の逆方向へ移動する場合はエージェントの列位置から 1 を除きます
            col -= 1;
        }
    }

    // エージェントの状態を更新します
    agentStatus["row"] = row;
    agentStatus["col"] = col;
    agentStatus["moveDirection"] = moveDirection;

    // 移動したので、true を返して終了します
    return true;
}

// 暗渠ブロックかどうかを判定する関数
function isWaterCover178(blockId: number) {
    if (blockId == dic_item178["trapdoor"] || blockId == dic_item178["slab"]) {
        return true;
    }
    return false;
}

// 暗渠カバーを設置する関数
// エージェントは水路と同じ向きを向いており、水路の斜め上の高さにいることを前提にします
function placeWaterCover178(item: number,
    positiveDirection: number,
    supportItem: number) {
    // 地下通路を掘るときの地面ブロックを記録する配列
    let grounds: number[] = [];
    let negativeDirection = dic_opposite[positiveDirection];

    // 補助支柱の作成
    agent.move(positiveDirection, 1);
    agent.setItem(supportItem, 1, 1);
    agent.place(negativeDirection);

    // 地下通路の作成・移動
    grounds.push(agent.inspect(AgentInspection.Block, DOWN));
    agent.destroy(DOWN);
    agent.move(DOWN, 1);
    grounds.push(agent.inspect(AgentInspection.Block, DOWN));
    agent.destroy(DOWN);
    agent.move(DOWN, 1);
    grounds.push(agent.inspect(AgentInspection.Block, negativeDirection));
    agent.destroy(negativeDirection);
    agent.move(negativeDirection, 1);

    // 暗渠カバーの設置
    agent.turn(RIGHT);
    agent.turn(RIGHT);
    agent.setItem(item, 1, 1);
    agent.place(UP);
    agent.turn(RIGHT);
    agent.turn(RIGHT);

    // 地下通路を戻りつつ現状復帰
    agent.move(positiveDirection, 1);
    agent.setItem(grounds.pop(), 1, 1);
    agent.place(negativeDirection);
    agent.move(UP, 1);
    agent.setItem(grounds.pop(), 1, 1);
    agent.place(DOWN);
    agent.move(UP, 1);
    agent.setItem(grounds.pop(), 1, 1);
    agent.place(DOWN);

    // 補助支柱の撤去
    agent.destroy(negativeDirection);
    agent.move(negativeDirection, 1);

    return;
}

// エリアをコピーする関数
function copyArea178(agentStatus: { [key: string]: number },
    areaStatus: { [key: string]: number },
    areaBlocks: number[][]) {
    // コピーするブロック配列
    let blocks = [];

    // エリア内の床のブロックを読み取りながら、元の床に戻していきます
    while (true) {
        // 足元のブロックを読み取り、畑ブロック配列へ記録します
        let blockId = agent.inspect(AgentInspection.Block, DOWN);
        blocks.push(blockId);

        // 次の位置へ移動します
        let shouldContinue = move178(agentStatus, areaStatus);
        if (shouldContinue == false) {
            break;
        }
    }

    // コピーしたブロック配列をエリアブロック連想配列に保存します
    areaBlocks[areaStatus["areaId"] - 1] = blocks;
    return;
}

// エリアをペーストする関数
function pasteArea178(agentStatus: { [key: string]: number },
    areaStatus: { [key: string]: number },
    areaBlocks: number[][]) {
    // コピーしたブロック配列を取得します
    let blocks = areaBlocks[areaStatus["areaId"] - 1];

    // ペーストしたブロックを記録する配列
    let pastedBlocks: number[] = [];

    // 補助支柱のアイテム番号
    let supportItemId = dic_item178["support"];

    // エリア内のブロックを置き換えていきます
    while (true) {
        // 足元のブロックを削ります
        agent.destroy(DOWN);

        // ブロック配列から順にブロックを取り出します
        let blockId = blocks.shift();

        // ブロックを置く前に暗渠かどうか判定します
        if (isWaterCover178(blockId)) {
            // 暗渠を作ります
            placeWaterCover178(blockId, agentStatus["moveDirection"], supportItemId);
        } else {
            // ブロック設置
            agent.setItem(blockId, 1, 1);
            agent.place(DOWN);
            pastedBlocks.push(blockId);
        }

        // 次の位置へ移動します
        let shouldContinue = move178(agentStatus, areaStatus);
        if (shouldContinue == false) {
            break;
        }
    }

    // エリアブロック連想配列にペーストしたブロック配列を保存します
    areaBlocks[areaStatus["areaId"] - 1] = pastedBlocks;

    return;
}

// 畑エリアをコピーするコマンド
player.onChat("17-8copy_farm", function () {
    // スタート地点から1歩進みエリア内に入ります
    agent.move(FORWARD, 1);

    // エージェント状態を初期化します
    dic_agentStatus178["row"] = 0;
    dic_agentStatus178["col"] = 0;
    dic_agentStatus178["moveDirection"] = RIGHT;

    // エリア状態を初期化します
    dic_areaStatus178["areaId"] = dic_areaId178["farmlandArea"];

    // エリア内のブロックをコピーします
    copyArea178(dic_agentStatus178, dic_areaStatus178, arr_areaBlocks178);
});

// 床エリアをコピーするコマンド
player.onChat("17-8copy_floor", function () {
    // スタート地点から1歩進みエリア内に入ります
    agent.move(FORWARD, 1);

    // エージェント状態を初期化します
    dic_agentStatus178["row"] = 0;
    dic_agentStatus178["col"] = 0;
    dic_agentStatus178["moveDirection"] = RIGHT;

    // エリア状態を初期化します
    dic_areaStatus178["areaId"] = dic_areaId178["floorArea"];

    // エリア内のブロックをコピーします
    copyArea178(dic_agentStatus178, dic_areaStatus178, arr_areaBlocks178);
});

// 畑エリアをペーストするコマンド
player.onChat("17-8paste_farm", function () {
    // スタート地点から1歩進みエリア内に入ります
    agent.move(FORWARD, 1);

    // エージェント状態を初期化します
    dic_agentStatus178["row"] = 0;
    dic_agentStatus178["col"] = 0;
    dic_agentStatus178["moveDirection"] = RIGHT;

    // エリア状態を初期化します
    dic_areaStatus178["areaId"] = dic_areaId178["farmlandArea"];

    // エリア内のブロックをペーストします
    pasteArea178(dic_agentStatus178, dic_areaStatus178, arr_areaBlocks178);
});

// 床エリアをペーストするコマンド
player.onChat("17-8paste_floor", function () {
    // スタート地点から1歩進みエリア内に入ります
    agent.move(FORWARD, 1);

    // エージェント状態を初期化します
    dic_agentStatus178["row"] = 0;
    dic_agentStatus178["col"] = 0;
    dic_agentStatus178["moveDirection"] = RIGHT;

    // エリア状態を初期化します
    dic_areaStatus178["areaId"] = dic_areaId178["floorArea"];

    // エリア内のブロックをペーストします
    pasteArea178(dic_agentStatus178, dic_areaStatus178, arr_areaBlocks178);
});