11月8日 (金)、KCG 11月祭の1日目に「利きコード選手権」というクレイジーなイベントを開催しました。
企画意図
匿名のソースコードを見て指摘し合ってみると盛り上がりそう、という単純な動機。
それと同時にコーディングについて学習しよう、他の人のコードを読む習慣を付けよう、という教育的効果 (後付け)。
概要
- 準備段階であらかじめ問題を設定して、コードを学生と教員を含めて10人くらいに書いてもらう。
- 当日の参加者は (コードを書いていなくてもかまわない)、匿名のコードを読み比べて学生のコードか教員のコードかを2択で当てる (Google フォームで解答)。
- その際、各問題に対して20分ほどの議論時間を取り、参加者は匿名のコードに対して自由にコメントする。
- 最も当てることができた人が利きコーダーとして表彰される。
- 最後に各問題のいろいろな解法について解説。
壇上ではコードを書いた人同士でコメント合戦が繰り広げられるの図 ↑
結果
コンピュータの専門学校らしい企画ができました。
十人十色のコードが集まり、とても盛り上がったので各所で流行ってもいいんじゃないかと思います。
ただし、学習の面で有意義にするためにも、難易度設定、問題選択、解説を準備する必要があります (今回はかなり準備した)。
以下では詳細を書いていきます。
問題セット
問題は競技プログラミングサービスの AtCoder の過去問から出題し、プログラミング言語としては学校の授業でも使われることの多い Java 8 または JavaScript に限定しました。
AtCoder 上での実行および提出は必須とはしていません。また入出力の部分もあまり本質ではないため、引数 (args) を使うなどの別の方法でもよいこととしました。
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
こちらの3問は必須です。
(1) 81 (難易度 5)
(2) Slimes (難易度 34)
(3) AKIBA (難易度 42)
以下は任意です。(余裕のある人向け)
(4) Guidebook (難易度 198)
(5) 友達の友達 (難易度 1008 とあるけど今だともっと低いはず)
※ 難易度: AtCoder Problems における推定値で、そのレート (戦闘力) の人が正答率 50% であることを表します。例えば、レート 5 のキャラが1問目を正解できるかどうかは半々です。
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
問題文がシンプルで、実務に近くて、別解のパターンが多くて、、とかいろいろ検討して厳選しました。もとは3問目に「Guidebook」だったのですが、初回だし大変かなと思って「AKIBA」にして、難易度を100未満としました。
解説
とりあえず今回の記事では1問目の解法のみ書いておきます。
私は普段は C# を使っていますが、今回のために Java 8 と JavaScript で解答例を作成しました。
(1) ABC 144 B – 81 (難易度 5) 解答例 (Java 8, JavaScript)
与えられた整数 N を 1 以上 9 以下の 2 つの整数の積として表すことができるか。
ループと条件分岐が必要となる典型的な問題です。
アルゴリズム:
- 81通りを全探索
- 2重ループ
- O(N2)
- i ≦ j に制限してもオーダーは変わらず
- 割るほうだけでループ
- 商は自動的に決定
- O(N)
コーディング スタイル:
- ループの実現方法
- for ループ
- 関数型パラダイム、ラムダ式
- 別メソッド化
- for の内部で return
タイトルが「81」であることから反射的に2重ループを使いたくなります。今回の制約では全探索でも問題ありませんが、N が大きくなって「1000000以下の2つの整数の積」とかになると数秒では完了しません。
また、繰り返し処理については for 文を使う人が多いとは思いますが、Java の Stream を使う ( import java.util.stream.*;
) と、N が与えられればあとは1行で書けます。JavaScript でも Array で同様のことができます。
System.out.println(IntStream.range(1, 10).anyMatch(i -> n % i == 0 && n / i <= 9) ? "Yes" : "No");
あとはネタ枠として、キモい for 文を挙げておきます。
boolean b = false; for (int i = 1; i <= 9 && !(b = n % i == 0 && n / i <= 9); i++) ; System.out.println(b ? "Yes" : "No");
与太話
10年以上前のイメージでは、コードレビューといえばクラス設計やコーディングスタイルに関するものがほとんどでしたが、近年では大量のデータを扱う開発現場も増えてくるなど、実現したいことの要求が上がるにつれてアルゴリズムが相対的に重視されてきていると感じます。
例えば大量のデータ処理を現実的な制限時間以内に完了させるにも、「どのような関数がどれだけ呼び出されるか」というような精確な見積りが必要となります。リソース制約の厳しいゲーム系の開発などでは以前からそうなのだろうと想像します。
逆にコーディングスタイルに関しては、スマートデバイス、電子工作、機械学習などを扱うことも増えてプログラミング言語が多様化したこともあり、最低限の規約を守っていれば可で、各エンジニアのスタイルが尊重される風潮にあると思います。
他の言語文化にいるエンジニアにローカルの規約を守ってもらうのはなかなか酷です。
むしろ昔はアルゴリズムに触れなさすぎたという印象で、今くらいのバランスが良いのではないかと思います。コードレビューで時間を割くべきポイントが遷移してきているのですね。
で、それぞれの開発現場の状況に合わせて最適な実装を提供できるようになるには、
- 複数の解法を経験しましょう
- 他の人のコードを読みましょう
と考えています。
さて、次回は残りの問題の解説です。