JavaScript
AtCoder
ECMAScript
競技プログラミング

AtCoder見てたらテクいコードが読めるようになった話

無職ワイ、競プロ1に興味を持つ

ワイ「ちょくだいはんがいっつも楽しそうに競プロの事をつぶやいとるから、ワイもAtCoderやりたくなってきたで。」
ワイ「AtCoderJobsいうサイトもあって、AtCoderでの評価をもとに就活もできるらしいしな」
ワイ「35歳無職のワイにはピッタリや」

AtCoderとは

AtCoder
https://atcoder.jp/
競技プログラミングのオンラインコンテストに参加できるサイトやで。
自分のランクを上げていって、就活にも活かせるみたいやで。

凄い人が多そう

ワイ「ゆーてもワイのようなザコーダーがいきなりコンテストに参加するんは精神的ハードルが高いで」
ワイ「とりあえずAtCoderのサイト覗いてみよか」

AtCoderを覗いてみる

ワイ「なになに、コンテストはリアルタイムでしか参加できひんけど、過去問にはいつでも挑戦できるんか」
ワイ「どれどれ」

問題文
シカのAtCoDeerくんは二つの正整数 a, b を見つけました。
a と b の積が偶数か奇数か判定してください。
ABC086A - Productより引用

ワイ「なるほどな」
ワイ「シカくんが整数 a と b を見つけたんやな」
ワイ「それを偶数か奇数か判定せなあかん
ワイ「ようある場面や」
ワイ「森の中かなんかで見つけたんやろな」

ワイ「・・・でもってなんやねん」
ワイ「いきなりそんな専門用語を使われても」
ワイ「なになに、積ってのはabを掛けた数って意味か」

出力
積が奇数なら Odd と、 偶数なら Even と出力せよ。
ABC086A - Productより引用

ワイ「この問題ならワイでも解けそうやで」

解いてみる

ワイ「おお、ページの下の方にテキストエディタみたいなんがあるで」
ワイ「これを使ってコードを書いて問題に答えるんやな」
ワイ「ほな言語はJavaScriptを選択、と」
ワイ「コードの雛形をこのページからコピペして・・・」
ワイ「余分なとこは消して、と」

"use strict";
function Main (input) {
  // 引数 input に「3 5」みたいな文字列が入ってくるので、それを元に問題を解いていく。

}

//標準入力から文字列を受け取ってMain関数を実行
Main(require("fs").readFileSync("/dev/stdin", "utf8"));

ワイ「おっしゃ、準備完了や」
ワイ「inputいう引数に"3 5"みたいな文字列が入ってくるから」
ワイ「その文字列を分割して整数abとして使えばええんや」
ワイ「それを掛け算して・・・」
ワイ「その結果が偶数か奇数かで条件分岐すればええねやな」
ワイ「それなら、こうや!」

"use strict";
function Main (input) {
  // 入力された文字列を半角スペース区切りで分割
  const split = input.split(" ");

  const a = split[0]; // 1つ目の数字を a とする
  const b = split[1]; // 2つ目の数字を b とする

  let result; // 結果を入れる用の変数

  if (a * b % 2 === 0) {
    // aとbの積を2で割って、余りがなければ偶数
    result = "Even";
  } else {
    // じゃなきゃ奇数やで
    result = "Odd";
  }

  console.log(result);
}
//標準入力から文字を受け取ってメイン関数を実行
Main(require("fs").readFileSync("/dev/stdin", "utf8"));

ワイ「たぶんできたで」
ワイ「提出っと」
ワイ「どや!」

結果
AC (正解)

ワイ「おっしゃ!JavaScript 完全に理解したで!」

人の回答を見てみる

ワイ「なんや、このページで他の人らの回答も見れるやないか」
ワイ「けど、いうても今みたいな簡単な問題・・・」
ワイ「誰が解いても一緒やろ」
ワイ「偶数ならEven奇数ならOdd、ただそれだけやで」

ぜんぜんちがった

ワイ「なんや、他の人らの回答一覧をコードの長さ実行時間順でソートしたりもできるやん」
ワイ「ほえぇ、この問題でもこんなにコードの長さに差が出るんかいな」
ワイ「ちょっと、短く書いてる人のコード見てみよか」

