DISCO presentsディスカバリーチャンネル コードコンテスト2021参加記

www.discoverychannel.jp

略称DDCC2021。 これに参加して、こんな感じでパチンコをしてきた。

このコンテストは毎年こんな感じで実機を動かす問題。 画面の中ではなく物を動かすのは楽しそうだよなぁと思っていたので、参加できて満足。 まあ、順位はショボかったけど。

予選

例年はAtCoder上で開かれていたのに、今年は自社のサイト。 別にAtCoderが嫌いなわけではないけど、日本のプログラミングコンテストAtCoderに独占されてしまうのはそれはそれで不安なので、良い流れ。

そのせいか問題は(ABCを全完できるくらいの人にとっては)簡単。 私は開始45分くらいで全部解いた。

procon.disco.co.jp

「いくら問題が簡単とはいえ、強い人と弱い人の差は出るだろ? なぜお前が本戦に進めているの?」という話がある。 いつもは本戦に200人くらい集めていて、この本戦に行ったことはある。 ただし、実機を動かせるのは、本戦の中でのコードコンテストで上位の人だけ。 私は指をくわえて見ていた。 今年は感染症対策のために人数を絞り、コードコンテスト無しで全員が実機を動かせる。 就活年度の学生が20人、その他の人が10人。 私の実力ではまず無理な人数。

ひとつはAtCoderでの開催ではないので、気が付いていない人がそれなりにいたこと。 また、事前に申込みが締め切られるので、コンテスト開始直前に気が付いても遅い。 Twitterで「気が付かなかった」と嘆いている人がそれなりにいた。

もうひとつ、

Q: stdc++やboostなどのライブラリは使用可能ですか?

A: C/C++の標準ライブラリではないため、使用できません。

https://procon.disco.co.jp/backnumber/ddcc2021_qual/faq.html

というルールに引っ掛かった人が多かったのではないかという噂がある。 stdc++とは、gccに存在するbits/stdc++.hというヘッダファイルで、これを#includeすると全ての標準ヘッダが#includeされる。 普段から使っている人がそれなりにいるらしい。 懇親会でもあれば中の人に真相を訊いてみたかったけど、無かったので闇の中。

問題の解答とソースコードを合わせて提出する昔のGoogle Code Jamのような形式で、コンテスト中の正否は解答だけで判定されるので、コンテスト中には気が付けない。 昔のGoogle Code Jamは、たしか「なんなら手で解いても良いよ」で提出されたソースコードはチェックされていなかったと思うけど、DDCCは後からソースコードを動かしてたしかにその出力が出てくるのか確認しているのかもしれない。 まあ、リアルタイムにそれをやろうとすると大変だろうな。

本戦(問題以外)

当日に緊急事態が宣言されていたら、オンラインで後日にという話だった。 緊急事態宣言は終了したから無事開催。

正直、「よくやるなぁ。まあやるなら行くけど」と思っていた。 感染症対策はしっかりしていた。 まず、受付で付けてきたマスクを主催者が用意したものに交換。 「マスク着用必須です」は今なら良く見るけど、これだけでは参加者がどんなマスクを付けているのか分からないのか。 アルコール消毒。 エレベーターはスタッフ1人と参加者3人以下を厳守。 200人集めていたときと同じ広い会場に、参加者別にビニールテントが組み立てられていた。 机の上には、アルコールスプレーとフェイスシールドとゴミ袋(会場のゴミ箱は使うなということか)。 会場の自販機は使用禁止。

最後に実機で確認するときは参加者が周りに集まって観戦する。 ここでも実機の周りにビニールテントを置いていた。 あ、会場の隅にあったビニールテントは単なる予備ではなかったのか。 3グループに分かれての入れ替え制で、入れ替え時には消毒。

解散前には「オフ会しないでまっすぐ帰れ」と釘を刺していた。

本戦(問題)

f:id:kusano_k:20210328153729j:plain

問題は、冒頭の動画の通り。 射出機の角度に加えて、台の角度を動かせる。 カイジのような20トンの水は必要無い。 玉を打ち出しながら台の角度を変えることはできない。 プログラムは、(台の支柱3本それぞれの高さ、射出機の角度、玉を何発打つか、玉を打った後の待機時間)の列を出力する。 装置はこれを読んで、台と射出機の角度を変えてから、玉を打ち出す。 玉は全100個。 1個の穴あたり有効なのは10個までで、穴に入った有効な玉数×1個でも玉が入った穴の個数が得点。 最初に全動作をまとめて出力するので、穴に入った個数を見てから動きを変えるようなことはできない。

まずはシミュレーターで競う。 どのような動作をしたのかは分からず、点数だけが返ってくる。 これで正の点数を取った人だけが実機で動かせるとのこと。

