KOTH:ヒットアンドサンク


12

前書き

5回目のKOTHでは、よく知られているBattleshipに基づいたいくつかの工夫を加えたチャレンジを紹介します。指揮する艦船は1つだけで、その種類は5つの「伝統的な」クラスから選択できますが、移動を含め、各ターンで複数のアクションを実行できます。これはFFA(Free For All)としてプレイされ、あなたの目標は最後の船に立つことです。

原理

ゲームはターンベースです。ゲームの開始時に、船のクラスを選択する必要があります。その後、各ターンで、プレイヤーは自分の船に応じていくつかのアクションを実行できます。

ゲームは2Dグリッド(X、Y)で行われ、その側はこのように定義され
X = 30 + numberOfPlayer
Y = 30 + numberOfPlayer
ます。各船の開始位置はランダムです。

プレイ順は毎ターンランダム化され、「キュー」での自分の位置もプレイヤーの数もわかりません。ゲームは100ターン、または1隻の船が生き残るまで続きます。

敵の船にぶつかったり、ぶつかったりするたびに、ポイントを獲得したり失ったりします。最高スコアのプレイヤーが勝ちます。賞金は勝者に授与されます(参加者の数に応じた値)。

コントローラはコマンド引数を介して入力を提供し、プログラムは標準出力を介して出力する必要があります。

構文

最初のターン

プログラムは引数なしで1回呼び出されます。船を選択するには、1〜5の整数を含める必要があります。

1:駆逐艦[長さ:2、移動/ターン:3、ショット/ターン:1、射程:9、地雷:4]
スキル:自由船の回転(クールダウンなし)

2:潜水艦[長さ:3、移動/ターン:2、ショット/ターン:1、範囲:5、地雷:4]
スキル:プランジ/サーフェス(出力を参照)。水中では、「移動」アクションのみを使用でき、スキャンでのみ表示できます。あなたはショットでヒットすることはできませんが、地雷からダメージを受けることができます。

3:巡洋艦[長さ:3、移動/ターン:1、ショット/ターン:2、射程:9、地雷:2]
スキル:修理可能(出力を参照)

4:戦艦[長さ:4、移動/ターン:1、ショット/ターン:3、範囲:7、地雷:1]
スキル:シールド可能(出力を参照)

5:キャリア[長さ:5、移動/ターン:1、ショット/ターン:1、範囲:7、地雷:3]
スキル:ショットはターゲットにAOE(領域の範囲)ダメージを与えます(1範囲のスプラッシュダメージ)。ターゲットがショットでヒットした場合、この船の最大2つのセルも損傷を受けます。

ターン

入力

プログラムが呼び出されるたびに、次の形式の引数を受け取ります。

Round;YourPlayerId;X,Y,Direction;Hull;Moves,Shots,Mines,Cooldown;Hits,Sunken,Damage;Underwater,Shield,Scan;Map

ラウンドは1から始まります。

入力例

1;8;1,12,0;111;1,2,2,0;0,0,0;0,0,0;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.O.....UUUUUUUUXXXX.O.....UUUUUUUUXXXX.O.....UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUXXXX.......UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU

ここでは、それは第1ラウンドであり、プレイヤー8です。
あなたの船は(X = 1、Y = 12)に位置し、方向は上(0 =上、1 =右、2 =下、3 =左)です。 )。
船体は損傷していません(船の長さは3で、各ビットは真です[1 = OK、0 =損傷])。1回移動し、2回撃ち、2つの地雷を残して、「スキル」を使用できます(クールダウン= 0)。
あなたは何もヒットしませんでしたし、船を沈めたこともありませんし、あなたもヒットしませんでした。
水中ではなく、シールド(存在する場合)はアクティブにならず、スキャンもアクティブではありません。
地図の詳細は後で...

出力

このターンに実行するアクションを説明する文字列を出力する必要があります。出力文字列の文字の順序は、アクションの順序を定義します。船の制限を超えない場合、同じアクションを複数回出力できます。1つまたは複数のアクションが無効な場合、各アクションは個別にと見なされWます。使用可能なアクションのリストは次のとおりです。

