はじめに
Siv3Dアドベントカレンダー11日目の記事です.今年の高専プロコンでの経験を踏まえ,Siv3Dを用いた高専プロコン競技のビジュアライザで実装するべきだったことを,来年のために書きます.
procon35について
今年行われたのは第35回で,#procon35というタグがついていました.奈良で行われ,競技部門は画像を色ごとに0~3に割り当て,並べ替えられたものが与えられるので,それを指定の操作により復元するというものでした.
これは1回戦の柿だったきがします.遠目に見たら皿の上に柿が二つ載っているような写真に見えるような見えないような...
大会結果
試合はというと,準決勝まで行きましたが,力及ばず敗退してしまいました.
言い訳にはなりますが,ビームサーチを書いていて,十分間に合うと思っていたプログラムが12秒間に合いませんでした.
Siv3Dの非同期処理について
公式ドキュメント
が分かりやすいと思います.
ざっくりいうと,メインループを止めずに重い処理をすることができます.
本番当時の実装と新しく実装したこと
本番では,
Manual
(人力),Algo
(貪欲,ビムサのどちらか),Auto
(ビムサ)の三つのモードを用意していました.3人チームで,私はビムサ(一番時間がかかる),他の二人にはパラメータを変えて貪欲と軽いビムサを打ってもらいました.
私が使っていたのはcore i9にRTX4090のモバイルゲーミングPCを使っていて,マシンパワーにより十分ビームサーチが間に合うため,ビムサだけは知らせておけばよいと高を括っていました.しかし,会場のコンセントにつなげてもパフォーマンスが出ずに,間に合いませんでした.本番前にパラメータをいじるために使いすぎて熱暴走したのが今のところ有力です.
こんなイレギュラーが起きたときに,すぐさま軽いアルゴリズムに変更できればよかったものの,当時は実装出来ていませんでした.
そこで,非同期処理の出番です.
// 非同期処理の宣言
AsyncTask<実行したい関数の戻り値の型> task;
// Autoモードの非同期処理
AsyncTask<Algorithm::Solution> automatedTask;
// アルゴリズムモードの非同期処理
AsyncTask<Algorithm::Solution> algorithmTask;
// 非同期処理の呼び出し
task = Async(関数名, 引き数1, 引き数2, ...);
// Autoのボタンを押す
automatedTask = Async(Algorithm::solve, Algorithm::Type::BeamSearch, board, patterns);
// アルゴリズムの実行ボタンを押す
algorithmTask = Async(Algorithm::solve, algorithms[currentAlgorithm], board, patterns);
引き数が参照渡しのときはstd::ref()
をそれぞれつけなければいけないところにハマりました.
分かりにくいですが,Auto
ボタンを押して,バックでビームサーチを走らせながらも,Algorithm
ボタンを押してより高速な貪欲法を呼び出して解くことができます.
まとめ
来年のプロコンには非同期処理を活用したい!!
対面で見てくださったSiv3Dの鈴木さん,ありがとうございました.