LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書くE28の実装例 ( go )

Posted at

オフラインリアルタイムどう書くE28の問題「増築の果ての隣室」の実装例を、go言語 で。

問題 : http://nabetani.sakura.ne.jp/hena/orde28sqst/
実装リンク集 : https://qiita.com/Nabetani/items/4e3fac2746ca05a93165
イベント : https://yhpg.doorkeeper.jp/events/81346

次回のイベントは 12/8。
詳しくは
https://yhpg.doorkeeper.jp/events/82699
を御覧ください。楽しいよ?

で。
実装例は以下の通り:

e28.go
package e28

import (
    "fmt"
    "strconv"
    "strings"
)

type operation struct {
    dir   byte
    count int
}

type room struct {
    left, top int64
    w         int64
}

func (p room) bottom() int64 {
    return p.top + p.w
}

func (p room) right() int64 {
    return p.left + p.w
}

func getOps(src string) []operation {
    r := []operation{}
    for i := 0; i < len(src); i += 2 {
        op := operation{src[i], int(src[i+1] - '0')}
        r = append(r, op)
    }
    return r
}

func topOf(rooms []room) int64 {
    r := rooms[0].top
    for _, ro := range rooms {
        c := ro.top
        if c < r {
            r = c
        }
    }
    return r
}
func bottomOf(rooms []room) int64 {
    r := rooms[0].bottom()
    for _, ro := range rooms {
        c := ro.bottom()
        if r < c {
            r = c
        }
    }
    return r
}
func rightOf(rooms []room) int64 {
    r := rooms[0].right()
    for _, ro := range rooms {
        c := ro.right()
        if r < c {
            r = c
        }
    }
    return r
}

func leftOf(rooms []room) int64 {
    r := rooms[0].left
    for _, ro := range rooms {
        c := ro.left
        if c < r {
            r = c
        }
    }
    return r
}

func newrooms(rooms []room, op operation) []room {
    t := topOf(rooms)
    b := bottomOf(rooms)
    r := rightOf(rooms)
    l := leftOf(rooms)
    ret := []room{}
    for i := 0; i < op.count; i++ {
        switch op.dir {
        case 'N':
            w := (r - l) / int64(op.count)
            ret = append(ret, room{l + int64(i)*w, t - w, w})
        case 'S':
            w := (r - l) / int64(op.count)
            ret = append(ret, room{l + int64(i)*w, b, w})
        case 'W':
            w := (b - t) / int64(op.count)
            ret = append(ret, room{l - w, t + int64(i)*w, w})
        case 'E':
            w := (b - t) / int64(op.count)
            ret = append(ret, room{r, t + int64(i)*w, w})
        }
    }
    return ret
}

func build(base int64, ops []operation) []room {
    r := []room{room{0, 0, base}}
    for _, op := range ops {
        r = append(r, newrooms(r, op)...)
    }
    return r
}

func hasIntersection(a0, a1, b0, b1 int64) bool {
    if a0 < b0 {
        return b0 < a1
    }
    if b0 < a0 {
        return a0 < b1
    }
    return true
}
func isNeibour(a, b room) bool {
    if a.top == b.bottom() || a.bottom() == b.top {
        return hasIntersection(a.left, a.right(), b.left, b.right())
    } else if a.left == b.right() || a.right() == b.left {
        return hasIntersection(a.top, a.bottom(), b.top, b.bottom())
    }
    return false
}
func solve(src string) string {
    split := strings.Split(src, "/")
    ops := getOps(split[0])
    myroom, _ := strconv.Atoi(split[1])
    base := int64(1)
    for _, op := range ops {
        base *= int64(op.count)
    }
    rooms := build(base, ops)
    ans := []string{}
    for n, ro := range rooms {
        if isNeibour(rooms[myroom-1], ro) {
            ans = append(ans, fmt.Sprint(n+1))
        }
    }
    return strings.Join(ans, ",")
}
e28_test.go
package e28

import "testing"

func Test(t *testing.T) {
    var tests = []struct {
        name  string
        input string
        want  string
    }{
        {"0", "N7N4E5/8", "1,7,12,13,14"},
        {"1", "E1/1", "2"},
        {"2", "N6/5", "1,4,6"},
        {"3", "W5/3", "1,2,4"},
        {"75", "N9S9S3S6N6S7N8W4E9W7E3N5W8S9E9E9W6N3N9W8/119", "73,74,78,113,120,122,123,124,131,132,133,134"},
    }

    for _, test := range tests {
        got := solve(test.input)
        if got != test.want {
            t.Errorf("%v: solve(%q)=%q, want %q\n", test.name, test.input, got, test.want)
        }
    }
}

テストデータの大半は省略。

ruby 版 https://qiita.com/Nabetani/items/bb4b06467dbe1cc6c6dd を移植した。

ruby だと

ruby
  t = f.map(&:top).min

で済むところを

go
func topOf(rooms []room) int64 {
    r := rooms[0].top
    for _, ro := range rooms {
        c := ro.top
        if c < r {
            r = c
        }
    }
    return r
}

と書かなければならないとことかがつらい。

あと。

スライスにスライスを追加するイディオムが気持ち悪い気がする。
こんな

go
        r = append(r, newrooms(r, op)...)

感じ。

あと関係ないけど。
なんで スペースじゃなくて TAB なんだろう。
スペースのほうがいいと思うんだけどなぁ。

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