M :向いている方向に1つのセルを移動します(1つの移動を消費します)
B:向いている方向から1セル
C戻します(1移動を消費します):船を時計回りに回転させます(駆逐艦の場合は1移動/自由に消費し
Kます):船を回転させます反時計回り(1移動を消費/駆逐艦の場合は無料)
A:向いている方向に船を叩きます(他の船が向いている方向にセルを占領している場合のみ動作します/船を動かさない/すべての動きを消費します)
F:範囲内のセルに1発発射します(1発消費します)。この形式で標的さ電池によって( - X [+ - ] [+])に従わなければならないY /例:F+2-3
N:場所あなたの船に隣接するセルに1つの鉱山()すべてのショットと1つの鉱山を消費します。([+ - - ] X [+])Y /たとえば、この形式で標的さのセルが続かなければなりませんN+0+1
S:次のターンのスキャンを有効にします(すべてのショットを消費します)
R:損傷した船体を船の「ヘッド」に最も近く修復します(すべてのショットを消費し、クールダウン= 3ターン/巡洋艦のみ)
P:プランジ/表面(すべてのショットを消費し、クールダウン= 3ターン、最大持続時間= 5ターン/潜水艦のみ)
D:シールドをアクティブにして、次のターン中に次のダメージを防ぎます(すべてのショットを消費、クールダウン= 3 /戦艦のみ)
W:待機(何もしません)

明確化:「すべての動き/ショットを消費する」とは、このターン中に自分の動き/ショットを使用したことがない場合にのみ、このアクションを使用できることを意味します。

出力例

MF+9-8CM :1つのセルを移動し、船の「頭」に対する相対位置が(targetX = X + 9、targetY = Y-8)のセルで発砲し、時計回りに回転して、最終的に1つのセルを再び移動します。

ゲームプレイ

グリッド

3人のプレイヤーが配置されているグリッドの例(33 x 13)は次のとおりです。

███████████████████████████████████
█                                 █
█       00                        █
█   2                             █
█   2                             █
█   2                             █
█                                 █
█       11111                     █
█        M                        █
█                                 █
█                                 █
█                                 █
█                                 █
█                                 █
███████████████████████████████████

ご覧のMように、プレイヤー1のすぐ隣に地雷があります。

プレイヤー2の位置と方向を理解してみましょう。

プレイヤー2の位置はX = 3、Y = 4、方向= 3です。方向は「下」なので、残りの「船のセル」は「頭」の上に配置されます(X = 3、Y = 3) &(X = 3、Y = 2)

プレイヤーの地図

各プレイヤーが受け取る最後の議論は、「自分の」マップです。デフォルトでは、船は5セルの範囲内のすべてを検出しますが、スキャンをアクティブにしてこの範囲を9に増やすことができますます。

引数の長さは常に361(19 x 19)文字です。これは、船の「頭」を中心とした正方形を表します。各文字は、このように定義された要素に対応します。

.:空のセル
O:あなたの船
M:鉱山
X:壁(マップ外のセル)
U:不明(スキャンで明らかになる)
A:敵船の損傷したセル
B:敵船の損傷したセル
C:敵船の水中の損傷のないセル(スキャンでのみ見られる)
D:敵船の水中損傷セル(スキャンでのみ表示)
W:残骸(死んだ船)

文字列は、最初の行の19文字で構成され、その後に19行目までの2行目の19文字が続きます。

プレーヤー2がスキャンありとスキャンなしで受信するものを見てみましょう(理解を深めるために改行しますが、プレーヤーには送信しません)。

XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXX
XXXXXX.............
XXXXXX.......AA....
XXXXXX...O.........
XXXXXX...O.........
XXXXXX...O.........
XXXXXX.............
XXXXXX.......AAAAA.
XXXXXX........M....
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXX.............
XXXXXXXXXXXXXXXXXXX

UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUXXXXXXXXXXXUUUU
UUUUXX.........UUUU
UUUUXX.......AAUUUU
UUUUXX...O.....UUUU
UUUUXX...O.....UUUU
UUUUXX...O.....UUUU
UUUUXX.........UUUU
UUUUXX.......AAUUUU
UUUUXX........MUUUU
UUUUXX.........UUUU
UUUUXX.........UUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUU

鉱山

機雷がトリガーされるのは、船が機雷が占有しているセルに移動したとき、または機雷が発砲されたときです。鉱山はアクション「Ram」ではトリガーできません。

地雷は、AOEダメージ(1範囲のスプラッシュダメージ)を、地雷を置いた人にも全員に与えます。別の地雷が爆発の範囲内にある場合、地雷は「連鎖」爆発を引き起こす可能性があります。

回転

回転は、船の「頭」を中心とした中心対称です。回転が地雷をトリガーするのは、それが「仕向地」に配置されている場合のみです(アークでは地雷をトリガーしません)。

影響範囲

1レンジのスプラッシュダメージ(地雷およびキャリアのショットの場合)は、最初のショット/爆発(x、y)を中心とした3x3(9セル)の正方形で定義されます。それらの座標にヒットします:[x - 1; y - 1],[x - 1; y],[x - 1; y + 1],[x; y - 1],[x; y],[x; y + 1],[x + 1; y - 1],[x + 1; y],[x + 1; y + 1]

得点

