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

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

今回の問題は以下です。

座標系での規則的な移動 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】

実装

最初は以下のように実装しました。

package main
import "fmt"
func main(){
    var x, y, n int
    fmt.Scan(&x, &y, &n)
    
    // stepは偶数の時に増える
    // 方角が変わるのはc数だけ移動したとき
    step := 0
    c := 0
    d := "E"
    for i := 0; i < n; i++ {
        if i % 2 == 0 {
            step++
        }
        
        // cの数だけ移動していた場合、現在の方角を変える
        if i == c {
            switch d {
                case "E":
                    d = "S"
                case "W":
                    d = "N"
                case "N":
                    d = "E"
                case "S":
                    d = "W"
            }
        }
        
        switch d {
            case "E":
                x++
            case "W":
                x--
            case "N":
                y++
            case "S":
                y--
        }
    }
    
    fmt.Println(x, y)
}

ですが、これだとcに何を入れればいいのかわからず断念してしまいました。

cに何を入れるべきか、それは今の方向に対して何回進んでいるか入れればいいとAIから助言をもらって実装を修正しました。

package main
import "fmt"
func main(){
    var x, y, n int
    fmt.Scan(&x, &y, &n)
    
    // stepは偶数の時に増える
    // 方角が変わるのはc数だけ移動したとき
    step := 1
    count := 0     // 今の方向に進んだ歩数
    turnCount := 0 // 同じ距離で曲がった回数
    d := "E"
    for i := 0; i < n; i++ {
        switch d {
            case "E":
                x++
            case "W":
                x--
            case "N":
                y--
            case "S":
                y++
        }

        // countの数だけ移動していた場合、現在の方角を変える
        count++
        if step == count {
            count = 0
            switch d {
                case "E":
                    d = "S"
                case "W":
                    d = "N"
                case "N":
                    d = "E"
                case "S":
                    d = "W"
            }
            turnCount++

            // 2回曲がるごとに、次に進む距離を1増やす
            if turnCount == 2 {
                step++
                turnCount = 0
            }
        }
    }
    
    fmt.Println(x, y)
}

修正したら動きました。

もっとスマートにはできそうです。

ということで解答例のコードを参考に修正しました。

package main
import "fmt"
func main(){
    var x, y, n int
    fmt.Scan(&x, &y, &n)
    
    // stepは偶数の時に増える
    // 方角が変わるのはc数だけ移動したとき
    dir := []string{"N","E","S","W"}
    step := 1
    count := 1     // 今の方向に進む歩数
    first := true  // 曲がったのが一回目か二回目かのフラグ
    d := 1 // 方向管理
    
    for i := 0; i < n; i++ {
        switch dir[d%4] {
            case "E":
                x++
            case "W":
                x--
            case "N":
                y--
            case "S":
                y++
        }
        
        count--
        if first && count == 0 {
            // 曲がるのが一回目のとき
            count = step
            first = false
            d++
        } else if count == 0 {
            // 曲がるのが二回目のとき
            step++
            count = step
            first = true
            d++
        }
    }
    
    fmt.Println(x, y)
}

かなりコードがすっきりしました。

👍