フィールドと地形
エンジンの担当 この章は、フィールドの決まりです。地形・サプライ・縮小エリアは、エンジンが自動で起こします。あなたの bot は、state を通して見ることができます。
試合をする場所は、横 20 マス × 縦 15 マスの方眼です。 いちばん外の 1 周はかならず鉄の壁なので、実際に走れるのは 18 × 13 マスです。
4 つの地形
Section titled “4 つの地形”| 地形 | 数 | タンク | たま |
|---|---|---|---|
| 平地(EMPTY) | 0 | 通れる | 通る |
| 木箱(BRICK) | 1 | 通れない | こわせる。2 発で消える |
| 鉄ブロック(STEEL) | 2 | 通れない | はね返る(1 発につき 1 回) |
| 水たまり(WATER) | 3 | 通れない | 上を飛びこえる |
この 4 つのちがいが、そのまま作戦になります。
- 木箱のかげにかくれる → でも撃たれると 2 発でこわれる。一時しのぎ
- 鉄のかげにかくれる → こわれない。でも相手の跳弾が回りこんでくる
- 水たまりのむこうの敵 → 近づけないのに、たまは届く。一方的に撃てる場所
水たまりは「安全な堀」ではありません。たまは平気で越えてきます。
プログラムから地形を見る
Section titled “プログラムから地形を見る”地形は state.map.grid に入っています。grid[y][x] の順で、Y が先です。
def update(state): grid = state.map.grid # 自分のすぐ右のマスは何か gx = state.me.grid_x gy = state.me.grid_y right = grid[gy][gx + 1]
if right == 2: # 鉄ブロックだった return {"drive": "stop", "fire": False}
return {"drive": "forward", "fire": True}木箱のこわれぐあいは state.map.brick_hp[y][x] で見られます(2 → 1 → 0)。
0 になったマスは平地に変わります。
マップは毎回ちがう。でも公平
Section titled “マップは毎回ちがう。でも公平”マップは試合ごとに作りなおされます。木箱や鉄の場所は毎回ちがいます。
ただし、でたらめではありません。「シード」という数字ひとつから作られるので、 同じシードなら何度でも同じマップができます。 だから「さっきの試合をもう一度」ができます(くわしくは決定論)。
そしてもうひとつ、大事な約束があります。
作られる割合はこうなっています。
| 地形 | 割合 |
|---|---|
| 平地 | 70% |
| 木箱 | 18% |
| 鉄ブロック | 7% |
| 水たまり | 5% |
さらに、次の場所はかならず平地になります。
- スタート地点のまわり 3×3(
(2,2)と(17,12)のまわり)— 出たとたんに詰んでいた、を防ぐため - まん中の 6 マス — あとで出てくる「サプライ」が落ちてくる場所
そして最後に「スタートからスタートまで歩いて行けるか」を確かめています。 行けなければ、壁をひとつずつ消して道を通します。 「行けない場所」があるマップは出てきません。
スタートの場所
Section titled “スタートの場所”| 場所 | 最初の向き | |
|---|---|---|
| ● A(青まる) | (2.5, 2.5) 左上 | 0 度(右) |
| ■ B(オレンジ四角) | (17.5, 12.5) 右下 | 180 度(左) |
色だけでなく 形でも見分けられるようにしてあります(A = ● / B = ■)。 色の見え方は人によってちがうからです。
まん中に落ちてくるサプライ
Section titled “まん中に落ちてくるサプライ”試合の途中、20 秒と 40 秒のときに、まん中 (10.0, 7.5) にサプライが落ちてきます。
0.5 マスまで近づくと拾えます。
拾うといいことが 2 つあります。
- バリアの残り回数が 1 増える(さいだい 4 回)
- 10 秒のあいだ、つぎに撃てるまでが 1.2 秒から 0.8 秒に短くなる
効果が 10 秒で切れるのはわざとです。 先に取ったほうが一方的に強いままにならないようにしてあります。 2 回落ちてくるので、1 回目を取られても逆転のチャンスがあります。
両方が同時に届いたときは、2 人とも取れます。取りあいで喧嘩になりません。
終わりが近づくと、戦う場所がせまくなる
Section titled “終わりが近づくと、戦う場所がせまくなる”残り 20 秒(40 秒経過)から、2.5 秒ごとに 6 回、まわりが鉄の壁に変わっていきます。
最後に残るのは、まん中の 8 × 3 マスだけです。
def update(state): # 縮小がはじまったら、まん中へ向かう if state.shrink.active: want = angle_to(state.me.x, state.me.y, 10.0, 7.5) return {"drive": "forward", "steer": want, "fire": True, "barrier": False}
return {"drive": "forward", "steer": state.me.angle, "fire": True, "barrier": False}state.shrink には、いまの安全な範囲(min_x / max_x / min_y / max_y)と、
次にせまくなるまでの秒数(next_in)が入っています。
この仕組みのおかげで、逃げ回って時間切れという試合はほぼ起きません。
- 撃ちかたとバリア → たまとバリア
- タンクの動かしかた → タンクのうごかしかた
- 壁ごしに見えているか調べる → 視線判定と DDA