1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

出口のない迷路 ラビリンス

1
Posted at

今回は、クラスを使って応用問題に挑戦していく!

クラス名にしたラビリンス(Labyrinth)がかっこよすぎて、コードを書くのが楽しすぎた(子どもかw)

というか、自力でBクラスの問題を解けるようになってきたの成長を感じる😎



問題概要

あなたは出口のない迷路(ラビリンス)に迷い込んだ。
脱出するには、迷路の「地点」を指示に従って移動しながら、その地点に置かれたアルファベットをつなげて「呪文」を作る必要がある。。


迷路の構成

  • 迷路には N 個の地点がある(地点は番号で管理)
  • 各地点からは、他の地点へ向かう 2本の一方通行の道がある

入力内容

  • 1行目
    • 地点の数 N
    • 移動の回数 K
    • 移動を開始する地点の番号 S
  • 続くN行(地点情報)
    • i番目の行には、地点 i に置かれたアルファベット a_i
    • 1本目の道がつながる地点の番号 r1_i
    • 2本目の道がつながる地点の番号 r2_i
  • 続くK行(移動指示)
    • i回目の移動で選ぶ道の番号 M_i(1か2)

求めるもの

  • 最初の地点 S からスタートし、与えられた指示に従って地点を移動する。
  • 移動で訪れたすべての地点(開始地点も含む)に置かれたアルファベットを順に繋げた文字列を作る。
  • その文字列(呪文)を出力する。








✅ OK例:シンプル

const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];

rl.on('line', (line) => {
  lines.push(line);
});

rl.on('close', () => {
  // 入力の解析
  const [N, K, S] = lines[0].split(' ').map(Number);

  // 迷路の地点クラス
  class Point {
    constructor(char, first, second) {
      this.char = char;
      this.first = Number(first);
      this.second = Number(second);
    }
  }

  // 地点情報を配列に格納
  const points = lines.slice(1, N + 1).map(line => {
    const [char, first, second] = line.split(' ');
    return new Point(char, first, second);
  });

  // 移動指示の配列 (数字1 or 2)
  const moves = lines.slice(N + 1).map(Number);

  // 移動開始地点のインデックスに変換 (0始まりにする)
  let current = S - 1;

  // 呪文の文字列として訪れた地点の文字を格納する配列
  const spell = [];
  spell.push(points[current].char);  // 最初の地点の文字も追加

  // 移動回数分ループ
  for (const move of moves) {
    // moveは1か2なので対応する道をたどる
    current = (move === 1) ? points[current].first - 1 : points[current].second - 1;
    spell.push(points[current].char);
  }

  // 呪文を結合して出力
  console.log(spell.join(''));
});

🔍ポイント解説

  • クラスPoint を用いて地点情報をわかりやすく管理

  • 配列points に地点の情報を格納。地点番号は 1 始まりなので、アクセスは 0 始まりに調整

  • spell配列に最初の地点の文字をまず格納し、その後移動先の文字も追加していく

  • 移動の指示 moves12 なので、firstsecond の経路を選択し、現在地を更新

  • 最後に spell の文字を連結して呪文として出力








✨OK例:ラビリンス

class Labyrinth {
    static spell = [];
    static points = [];
    static current = 0;
    
    constructor(str, first, second){
        this.str = str;
        this.first = Number(first);
        this.second = Number(second);
    }
    static start(point){
        this.current = point - 1;
        this.spell.push(this.points[this.current].str);
    }
    static move(choice){
        const point = this.points[this.current][choice] - 1;
        this.spell.push(this.points[point].str);
        this.current = point;
    }
    static cast() {
        console.log(this.spell.join(''));
    }
}




const rl =  require('readline').createInterface({input:process.stdin});
const lines = [];

rl.on('line', (input) => {
    lines.push(input);
});


rl.on('close', () => {
    const [N, K, S] = lines[0].split(' ').map(Number);
    
    lines
      .slice(1, N+1)
      .forEach(p => {
        const [str, first, second] = p.split(' ');
        Labyrinth.points.push(new Labyrinth(str, first, second));
      });
      
      
    Labyrinth.start(S);
    
    const choices = lines.slice(N+1).map(Number);
    for(const choice of choices){
        if(choice === 1){
            Labyrinth.move('first');
        }
        else if(choice === 2){
            Labyrinth.move('second');
        }
    }
    
    Labyrinth.cast();
});

