0
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?

今回は paiza の「3Dプリンタ」の問題に挑戦!


問題概要

〇 入力されるのは立体のデータ

  • 立体は **1×1×1 の立方体(セル)**の集合で表現される。
  • 座標系は (x, y, z) (奥行き・横幅・高さ)。
  • データは X, Y, Z のサイズで与えられる。

〇 入力

  • 1行目: X Y Z
  • 以降:各 z 層について
    • X 行の文字列(それぞれ長さ Y
    • 各文字は '#'(セルあり)または '.'(セルなし)
    • 層と層の間には "--" の区切りが入る。

〇 出力

  • 立体を x軸正方向(正面)から見た図 を出力する。
  • 出力は Z行 × Y列 の文字列。
  • 各セル (y,z) について、どこかの奥行き x に '#' があれば見えるので '#'、そうでなければ '.'。

〇 条件

  • 1 ≦ X, Y, Z ≦ 50



入力例:

3 26 5
............#.............
......#..#.....#####......
#.....................#..#
--
............#.............
......#..#......#.........
#.....................#..#
--
............#.............
......####.......#........
####..................####
--
............#.............
......#..#........#.......
#..#..................#..#
--
............#.............
......####.....#####......
####..................####
--

出力例:

####..####..#..#####..####
#..#..#..#..#.....#...#..#
####..####..#....#....####
#.....#..#..#...#.....#..#
#.....#..#..#..#####..#..#






✅OK例:二次元配列

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

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

rl.on('close', () => {
    const [X, Y, Z] = lines[0].split(' ').map(Number);
    
    const result = Array.from({ length: Z }, () => Array(Y).fill('.'));
    
    for (let z = 0; z < Z; z++) {
        for (let x = 0; x < X; x++) {
            const row = lines[1 + z * (X + 1) + x]; // この行が層z, 行x
            for (let y = 0; y < Y; y++) {
                if (row[y] === '#') {
                    result[z][y] = '#'; // (y,z) にセルが見える
                }
            }
        }
    }
    
    // z=0 が上なので、出力は逆順
    for (let z = Z - 1; z >= 0; z--) {
        console.log(result[z].join(''));
    }
    // result.reverse().forEach(r => console.log(r.join('')));
});

  • 入力処理
    • 1行目で X, Y, Z を読み込む
      • X = 奥行き(x方向のセル数)
      • Y = 横幅(y方向のセル数)
      • Z = 高さ(z方向のセル数)
    • 残りの行は3D立体データ。各層(zごと)に X 行あり、層の間に "--" が入っている。

  • 出力用の配列 result を用意
    • サイズは Z 行 × Y 列。
    • 初期値はすべて '.'。
    • result[z][y] が「高さz・横yの見た目セル」を表す。

  • データを走査
    • 各層 z について:
      • z の最初の行は lines[1 + z * (X + 1)]
        (X+1) を掛けるのは "--" の区切り行を含むため。
      • x 行について文字列を読み取る。
      • 行内の各 y を走査し、'#' があればその (y,z) の位置が正面から見えるので result[z][y] = '#' に更新。

  • 出力
    • z=0 が入力では下の層だが、出力では上に表示する必要があるため、Z-1 から 0 へ逆順で result を出力。
    • 各行は result[z].join('') で文字列化して出力。




✨OK例:三次元配列

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

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

rl.on('close', () => {
    const [X, Y, Z] = lines[0].split(' ').map(Number);

    // 3次元配列 [x][y][z]
    const cube = Array.from({ length: X }, () =>
        Array.from({ length: Y }, () => Array(Z).fill('.'))
    );

    let lineIndex = 1; // 2行目以降からデータ開始
    for (let z = 0; z < Z; z++) {
        for (let x = 0; x < X; x++) {
            const row = lines[lineIndex++].trim();
            for (let y = 0; y < Y; y++) {
                cube[x][y][z] = row[y];
            }
        }
        lineIndex++; // "--" を飛ばす
    }

    // 出力:z=1 が上、z=Z が下 → 逆順で出す
    for (let z = Z - 1; z >= 0; z--) {
        let row = "";
        for (let y = 0; y < Y; y++) {
            let visible = '.';
            for (let x = 0; x < X; x++) {
                if (cube[x][y][z] === '#') {
                    visible = '#';
                    break;
                }
            }
            row += visible;
        }
        console.log(row);
    }
});

  • 入力読み込み準備
    • 1行目で X Y Z を取得。
      • X = 奥行き
      • Y = 横幅
      • Z = 高さ
    • それ以降の行を lines に保持。

  • 3D配列を作成
    • cube[x][y][z] の形でセルを管理。
    • 初期値は全部 '.'。
    • Array.from を使って X × Y × Z の配列を生成。

  • 入力データを cube に格納
    • lineIndex = 1(データ開始位置)。
    • 各層 z ごとに:
      • その層には X 行がある。
      • 各行 row を取り出し、文字ごとに cube[x][y][z] に代入。
        • row[y] が '#' → セルあり
        • '.' → セルなし
    • 1層の処理が終わるたびに "--" 区切り行をスキップ。

  • 正面図を作成
    • 出力は 高さ Z × 横幅 Y
    • ただし「z=1 が上、z=Z が下」なので z を逆順に走査。
    • 各 (z,y) について:
      • 奥行き方向に x=0..X-1 をチェック。
      • どこかで '#' が見えたら、その位置は '#' として確定。
      • 最初に見えた時点でループを抜ける。

  • 出力
    • 1行ごとに文字列を組み立て、console.log で出力。
    • z の逆順処理により「正面図が上から下へ」正しく描かれる。






📝まとめ

  • 入力の構造を理解するのが最重要
    • X(奥行き)行が1つの層(高さz)を構成し、層の間は "--" で区切られている。
  • 出力は「投影図」
    • 「正面から見たときに見えるセル」を判定する問題。
    • (y,z) の視点で奥行き方向 x を走査して、最初に '#' が出たら可視。
  • 実装の2パターン
    • 二次元配列に直接記録
      • result[z][y] に「見えるかどうか」をその場で更新。
      • メモリ効率がよく、シンプル。
    • 三次元配列に立体を保持 → 投影処理
      • cube[x][y][z] に格納し、その後で可視判定。
      • 少し冗長だが「立体を完全に持つ」ので直感的で分かりやすい。
  • 出力の注意点
    • 入力上の z=0 が底だが、出力では上から z=0 を表示する必要がある。
    • そのため 出力は z を逆順で処理するのがポイント。




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

0
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
0
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?