function m(i) {
  console.log(["Even","Odd"][i.split(" ").map((e)=>parseInt(e)).reduce((p,n)=>p*n)%2]);
}
m(require("fs").readFileSync("/dev/stdin", "utf8"));

提出 #3148680より引用

ワイ「みじかっ!」
ワイ「処理部分、1行やないか
ワイ「何をしとんねん」
ワイ「全然読まれへんわ」
ワイ「こわいこわいこわい」

今後のために

ワイ「再就職した時に、同僚がこんなコード書いてたら全く読めへんから仕事にならへんで」
ワイ「この機会にこのコード読めるようにしとこ・・・」

ワイ「ええと・・・まずは」

["Even","Odd"]

ワイ「EvenOddの配列を作っとんな」
ワイ「その後に」

[i.split(" ").map((e)=>parseInt(e)).reduce((p,n)=>p*n)%2]

ワイ「と続くわけやな」
ワイ「ようは↑この部分が 01 になって」

["Even","Odd"][0] // つまり "Even"

ワイ「もしくは」

["Even","Odd"][1] // つまり "Odd"

ワイ「を出力してんねやな」
ワイ「カッコええコード書きはんな〜・・・」

ワイ「ほんで、具体的にどうやって 01 に変換しとんねん」
ワイ「まずは」

i.split(" ")

ワイ「入力内容( i )を半角スペース区切りで分割( split )して配列にして・・・」

.map((e)=>parseInt(e))

ワイ「その配列をmapメソッドとparseIntで全て文字列から整数に変換してるんか・・・」
ワイ「そして・・・」

.reduce((p,n)=>p*n)

ワイ「その配列の要素全てを掛け合わせた数をreduceメソッドで求めてんのんか」

%2

ワイ「ほんで最後に2で割った余りを求めると・・・」
ワイ「01 になんねんな」

ワイ「ほえ〜」
ワイ「かっこええ・・・」

ワイ「入力文字列を分割して、数値にして、掛け合わせて、2で割った余りを求めて・・・って1行で出来んねんなあ」

ワイ「でも、よう考えたらmapparseInt(整数への変換)要らんやろ」
ワイ「文字列同士を足し算すんのは "3" + "5" = "35"みたいになって危険やけど」
ワイ「掛け算なら大丈夫やで」
ワイ「念の為か・・・?」

ワイ「あれ?

ワイ「・・・このコード・・・」

ワイ「2ヶ月前にワイが書いたコードやないか!!!」
ワイ「そういえば無職になりたてのころ、AtCoderはんに登録してテクい書き方を真似したりしとったわ・・・」
ワイ「なんでワイは退化してんねん」
ワイ「アホやでワイ」

逆に一番コードが長い人の解答を見てみる

ワイ「なんや、一番コードが長い解答、200行超えやん」
ワイ「偶数か奇数か求めるのに200行て」
ワイ「一体どんな処理をしてんねん」
ワイ「・・・読んでみたけど全く意味分からへんわ」

ワイ「むしろさっきのメッチャ短いコードのほうがよっぽど読みやすいわ・・・」
ワイ「変わったコード書く人もおんねんなぁ・・・」

まとめ

ワイ「こんな簡単な問題でも、こんなに色んな書き方ができんねんな〜」
ワイ「1つの問題に対する、色んなユーザの膨大な解法や書き方を読むことが出来て」
ワイ「これが一番コードリーディングの勉強になるかもしれへん」
ワイ「コンテストに参加すらしてへんのにメチャクチャ勉強になったわ・・・」

ワイ「せや、ワイの作ったなもなきくらすたいうサイトで」
ワイ「AtCoder で 人のコードをただ読む くらすた
ワイ「いうクラスタでも作って、AtCoder友達でも募集しよか」
ワイ「そんでその子らに近づいて」
ワイ「その子らの会社に入れてもらうで!!!!!」
ワイ「完璧な作戦やで」

スペシャルサンクス

ワイ「ちょくだいはん、問題や解答の引用を許可してくれてありがとうやで〜」

※ワイはAtCoderはんの回し者とちゃうで。ただの無職やで。

ワイシリーズは

ほかにもたくさんあるから読んでってや〜!


  1. 「競技プログラミング」の略。