問題:http://nabetani.sakura.ne.jp/hena/ordf05rotblo/
実装リンク集:http://qiita.com/Nabetani/items/a6ed674166a151fd0a0a
まずは最初に書いた 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
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 を作るコードも不満。
でもまあ、書けたので良しとしよう。