🔍ポイント解説:

🔹 ブラケット記法

this.points[this.current][choice]

choice‘first’ または ‘second’ という文字列、

this.points[this.current] は現在の地点オブジェクト、

そこに . で直接アクセスする代わりに、[choice] と書くことで動的にプロパティを指定できる。


例えば、choice = ‘first’ なら this.points[this.current].first と同じ意味になる。

これは変数でプロパティ名を指定したいときに使うテクニック。



🔹 static プロパティとメソッドの利用

  • spellpointscurrent は全てクラス全体で共有する情報なので static として定義。

  • メソッドも static にしているので、インスタンス化しなくても Labyrinth.start() などとして呼び出せる。

  • これで状態管理が一か所にまとまり、扱いやすくなっている。



🔹 0始まりのインデックスに変換している理由

  • 入力の地点番号は1から始まるが、配列のインデックスは 0 から。
  • そのため -1 して変換している。






🗒️まとめ

  • ブラケット記法でプロパティを動的に指定
  • 2つ目のコードの方が、3つ目4つ目の道を拡張したい時に容易




僕の失敗談(´;ω;`)と解決法🐈










class Labyrinth {
    // 呪文をつなげていく配列(クラス全体で共有)
    static spell = [];
    // 迷路の地点オブジェクトを格納する配列(クラス全体で共有)
    static points = [];
    // 現在いる地点のインデックス(0始まり、クラス全体で共有)
    static current = 0;
    
    // 1地点分の情報を持つインスタンスの初期化
    constructor(str, first, second){
        this.str = str;           // 地点に置かれたアルファベット(呪文の1文字)
        this.first = Number(first);   // 1つ目の道の行き先(地点番号)
        this.second = Number(second); // 2つ目の道の行き先(地点番号)
    }

    // ゲーム開始時の初期処理:現在地設定と呪文に最初の文字を入れる
    static start(point){
        this.current = point - 1;                 // 与えられた地点番号を0始まりのインデックスに変換
        this.spell.push(this.points[this.current].str); // 最初の地点の文字を呪文に追加
    }

    // 移動処理:choice は 'first' か 'second' の文字列でどちらの道を選んだかを表す
    static move(choice){
        // ここがポイント!ブラケット記法を使ってプロパティを動的にアクセス
        // this.points[this.current] は現在の地点オブジェクト
        // [choice] は 'first' または 'second' を動的に指定してその道の行き先番号を取得
        // -1 して0始まりのインデックスに変換
        const point = this.points[this.current][choice] - 1;

        // 移動先の地点の文字を呪文に追加
        this.spell.push(this.points[point].str);

        // 現在地を移動先に更新
        this.current = point;
    }

    // 呪文をつなげた文字列を出力
    static cast() {
        console.log(this.spell.join(''));
    }
}




const rl =  require('readline').createInterface({input:process.stdin});
const lines = [];

rl.on('line', (input) => {
    lines.push(input);
});

rl.on('close', () => {
    // 入力の1行目から N=地点数, K=移動回数, S=開始地点 を取得
    const [N, K, S] = lines[0].split(' ').map(Number);
    
    // 2行目からN+1行目までの地点情報をLabyrinth.pointsに追加
    lines
      .slice(1, N+1)
      .forEach(p => {
        const [str, first, second] = p.split(' ');
        Labyrinth.points.push(new Labyrinth(str, first, second));
      });
      
    // ゲーム開始地点のセット
    Labyrinth.start(S);
    
    // 移動指示を配列にしてループ処理
    const choices = lines.slice(N+1).map(Number);
    for(const choice of choices){
        if(choice === 1){
            Labyrinth.move('first');   // 1番目の道を選択
        }
        else if(choice === 2){
            Labyrinth.move('second');  // 2番目の道を選択
        }
    }
    
    // 呪文を出力
    Labyrinth.cast();
});
1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?