paizaでSwiftがつかえるオンラインハッカソンが始まりました。
OSSで公開されたので今後使える環境も増えていくかと思います(Atcoderにも入りそうな兆し?)。
さて、実際に競技プログラミングでSwift使ってみて、困ったこと等が幾つかあったので、ここに共有しておきます。
なお、Swiftの構文等はこの記事では扱わないので別のところを参照してください。
基本的な書き方
とくにmain関数のようなものは必要ないので直接コードを書いていけばいいです。
環境がないとかであればコードを書くのはこのサイトを使うのが良いかと思います。実際Xcodeでプロジェクト作ってとかはめんどくさかったので、私はここで書きました。
標準入力について
ここが一番ハマりました。ググるとNSFileHandleを使うとでてきますがどうもNSxxxx系のクラスは利用できないっぽいです(Linux上で動いてる関係?詳しい理由はわかりません。)。
readLine
という関数で標準入力から一行取ってくることができました。
以下の感じで使います。
let line: String = readLine()!
let n: Int = Int(readLine()!)!
!
が随所に入ってくるのが微妙ですが、言語仕様上どうしようもないです。
標準出力に関しては普通にprint
を使えばいいです。
一行にたくさん数値がくる系の入力
scanfのようなものがないので、splitしてmapしたいところです。が、よく使われるであろうline.componentsSeparatedByString(" ")
が使えません(多分NSxxxx系が使えないせい)。
String
にsplit
メソッドはありませんが、幸いCollectionType
にあるのでそちらを使います。
extension String: CollectionType {} // splitを使うためのおまじない
let a: [Int] = readLine()!.split(" ").map { Int($0)! }
長ったらしいので、関数化しておくと良いかと思います。
func readInts() -> [Int] {
return readLine()!.split(" ").map { Int($0)! }
}
なお、固定数の数値が入力されて、それぞれに名前が付けたい場合があると思いますが、以下のようにすると楽で良いと思います。
prefix operator * {} // Pythonのリストを展開するオペレーターのイメージで*
prefix func * <T> (a: [T]) -> (T, T) { return (a[0], a[1]) }
prefix func * <T> (a: [T]) -> (T, T, T) { return (a[0], a[1], a[2]) }
let (w, h) = *readInts()
let (a, b, c) = *readInts()
ちなみに文字列のjoinは特に何もしなくても使えます。
競技プログラミングでも出力時に結構使いますね。
["a", "b", "c"].joinWithSeparator(" ") // "a b c"
配列の作成
これは私は困らなかったですが、困る人がいそうな気がするので。
ぱっと思い浮かぶので2通りほどあるので、好きな方を使えばよいかと思います。
let a1: [Int] = [Int](count: 3, repeatedValue: 0) // [0, 0, 0]
let a2: [Int] = (0..<3).map { _ in 0 } // [0, 0, 0]
// 後者のほうが応用が効くので使いやすいかもしれないです
let b: [Int] = (0..<3).map { $0 } // [0, 1, 2]
まとめ
RubyとかのLL系ほどではないけど、気軽に書けるけどちゃんと型がついてるので安心できるので、競技プログラミングでSwiftという選択肢はありかなという感じ(同じ用途ならScalaとかのほうが今のところは現実的かなという感じがするが)。
未検証ですが、コンパイルされて実行されるので実行速度的にもそこそこ速そうです。
今後Swiftが使える環境が増えていくといいですね。