穴の方向に射出機を向けるだけでしょ? → フォーマットエラー。 なぜかと思ったら、射出機の可動範囲を超えていた。 直接は狙えない穴もあるのか。 まあ、正の点数を取れば良く満点を取る必要は無いから、範囲を超えたやつはクリップしておくか → 正の点数ゲット。 ちなみに、この前半の点数はどうでも良いと思っていたが、最後の実機で同点だったらシミュレーターの点数で順位を付けるというルールがあり、これで最終的に順位がちょっと落ちた。

角度的に直接狙えない穴がある。 また、穴の位置をExcelでプロットすると、他の穴の後ろにある穴もある。

f:id:kusano_k:20210330012810p:plain

ここで台を傾けるのか。 なるほど。 手元でも玉の動きを物理的にシミュレートして、台と射出機の角度をランダムに決めて、狙った穴に入るかどうかを判定すれば良いだろう。 という実装をしている間に時間切れ。 ちなみに、シミュレートは0.001秒ごとに玉の位置と速度を更新するようにしたけど、台を左右にしか傾けないならば数値計算でわりと簡単に出せるっぽい。 他の参加者が言っていた。 たしかに。

シミュレーションの順位発表。 真ん中ちょい下くらい。 この時点で台を傾けるところまで実装している人も多いのか。 さすが。

会社紹介を聞いて、実機コンテストの問題発表。 だいたいそのままだけど、制限時間が短くなるらしい。 台や射出機の角度を10回変えると考えると、時間が足りない。 10個全部の穴を狙うのか、穴の数を絞って球数を増やすのかの駆け引きだろうか。 コーディング時間が短くて焦っていたからあまり自信は無いけど、狙う穴の数を絞る選択肢は無いよなぁ。 角度をランダムに決めて入るかどうかをシミュレートするやつ実装完了。 実機コンテストも提出の度に(運営の)シミュレーターのスコアが返ってくる。 想定しているスコアよりも低いのはなぜだ……。

実機での中間確認。 ああ、玉を打ち終わった後で次の角度の変更が行われるとはいえ、打った玉はまだ移動中で、そこで台を動かすと移動中の玉の狙いがズレてしまうのか。 玉を打った後の待機時間はそのためね。 でも、時間はギリギリだから、ただ待つくらいならとりあえず打っておいたほうが良いよなぁ。 運良くどこかの穴に入るかもしれないし。

コーディング2回目。 台を傾けなくても狙える穴のときに台を傾けるのは悪手なので、傾けないようにする。 角度ガチャだけだと一瞬で実行が終わる。 後は何をしよう。 実機には当然誤差があるはずである。 ギリギリだと入るかどうか怪しいよね。 ということで、狙った穴のサイズを小さいと思い、狙っていない穴のサイズは大きいと思って、なるべく中心を狙うようにしてみる。 本当は出た結果を微調整すると速いのだろうけど、それはやっていない。

終結果。 冒頭の動画のように、台を傾けないで狙える穴にはだいたい入ったけど、傾けて狙うものはほとんど入らずに終了。 悲しい。

他の参加者の話を聞くに、台の傾きをなるべく小さくするというのがポイントだったらしい。 1回目の確認のときに、「やっぱり傾けるとどうしてもズレるな。傾きを変えると移動中の玉が外れる以外にもこのデメリットがあるので、傾けなくてすむ穴は傾けないべきだな」とは考えていたけれど、0-1ではなくて、傾きが大きければ大きいほど誤差が大きくなるとまで考えるべきだった。

手前で曲がってしまっている。 解説の人が「転がり抵抗」がどうこうと言っていた。 台の素材は堅いゴムみたいな感じだったから、抵抗が大きくて速度が落ちるんだろうなぁ。

uwiさんが、傾きを固定するということをしていて頭が良いなと思った。 たしかに、ちょっと軌跡を曲げられれば何でも良いので、1種類の傾きで複数の穴が狙える。 射出機の角度を変えるだけでも一緒に台の角度を変えても使う時間は一緒だけれど、台を傾けなければ事前に打っている玉の軌跡が変わらないというメリットがある。

台の角度は3本の支柱の高さで変えるので、好きな向きにできる。 「左右は使うけど、前後方向の傾きを変える意味は無いよね」と思っていた。 奥の方を下げることで、玉を加速させて早く穴に入れ、次の角度変更の影響を小さくしている人がいた。 なるほど。

実機ならではだと思ったのが、隅に当てて穴に入れている人がいた。 この台の周囲には隙間があって台から外れた玉は落ちていくのだけど、台の隅だけは支えるため隙間が無い。 ここを狙って枠に反射させ、そのままでは狙えない穴を狙っていた。

「これ時間的に満点は無理ですよね?」「いや、射出機と台の角度を10回変えると無理なのであって、ギリギリを狙って2個の穴に入れられれば可能性はある」という話もあった。

「考えることが少なくてつまらなくない? 時間も限られているからしょうがないか」とか思っていたけど、本当は考えることはいくらでもあったわ。私の考えが足りないだけだった。リアルに物を動かしているのだから、そりゃそうか。面白い。