スコアリングは次の式で定義されます:
Score = Hits + (Sunken x 5) - Damage taken - (Alive ? 0 : 10)

ここで::
hits敵船のRam、Shot、またはMine爆発によるヒット
sunken数(チェーン爆発を含む、敵船のセルによる1ヒット):沈没した敵船での「最後のヒット」の
damage数:数受けたヒット(修復では減少しませんが、シールドでは防止され
aliveます):船が最後に生きているかどうかを確認します(少なくとも1つのハルセルが損傷していない)

コントローラ

GitHubでコントローラーを見つけることができます。また、Javaで記述された2つのサンプルボットも含まれています。実行するには、プロジェクトをチェックアウトし、Java IDEで開きます。クラスGameのmainメソッドのエントリポイント。Java 8が必要です。

ボットを追加するには、最初にコンパイル済みのJavaバージョン(.classファイル)またはインタープリター言語のソースが必要です。プロジェクトのルートフォルダーに配置します。次に、playersパッケージに新しいJavaクラスを作成します(既存のボットを例に取ることができます)。このクラスは、メソッドString getCmd()をオーバーライドするPlayerを実装する必要があります。返される文字列は、ボットを実行するためのシェルコマンドです。たとえば、次のコマンドを使用してRubyボットを機能させることができます。「C:\ Ruby \ bin \ ruby​​.exe MyBot.rb」を返します。最後に、ゲームクラスの一番上にあるプレーヤー配列にボットを追加します。

ルール

  • ボットは、特定の他のボットを倒したりサポートしたりするために書かれてはなりません。
  • ファイルへの書き込みが許可されています。「yoursubmissionname.txt」に書き込むと、ゲームが開始される前にフォルダーが空になります。他の外部リソースは許可されません。
  • 提出には応答するまでに1秒かかります。
  • 提出物をコンパイルして実行するコマンドを提供します。
  • 複数の提出物を書くことができます

サポートされている言語

すべての言語をサポートしようとしますが、無料でオンラインで利用できる必要があります。「メインストリーム」言語を使用していない場合は、インストール手順を提供してください。

現時点では、Java 6-7-8、PHP、Ruby、Perl、Python 2-3、Lua、R、node.js、Haskell、Kotlin、C ++ 11を実行できます。


興味深いKotHについて、いくつか質問があります。複数の提出物(たとえば、船の種類ごとに1つ)を作成できますか?AoEについて話しているとき、それは右の位置の周りの正方形です([x + 1; y + 1]にヒットします)?
-Katenkyo

@Katenkyoはい、複数の提出物を書くことができます。はい、9個のセルにヒットします[x - 1; y - 1],[x - 1; y],[x - 1; y + 1],[x; y - 1],[x; y],[x; y + 1],[x + 1; y - 1],[x + 1; y],[x + 1; y + 1]
。– Thrax

潜水艦は自動的に浮上しますか?どのターンに?
破壊可能なレモン

ターンは同時に取られますか?
破壊可能なレモン

また、ラム能力について何が便利ですか?(なぜ撃つだけではないのですか?)
破壊可能なレモン

回答:


3

RandomBot

これはボットの例です。船、アクション、およびターゲットセル(必要な場合)をランダムに選択します。

import java.util.Random;

public class RandomBot {

    int round;
    int playerID;

    public static void main(String[] args) {

        if (args.length == 0) {
            Random random = new Random();
            int ship = random.nextInt(5);
            String[] ships = { "1", "2", "3", "4", "5" };
            System.out.println(ships[ship]);
        } else {
            new RandomBot().play(args[0].split(";"));
        }
    }

    private void play(String[] args) {

        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);

        String[] actions = { "M", "B", "C", "K", "F", "S", "N", "A" };
        Random random = new Random();
        int action = random.nextInt(8);

        int rangeX = random.nextInt(5);
        int rangeY = random.nextInt(5);
        int mineX = random.nextInt(1);
        int mineY = random.nextInt(1);

        String signX = random.nextInt(1) == 1 ? "+" : "-";
        String signY = random.nextInt(1) == 1 ? "+" : "-";

        System.out.println(actions[action] + (action == 4 ? signX + rangeX + signY + rangeY : "") + (action == 6 ? signX + mineX + signY + mineY : ""));
    }

}

PassiveBot

これはボットの例です。何もしません。

public class PassiveBot {

    int round;
    int playerID;

    public static void main(String[] args) {

        if (args.length == 0) {
            System.out.println("5");
        } else {
            new PassiveBot().play(args[0].split(";"));
        }
    }

    private void play(String[] args) {

        round = Integer.parseInt(args[0]);
        playerID = Integer.parseInt(args[1]);

        System.out.println("W");
    }

}

3

PeaceMaker、Python 2(戦艦)

