paizaラーニング レベルアップ問題集 Aランクレベルアップメニュー JavaScript マップの判定・縦横

マップの判定・縦横 (paizaランク B 相当)

https://paiza.jp/works/mondai/a_rank_level_up_problems/a_rank_snake_map_boss

JavaScriptで解いてみました。いくつか解答例を載せたので、理解しやすいところ、しっくりくるところを参考にしてください。

# 解答例(上下左右判定)
上下左右ひとつひとつ調べました。

```javascript:JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//盤面の行数を表す整数 H , 盤面の列数を表す整数 W
const [H,W] = lines[0].split(" ").map((num) => Number(num));
//盤面
const board = [];
for (let i = 1; i <= H; i++) {
    board.push(lines[i]);
}
//盤面全てのマスについて調べる
//y座標、行について
for (let i = 0; i < H; i++) {
    //x座標、列について
    for (let j = 0; j < W; j++) {
        //上下左右が'#'ならtrue
        let[left,right,up,down] = [false,false,false,false];
         //左端のマスの場合は「右のマスが "#"」であれば
        if (j === 0 && board[i][1] === "#") {
            left  = true;
            right = true;
        }
        //右端のマスの場合は「左のマスが "#" 」であれば
        if (j === W - 1 && board[i][W - 2] === "#") {
            left  = true;
            right = true;
        }
        //上端のマスの場合は「下のマスが '#'」であれば
        if (i === 0 && board[1][j] === "#") {
            up   = true;
            down = true;
        }
        //下端のマスの場合は「上のマスが '#'」であれば
        if (i === H - 1 && board[H - 2][j] === "#") {
            up   = true;
            down = true;
        }
        //左右のマスが”＃”であれば
        if (board[i][j - 1] === "#" &&
            board[i][j + 1] === "#") {
            left  = true;
            right = true;
        }
        //上下のマスがどちらも '#' であれば
        if (i !== 0 && i !== H - 1 && 
            board[i - 1][j] === "#" &&
            board[i + 1][j] === "#") {
            up   = true;
            down = true;
        }
        //上下左右のマスが全て '#' であるマスの y , x 座標を出力
        if (left === true && right === true &&
            up   === true && down  === true) {
            console.log(`${i} ${j}`);
        }
        
    } //for j
    
} //for i
```

# 解答例(行列判定)
左右上下ではなく、行と列で調べました。

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//盤面の行数を表す整数 H , 盤面の列数を表す整数 W
const [H,W] = lines[0].split(" ").map((num) => Number(num));
//盤面
const board = [];
for (let i = 1; i <= H; i++) {
    board.push(lines[i]);
}

//盤面全てのマスについて調べる
//y座標、行について
for (let i = 0; i < H; i++) {
    //x座標、列について
    for (let j = 0; j < W; j++) {
        
        //行列が＃か判定
        let[row,colum] = [false,false];
        
         //左端のマスの場合は「右のマスが "#"」であれば
        if (j === 0 && board[i][1] === "#") {
            row  = true;
        }
        //右端のマスの場合は「左のマスが "#" 」であれば
        if (j === W - 1 && board[i][W - 2] === "#") {
            row  = true;
        }
        //上端のマスの場合は「下のマスが '#'」であれば
        if (i === 0 && board[1][j] === "#") {
            colum = true;
        }
        //下端のマスの場合は「上のマスが '#'」であれば
        if (i === H - 1 && board[H - 2][j] === "#") {
            colum = true;
        }
        //左右のマスが”＃”であれば
        if (board[i][j - 1] === "#" &&
                   board[i][j + 1] === "#") {
            row  = true;
        }
        //上下のマスがどちらも '#' であれば
        if (i !== 0 && 
                   i !== H - 1 && 
                   board[i - 1][j] === "#" &&
                   board[i + 1][j] === "#") {
            colum = true;
        }
        
        //左右上下全て＃ならば
        if (row && colum) {
            console.log(`${i} ${j}`);
        }
        
    } //for j
    
} //for i

