ICFPC 2011

注:コンテスト直後に殴り書いた記事をちょっと修正して公開しました。はてな使い方良く分かってない...。


今年はコンテスト主催側に参加させてもらっていました。コンテスト期間中にすることがなくて悲しいというか、実質一月前から一週間くらい前までの期間にテストプレイヤー(バランス調整)を延々とやっていて、そこで既に終戦していたというか。(ここに書いてあることは、コンテスト主催者の何かを反映するものではなくて、単に個人的な思いつきなどであって、しかもコンテストが終わった今となっては時代遅れな内容だと思います...。)

個人的に想定していたルーチン色々

一番単純なルーチンは、help:16n;attack:n;というルーチンでした。要は16nの大きさのhelpができれば、1.6n回復するので、その分を攻撃にあてましょうと。副作用で0.6nほど残るのですが、ちょうど10倍にするよりも16倍の方が作りやすいので。nを256くらいにして無限ループさせてやれば、10000程度のダメージであれば当たります。(適当にgetしながらやれば4ターンに1スロットくらいやっつけられる。)


ちなみにhelpは常に同じスロットを指定して使うことしか個人的には考えていませんでした。実はhelpは当初1:1で、役に立たない困ったちゃんだったのですが、こうすると誰も使わないカードになってしまうので、少なくとも1よりは大きくしようという話になりました。ここで2とか1.5とか登場したのですが、これはまずくて、指数爆発するルーチンが簡単に作れてしまい、最終的に1.1ということになりました。(help:1;x4;attack:1;で1をdblして再帰などとやると、相手のスロットを確実に仕留めた上に最大値の半分くらい残る。しかもスロットの体力が少し残っていれば発動する。)


頭が良くないけれど、足の速いルーチン(全然チューニングしていないけれど、何もしてこない相手なら250ターンもかからずやっつけられる)として、help:8192;x2;attack:11264;(値は適当に)を絨毯爆撃というルーチンがあります。絨毯爆撃は、対象のスロットをsuccしながら再帰することで実現されます。こちらもダメージを受けるけれど、相手にも大ダメージ、という感じです。これはattackもhelpも1:1の時代には、inc;attack:10000;で代用可能でしたが、比率をチューニングして、重たくなるように修正されました。最終的にattackとhelpを一回ずつやったときに1:0.99という1よりも小さくなるようにすることで決着しました。


後はzombie系のルーチンがいくつか。当初zombie時にattack,help,inc,decの反転などはなく、zombieは相手のスロットを破壊する用途(しかもhelpが1:1なのでhelpでも投げつけてしまえ)しかなかった状態でした。なぜ破壊するかというと、やっつけて使えなくなったスロットでもgetの前にreviveを挟めば回収できてしまうためです。(この時点ではzombieの本当の使い道に気付いていなかったので、反転していなくても問題なかったのですが。)


ということで、zombieを強くする話として、毎ターン(Iに)適用という話がでてきました。それでも使えないので、zombieは何があってもIに書き戻さないとか...。しかし反転した途端に話は変わって、今度はzombieが強すぎるのではと。(反転しなくても実はバランスはさほど変わらないので、反転していなかったら崩壊していたかも。)結局zombieは常にIに書き戻ることになりました。(たとえ返り値が自分になるように調整しても。)


結局のところzombieの主目的は相手にzombieを送りつけることで、こうすると、自分が壊れようがなにしようが、相手にzombieが残り、次のターンになる前にzombieを返してくれるので、無限ループするわけです。(これはかなりのチームが使っているどころか、序盤から思いついていたっぽい?パラメータが確定した状態で渡されるとそういう発想から入れるのでしょうか?)重要なことは、相手にzombieを送りつけられたらすぐにreviveしましょう、ということ。ですが、reviveだけだと、dec;zombie;に対応できないので、結局は負けてしまいそう...。reviveした後に十分な体力に復帰できるだけの余裕がある状況は想定しづらく、この時点で大分勝敗は決していそうな気も...。


で、話は戻してzombieですが、結局無限ループは相手にzombieを送りつければ達成されるので、後はどうやってもIに戻るので、適用回数上限までループするルーチンを後ろにくっつけるのが正解という感じです。相手側では、attack,help,incを駆使して適当に攻撃しまくり、自分側ではreviveを絨毯爆撃かなぁ、というのが率直な感想です。もちろんzombieは一つである必要はないのですが、自分側のzombieは自分にとって何一ついいことをしてくれないので、reviveする他ないという感じです。(ちなみに反転の影響で、zombieがreviveを発動しても何も起こらないという仕様で進んでいたのがコンテスト数日前にこの目的のために使えるように修正が入りました。)


以上が3週間くらいかけて想定していたすべてで、ほとんど何もやっていないに等しい状態であることが分かります。対戦ゲームなので、きっと収束しないだろう、とは(甘い考えながらも)思っていて、実際そんな感じに進んだようで何より。


ちなみに、相手の手を真面目によんでいる人で、遅延評価していない人がいると、Sとgetでフィールドを指数的にでかくされると、メモリ制限にひっかかって死ぬと思うんですが、どうなんでしょう?(これもやってるチームあったらしい!)


(修正入りました、とかかなり客観的に言ってるけれど、バランス調整には大分貢献したつもりですよ?)