18-8 ドキドキ分岐ポイント③

解説動画

解答画像

// -- 18-8 線路を読み取り、修復する ----------------------------------------------------

// 線路パターンの連想配列
let dic_railBlocks188: { [key: number]: number[] } = {
    // 初期状態は、空です
};

// エージェントの状態の連想配列
let dic_agentStatus188: { [key: string]: number } = {
    "block": 0, // 持つブロック番号
    "forward": 0, // 前の移動距離
    "right": 0, // 右の移動距離
    "placeDirection": DOWN, // ブロックを置く方向
    "moveDirection": RIGHT // 印を探すときの移動方向
};

let airBlockId188 = 0; // 空気ブロックのID

let fenceBlockId188 = 262229; // フェンスのブロックID

// 反対方向の連想配列
let dic_oppositeDirection: { [key: number]: number } = {
    [FORWARD]: BACK,
    [BACK]: FORWARD,
    [RIGHT]: LEFT,
    [LEFT]: RIGHT,
    [UP]: DOWN,
    [DOWN]: UP
};

// エージェントを前へ移動させる関数
function moveForward188(agentStatus: { [key: string]: number }): boolean {
    let canMove = agent.move(FORWARD, 1);
    if (!canMove) {
        player.say("エージェントが前へ移動できません!");
        return false;
    }
    agentStatus["forward"] += 1;
    return true;
}

// エージェントを後ろ移動させる関数
function moveBack188(agentStatus: { [key: string]: number }): boolean {
    let canMove = agent.move(BACK, 1);
    if (!canMove) {
        player.say("エージェントが後ろへ移動できません!");
        return false;
    }
    agentStatus["forward"] -= 1;
    return true;
}

// エージェントを右に移動させる関数
function moveRight188(agentStatus: { [key: string]: number }): boolean {
    let canMove = agent.move(RIGHT, 1);
    if (!canMove) {
        player.say("エージェントが右に移動できません!");
        return false;
    }
    agentStatus["right"] += 1;
    return true;
}

// エージェントを左に移動させる関数
function moveLeft188(agentStatus: { [key: string]: number }): boolean {
    let canMove = agent.move(LEFT, 1);
    if (!canMove) {
        player.say("エージェントが左に移動できません!");
        return false;
    }
    agentStatus["right"] -= 1;
    return true;
}

// エージェントにブロックを設置させる関数
function placeBlock188(agentStatus: { [key: string]: number }): boolean {
    // 空のブロックを置く場合は何もせず true を返して終了します
    if (agentStatus["block"] == airBlockId188) {
        return true;
    }
    agent.setItem(agentStatus["block"], 1, 1);
    let canPlace = agent.place(agentStatus["placeDirection"]);
    if (!canPlace) {
        player.say("エージェントがブロックを設置できません!");
    }
    return canPlace;
}

// エージェントにレールのブロックを読みとらせる関数
function scanBlock188(agentStatus: { [key: string]: number }, railBlocks: { [key: number]: number[] }) {
    while (true) {
        // 足元のブロックと、レールのブロックを読み取ります
        let downBlockId = agent.inspect(AgentInspection.Block, DOWN);
        player.say(`足元のブロックID: ${downBlockId}`);

        let railBlockId = agent.inspect(AgentInspection.Block, LEFT);
        player.say(`レールのブロックID: ${railBlockId}`);

        // 足元のブロック番号をキーとして、線路パターンの連想配列へレールのブロック番号を登録します
        if (railBlocks[downBlockId] == undefined) {
            railBlocks[downBlockId] = [railBlockId];
        } else {
            railBlocks[downBlockId].push(railBlockId);
        }

        // 前へ進むかどうかを判定します
        let forwardBlockId = agent.inspect(AgentInspection.Block, agentStatus["moveDirection"]);
        if (forwardBlockId == fenceBlockId188) {
            // 前にフェンスがある場合は、前へ進まずにループを抜けます
            player.say("前にフェンスがあるので、これ以上進みません");
            break;
        }
        // 次のレールを読み取るために、前へ進みます(前以外には進みません)
        if (agentStatus["moveDirection"] == FORWARD) {
            moveForward188(agentStatus);
        }
    }
}

