inani_waonの日記

コンテスト覚書

CodinGame Green Circle 参加記録

CodinGameのコンテスト、Green Circleに参加しました。

www.codingame.com

お題はちょっとゲームバランス偏り気味なゲームAIです。

結果はGoldリーグで、全体1758人中92位でした。

 

(今回の記事はゲーム内容への言及薄めで、実装寄りのお話が多いです)

 

問題

システム開発に役立つスキルを取得して使いながら、5つのアプリをリリースしてね。

(デッキを強化して勝利点を5点取ってね)

4リリースまでは技術的負債(ペナルティカード)を受け取ることで条件の穴埋めが出来るけど、5リリース目は完全に条件を満たさないと駄目だよ。

 

詳しいルールはツカモさんが翻訳記事を書いてくださっています。いつもありがとうございます。

tsukammo.hatenablog.com

元ネタはボードゲームSamsaraで、有名どころだとドミニオンなどが近いようです。

私はどちらもやったことが無いのですが、たまたま最近やや近いゲームをやったことがありました。近いと言ってもデッキ構築なだけですが。

 

考察

これは実装が重いやつ。(明文化されていないルールも多く、調査も辛い…)

そして、勝ち筋が少なくて…ほぼ1本道が2本あるくらいでは?

おまけにジャッジもビジュアライザもバグが多く。何が正しいのか分からーん。

うーん、これは楽しく取り組めそうにない。

ということで、今回はランダムを交えたMCTSの練習として取り組むことに。*1

 

まず何をどう探索するの?という問題はあるのだが、*2今回は相手の行動を詳しくシミュレートせず、自分の5回リリースの速さを評価する探索とした。ランダム部分については、観測結果を受けて次の行動を決めるという動きにしたかったので、カードをドローしたタイミングでドロー内容で分岐することにした。相手の動きは相互手番風にすると相手がリリースを目指さずこちらの邪魔を目的にする不思議探索になってしまうので、相手の動きもランダムにした。*3

 

実装(構成編)

まずはシミュレータを書いて、原始モンテカルロ法をするところから。

ゲームシミュレータがとても重いことと、順位を最終目標としていないことから、今回は速度重視でベタ書きな†Technical Debt†コードではなく、メンテナンスしやすいものを考えて作っていく。*4

 

まず、分岐点となる状態(プレイヤーがコマンドを送信する状態や、ランダムなドローが発生する状態など)をGoFのStateパターンで実装する。GameStateと名前がややこしいのでPhaseと呼ぶ。Phase構成は、以下の通りとした。

Move→Throw→Give→Skill(PlayCard)→Release→EndDraw(ターン終了時のドロー)→OppTurn(相手ターン)→Move

別枠で、SkillDraw(traningやcodingによるドロー)がSkillと相互に遷移する関係として存在する。

各Phase(Throw, Give, Skill, Release)は、行動やゲームエンジン側の判断により飛ばされることがある。基本は一本道なこともあり、遷移先を判断するよりも、遷移先でPhaseが存在するか判断した方が楽そうだった。

 

Phaseには入口処理であるEnter()と、出口処理であるExit()を作る。

例えばSkillPhase(ルール上での呼称はPlayCard)のEnter()ではMoveによるカードを入手したり*5、ThrowPhaseのEnter()ではThrowが無い場合や強制支払いがある場合に即GivePhaseに行ってねという追い出しを行ったりする。*6

Exit()では次のPhaseへの移行を行う。基本的にはPhaseに応じた行動を何かする度にExit()すべきかを判断するので、その判断を行うTryExit()を用意して、行動の度にそちらを呼び出す。Exitしないケースとしては、SkillPhaseはcodingの効果により使用回数が残っていると、行動後もSkillPhaseに留まる。

 

終わってみての反省点だけど、SkillPhaseの前にMoveによるカード入手だけのPhaseがあっても良かったかも。別に分岐点でしか状態を作ってはいけないわけではないし、SkillPhaseが始まったら移動によるカードを入手するというのはなんか直感的じゃないので。あとはスキルの使用回数もそっちで初期化すれば、skill使用後も留まるのを自己遷移としても表現できた。*7

少しネックになるのはジャッジ側の指示により途中状態(SkillPhaseなど)から開始されるケースで、この時にEnter()から入ってしまうと行うべきでない処理(移動によるカードの入手やスキル使用回数の設定など)が走ってしまうので、Enter()とは別口で初期状態に遷移しないといけない。複数手をインタラクティブで行う故の問題。特にGiveやPlayCardフェイズは残り回数が入力で与えられないので、ここはかなり美しくない実装になる。

あとは各Phaseは、合法手の列挙(選択用か確率用)、プレイアウトを行うための関数*8を持つ。シミュレータはGameStateのNextPhaseメンバに対してそれらの指示を出す。Phaseはそんな感じ。

 

各行動(Move, throw, 各skillなど)による効果はGoFのCommandパターン。割愛。

Phaseのプレイアウト関数も別関数からCommandを取得し、それを実行する形にすると良かった。というのも、今回は枝が多そうなのでThrow,Give,Skillなどがほぼルールベースで固定の動きをするだけだったのだが、そうなるとジャッジに出力を返すときにルールベースで同じ判断を行わないといけない。その行動の取得をプレイアウトと共用にすれば、二重管理を防ぐことができる。

 

こうして原始モンテカルロで動いたら、改めてMCTSに改造する。といういつものパターン。

 

実装(ゲーム編)

特に工夫した点。

 

ドローによる分岐

ターン終了時のドローはカード10種類に対して標準4枚(最大9枚)と非常に組み合わせ数が多い。これら全てを分岐すると展開が間に合わない*9ため、20回サンプリングしてそのいずれかに飛ばすことにした。ケースによっては実は20パターンも無いことがあり、その場合は真面目に計算した方がいいのだが、今回はそのままスルー。

 

他の人の解法を見て

終局まで探索するタイプだと、相手の状態も仮定して動くMCTSが強いようだった。そこまで行くとランダムによる分岐がえぐそうなんだけど、木は全体で1つ作って、ドローによる盤面再生はその都度行うらしい。ばらばらの前提から分岐するので滅茶苦茶になりそうなんだけど、UCBの計算するときに親の探索数をそれらしい値に設定するといいとか。

 

感想

楽しいコンテストではなかったです。どちらかというとアンチパターン展覧会。

成績も今回はGold止まりでしたが、目的を決めてそれ自体は達成出来たので、たまにはこういう参加スタイルも良いなと思いました。

*10

 

*1:もちろんLegend行けるなら行きたいの気持ちはあり。

*2:めっちゃ重要。

*3:正直方針としては良くないが、練習なので管理しきれるものにしましょうということで…。

*4:作り始めた時点ではまだバグが酷かったり、バランスの再考の必要性が囁かれていたりで仕様も怪しかった。

*5:Throw, Giveの時点ではまだカードを入手していないため、入手タイミングはここになる。

*6:1択の行動を行って抜けるという方法もあるが、強制支払いはPhaseが存在せず内部的に処理されるという挙動も再現するためこうした。