PeaceMakerは、最も近い敵(スパイラル距離)を3回撃ち、鉱山から少なくとも2セル離れた状態で一列に前後に動きます。

from os import sys

def reversedSpiralOrder(length):

    #Initialize our four indexes
    top = 0
    down = length - 1
    left = 0
    right = length - 1
    result = ""

    while 1:

        # Print top row
        for j in range(left, right + 1):
            result += str(top * length + j) + ";"
        top += 1
        if top > down or left > right:
            break

        # Print the rightmost column
        for i in range(top, down + 1):
            result += str(i * length + right) + ";"
        right -= 1
        if top > down or left > right:
            break

        # Print the bottom row
        for j in range(right, left + 1, -1):
            result += str(down * length + j) + ";"
        down -= 1
        if top > down or left > right:
            break

        # Print the leftmost column
        for i in range(down, top + 1, -1):
            result += str(i * length + left) + ";"
        left += 1
        if top > down or left > right:
            break

    result = result.split(";")
    del result[-1]
    return result[::-1]

def canMove(x, y, direction, hull, map):

    # M = 1, B = 2
    moves = 0

    if direction == 0:
        y1 = -1
        y2 = -2
        hx1 = hx2 = x1 = x2 = 0
        hy1 = -y1 + hull
        hy2 = -y2 + hull
    elif direction == 1:
        x1 = 1
        x2 = 2
        hy1 = hy2 = y1 = y2 = 0
        hx1 = -x1 - hull
        hx2 = -x2 - hull
    elif direction == 2:
        y1 = 1
        y2 = 2
        hx1 = hx2 = x1 = x2 = 0
        hy1 = -y1 - hull
        hy2 = -y2 - hull
    elif direction == 3:
        x1 = -1
        x2 = -2
        hy1 = hy2 = y1 = y2 = 0
        hx1 = -x1 + hull
        hx2 = -x2 + hull

    if map[y + y1][x + x1] == "." and map[y + y2][x + x2] != "M":
        moves += 1

    if map[y + hy1][x + hx1] == "." and map[y + hy2][x + hx2] != "M":
        moves += 2

    return moves

if len(sys.argv) <= 1:
    f = open("PeaceMaker.txt","w")
    f.write("")
    print "4"
else:
    arguments = sys.argv[1].split(";")
    sight = 19

    round = int(arguments[0])
    playerID = int(arguments[1])
    x = int(arguments[2].split(",")[0])
    y = int(arguments[2].split(",")[1])
    direction = int(arguments[2].split(",")[2])
    hull = arguments[3]
    moves = int(arguments[4].split(",")[0])
    shots = int(arguments[4].split(",")[1])
    mines = int(arguments[4].split(",")[2])
    cooldown = int(arguments[4].split(",")[3])
    hits = int(arguments[5].split(",")[0])
    kills = int(arguments[5].split(",")[0])
    taken = int(arguments[5].split(",")[0])
    underwater = int(arguments[6].split(",")[0])
    shield = int(arguments[6].split(",")[1])
    scan = int(arguments[6].split(",")[2])
    map = [[list(arguments[7])[j * sight + i] for i in xrange(sight)] for j in xrange(sight)]

    initialShots = shots


    priorities = reversedSpiralOrder(sight)

    actions = ""
    sighted = 0
    for priority in priorities:
        pX = int(priority) % sight
        pY = int(priority) / sight

        if map[pY][pX] == "A":
            sighted += 1
            if shots > 0:
                shots -= 1
                actions += "F" + ("+" if pX - 9 >= 0 else "") + str(pX - 9)  + ("+" if pY - 9 >= 0 else "") + str(pY - 9)

    if shots == initialShots and sighted > 0:
        actions += "D"
    elif shots == initialShots and sighted <= 0:
        actions += "S"
    else:
        actions += ""

    f = open("PeaceMaker.txt","r")
    fC = f.read(1)
    lastDirection = int("1" if fC == "" else fC)

    y = 9
    x = 9

    if lastDirection == 1:
        if canMove(x, y, direction, len(hull), map) == 1 or canMove(x, y, direction, len(hull), map) == 3:
            actions += "M"
        elif canMove(x, y, direction, len(hull), map) == 2:
            actions += "B"
            lastDirection = 0
    elif lastDirection == 0:
        if canMove(x, y, direction, len(hull), map) == 2 or canMove(x, y, direction, len(hull), map) == 3:
            actions += "B"
        elif canMove(x, y, direction, len(hull), map) == 1:
            actions += "M"
            lastDirection = 1

    f = open("PeaceMaker.txt","w")
    f.write(str(lastDirection))

    print actions

1
「PeaceMakerシュート」。あなたはそこで私を失いました。
Okx
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.