(競技)プログラミングの問題を解いて4年ぐらいたった

nardtree
7 min readJun 29, 2018

--

プログラミングは身近なもの

もともと新卒で入った会社を辞めた時、田舎で好きなことをして暮らしたいというモチベーションがわずかにあって、結局それは成し遂げることができなかったのですが、ぼんやりとゆっくりと時間が流れる雲と時間の中に溶けて消えていく知識と技能を感じました。

無職になってからは、プログラミングの技能はいくつかのコードの問題のサイトを利用して維持し、正しく維持する方法を模索していました。

空き時間や、暇なときに、定期的に行うという方法をとっていたのですが、atcoderでABCの問題(のABC)をほぼ解ききったので、とりあえず、一つ目の区切りを得たのかなと思います。

大体、通しで4年ぐらいやっているのでしょうか。4年、長いのか短いのか。

利用したもろもろのサービスやなんやら

  • CodeForce
  • Project Euler
  • AtCoder
  • YukiCoder

気質とモチベーション

個々人の才覚と気質に応じてモチベーションにはいくつかの要素があると思います

私の支配的なモチベーションの要素はこの辺で、3が60%程度を占めているなど、大きな割合を占めています。

  1. 競争好き
  2. 知的欲求
  3. (アルゴリズムとデータ処理の)美的感覚

これがあんまりいろいろなコンペティションに参画をしていない理由になるのですが、人間には時間は有限で、3を優先しようとすると1より、アルゴリズムやデータ構造の本を読んだり理論のサーベイを優先するようになります。

人により性格のパラメータの分布は様々だと思うので、好きなように、やりたいようにやるといいのでしょう。

得たもの、失ったもの

得たもの

  • データ構造(List, Map, Set)を操る力
  • 課題が与えられたときに適切にアウトプットする力

失ったもの

  • 漫画や映画などを楽しむ時間
  • 何かまじめに長時間話を聞く際に、偉い人の話を聞かないで考え込んでしまうので、ぽかをしたりする

私自身のコードの価値基準

私が楽しんでやるのは、複雑な副作用を持つ仕組みより、コード上で可能な限り簡潔に思考とコードの文脈が一致するかという、あまり普通の人が意識しない点をとても重要視していました。

思考とコードの距離が近い(いいか悪いかはおいておいて)ので、自分の中でよく把握している仕組みやデータ構造の状態に還元するという視点に立つと、実業務でも圧倒的なベロシティを出すことができます。

これとデータサイエンスの柔軟なモデリングの価値を合わせて、問題設計をできるだけ簡潔に、分析側も、開発側も、運用側も、いずれのドメインにおいても最小コストとなるような提案が得意になり、やってよかったなって思っています(次はここにKaggle要素を入れたいと考えています)

プログラミング言語

Kotlin

今、メインで使用しているのは雑で弱いScalaことKotlinなのですが、実際これは自分を思考をコードにして、データを操作するという意味でとても良い言語に思います。

もともと、ScalaでSparkやHadoopを書いていたので、最初はScalaでいろいろな問題を解いていたのですが、途中からドキュメントの管理具合とSNSの諸事情によりKotlinに乗り換えました。

最近ではサーバサイドKotlinなるものがあるみたいですが、私の周りも含め、Android界隈に比べると、全然流行っていないので、Javaで書かなくては行けない何かの仕組みを、なんとかグルー的につなげる役割とかを期待しています。

まぁ、自分はJavaとか絶対無理of無理だったのですが、Javaで作られたプロダクトをどうにかしなくては行けない機会はそれなりに多いので持っててよかったと思います。

Scalaのほうがマシだ論あるのですが、Eitherによるモナドがよく引き合いに出されるので、少し注視して劣ってないことを示したいと思います。

val r = for{
userA <- tryToGetUserInfo(arg1)
userB <- tryToGetUserInfo(arg2)
} yield userA.friends.contains(userB)
match r {
None => Left("invalid user id!")
Some(r) => Right(r)
}

これが、ifを挟まなくてはいけないという主張ですで、こうなってしまうって話ですが、

val userA = tryToGetUserInfo(arg1)
val userB = tryToGetUserInfo(arg2)
val result = if(userA != null){
userB?.friends.contains(userA)
}
when(result){
null -> "invalid user id!"
else -> result
}

?.letというnullableでnullでなければプロシージャをifを使わずコンテキストをコントロールすることができます

val m = mapOf( 0 to 1, 1 to 0)
fun main(args:Array<String>) {
val userA = m[0]
val userB = m[1]
val output = userA?.let { a -> userB?.let { b -> /*ここで何かマッチング処理*/ } } ?: "invalid user id"
}

どちらが優れているとは言いませんが、己の今のポジションで習得が容易なもので、有益なものを学べばいいはずです。

C++

C++03をお仕事で書いていたときは、STLやテンプレートの謎の人間に全く考慮していないログを見たとき、絶望と、失意に染まりましたが、いささか思考をフラットに保ったとき、今のgccのコンパイラも、clangのコンパイラもどちらも極めて優れたコンパイラになっており、全くデバッグさせる気がなかったエラーログから可読性が良いものになっており、とても良かったです。

もっと本質的な部分としては、C++は配列をまとめて宣言することができて、これを操作するテーブルとして動的計画法やメモ化を用いるアルゴリズムを簡単に載せやすいというメリットがあります。

私はあまりC++を多用しないのでマクロとかを用意していませんが、どうしてもTLEしてしまうときや、むしろ実装が楽になるときは、今はC++をよく使うようにしました。

コードの管理

GitHubでやると良いでしょう。草が生えることで進捗が可視化されて、怠けていて、何もやらなかったときは本当にだめなんだなと自覚的になることができます。

わたしの場合だと、飲み会や旅行や出張など体力的にきついことがあると、進捗が止まってしまうのを経験的にも知っていますので、程々にコントロールしながら進んでいます。

私のコミット状況

結局

頭を捻ってもこれ以上あまり書くことがなく、やる意味とか意義は微妙な感じだということが体感として、わかってしまったのですが、脳をいつでも回転できる状態にアイドリングしておく術としては有効そうで、そこが一番のメリットなのではないかと思います。

他の人の意見とか

--

--