*7:それが美しいかは別。

*8:メソッド。

*9:間に合わないと原始モンテカルロとそんなに変わらないか、展開の半端さによっては劣化する。

*10:ランダムありMCTSしたいだけならもっと軽い題材で良いのは気づかないフリをしつつ…。

AHC011 - Sliding Tree Puzzle 参加記録

AHC011に参加しました。

atcoder.jp

問題はSliding Tree Puzzle。

スライドパズルの問題です。

得点は37.4Mで理論値の75%弱。

登録4073人、提出961人中、59位でした。(暫定テスト62位)

 

問題

木(グラフ的な意味で)が書いてるスライドパズルを完成させてね。

完成した場合は手数が少ないほどいいよ。

 

考察(初期)

基本はデカい15パズル。

同じパネルが複数あるのと、木が成立さえすればいいので解が複数ある。

 

MM120前後に似た問題があったような。あれは回転だったか。確か端から順に作っていって、探索が利くサイズになったら探索という解法がメジャーだった。これもそれで良いんじゃないかな。

 

手数上限は2 * N^3。

パネルを1マス動かすには、最大で

↓←←

→■↑

のような5手*1+動かすパネルに近づくための手数を使うので、最小のN=6でも愚直な移動が間に合いそう。Nが大きい方が余裕があるのかな。とにかく設計図さえ完成すれば手数不足になることは無さそうだ。

 

逆に設計図を作らず行き当たりばったりで都合よく木を作れるかというと厳しそう。

再反復化とか色々手法はあるようだけど、結局解が見つからない限り深いBFSをすることになるのでは?

A*…も良い評価関数を書いて短い手数で到達出来てこそだよなあ。基本的には隅から完成させないと局所解にはまりそうで、そういうのも評価関数に盛り込んで…辛くない?

順位表やseed=0共有を見た感じ、トップ層もN=6で100手くらいは使ってそう。流石に深すぎ。

 

設計図を作るには、DFSか焼きなまし…多分焼きなましかな。

設計図自体にも良し悪しはあるし、多様性を出したいなら焼きなましの方が良さそう。

(DFSは最後まで回しきれないと前半の値が偏るので)

 

あとはもう、一度作ってみるしかないね。

 

もうちょっと考察(途中で気づいたこと)

「木であること」を良い感じに利用する方法が何かあるんじゃないか?

閉路が無くて、T字や十字は枝の統合*2のためだけに使われている。

未接続の辺がある部分木を統合していくとか…はきつそうかな。

でも、葉の数が決まっていて、T字十字が枝の統合だけに使われているということは、再構築して全連結したものも閉路が生じることは無い…?全連結できたら閉路気にしなくて良いじゃん。

 

あとはパネルの移動なんだけど、

↑←←←

こういう移動をするとき、

↑←

 ↑←

  ↑←

こうした方が良い。

↓←←

→■↑

上記手順は5手かかるが、

↓←

■↑

上記手順は3手で良い。縦横ジグザグに動くとこの3手パターンの連続になる。

なので、移動コストは

Min(dx, dy) * 6 + (Max(dx, dy) - Min(dx, dy)) * 5

となる。(dx=x距離、dy=y距離)

終了後の感想:探索する解法の人が評価にユークリッド距離を使うと良いと言っていたのとちょっと関連ありそう?

 

 あとはパネルを1個ずつじゃなくて複数纏めて運べたらいいんだけど、並べる順番は正しいか、分断が発生しないか、という考慮が必要になってくるので結構苦しい…。2個までならルールベースでなんとかなるか?でもジグザグ移動によるコスト軽減が大きくて、2個じゃそこまで効果出ないんだよね。

(順番的には複数運びたいねの方が先にあった)

 

そういえば、MM128(Regional)にちょっとだけ似ている?目標盤面を作って愚直に動かす。同種タイルが盤面全体に散っていた方が、現在位置と目標位置のマッチングで改善しやすい。ロールケーキ食べたい。(MM128でもAHC011でもkomoriさん強かった)

 

現在位置と目標位置のマッチングはタイルの種類ごとに出来るよね。密なのでハンガリアン法でもそこまで問題なさそう。

 

最終的にやったこと

全体像

1.焼きなまし法で設計図を作る

ここでの目標は、全連結かつ初期盤面に近い設計図を作ること。

2000msまで焼きなまし、最大10件の設計図を作成する。

局所解にはまりやすそうだったので、3件並列で焼きなましした。また、10件の設計図は多様性を持たせたかったので、完成したら最初からやり直しとした。*3*4

設計図の評価は移動元と移動先でマッチングしたコストの総和(コストは移動の実コスト)として、優先度付きキューで上位10件を取った。

2.設計図通りにパズルを解く

2800msまでパズルを解き、最短の手順を作成する。*5

ひたすらルールベースで時間いっぱい何回も解く。初回は貪欲だが、2回目以降は少しずつランダム要素が増していく。たまに解けないパターンになることがあるが、主にマッチングのせいなのでマッチング部分のランダム比重を増やす。

