Go
golang
どう書く
yhpg

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

オフラインリアルタイムどう書く F08 の実装例
問題:http://nabetani.sakura.ne.jp/hena/ordf07chairs/
実装リンク集:https://qiita.com/Nabetani/items/de5b9d3230603033ed74

Go の練習で書いてみた。
まだ全然手に馴染んでいない。

実装
package f08

import (
    "fmt"
    "math"
    "strings"
)

var order = []int{1, 3, 5, 7, 9, 8, 6, 4, 2}

func mapInt(src []int, pred func(int) int) []int {
    dest := make([]int, len(src))
    for i := 0; i < len(src); i++ {
        dest[i] = pred(src[i])
    }
    return dest
}

var revorder = mapInt(order, func(x int) int { return -x })

func minpos(a []int) int {
    p := 0
    minval := int(math.MaxInt32)
    for pos, val := range a {
        if val < minval {
            minval = val
            p = pos
        }
    }
    return p
}

func index(chairs []string, ord []int) int {
    scores := make([]int, len(chairs))
    for i := range chairs {
        if chairs[i] != "-" {
            scores[i] += 10000
        }
        if chairs[(i+1)%len(chairs)] == "-" {
            scores[i] -= 100
        }
        if chairs[(i+len(chairs)-1)%len(chairs)] == "-" {
            scores[i] -= 100
        }
        scores[i] += ord[i]
    }
    return minpos(scores)
}

func process(chairs []string, cmd rune) {
    switch {
    case 'a' <= cmd && cmd <= 'z':
        for n := range chairs {
            if chairs[n] == strings.ToUpper(fmt.Sprintf("%c", cmd)) {
                chairs[n] = "-"
                break
            }
        }
    case 'A' <= cmd && cmd <= 'Z':
        var ord []int
        if cmd < 'N' {
            ord = order
        } else {
            ord = revorder
        }
        ix := index(chairs, ord)
        chairs[ix] = fmt.Sprintf("%c", cmd)
    }
}

func solve(src string) string {
    chairs := make([]string, len(order))
    for i := range chairs {
        chairs[i] = "-"
    }
    for _, cmd := range src {
        process(chairs, cmd)
    }
    return strings.Join(chairs, "")
}
テスト
package f08

import (
    "testing"
)

func Test(t *testing.T) {
    var tests = []struct {
        name  string
        input string
        want  string
    }{
        {"0", "NABETanI", "I-E--T-B-"},
        {"1", "A", "A--------"},
        {"2", "Aa", "---------"},
        // 中略
        {"48", "WFNwBfbSAXCZzMDJUcKx", "AM-JSUNDK"},
    }
    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)
        }
    }
}

評価関数で「座りたくなさ」を表現し、「座りたくなさ」が最小である席を見つけるという順当な実装なのだが。が。

  • minpos という関数を書いてしまった。
  • ruby の map に相当する関数を書いてしまった。

辺りが不満。ライブラリにないのかなぁ。
テンプレート(のようなもの)がないから書きようがないのかなぁ。

あと。 rune である cmdstring に変換する方法がわからなかったので Sprintf してしまった。strconv 辺りにありそうなんだけど、見つけられなかった。
くやしい。

ちなみに、chairs[]string なのは、最後に Join したいから。最初は []rune で書いていたんだけど、Join 出来なかったので []string に変更した。

そんなところかな。