```

# 解答例(python3の場合の模範解答参考)
行で、左側・左端と右側・右端をまとめ、
列で、上側・上端と下側・下端をまとめました。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//盤面の行数を表す整数 H , 盤面の列数を表す整数 W
const [H,W] = lines[0].split(" ").map((num) => Number(num));
//盤面
const board = lines.slice(1).map(line => line.split(""));

//盤面全てのマスについて調べる
//y座標、行について
for (let i = 0; i < H; i++) {
    //x座標、列について
    for (let j = 0; j < W; j++) {
        
        //行と列について＃か判定
        let[row,colum] = [false,false];
        
        //行について
        //左側、左端もしくは"#"ならば
        if (j === 0 || board[i][j - 1] === "#") {
            //右側、右端もしくは"#"ならば
            if (j === W - 1 || board[i][j + 1] === "#") {
                row  = true;
            }
        }
         
        //列について
        //上側、上端または"#"ならば
        if (i === 0 || board[i - 1][j] === "#") {
            //下側、下端または"#"ならば
            if (i === H - 1 || board[i + 1][j] === "#") {
                colum = true;
            }
        } 
        
        //左右上下全て＃ならば
        if (row && colum) {
            console.log(i,j);
        }
        
    } //for j
    
} //for i
```
# 解答例(C++の場合の模範解答参考)
上下左右を調べるときに、移動の変化量である [-1,1] を配列 move で持つと、for文+if文2つにできます。
上下左右の全てで条件を満たすかどうかを判定するために 変数 ok を用います。
盤面内 かつ #でなかったときに、falseにします。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//盤面の行数を表す整数 H , 盤面の列数を表す整数 W
const [H,W] = lines[0].split(" ").map((num) => Number(num));
//盤面
const S = Array(H);
for (let i = 0; i < H; i++) {
    S[i] = lines[i + 1];
}
//移動の変化量move
let move = [-1, 1];

//盤面全てのマスについて調べる
//y座標、行について
for (let i = 0; i < H; i++) {
    //x座標、列について
    for (let j = 0; j < W; j++) {
        
        //上下左右の全てで条件を満たすかどうかを判定
        let ok = true;
        //kはmoveのインデックス,移動の変化量move[0]= -1,move[1]= 1
        for (let k = 0; k < 2; k++){

            //行方向iの移動について、move[k] = -1左 または 1右 移動した時
            //盤面内　かつ　#でないなら ok=false            
            if(0 <= i+move[k] && i+move[k] < H &&
             S[i+move[k]][j] !== '#'){
                ok = false;
                break;
            }
            //列方向jの移動について、move[k] = -1上 または 1下 移動した時
            //盤面内　かつ　#でないなら ok=false
            if(0 <= j+move[k] && j+move[k] < W &&
             S[i][j+move[k]] !== '#'){
                ok = false;
                break;
            }
        }
        
        //左右上下全て＃ならば
        if (ok) {
            console.log(i + " " + j);
        }
    } //for j
} //for i

```
# 解答例(Rubyの場合の模範解答参考)
forEachを使いました。
左右のマスの文字が # のとき flag_row を true にします。
上下のマスの文字が # のとき flag_clm を true にします。
端の時は問題に従ってtrueになるようにしています。
flag_row && flag_clm で上下左右の全てのマスの文字 # であるかを判定できます。

```javascript:JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//盤面の行数を表す整数 h , 盤面の列数を表す整数 w
const [h, w] = lines[0].split(" ").map((num) => Number(num));
//盤面
const board = lines.slice(1).map(line => line.split(""));

//盤面全てのマスについて調べる
//y座標、行rowについて
board.forEach((row, y) => {
    //x座標、列について
    row.forEach((_, x) => { //第一引数は使わないので_にしています。
        let flag_row = false;
        let flag_clm = false;
        //左右のマスの文字が # のとき flag_row を true にします。
        //端の時は問題に従ってtrueになるようにしています。
        if (x === 0 || row[x - 1] === '#') {
          if (x === w - 1 || row[x + 1] === '#') {
            flag_row = true;
          }
        }
        //上下のマスの文字が # のとき flag_clm を true にします。
        ////端の時は問題に従ってtrueになるようにしています。
        if (y === 0 || board[y - 1][x] === '#') {
          if (y === h - 1 || board[y + 1][x] === '#') {
            flag_clm = true;
          }
        }
        /*flag_row && flag_clm で上下左右の全てのマスの文字が
         # であるかを判定できます。*/
        if (flag_row && flag_clm) {
          console.log(y + ' ' + x);
        }    
    }); //forEach _ x
}); //forEach row y
```