// フェンスに囲まれたエリアで足元の印を探し回る関数
function searchMarkerInArea188(agentStatus: { [key: string]: number }, railBlocks: { [key: number]: number[] }): number {
    while (true) {
        // 足元のブロックを調べます
        let belowBlock = agent.inspect(AgentInspection.Block, DOWN);

        // 印が見つかった場合、そのブロックIDを返します
        if (railBlocks[belowBlock] != undefined) {
            player.say(`印を発見しました:ID ${belowBlock}`);
            return belowBlock;
        }
        // 見つからなかった場合、次の場所へ移動します
        let canMove = moveNextInArea188(agentStatus);
        if (!canMove) {
            // 次の場所へ移動できなくなった場合は、0を返します
            return 0;
        }
    }
}

// フェンスに囲まれたエリアで次の場所へ移動する関数
function moveNextInArea188(agentStatus: { [key: string]: number }): boolean {
    // 移動が成功したかどうかの変数(この関数から返す戻り値)
    let canMove = false;

    // もし、次の印を探す方向にフェンスがあれば、前へ移動して、印を探す方向を反対にします
    let blockId = agent.inspect(AgentInspection.Block, agentStatus["moveDirection"]);
    if (blockId == fenceBlockId188) {
        // もし、前にフェンスがあれば、移動できないので、false を返します
        let forwardBlockId = agent.inspect(AgentInspection.Block, FORWARD);
        if (forwardBlockId == fenceBlockId188) {
            return false;
        }
        moveForward188(agentStatus); // 前へ移動します
        agentStatus["moveDirection"] = dic_oppositeDirection[agentStatus["moveDirection"]]; // 印を探す方向を反対にします
        return true; // 移動したので、true を返します
    } else {
        // 次の印を探す方向にブロックがない場合は、移動します
        if (agentStatus["moveDirection"] == RIGHT) {
            canMove = moveRight188(agentStatus);
        } else if (agentStatus["moveDirection"] == LEFT) {
            canMove = moveLeft188(agentStatus);
        }
    }

    return canMove;
}

// 線路を修復する関数
function buildRails188(agentStatus: { [key: string]: number }, blocks: number[]) {

    let startForward = agentStatus["forward"]; // エージェントが線路修復を開始したときの前の移動距離を記録します

    // レールを設置していきます
    for (let i = 0; i < blocks.length; i++) {
        agentStatus["block"] = blocks[i];
        placeBlock188(agentStatus);
        // 前へ移動します
        moveForward188(agentStatus);
    }

    // 線路を修復し終わったら、エージェントを線路修復を開始したときの位置まで戻します
    while (agentStatus["forward"] > startForward) {
        moveBack188(agentStatus);
    }
}

// チャットコマンドで線路パターンを読み取る処理を開始します
player.onChat("18-8scan", function () {

    // 線路パターンの連想配列を初期化します
    dic_railBlocks188 = {};

    // エージェント状態を初期化します
    dic_agentStatus188["block"] = 0;
    dic_agentStatus188["forward"] = 0;
    dic_agentStatus188["right"] = 0;
    dic_agentStatus188["up"] = 0;
    dic_agentStatus188["placeDirection"] = DOWN;
    dic_agentStatus188["moveDirection"] = FORWARD; // 読み取り時の移動方向は、前です

    // エージェントを1歩前に移動させます
    moveForward188(dic_agentStatus188);

    // エージェントの位置にあるブロックを調べて、線路パターンの連想配列へ登録します
    scanBlock188(dic_agentStatus188, dic_railBlocks188);

    player.say("線路のパターンをすべて読み取りました");
});

// チャットコマンドで線路を修復する処理を開始します
player.onChat("18-8build", function () {
    // エージェント状態を初期化します
    dic_agentStatus188["block"] = 0;
    dic_agentStatus188["forward"] = 0;
    dic_agentStatus188["right"] = 0;
    dic_agentStatus188["up"] = 0;
    dic_agentStatus188["placeDirection"] = DOWN;
    dic_agentStatus188["moveDirection"] = RIGHT; // 修復時の移動方向は、初期状態では右です

    // エージェントを1歩前に移動させます
    moveForward188(dic_agentStatus188);

    while (true) {
        // 地面の印を探します
        let markerBlockId = searchMarkerInArea188(dic_agentStatus188, dic_railBlocks188);
        if (markerBlockId <= 0) {
            // 印が見つけられないまま移動できなくなった場合は、エリアを探索し終えたので、終了します
            break;
        }

        // 線路の材料ブロック番号の配列を取得します
        let blocks = dic_railBlocks188[markerBlockId];

        // 線路を修復します
        buildRails188(dic_agentStatus188, blocks);

        // 次の場所へ移動します
        let canMove = moveNextInArea188(dic_agentStatus188);

        // 次の場所へ移動できなくなった場合は、終了します
        if (!canMove) {
            break;
        }
    }

    player.say("作業を終了します");
});