オフラインリアルタイムどう書く F05 の ruby と kotlin による実装例


問題：http://nabetani.sakura.ne.jp/hena/ordf05rotblo/
実装リンク集：http://qiita.com/Nabetani/items/a6ed674166a151fd0a0a

まずは最初に書いた ruby から：

```ruby:ruby
N=5

def rot( cells, cx, cy )
  r = Array.new(N){ [0]*N }
  N.times do |y|
    N.times do |x|
      next unless cells[y][x]==1
      nx = -(y-cy)+cx
      ny = (x-cx)+cy
      return nil unless (0...N)===nx && (0...N)===ny
      r[ny][nx]=1
    end
  end
  r
end

def solve( src )
  center, map = src.split(":")
  cells = map.split("/").map{ |x| x.chars.map(&:to_i) }
  rotated = case center
  when "a"; rot( cells, 1, 2 )
  when "b"; rot( cells, 1.5r, 1.5r )
  end
  rotated ? rotated.map(&:join).join("/") : "-"
end

DATA.map{ |line|
  num, src, expected = line.split( /\s+/ )
  actual = solve( src )
  okay = actual == expected
  puts "%s %s %s->%s( %s )" % [ num, okay ? "ok" : "**NG**", src, actual, expected ]
  okay
}.all?.tap{ |x| puts( x ? "okay" : "something wrong" ) }

__END__
0 a:00000/00110/00100/00100/00000 00000/00000/00000/11100/00100
1 b:00000/00000/00000/00011/00011 -
2 a:00000/00000/00000/00011/00011 -
55  a:01011/10001/00000/00000/00000 -

```

いつも通り、テストデータの大半は省略。

順当にブロックを回しているつもり。
セルの座標から中心を引いて、回転行列をかけてから中心を足す。
ブロック内ブロックから return で抜けているところが ruby ならではの技。


続いて、kotlin。
上記の ruby を移植しただけ。
kotlin 歴が極めて浅いのできっとなにかおかしいと思う。

```kotlin:kotlin
val N = 5

class MyException() : Throwable() {}

fun rotate(cells: List<List<Char>>, cx: Double, cy: Double): List<List<Char>> {
    val r = mutableListOf<MutableList<Char>>()
    (0 until N).forEach {
        val s = (0 until N).map { '0' }.toMutableList()
        r.add(s)
    }
    try {
        (0 until N).forEach { y ->
            (0 until N).forEach { x ->
                if (cells[y][x] == '1') {
                    val nx = Math.round(-(y - cy) + cx).toInt()
                    val ny = Math.round((x - cx) + cy).toInt()
                    if (nx in (0 until N) && ny in (0 until N)) {
                        r[ny][nx]='1'
                    } else {
                        throw MyException() //
                    }
                }
            }
        }
        return r;
    } catch (e: MyException) {
        return mutableListOf<MutableList<Char>>()
    }
}

fun solve(src: String): String {
    val split: List<String> = src.split(":")
    val center = split[0]
    val cells = split[1].split("/").map { line -> (0 until 5).map { line[it] } } // TODO:もっときれいに書けるはず
    val rotated = if (center == "a") {
        rotate(cells, 1.0, 2.0)
    } else {
        rotate(cells, 1.5, 1.5)
    }
    if (rotated.isEmpty()) {
        return "-"
    }
    return rotated.map { it.joinToString("") }.joinToString("/")
}

fun test(src: String, expected: String): Boolean {
    val actual = solve(src)
    val okay = (actual == expected)
    print(if (okay) {
        "ok"
    } else {
        "***NG***"
    })
    println(src)
    return okay
}

fun main(args: Array<String>) {
    var okay = true
/*0*/ okay = okay and test("a:00000/00110/00100/00100/00000", "00000/00000/00000/11100/00100");
/*1*/ okay = okay and test("b:00000/00000/00000/00011/00011", "-");
/*55*/ okay = okay and test("a:01011/10001/00000/00000/00000", "-");
    println(if (okay) {
        "okay"
    } else {
        "something wrong"
    })
}
```

ruby では ブロック内ブロックから return で抜けているところは、仕方ないので throw した。もっといい方法がありそうなものだけどわからない。

「// TODO:もっときれいに書けるはず」と書いたところが一番の不満。
MutableList の MutableList を作るコードも不満。

でもまあ、書けたので良しとしよう。