今までの最善スコアを達成不可能になったら足切りする。(見込みは特に計算せず、実際にオーバーしたら足切り

詳細

 1. 焼きなまし法で設計図を作る

近傍は2点swap、評価は連結成分のサイズ^2の総和。温度は固定。

全てのタイルを同一連結成分にすることが目的なので、同一連結成分にならない原因となっているタイルを交換しやすいように優先度を付ける。隣接セルの一方だけが辺を伸ばしている状態、隣接セル同士で同一連結成分でない状態が不整合なので、それらのセルをいくらか優先する。*6

最終目標は全連結なので、この評価でいいのか?というのはちょっとある。どちらかというと、完成できない場合を見越した評価だよね。*7

外周のタイルが外に辺を向けないことは自明なので、前処理として焼きなまし開始前に貪欲で外周のタイルを近場のタイルと交換している。効果はあまり無かったかも…?

また、15パズルだと完成不可能なパターンというのがあるが、同種タイル同士を交換することでパリティほぼ回復できる。*8そのため、そのチェックは行わなかった。あと、全連結した場合は閉路ができないので閉路チェックもしなかった。全連結できなかったら破滅しようね。

2.設計図通りにパズルを解く
2-1. 3×3になるまで一辺ずつ設計図通りに完成させる

探索しきれる保証があるのは3×3。

残りがそのサイズになるまでは、一辺ずつルールベースで愚直に完成させる。どのタイルをどこに動かすかはハンガリアン法を使った二部マッチングで決定した。*9コストは愚直に移動する場合の実コストとした。

一辺の最後の2マスは同時に完成させないといけない。最後の2マスの目標セルそれぞれにタイルが既にあるか(また、その位置が正しい側か)で場合分けしてルールベースで動かすようにした。

ここでは、奥、手前、開始側、のような概念を扱えるものを作ったのが結構効いた気がする。これが無ければ実装量が8倍か、非効率な動きをしないといけなかった。*10

2-2.3×3を完成させる

これは完全にアルゴで、初期盤面と完成盤面の双方向からDFSするだけ。

ただし絶対に解けないパターンがある。その判定方法はサイトによって書いていることがまちまちだったが、最終的には下記サイトを参考にした。*11

8パズル,15パズルの不可能な配置と判定法 | 高校数学の美しい物語

 

感想戦スペースで双方向DFSが上手く行くのが分からんという人がいたので少し補足。

3×3は同種タイルが無い場合でも最大31手であることが証明されている(らしい)ので、

一方が15手、もう一方が16手探索したところで盤面がぶつかって完成できる。

3^15=14,348,907

3^16=43,046,721

なので、もっと刈れることを考えればギリギリ全探索できそうなライン。

(実際は初手は最大4方向なのと、端にいると1~2方向にしか動けないので厳密な値ではない。盤面数はこれよりかなり少ない)*12

参考までに、4×4は最大80手なので3^40=12,157,665,459,056,928,801*13で死ぬ。

 

やってみたかったこと

・探索

分岐の種類が多くて時間的に対応が無理そうだった。*14

・複数を同時に運ぶ

2個同時で、最大2割*15くらい手数を削減できたかも。でも限界が見えているから実装の重さもあってやりたいことではないなぁ。

・大きい盤面をヒューリスティックで解く

上位陣は割とこれっぽい。大体A*系統やビームサーチ系統。

A*はちょっと気になってたのでやってみたかったけど、基本的に1発勝負になりそう。私は数を撃つ方針だったので切り替えは辛かった。

・雑に運んで3×3を完成させるのを繰り返す

N=6なら3×3が4個、N=9なら3×3が9個あるものとみなせる。

ただ3×3が解無しになるのを避けないといけないので、そこが割と大変そう。

3×3の初期盤面と完成盤面の対応パターンは9P9=362,880で前計算や埋め込みが出来そうなので、その部分の計算はO(1)になる。

最終日はこれをやるか悩んで、結論としてお昼寝した。

 

日記

1日目
DFSで完成図作成できるかな~。無理だね。(辺の分断のみで枝刈り)
閉路禁止で枝刈りとか、枝で格子を作って葉を中に置くようにすれば多少マシ?でもN=10は厳しくない?

(UnionFindで閉路チェックできることに気づいていない)

2日目
焼きなましで完成図作成できるかな~。出来そうだね。
雑にswapを1秒回せばN6~8は行ける。N9~10も孤立は1~2個程度か。今は保留するけど近傍弄れば行けるっしょ。

(2,3ケース回しただけなので失敗が多いことに気づいていない)

3日目
移動元と移動先をマッチング。
実際に動かすところは実装イヤイヤ。
1個ずつなら行けそうだけど、15パズルで言うところの3,4同時セットがきついよ。

4日目
1タイル動かすのを途中まで実装。

5日目
1タイルを動かすのが完成。
4つ運ぶのに52手。40M取れる動きじゃないなあ。
2タイル動かすのは場合分けするしかないのか?
40M前提なら複数同時に動かす前提で作るか、1列一括で動かすとか作った方が良さそう。

6日目
場合分けしまくって最後2個動かすのが完成。
上手く動いたので、3*3を残して完全に動くようになる。

7日目

3*3を完成させる。
テスト用にPsyhoさんのmmtesterを導入。
無限ループがあると挙動が壊れるらしく、無限ループ対策を行う。
6*6が不可能パターンなことはほぼ無いんだけど、3*3の残り方によって不可能になるっぽい。
乱択要素を入れて時間いっぱい試行。とりあえず回って平均65%。

8日目
ん-、これ3*3を解いて回る問題では…?
実装したくないなぁ。

9日目
とにかく悪い状態を引くとスコアが落ちるので、焼きなましも移動シミュも多点にしまくる。雑に設定していたパラメータを調整していく。あとお昼寝。

 

感想

今回は多数のアルゴリズムを組み合わせて使う問題で、かつ最適な解法がすぐに出てくる問題ではなかったので、かなり負担が大きかったです。

1辺ずつ完成させる方針でも、最後の2個同時セットを作り切らないといけないのでスコア50%の壁が大きかったですね。

今回は手法よりは参加態度が駄目駄目で、何かを見ながら作業していつの間にか手が止まっているというのが常態化していました。*16

いや、手法も駄目だったんですが。証明されてないけど実際にやると上手く行く系はどうも漏れやすいですね…。これを解決するのは知識よりは意識の問題な気がします。あと挑戦したうえで滑り止め方針を準備できる実装速度。

何にせよ、もっとメリハリ付けてやりたいですね。

*1:返し縫いっぽい。本返し縫いよりは半返し縫いの方が糸が短くて良さそう。

*2:逆から見れば分岐。

*3:完成したものをそのまま焼き続けても大きい違いが出にくかった。

*4:こういう感覚でしたが、終盤までbestでなくcurrentを返すバグがあり、感覚が間違っている可能性があります。

*5:ジャッジ上だと+98msくらいになり、2900msだとかなり怖かった。

*6:同一連結成分でないことはそのセルが原因とは限らないが。

*7:動いてるからヨシ!

*8:同種タイルが2個あれば絶対に回復できるようです。

*9:一辺完成するたびに再マッチング。

*10:作りは結構酷くて20点レベル…。

*11:僕にはよく分からないけど偉い人がこんな事を言っていたよ、という論調の情報は疑って見た方が良さそう…(特大ブーメラン)

*12:他の方によると、9! = 362,880通りらしいし、双方向からやらなくても普通に間に合うらしい。

*13:実際は16! ≒ 2e+13通り

*14:どの辺をどの方向から完成させるか、移動元と移動先のマッチング、移動する際の経路

*15:最高に都合が良かった場合。

*16:実装イヤイヤ。

CodinGame Spring Challenge 2022 参加記録

CodinGame Spring Challenge 2022に参加しました。(常設名:Spider Attack)

 

www.codingame.com

いつものゲームAIです。

結果はLegendリーグ156/400位で、全体156/7,705位でした。あと日本人28/445位。

 

ゲーム概要

RTSやMOBA感のある戦略ゲームでした。*1

ルールはツカモさんによる翻訳記事があるのでそちらに丸投げします。*2

簡単に要素を挙げると、

・非グリッド(厳密には巨大グリッド)

・不完全情報(戦場の霧)

・2P×3キャラ(+中立ユニット)同時着手

という探索絶対殺すマンです。

 

最終的にやったこと

ルールベース。プレイヤー番号ごとに位置を考慮するのは大変なので、入力を反転させて常に自分が左上プレイヤーだと思い込むようにする。

80ターンまでマナを稼いで、攻撃2:防御1に分かれる。

マナ稼ぎ

モンスターの出現位置は固定(出てくる角度でちょっとブレるくらい)なので、その位置に居座る。これで基本的には拠点にモンスターを近づけずに稼ぐ。倒しきれずに拠点に向かいそうなモンスターはCONTROLで出現位置に跳ね返す。敵に先に喰われることが少ないので、最高効率かはともかく安定する。

この時拠点に向かうモンスターが視野外で見逃してしまうのが痛いので、拠点に向かうモンスターのspawnerから遠い順>拠点に向かわないモンスターのspawnerから近い順で攻撃しに行くようにした。

防御

拠点に一番近いモンスターを追いかける。追いつく前は追いつくターン*3から最短ルートを計算する。追いついた後は角度と速度を適当な分解能で全探索し、後続モンスターの巻き込みや敵ヒーローからの逃げで貪欲に移動する。

間に合わない場合のWIND、操られたことがある場合のSHIELDなどもルールベースで撃つ。あとは拠点外のモンスターを画面外KBで消したり。

マナ稼ぎ時には他のヒーローが下側からの侵入を防いでくれるのでその前提で守るが、下側のヒーローが攻撃に出るとホイホイ侵入されて不安定になる。やられる前にやろう!

攻撃

複数の攻めに同時対応できない状況を目指した。

・SHIELD付きモンスターでゴールを狙い、駄目でも相手ヒーローを奥に押し込む。*4

・相手ヒーローをCONTROLで引きずり出す。*5

・2人同時WINDで4400飛ばして直接ゴールを狙う。1ターン前に1人WINDで+2200も狙う。

CONTROLとWINDは相性が悪いかも?

 

リーグ別やったこと

Wood2, Wood1

待機位置を設定して、拠点内に敵がいれば倒しに行く。いなければ待機位置に戻る。

Bronze

WINDやSHIELDのシナジーを見越して、攻2守1構成で実装スタート。攻撃担当2人を定位置に立たせてSHIELDとWINDを同時に叩き込むことで、連携攻撃実装の練習とした。防衛はWINDを使うくらいでそのまま…だけど防衛力が足りず、攻1守2にしたところで昇格。

Silver

細かい計算で最適化したり、固定位置待機でなく巡回できるようにしたり。守2は相互作用を考えて担当を割り当てたりするのが大変で(大変なためうんうん唸るだけで実装しなかったので)、やはり防衛が安定せず。ルールを読み込んだところspawnerが4つしか無いことに気づき、spawnerでマナ稼ぎしながら拠点に近づかせない方針に。これでやられる前にやれば守備は雑でもいいので、攻2守1に戻す。

Gold

後続モンスターの巻き込み、モンスターをspawnerに送り返すなど、更に最適化。2人で同時WINDするのを作る。防衛役が自己SHIELDを張るかを相手の戦術に合わせる。Legend昇格の決まり手がSHIELDをやめるってどうなん?(じゃんけんなので。)

Legend

条件チェックを厳密化など。*6マナ効率が良くなったので、攻撃開始ターンを120→80に早期化。

 

雑多考察メモ

AHC008風な同時着手の振る舞い作りの問題だが、こちらは誰かの行動を決めたことによる影響が多岐に渡り、管理しにくい。こういうケースの対処法は、手元のゲームプログラミング本によるとダブルバッファが良いらしい。State全体をダブルバッファにしてもいいが、一部だけダブルバッファにしてもいい。私が偶然していた実装はStateを変化させずに決定済の行動だけ持って判定時に考慮に入れるという方法で、この後者に近かった。多分このゲームだと前者の方が合いそう。

攻1守2と攻2守1の違い。攻2は攻め方が多彩になり、同時に何かすることによるシナジーも生み出せる。守2は、モンスターが弱く1人で対処できるうちは並列として機能するため、片方が操られたり飛ばされたり、隙間から攻められたりというのに強い。モンスターが強くなると、1人では削りきれないモンスターを共同で倒す直列の動作をするようになる。つまり、序盤から終盤にかけてどちらも安定度が増す。どちらが良いかは難しいが、10日の完璧な実装で強いのは攻1守2、10日の雑実装で強いのは攻2守1だろうか。4400砲や6600砲の有効度で決まりそう。

マナアドバンテージ。中途半端な攻撃は自分のマナを減らし、敵のマナを増やすだけ。普段は無駄遣いせず、ここぞという時に飽和攻撃するのがいい。WIND合戦は1:1くらいで双方消耗するが、SHIELDは自分だけ消耗して相手は稼ぐことになりやすい。実際に攻めるのはマナを使うが、マナを使わずに相手陣に居座り、相手に対処を空撃ちさせる(そしていざ本当のチャンスとなれば実際に叩き込む)という方法もある。

事故は起こるさ。視界2200に対してヒーロー2人がそれぞれ最高速度で近づくと1600で、視野外から一気にWIND範囲に入ってしまったり、一度CONTROLされると復帰の手が無かったり、WINDで飛ばした先でもう1回WIND出来たりと、とにかく事故は起こるさの設定。相手の認識外から行動を起こしたり、想定外の行動を起こすのは有効度が高そう。

 

感想

勝ち筋を自分で選べるゲームで、最終戦術を何にして実装リソースを注ぐかを決めるのは難しかったです。また、特定の戦術(≒特定個人)へのメタも存在する環境でした。プログラマ同士の対戦をエージェントが代理でやるみたいな感じだったのと、何かが視界に入ったときには対処困難というのがあり、それよりゲーム木探索したいはちょっとありましたね。*7

これはこれで楽しいんですが、正しい道に進んでいるか分からない、ゴールが見えない系なので半月マラソンラッシュの締めとしては重かったです。処理順が複雑なのもあって、綺麗なコードを書くのも難しかったですし。

順位的にも目標の上位2%に微妙に届かなかったのですが、去年のコンテストよりは伸びていたので爆死の傷は癒せたかなというところです。*8

あと、流石に疲れたので休みたいです。

 

余談

 

このツイートで何かに似ていることに気づいてしまったのですが、このゲームのビジュアライザをよく見ると…。

 

・1Pは青い服

・拠点回りは黄金とまでは言わないが黄色い畑

・つまり「青き衣をまといて金色の野に降り立つ」

・なんか体に悪そうな霧が出てる

・森から出てきて直進し続ける虫

・そんな虫をCONTROLで森へ帰したり相手の拠点に送り付けることができる

・WIND(風)

・去年のパクリ元はジブリ

 

…ナ●シカじゃん。

*1:MOBAやったことないです。

*2:いつもありがとうございます。

*3:二分探索で求める。

*4:Health>16に限定した。

*5:マナ消費がとんでもないのでMana≧100に限定した。

*6:WINDする前にダメージを与えてモンスターを倒してしまうケースなど。

*7:上位は頑張ってしていたようです。

*8:ラソンの傷はマラソンでしか癒せない。

Topcoder MM135 - BridgeBuilder 参加記録

TopcoderのMarathonMatch135に参加しました。

 

www.topcoder.com

 

問題はBridgeBuilder。パズル「橋をかけろ」のほぼコピーでした。

結果は提出44人中、17位でした。(暫定も17位)

 

問題

パズル「橋をかけろ」を解いてね。

頂点は全部使わなくてもいいし、連結成分がいくつかに分かれてもいいよ。

でもスコア的には大きい連結成分が1つある方がいいよ。

1辺の橋の上限数(C)はケースによって2~5だよ。*1

 

考察

パズルの解法は理解。

部分解(それなりの大きさの連結成分)を求めるのがそもそも大変そう。連結成分に含む全ての島が条件を満たしていないといけないので、大きい連結成分を見つけるために「広げる」、連結成分を完成させるために「収束させる」という2つの方針を両立させないといけない。そんなボドゲあったな。

小さめのものを見つけるのも大変だし、小さい連結成分に島を付け加えて大きい連結成分を作れるかというと、そういう保証も無いように見える。そうなると、適当にガチャガチャやって上手くいくか見るしかない…のか?

連結成分同士が干渉せず、スコア計算も完全に分かれているのは日本橋ハーフマッサージチェアっぽい。うーん、解法も同じにしてみるか?

使う島を決めればパズルを解くだけになる。そうして成立する連結成分をいくつか求めたら、得点が最大になるよう組み合わせる。大きい連結成分を作れるように島たくさんでも探索したいが、それが出来なかったときのために小さめでも探索したい。うーん、島2個からランダムに1個ずつ増やして、最大まで行ったらリセットの形にするか。

連結成分の組み合わせは、スコア的にはほぼ貪欲になりそう。とりあえず貪欲で組んだ後は、焼きなましやビームサーチでも出来そうだけど、今まで使ったことの無いchokudaiサーチを使ってみようかな。

 

やったこと

島を全部連結

パズルを解く。

1方向にしか繋げない場合と、任意の方向に橋をかけないと矛盾が生じるパターンに対応。確定で橋を増やせる場所が無いなら頂点を1つ決めて、分岐で各方向に橋を1つかける。*2

seed1~1000のうち、996~997ケース程度は時間内に計算可能。

全て同一の連結成分に出来るもの、複数の連結成分に分かれるもの、解決不能なものがある。*3

そのため、全部の島を使うのが最善ではないケースがある。seed=1が分かりやすい。

上手く行かないケースではサンプルコードの解をそのまま出す。

提出結果は12点。

島2つ成分を列挙

探索出来る回数にもよるけど、小さい連結成分は全列挙して良さそう。

とりあえず島全部の連結に加えて、この成分を使って貪欲に組み合わせる。

提出結果は13点。

島N個成分を列挙

島2つから始めて、接続可能な島をランダムに1個ずつ増やす。

重複する島成分は島有無のZobristHashで排除。組み合わせることを考えると橋の有無単位でHashした方が良かったかも。まぁ、連結成分の大きさでほぼ決まるので誤差だと思うことに。

連結成分が2個以上に分かれるのは許容した。これを弾くとスコアが下がる。あと、連結成分の登録は横着して複数連結成分を1セットで登録した。(この辺の仕様が決まり切らないので作り切れなかった)

橋の数の和が奇数になる場合は成立しないのでシミュレート自体スキップ。

提出結果は47点。

組み合わせをchokudaiサーチに

各種ブログやツイートを参考に組む。

時間軸ごとの優先度付きキュー(元ツイートだとHeapというものだった)が溢れてしまい、capacityの自動拡張か、あまりに悪い状態を追い出す機能(両端キュー)のどちらかが必要そうとなる。

今回はほぼDFSで良い問題と見て、溢れるならキューに入れないという最悪な対処でなんとかする。

提出結果は49点。

前計算&枝刈り

モンテカルロ系でもそうなんだけど、シミュレーションの妥当さというのは大事。妥当でないパターンを延々計算するのは無駄なので、枝刈りするべき。

同時使用できない島を求める。

C=2でBi=7の島を使うと仮定すると、必ず4方向に橋を張らないといけない。そうすると隣接の島も使うので、その島でも同様に必ず張る橋を…と再帰的に求める。この"必ず使う橋"同士が交差する島は同時使用できないと言える。

島を増やすとき、同時使用できない島を考慮する。

提出結果は55点。

何も分からん

明らかに上位と別ゲームをしているので、方針の見直し。

6000msから既存の連結成分を拡張する方針にしてみたり、単純な拡張ではなく焼きなましにしてみたりと色々実験するも改善なし。

やっぱり既存成分の拡張はあまり意味が無いのかなぁくらいの確認に。

それなりの人数が一晩レベルで高得点を取っているので、そんなに難しい手法では無さそうだけれど…。

ランダムに橋を増やす

全く別の解法に着手。

橋を適当に置いて行って、パターンが成立か破綻するまで続ける。(もちろんゲームルールから自明な橋は置く。)

CやEが多いケース(生成ルールに対して多方向に橋を張りやすく破綻しやすい?)、島が少ないケース(従来手法の方がはまる)、あたりは苦手な様子。

これだけで提出すると54点でちょっと下がる。

Cと島の数で戦略を切り替えて59点。

駄目押しの高速化で60点。で終了。

 

他の人の解法を見て

愚直に辺ごとの橋の数を探索するだけで良かったっぽい。

枝刈りが上手く効いたりラッキーで時間内に妥当な解を見つける必要がありそうなんだけど、なんか上手く行くらしい。

実行時間が間に合いそうもない手法に突っ込んで撃沈するのはいつもやりがちで今回は避けたんだけど、よりによって今回は当たり方針だったという。試さなかったのが悪いのはそれはそうなんだけど、なんかすっきりしない。

 

感想

〇初めてchokudaiサーチを試した。

〇過去の知見を活かした。

×過去の知見を活かした。

〇今月あと2本マラソンがある。

×今月あと2本マラソンがある。

*1:元ネタはC=2。

*2:重複盤面排除は最後まで付けてないです。

*3:ケース生成時に同一の連結成分になるよう生成しておらず、交差も考慮していないため。

A.I.VOICE API利用記録

A.I.VOICEのAPIを使って色々試してみたので、その感想です。

 

A.I.VOICE is 何

有料の音声読み上げソフトです。

APIAPIを通して音声を読み上げできる、というものです。

 

感想概要

A.I.Voice Editorを遠隔操作するものという感想でした。これを使って何か公開サービスを作ろうとなるものではないです。サーバー(複数人が利用できる形)で利用することは規約で禁止されていますし…。*1

今回は常時起動ソフトとして任意の情報を垂れ流すものを作ってみましたが、不満点はありつつもとても楽しいという感想でした。

 

サンプルを触った感想(C# + WPF

f:id:inani_waon:20220415052646p:plain

サンプルプログラム

サンプルを動かすと、何が出来る、Editor側の挙動がどうなる、という辺りはかなりイメージが掴めると思います。

基本的にはEditorに文字列を送ってから再生機能を遠隔で呼び出すという流れです。サンプルではこれらを個別のイベントで行っていますが、メソッドを連続で呼ぶことでも普通に動作します。

マスターコントロールの各パラメータも弄れますが、これで調声しながら使うのは難易度が高そうです。使うとしても音量調節くらい?私はAPI専用のプリセットを作って、用途に合うものを呼ぶことにしました。

また、リスト機能は使用しないことにしました。複数の再生を管理したいなら自分のソフト側でやればいいんじゃない?と思ってしまったので。優先度や再生期限などを付けて再生管理機能がリッチになると、A.I.VOICE側のリスト機能に任せるのは心許ない気がします。*2

 

作るもの

常時起動しておいて、時報を鳴らしたり各種サービスから取得した情報を流してくれるもの。適当に雑談とかもしてくれると楽しそう。

という妄想ですが、今回は時報と天気予報、それからTwitter読み上げまでにします。UIも拘らず、サンプルの改変に留めました。

 

内部実装

複数の再生が重なることを考慮して、再生キューを作りました。

再生キューへの追加

各機能(時報機能、Twitter読み上げ機能など)からObserverで。データ内容は、ボイスプリセット名と読み上げ内容があれば最低限動かせます。

再生キューからの再生

EditorがIdle状態のときしか正常に再生出来ないので、1秒ごとに状態をチェックして、再生可能ならキューの内容を処理するようにしました。APIで再生完了を知らせたりというものは無いようです。

 

作ってみた機能

時報

一定時間ごとに時刻をお知らせしてくれるものです。今は15分毎。

これが作れたら技術的には何でも作れるだろう感があります。任意のタイミングでリクエストをキューに積んで再生出来たら、あとは何処からリクエストが発生するかの違いでしかないので。

タイマー

一定時間後にお知らせしてくれるものです。

世間一般のタイマーは手で止めるまで主張し続けるものが多くて煩わしいと感じていたので、聞き逃さない前提ならこういうのの方がいいなとなりました。ポモドーロ・テクニックなどに使うのも良さそうです。

ツイート読み上げ

自分のホームツイートを読み上げてくれるものです。ライブラリとして、NugetパッケージのCoreTweetを使いました。

ホームツイートを読むのが普通な気がしますが*3地震速報アカウントなどを対象に読み上げることで、各種通知サービスの代替としても使えそうです。余計なサービスを通す分、可用性は下がりますが。

ホームツイートはAPIの呼び出し回数上限がネックになりがち(現状1回/分)ですが、リストなら制限が緩いとか色々あるようです。

何を再生するかの選択、絵文字(サロゲートペア)の対処、リプ先やURLなどを省くかなど、調整もした方が快適に使えます。

余談ですが、読み上げ経由で「OK Google」する実験では認識しませんでした。環境によるとは思いますが、うちではツイート経由で遠隔操作されることは無さそうです。

天気予報

天気名(晴れ など)、最低・最高気温を読み上げます。

起動時に何も言わなくて寂しい&接続成功してるか不安になるので、起動時に日付と天気を言うようにしてみました。

天気の取得にはOpen-MeteoのAPIを利用しました。

 

調声

字幕付きの動画を比較対象として、時報などで聞き取りやすく話す場合では相対的に話速はやや遅め、抑揚は大きめ、という暫定調整になりました。逆にツイートなどを垂れ流す場合、抑揚を抑えた方が聞き疲れないです。

また、ツイートのような自由な書式の文章を読み上げると、区切り認識の関係で各種ポーズが大量に入ることがあります。ポーズ長はそれぞれ短めが良さそうです。文末ポーズはマスターコントロールでしか変更できません…。追記→ポーズ長で調整するより、文章を矯正した方が良さそう。

 

出来たもの

起動時に日付と天気を話すところ。

外部からデータを拾ってA.I.Voiceに流すという流れを感じていただけると。

 

気になったこと

色々ありますが、全てにおいて「これそういう用途で使うものじゃないから」というオーラを感じました。

音量が小さすぎる

音源側で音量を最大にして再生機器側で絞る、というオーディオあるある設定をしていると、マスターコントロールで5倍、ボイスプリセットで2倍にしてやっと適正~やや小さいくらいです。リアルタイムな読み上げだと他の音源との兼ね合いがあるので、単独で利用するときより調整しにくいです。

マスターコントロールへの設定が多い

上記の音量や文末ポーズなど、マスターコントロールを変更せざるを得ないことが多いです。API利用のためにマスターコントロールを弄って、別の用途で使うときには戻して…というのはかなり不便そうです。せめてボイスプリセットで完結してくれると他の用途と両立しやすいのですが。

もしくはEditor側の設定に干渉しないよう別物として動かすか。

同時再生ができない

単独起動のEditorを通して操作する都合でこうなります。そもそも同時再生したいか?というのはありますが。*4

あと、API不定期に操作する間はEditorを占拠されるので、別の用途での利用もしにくいです。

特殊文字に弱い?

何らかの絵文字に反応してか、A.I.Voice Editor側がビジー状態のままになってしまうことがありました。その文章を読んでくれないだけなら良いのですが、Editorを再起動するまで一切読み上げてくれなくなります。

読み上げ失敗するツイートの例:

朝型のジェシー on Twitter: "今、業務で使いたい(しかも全然違う2箇所で!!!)からっていう理由で、Rubyのトポロジカルソートのページを見ていて、業務中に競プロできている!?!?と幸せを感じてる🥺✨"

「!?!?」まで文単位で読んだ後に固まるので、やっぱり絵文字が原因かなーと思いました。サロゲートペアを弾くようにしてからは異常は起きていないです。

→ver1.3.1.0で修正されました。

 

総括

常時起動サービスを作ってみましたが、そもそもそういう用途を想定したAPIではないなという感想です。*5

ただ、自分で実装した通りにボイロキャラが喋ってくれるのは楽しいです。技術的な話に限っても、Alexaに枠に捕らわれないさいきょうスキルを追加しているような感覚?それを勝手知ったる開発環境で出来るのはメリットが大きいと思いました。*6

欠点としては、類似ソフトのVOICEVOXと比べるとAPI操作に制限の多さを感じます。*7A.I.VOICEはプリセットとテキストを決めて再生するだけ、Editor側で立ち絵も付けてくれると非常にお手軽ではあるんですが、Editorに縛られている感覚は強いです。

それでもA.I.VOICEを使うとしたら、キャラクター目当てか、VOICEVOX等のAPIを使いづらい場合ですかね…。私はせっかく買ったので使い倒してみようと思いますが、いずれEditorに縛られない形で使えるようになるといいなぁと思いました。

OK Kotonoha、コリドールで対戦して。みたいな未来も遠くはない?*8

*1:ローカルで自分だけが利用可能なサービスになら使っても大丈夫そうです。

*2:今回はキュー的に使うので合わないという話で、用途とマッチしていれば普通に使うと思います。

*3:そもそも読み上げるのは普通か?

*4:したい気持ちはあるけど、実際に試して聞き取れるかはまた別の問題。

*5:じゃあ何を想定しているのかと言われると…動画編集ソフトとの連動?

*6:C#使いなので。

*7:VOICEVOXはAPI仕様を少し見ただけで触れてはいません。

*8:コドゲで作り溜めたゲームAIは役に立つ。

モノグサ プログラミングコンテスト2022(AHC009) - Robust Memory of Commuting Routes 参加記録

モノグサ プログラミングコンテスト2022(AHC009)に参加しました。

atcoder.jp

問題はRobust Memory of Commuting Routes。

割合で移動する人をゴールまで移動する問題です。

提出799人中704位でした。

 

問題

割合で移動する人をゴールまで移動させてね。*1

P(0.1~0.5)の割合で移動せずにその場に留まるよ。

 

考察

余分に壁にぶつかれば移動し損ねた人が追い付いてくる。

スライド移動すれば良さそう。

 

やったこと

ビームサーチとスライド経路探索の間で反復横跳びしていました。

 

ビームサーチは初動は良さそうだけど途中から反復横跳びしてしまう。

あとは纏まらずに薄くなってしまうので、薄さにペナルティを付けたりと評価関数に調整が必要そう。

 

スライド移動はビームサーチで時間を削ってしまったので、これ時間内に仕上がらないなぁ…という感じ。

 

結局提出できるか怪しい状態なので、正の点である最短ルートの移動をちょっとだけ伸ばしたものを出して終了。*2

その後手直ししたらビームサーチは最低限動いたけど、本当に最低限なので調整はたくさんしないと駄目そう。

 

他の人の解法を見て

焼き鈍しが強そう?

ビームにしろ、スライド移動で割合を纏めることを主眼に置いて探索単位を変えるなりした方が伸びそう。

スライド移動は遠回りになることも多いので、1マス単位で探索するビームだとかなり深くする必要がありそうで、つまり多様性を上手く保つ調整と高速化が必要そう。もしくは少量を高速にゴールさせる方針か。

 

感想

確率というか割合を使う問題でありながら運要素も無く、楽しそうな問題でした。拡張ダイクストラ慣れしていない+何かにはまって大ロスしたのもあって、4時間では全然足りなかった。8時間~長期でやりたかった…。

あとは下手にレートが上がってしまったうえに非減少レーティングなので、レートが上がる見込みが無いと全然気持ちが入らないっぽい。短期は水パフォ出れば御の字だろうし、長期も1ページ目は苦しいような問題も多いだろうから、向き合い方を見直さないといけないかも。

 

*1:1人のうち0.5人が移動したりする。

*2:飛び賞位置が近かったので、それ以上位置を変えたくなかったというのもある。

MC Digital プログラミングコンテスト2022(AHC008) - Territory 参加記録

MC Digital プログラミングコンテスト2022(AHC008)に参加しました。

atcoder.jp

問題はTerritory。領域を切り分ける問題です。

暫定テストは826人中9位、システムテストでは7位でした。

問題

f:id:inani_waon:20220226214245p:plain

グリッド上に動物がたくさんいてうるさいので、300ターンで人を動かしたり壁を置かせたりして人間の領域と動物の領域を切り分けてね。

人間が5~10人いてそれぞれ動き、動物の移動もターン毎に返ってくる、マルチエージェント的*1インタラクティブな問題だよ。

人間が広い場所にいると嬉しいけど、4近傍連結セル内に動物がいると特大ペナルティがあるよ。

考察

 まず、人間が広い場所にいるとスコアが増えるので、人間の領域は出来るだけ広くしたい。人間は複数人いるので、一番広い領域に全員で入るのが最も効率的。つまり、動物を出来るだけ小さい領域に入れる問題になる。

 動き回る動物を1手で囲うのは難しいので、残り1マスを閉めるだけの部屋を用意しておいて、入り口にその1マスを閉める担当を配備すると良い。*2

 今回もSeed=0のビジュアライズ結果を共有していいルールだったが、そこでも壁含めて3x14の巨大部屋を20個作って必要な場所だけ閉じるものがあった。ただ問題になるのは犬で、犬は人間の間を移動する動きになるので、出入口が1つの部屋に入っていくことは基本無い。*3ではどうするかというと、出入口が2つある通路のような部屋にする。これなら部屋の中を通ってくれるし、むしろ入口の2人の間を通るために積極的に部屋に入ろうとする。

 入口2つの部屋を準備して閉じる、という全体方針になるが、部屋を動的に配置するというのは難しい。テンプレートを準備して、その通りに配置させることにする。ではどういうテンプレートがいいか。部屋の大きさ、部屋の数という観点から考える。まず、部屋の大きさは小さいほど理論スコア*4が高くなる。部屋の数は、理論上は(複数同時入れを考えなければ)動物と同じだけあればいいことになる。ただし、部屋が小さくて少ないほど、動物が部屋の中にいる確率が低くなる。また、猫は部屋が小さいほど部屋に入りにくい。動物が部屋にいないことには部屋を閉じられないので、小さい部屋を過剰に用意し、必要な分だけ閉じるという方針が安定しそう。

 テンプレート完成後は、人を良さそうな入口に配置して実際に閉じるという問題になる。部屋にスコアを与えて、人を配置する部屋のスコアの総和を最大化するという方針か。色々調べたところ、どうやら最大カバー問題(最大被覆問題)の亜種ということになるようだ。最大カバー問題では1人を配置すると部分集合がカバーされるが、この問題では2人を配置しないといけない。他にも3人で2段をカバー出来たりするので、ここの計算が難しそう。最悪、3-3-4人で3チームにして、各チーム単位で目標を決めれば計算しきれるだろう。

 動的に探索しながら動くタイプも一応考察してはみたけど、動物から間2マス以上離れないと間に壁を置けないという仕様上、人間が団子になると犬に粘着されてまともに動けなくなりそうなので、高度な制御が必要になりそう。

 

やったこと

初動

 開始から数日遅れで参加登録。まずはじっくり考察。重実装なのは見えているので、実装ロスが出ないよう問題の性質を考える。

 下のようなテンプレートを用意してみた。中央を空けることで、上下の分断が起きないようにしている。この通路が悪さをする予感が無いでもないが、まあ実験的にやってみるのはありかな。通路が無い場合は、部屋は行ごとにどれか1つ空けるようにしないといけない。

f:id:inani_waon:20220226212916p:plain

初期レイアウト

 テンプレートの設置は、1人目は左端から順に縦向きに設置、2人目は右から、みたいな感じで固定順にした。初期位置に応じたマッチングは後で入れるけど、ロスは今は許容する。

 テンプレート完成後は、仕事が無くなった順に人数と縦位置が固定のチームを組んで、最適な列に移動する。評価は、目的とする部屋ごとに{(0.5^動物との距離) * (0.8^チームが到達するまでのターン)}の総和とした。3チームに対して9列なので、適切に前処理してやれば9^3パターンで全探索が普通に間に合う。*5

 土日+αで完成させて、提出スコアは50.6%。*6提出720人くらいのうち14~16位くらいだったかな。

レイアウト変更

 やはりというか、極太通路部分に動物が溜まる。牛がこの辺りで反復横跳びしているとどうしようもない。通路部分が多いというだけでなく、太いということも関係していそうだ。幅1なら2方向にしか動けないが、幅2なら3方向、幅3以上なら4方向に動けることも出てくる。方向が多ければ、それだけ期待した方向に動く確率は低い。ということで、レイアウトを変更した。

f:id:inani_waon:20220226222138p:plain

 段にある10列を全て使うと上下が分断されてしまうので、9列使ったら残りの1列は使わないようにしている。

 これで提出スコアは56.4%。この時点では牛が一番の強敵。

夢の全員野球

 ある程度配置を固定して10^3パターンにしているけど、明らかに仕事をしていない人がいる。1人ずつ目的地を設定できたら強いんじゃないか?と思い、挑戦してみる。

 無理でした。作りこめば可能性はあるんだけど、目的地が変わりすぎるせいで部屋の入り口前に留まれないので、全員が実質仕事していない状態になる。これを調整しきるのは至難と思い、この方針は一旦保留。*7

細かい改善

・動物ごとに重みを付ける(牛>豚>兎=猫>>犬)

・レイアウトの事前配置の担当列決めをマッチング(一次元なのでソートするだけ)

提出スコアは55.7%。手元ケースでは上がってるのでOK。

レイアウト追加

 1位は60%強で、捕獲完遂精度を高めても到達できそうにない。もっと小さい部屋をたくさん用意する方針に変えるか、1部屋に動物をたくさん詰め込まないといけない。(そもそもテンプレートを使う方針が合っているかというのはあるが、ここは自分を信じる)

 動物をたくさん捕まえる方針は、ある程度大きく動く動物は犬猫(兎)くらいで、うちコントロールできるのは犬だけなので限界がありそう。また、使用済の部屋が多いせいで手近に入れる部屋が無くなる問題もあり、そういう意味でも部屋が多い方が良い。テンプレートを2つ増やしてみる。

f:id:inani_waon:20220226215411p:plain

 この2つのテンプレートは多少無理があって、部屋が6段のレイアウトでは、部屋の中として封鎖ができる対象位置の、チェスでいう白黒が部屋ごとに1:3となっている。ただ部屋が3マスずつずれているので、全体としてみればそこまで変わらない。7段に至っては1:1で、犬すら捕獲が難しい。ここから、豚猫犬の2マス移動動物が対処しづらくなる。また、通路の割合が増えるため、猫が特に強敵。

 ただ多少捕獲失敗ケースが増えても、一定の捕獲完遂率があれば全体のスコアは上がる。ターンを余らせても何も嬉しいことは無いので、ここからはより上位のテンプレートが使えるように捕獲完遂率を上げていくことになる。

 提出スコアは57.4%。

細かい改善

・チームの仕事が無くなったら、他のY位置まで出張する

・なるべくチーム内の横座標を合わせる(一部のメンバーが壁置きで停止したら、他も停止する)

提出スコアは57.7%。

夢のドッグラン

 犬だけを捕獲するための細長い通路を端に別途作る。

 3~4匹も捕まえれば黒字の計算だが、ドッグランまでの移動に最大30ターン近くかかり、通路に引っかかった犬を待ち、犬が中に入り切るのを待ち、と時間のロスがかなり大きい。

 どうやら、元々時間に余裕のあるケースでないと厳しいようだ。ドッグランを中央に置くとか、最初に他の壁を置くより前にやればいくらか良さそうな気もしたけど、そこまで差は出ないかな。

 また、犬は元々他の動物と一緒に捕獲しやすい性質なのもあり、何処まで効果が出るかは疑問が残った。

細かい改善

・猫の目的地を予想する。猫が入らない部屋にはスコアを加えない。

 また、動物の重みを(猫>牛>豚>兎>>犬)に変更する。

・チーム内でしか部屋を閉じれなかったのを、全員で閉じれるようにした。

 また、複数同時捕獲の部屋や、上下端の部屋を優先するようにした。

提出スコアは58.3%。

使用レイアウト調整

 動きが良くなっている分、難しいレイアウトを使いやすくなった。NとMにより振り分ける基準を再設定。

提出スコアは58.2%。下振れっぽい。

ダメージコントロール

 動物が1匹残るだけでそのケースのスコアが半減する。これが怖いばかりに部屋が大きいレイアウトを使って得点の上限が伸びなくなっているので、1匹残して被害50%のところを、広めの部屋に入れて10%などに抑えたい。それが出来ればもっと攻めに行くことができそう。

 部屋単位で数部屋x数部屋のブロックを作ってみて、それを閉じるための移動が出来るか最小カットで確認して、みたいな感じで実装してみるも、あんまりチャンスが無い。そもそも動物の方が最大速度が速いので、慎重になりすぎているのだろうか。

 そもそも動物を残すのは全体の4%程度しかないので、多少攻めたレイアウトに挑むにしても、その1~2割でしか効果が無いというのはあまりに小さい…。結果的にレイアウトを攻めるまでの効果は得られず、動物残しがさらに少し減ったくらい。

 提出スコアは57.9%で、下振れ…だといいなぁ。ここでコンテスト終了。

 

他の人の解法を見て

暫定1位~2位の方は、事前配置して部屋を閉じて、最後の1匹に特殊対応を入れたりと、細かい手法は違うけど大枠は一緒かな。*8

通路幅が3でもいいのが意外でした。あと部屋が1x4(私のは2x2)だったけど、部屋を閉じることが出来る2マスを必ず通らないと部屋の向こう側に行けない構造なので、確かに向こうの方が良さそう。2x2は1/2を引いてくれないと部屋を閉じられないので…。

1x4通路も試作パターンの中にあったけど、途中(10列レイアウトにした辺り)で捨てちゃったんですよね。掘り返してみる価値はあったかな。

 

ビジュアライズ結果公開について

今回の問題は、上位陣からするとビジュアライズ結果公開との相性は悪かったんじゃないかなぁ…と思いました。理由は以下の通りです。

・犬猫のいない結果を見て方針を真似すると実はハズレという、初心者に対する罠になる。

・犬猫あり想定の結果が共有されると真似するの考察皆無実装ゲーになる。

・Seed=0以外を想定していそうな言及も、無いとは言えなかった。

 (そもそもseed=0とそれ以外で方針が違う人は少なそう)

・閃き+重実装ゲーなので、残り1日などで良い方法が共有されると、実装速度や時間の都合で勝敗が決まる。

ただ今回は参加者層の多くが想定しないであろう振る舞い重視のコンテストなので、ビジュアライザ共有が無いとそれはそれで苦しいのかな…とも。

 

感想

段階によってネックになる動物が変わって、その対応を考えていく問題解決の連続が面白かったです。最後まで実装イヤイヤ期が来なかった。

スコア計算はペナルティが多すぎて、ケース1000件回しでは済まない限界チューニングゲーになっていたところはありそうです。時間を長くして残り時間ボーナスにするとか、20匹に対して1匹残りなら5%ダウンとか、ペナルティが軽くなれば助かるかなと思いました。

 

 

※ビジュアライザの画像にはDOTOWN様の画像が使用されています。

*1:管制できるタイプはマルチエージェントではないという考えですが、厳密なところどうなんでしょう?

*2:動物愛護的な観点から、部屋には空調や設備類が完備されているものとします。

*3:人間の誰かを犠牲にすれば可能だが、それは全体方針に反するので出来ない。

*4:ここでは部屋1つにつき1匹の動物を入れた時のスコアとする。

*5:1秒で余裕ですが、適切に処理しなかったので2.5秒かかりました。

*6:この記事では、1ケースあたり10^8点に対しての10^6点を1%とします。

*7:その後、彼の姿を見た者はいない…。

*8:つまり事前配置パターンと手法の違いで負けたということでもあり…。