こんにちは、ナナオです。

前回に引き続き競プロを実施していきたいと思います。

今回の問題は以下です。

移動が可能かの判定・幅のある移動 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】

実装

コアとなるロジックはあまり変わらないのですが、途中で壁があったり壁を超えたりする場合はそれを超える手前の座標を出力したうえでStopと出力しなければいけないようです。

ちょっと大変でしたが実装しました。

package main
import "fmt"
func main(){
    var h, w, sy, sx, n int
    fmt.Scan(&h, &w, &sy, &sx, &n)
    
    s := make([]string, h)
    for i := 0; i < h; i++ {
        fmt.Scan(&s[i])
    }
    
    dir := []string{"N", "E", "S", "W"}
    c := 120 // 現在の向き
    for i := 0; i < n; i++ {
        var d string
        var l int
        fmt.Scan(&d, &l)
        
        lr := 1
        if d == "L" {
            lr = -1
        }
        
        move := l * lr // 移動量
        // X軸上に壁があるかどうか判定
        checkWallX := func(y, fromX, toX, lr int) bool {
            i := fromX
            for {
                i += lr
                if i == toX {
                    fmt.Println(y, toX)
                    return true
                }

                if i >= w || i < 0 || s[sy][i] == '#' {
                    fmt.Println(y, i - lr)
                    fmt.Println("Stop")
                    return false
                }
            }
        }
        // Y軸上に壁があるかどうか判定
        checkWallY := func(x, fromY, toY, lr int) bool {
            i := fromY
            for {
                i += lr
                if i == toY {
                    fmt.Println(toY, x)
                    return true
                }

                if i >= h || i < 0 || s[i][sx] == '#' {
                    fmt.Println(i - lr, x)
                    fmt.Println("Stop")
                    return false
                }
            }
        }
        // チェック結果を格納
        result := true
        switch dir[c%4] {
            case "N":
                result = checkWallX(sy, sx, sx + move, lr)
                sx += move
            case "S":
                result = checkWallX(sy, sx, sx - move, -lr)
                sx -= move
            case "E":
                result = checkWallY(sx, sy, sy + move, lr)
                sy += move
            case "W":
                result = checkWallY(sx, sy, sy - move, -lr)
                sy -= move
        }
        c += lr
        
        if !result {
            return
        }
    }
}

ポイントはcheckWall関数です。

ただX軸とY軸それぞれで用意している分、ちょっと長くなってしまいました。。

このロジックだと冗長なので、短くします。

解説を見て気づきましたが、移動はl変数に基づいて一つずつ行えばいいですね。

元の座標はly, lxで保持しています。

package main
import "fmt"
func main(){
    var h, w, sy, sx, n int
    fmt.Scan(&h, &w, &sy, &sx, &n)
    
    s := make([]string, h)
    for i := 0; i < h; i++ {
        fmt.Scan(&s[i])
    }
    
    dir := []string{"N", "E", "S", "W"}
    c := 120 // 現在の向き
    for i := 0; i < n; i++ {
        var d string
        var l int
        fmt.Scan(&d, &l)
        
        lr := 1
        if d == "L" {
            lr = -1
        }
        
        for j := 0; j < l; j++ {
            ly, lx := sy, sx
            switch dir[c%4] {
                case "N": sx += lr
                case "S": sx -= lr
                case "E": sy += lr
                case "W": sy -= lr
            }
            
            if sy >= h || sx >= w || sy < 0 || sx < 0 || s[sy][sx] == '#' {
                fmt.Println(ly, lx)
                fmt.Println("Stop")
                return
            }
        }
        c += lr
        
        fmt.Println(sy, sx)
    }
}

だいぶスマートになりました👍