コデモン、私はあなたを選ぶ!


55

親切な隣人のドクターツリーから、コデモンと呼ばれる3匹の魔法の生き物が渡されました。近くのカラービルの町でバトルトーナメントがあります。誰もいない最高のあなたですか?

概要

これはバトルトーナメントです。各プレイヤーは3匹のモンスターのチームをコントロールし、目的は他のチームをノックアウト(キル)することです。100ラウンドあり、勝ちと引き分けのポイントが与えられます。最もポイントの多いチームが勝ちます!

モンスター

コデモンは複雑な小さな生き物です。選択できる5つのタイプ(要素)、3つの統計、およびそれぞれに3つの移動スロットがあります。

タイプ

各Codémonには1つのタイプが割り当てられます。5つのタイプは、ノーマル、サイキック、ファイア、ウォーター、およびグラスです。それぞれに長所と短所があります。損傷は次のチャートに基づいています。

タイプチャート

数字はダメージ乗数です。たとえば、水を攻撃する火には0.5の修正(半分のダメージ)がありますが、グラスを攻撃する火は2倍になります(2)。

統計

各モンスターには、戦闘能力を決定する3つの統計があります。攻撃は、与えるダメージを増加させます。防御は、受けるダメージを減らします。速度により、速度の低いユーザーの前に移動できます。

各モンスターの開始値は、各ステータスごとに50で、最大100です。モンスターを作成すると、80個の追加のステータスポイントを割り当てることができます(それぞれ)。個々の統計が100を超えることはできないことを忘れないでください。したがって、100/80 / 50、90 / 80/60、または65/65/100の分布を持つことができますが、120/50/60は違法です。違法な統計情報を持つチームは失格となります。80ポイントすべてを使用する必要はありませんが、おそらく最低50/50/50を使用すべきではありません。

HPを統計と見なすこともできますが、各Codémonには変更不可の100 HPがあります。HPがゼロになると、戦闘を続けることができなくなります。HPは各戦闘の前に100に補充されます。

動き

各モンスターは3つの戦闘の動きを知っています。選択された3つは異なる必要があるため、パンチ/パンチ/パンチはありません。

15の動きがあり、それぞれ3種類です。各タイプには、直接攻撃、効果のある弱い攻撃、および唯一の効果の移動があります。

id  name        type    power   uses    usable  effect

0   Punch       N       20      -       NFWG
1   Heal        N        0      3       NFWG    Heals 50 HP
2   Slow        N       10      5       NFWG    Enemy speed x0.8
3   Pain        P       20      -       PFWG
4   Sleep       P        0      3       PFWG    No enemy action until wake
5   Weaken      P       10      5       PFWG    Enemy Atk x0.8
6   Fireball    F       20      -       NPFW
7   Burn        F        0      3       NPFW    Enemy -10 HP each turn
8   Sharpen     F       10      5       NPFW    Own Atk x1.25
9   Watergun    W       20      -       NPWG    
10  Confuse     W        0      3       NPWG    Enemy may strike itself (10 power)
11  Shield      W       10      5       NPWG    Own Def x1.25
12  Vine        G       20      -       NPFG
13  Poison      G        0      3       NPFG    Enemy -5xTurns HP each turn
14  Sap         G       10      5       NPFG    Enemy Def x0.8

type移動のタイプを指します。powerその顕著な力です。uses戦闘ごとに使用できる回数を示します(-無制限)。usableどのタイプで使用できるかを示します(たとえば、PunchはPsychicタイプには与えられないため、付与されませんP)。effect動きが持つ影響を示します。常に機能するヒールを除き、各エフェクトが機能する確率は75%です。

モンスターのステータスを変更するエフェクトの場合エフェクトがスタックされる場合があります。たとえば、ウィーケンを2回使用すると、相手の攻撃力が0.64に低下する場合があります。モンスターのステータスを変更しないエフェクト(スリープ、バーンなど)はスタックしません

スリープは相手をスリープ状態にし、各ターンの開始時に60%の確率で目を覚ます。眠っているモンスターは何もしません。

火傷はアクティブな場合、各ターンの終わりに10 HPのダメージを相手に与えます。も同様に機能しますが、ターンごとに量が増えます。最初のターンでは、それは5であり、その後はターンごとに5を獲得します。そのため、4ターン目までに20のダメージを与えます。これらは、モンスターのタイプの影響を受けたり、ボーナスの対象にならない、フラットなダメージです。

混乱は、指示されたとおりに行うのではなく、モンスターを攻撃させる可能性があります。この攻撃のパワーは10で、特定のターンに30%の確率で発生します。

明確にするため、効果は戦闘終了まで続きます(上記のスリープを除く)。

移動は、対応するタイプのモンスターが使用すると、パワーが20%増加します。たとえば、Vineを使用するGrassモンスターはブーストされますが、Punchを使用するモンスターはブーストされません。

秘密の統計

各モンスターの統計とタイプ(ただし動きはありません)は公開されています。対戦相手は、最善のアクションを選択するために、彼らが戦っているものを見ることができます。ただし、非表示のボーナスも利用できます。

具体的には、2戦ごとに、チームのモンスターごとに1つの「ボーナス」ステータスポイントが与えられます。死んだか生きているか、勝者でも敗者でも、すべてのモンスターにポイントが与えられます。これは、選択した3つの統計のいずれかに割り当てることができます。1つのモンスターにスタックすることはできません。各モンスターは毎回1つを取得します。これらのポイントは、100の制限の影響を受けません。100回の戦闘ラウンドがあるため、これにすべてのボーナスを割り当てた場合、149までの単一のステータスを取得できることを意味します。繰り返しになりますが、対戦相手はあなたの「ベース」統計のみを見るので、トーナメントに行くほど、知識は真実から離れていきます。

戦い

戦闘は3チームで行われ、各チームで1つずつアクティブになります。開始時に、対戦相手のチームが表示され、どのモンスターを最初の「アクティブ」プレイヤーにするかを選択するよう求められます。

その後、次の手順でターンが行われます。

  • 切り替え:必須のモンスター切り替えが行われます(ある場合)
  • バトルアクションを選択する
  • スイッチ:オプションのモンスタースイッチ(戦闘アクションとして選択)が実行されます
  • 睡眠チェック:睡眠から目覚めるチャンス
  • 攻撃1:可能であれば、より速いモンスターは選択した動きを使用します
  • 攻撃2:可能であれば、他のモンスターは選択した動きを使用します
  • 効果ダメージ:生きているモンスターに火傷/毒ダメージを与える

「より高速」とは、より高速のモンスターを意味します。両方の速度統計が同じ場合、毎ターンPRNGコインフリップで選択されます。

アクティブなモンスターが死亡するターンの終わりに、新しいアクティブを選択するように求められます。また、アクティブモンスターを任意のターンの移動として切り替えることできます(複数の生き物がいる場合)。繰り返しになりますが、あなたが自分の動きとして切り替えると、そのターンに戦闘の動きをすることはありません。

非アクティブの場合、モンスターは「処理」されません。これは、火傷/毒によるダメージ、毒カウンターの蓄積、睡眠からの覚醒などが発生しないことを意味します。切り替え時に効果が除去または変更されることはありません。これは他のモンスターと戦うゲームではありません。攻撃を上げて燃やした状態でスイッチアウトした場合、再びスイッチインしてもそこにいます。

効果的なダメージは、アクティブな敵を殺すかどうかに関係なく起こります。このようにして、両方のチームのメンバーが1ターンで死亡する場合があります。

あるチームが使用可能なモンスターを使い果たすと、彼らは負けます。両方のチームが同じターンで不足した場合、それは同点です。戦闘が1000ターン続くと、引き分けになります。

損傷を判定する公式は次のとおりです。

floor((effAttack / effDefense) * movePower * typeMultiplier * moveBoost)

effAttackそして、effDefenseしている効果的なモンスターの統計情報。効果的な攻撃は、攻撃とボーナス攻撃を追加し、効果が変化した場合に(0.8または1.25)を掛けることで得られます。これらの効果は積み重ねられる可能性があることに注意してください。

ダメージは、タイプ修飾子が0(通常<->サイキック)またはムーブのパワーが0(ヒール、バーンなど)の場合にのみ0になります。それ以外の場合、最小値は1に強制されます。

トーナメント

トーナメントは100ラウンド続きます。各ラウンドで、チームはシャッフルされ、ランダムに互いにペアリングされます。チームの数が奇数の場合、残り物はバイ(同点の得点)を受け取ります。戦いに勝つとチームに2ポイントが加算され、同点は1の価値があり、損失はありません。最後にポイントが最も多いチームが勝ちます!

チームが結ばれている場合、タイブレーカーの順序を決定するために、チームだけが1位で結ばれたトーナメントが行われます。

プロトコル

コントローラは、プログラムに4つのコマンドのいずれかを送信します。最初の文字がコマンドタイプを決定し、必要に応じてデータが続きます。

プログラムはコマンドを引数として受け入れ、1秒以内にSTDOUTで応答します。STDINを聞いて生き続けないでください。各コマンドは新しいプロセスを生成します。

データ/状態をディスクに書き込むことができます。チームと同じ名前のファイルをサブフォルダーに配置します。32キロバイトを超えるデータを書き込まないでください。そうしないと失格になります。データはラウンド間で保持されますが、トーナメント間でクリアされます。

コマンド

チームデータ

これは、トーナメントの開始時にチームを登録するために一度送信されます。返信はトーナメントごとに変わらず、一定でなければなりません。

クエリ:

T

応答:

name|member0|member1|member2

nameチーム名を含む文字列です。解析を容易にするために、英数字のみを使用してください。memberNは、各モンスターの詳細を示すメンバー文字列です。

メンバー文字列:

name:typeid:attack:defense:speed:moveid0:moveid1:moveid2

繰り返しになりますが、「名前」は文字列で、今回はこのモンスターの名前を使用しています。typeidそのタイプです。タイプIDは、上の図に示されている順序で、Normal = 0およびGrass = 4です。

次の3つのフィールドは基本統計です。上記の統計セクションで説明されている制限に留意してください。

最後の3つは、モンスターの動きです。IDは上記の移動チャートに示されています。

チームデータの返信の例は次のようになります。

DummyTeam|DummyA:0:50:60:70:0:1:2|DummyB:0:50:60:70:0:1:2|DummyC:0:50:60:70:0:1:2

ここでごみ、不正な形式、または違法なデータを送り返すチームは、修正されるまで参加しません。

アクティブを選択

これは、各戦闘の開始時、およびモンスターが死亡し、切り替える必要があるときに送信されます。

クエリ:

C#battleState

battleState現在の戦闘の状態を示します。ここで私と一緒に耐えてください、それはいです:

yourTeamState#theirTeamState

ここで、XteamState次のようになります。

name:activeSlot|member0state|member1state|member2state

activeSlot現在アクティブなモンスターを表示します(0-2)。加盟国には2つのフレーバーがあります。あなたのチームであれば、追加情報を提供します。そう、

あなたの memberXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:moveCount0:moveCount1:moveCount2:bonusAttack:bonusDefense:bonusSpeed:effectid:effectid:effectid

彼らの memberXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:effectid:effectid:effectid

idはを使用したくない場合にモンスターを追跡するために使用できる単なる整数識別子ですname

attack:defense:speedあなたの基本統計です。

poisonedturns 毒されたターン数を教えてくれます。

moveCountX各移動に使用した回数を示します。0の場合、使用できません。無制限の移動の場合、これはマイナスになります。

bonus(stat) 各統計に割り当てたボーナスポイントの量です。

effectidモンスターに適用された効果の可変サイズのリストです。そこうではない末尾なる:存在かないアクティブな効果があるかどうか、文字列に。積み重ねられた効果がある場合、それらはリストに複数の効果として表示されます。

エフェクトIDは次のとおりです。

0  NONE           (should not appear, internal use)
1  POISON
2  CONFUSION 
3  BURN 
4  SLEEP 
5  HEAL           (should not appear, internal use)
6  ATTACK_UP
7  ATTACK_DOWN
8  DEFENSE_UP
9  DEFENSE_DOWN
10 SPEED_DOWN

応答:

memberSlot

必要な応答は、アクティブにするメンバーを示す単一の数字0,1,2だけです。これは戦うことができるメンバーでなければなりません。1メンバー1が死亡した場合は返送しないでください。

バトルアクション

毎ターン、あなたは何をすべきかを決定する必要があります。

クエリ:

A#battleState

battleState前述したように、ここで正確です。

応答:

移動を使用するには、移動先のスロットを送り返します。たとえば、スロット0にパンチを割り当てた場合、送信0はパンチを実行します。

別のメンバーに切り替えるには、メンバーのスロットと10を送信します。したがって、メンバー2に切り替えるには、を送信します12

[0,1,2,10,11,12]にないものはすべて無効と見なされ、このターンにアクションは行われません。

ボーナス統計

2戦ごとに、チームメンバーごとに秘密のボーナスポイントを受け取ります。

クエリ:

B#yourTeamState

あなたのチームの状態は上に示したものと同じです。繰り返しさせてはいけません。

応答:

stat0:stat1:stat2

回答は、各チームメンバーの統計情報を増やします。攻撃は0、防御は1、速度は2です。

したがって、メンバー1の速度、メンバー2の攻撃、およびメンバー3の防御を高めるには、次のように応答します。

2:0:1

コントローラ

コントローラーはBitBucketで見つけることができます:https://Geobits@bitbucket.org/Geobits/codemon.git

コンパイル済みのクラスファイル、サブミッション、players.confをすべてフォルダーに入れて実行します。

コントローラのメインクラスはと呼ばれTournamentます。使用法は次のとおりです。

java Tournament [LOG_LEVEL]

0〜4のログレベルは、情報を増やします。レベル0はトーナメントを静かに実行し、結果を提供します。レベル3はターンごとの解説を提供します。レベル4はデバッグ出力です。

players.confプログラムを実行するために必要なコマンドライン文字列を1行に1つずつ追加するだけで、トーナメントに提出物を追加できます。で始まる行#はコメントです。

投稿に、myに追加する必要があるコマンドと、必要players.confなコンパイル手順を含めます。

含まれているのは、3つの通常の動きを持つすべての通常のメンバーで構成されるダミーチームです。彼らはランダムに動きを選択し、ひどい統計を持っています。楽しんでください。

その他のルール

  • 外部リソースを読み書きすることはできません(上記のように、独自のサブフォルダー、最大32 kBを除く)。

  • あなたのチームはトーナメント「ブラインド」に入る必要があります。つまり、特定の状況で特定のチーム/モンスターが何をするかを把握するために、他の人のソースを分析することはできません。対戦相手の動き/統計を分析し、トーナメントの進行を追跡できますが、この情報をハードコーディングすることはできません。

  • 他のプロセス/提出を妨げないでください。それらを呼び出したり、データを取得するためにリフレクションを使用したりしないでください。私のコンピューターを混乱させないでください。試さないでください。これは私の判断です。違反者は、今後のエントリーが禁止される場合があります。

  • 出場者は最大2つのエントリに制限されています。さらに提出する場合は、提出された最初の2つだけを採点します。取り消す場合は、削除します。

  • エントリは、他のエントリをサポートするためだけに存在することはできません。また、他の競技者を間接的に失格させないでください(たとえば、これをディスクに書き込もうとするDQプレイヤーに27Mのキャラクターチーム名を使用するなど)。各提出物は、独自のメリットで勝つためにプレーする必要があります。

  • プログラムは、一度に最大1つの子プロセスを生成できます(直接ではなく、子孫の合計)。メインプロセスとすべての子プロセスは、出力後すぐに終了する必要があります。どちらにしても、タイムアウトを超えないようにしてください。

  • トーナメントは、Intel i7 3770Kプロセッサーを搭載したUbuntuを実行しているコンピューターで開催されます。

結果

これらは現在のプレーヤーの結果です。それはです非常にトップ候補との間に密接な、と私は500までのラウンド数バンピング(およびボーナスポイントの間隔が一致するように調整)を考えています。異議、コメントはありますか?

------- Final Results -------

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

Googleドライブでの完全な実況結果


62
私は最高になりたい/コードがなかったように/クラッシュしないことが私のテスト/デバッグすることが私の原因です!/私はLANを移動します/スクリプティングは広範囲に渡ります/理解するために一生懸命に努力します/ BIOSが揚げたのはなぜですか!/コデモン、それはあなたと私です/すべての目に見えるゴルフ/コデモン、あなたは私の親友/プログラム終了後!/コデモン、本当の言語/セグメンテーション違反はありません/あなたは私を教えて、私はあなたを教えます/コデモン、すべてのゴルフを学ぼう!
カズウルフ

1
ラウンドを500に増やす代わりに、1つのラウンドが全員と戦う全員で構成されていると便利です。したがってbye、競合他社の数が不均等な場合はこれ以上は行われず、マッチペアが公平かつ均等に分散されることが保証されます。
フーバー

@foobar私はそれがで戦いをスケーリングするのでことを避けたかったn^2の代わりにn。現在の7人の競技者と100ラウンドだけで、それは2100戦です(300対現状、500ラウンドで1500)。エントリー数が増えると悪化するだけです。ラウンド数を減らすことはできますが、固有の変動性(ステータスに関しては特に)を減らすことをheし、50の倍数(ボーナスポイントの場合)を持つ方が簡単です。
ジオビット

このチャレンジにはアップデートは必要ありませんか?:)
GholGoth21

@ GholGoth21はい、そうだと思います。たぶん今日は行けないかもしれませんが、明日か翌日かもしれません。必要に応じて、木曜日までに更新されない場合はチャットでPingしてください。
ジオビット

回答:


16

ハッピー3キャンピングカー-PHP

野党を衰弱させる呪文で皮を剥いて、腐敗を見るのを好むlike病者の束。

編集:ミスター・ランピーは厳しく懲らしめられ、悪い言葉はもう言わない


ハンディハンディGrass - atk:50 def:99 spd:81 Confuse Poison Heal

問題のある握手で人々を混乱させるのを好む有毒な腕のないビーバー


フリッピーフリッピーWater - atk:50 def:99 spd:81 Confuse Burn Heal

退屈な話や火炎戦争にふさわしい掲示板ベテラン。


ナッツナッツFire - atk:50 def:99 spd:81 Burn Poison Heal

大量破壊兵器は彼のお気に入りのキャンディーです。


ゴツゴツゴツゴツPhp - lines:500 clarity:05 spd:01 Gather Guess Store

ほぼ2桁のIQと驚異的なメモリのおかげで、Lumpyは敵の動きを推測できます。まあ、ほとんど。


戦略

戦略は、できるだけ早く敵を中毒、火傷、混乱させることです。
スリープは、上記の3呪文ほど強力ではないように思われたため、使用されませんでした。
混乱は長期的には致命的です。攻撃を30%軽減し(ダメージ処理とスペルキャスティングの両方)、ヒーラーが自分自身を癒すのを防ぎ、ヘビーヒッターをひどく傷つけます(50 def / 100 atkモンスターはそれ自身に20ポイントのダメージを与えます)。

敵が完全に貼り付けられると、私のキャンピングカーは、彼が焼けるように焼け、腐って、死ぬまでパンチするのを見ているだけです。

高い防御力と回復力は、苦痛の際に受けるダメージを軽減するために使用されます。

私の3人のキャンピングカーが戦っている間、魔法の鹿であるLumpyはあらゆる動きで敵を監視し、時々それらを特定することができます。情報は戦闘機にフィードバックされ、戦闘機はそれを利用するために最善を尽くします。

防御後、スピードはブーストするための最も重要な統計です。
イニシアチブは、次の打撃が来る前にヒーリングを適用するために重要です。

攻撃はまったく使用されません。

呪文は究極の武器ですか?

毒、火傷、混乱のような呪文は、他の攻撃の全体的なロック/ペーパー/ハサミのロジックを回避します。

モンスターが影響を受けると、スペルキャスターが死亡した後でもHPを失います。まるでキャスターの幽霊が彼を攻撃し続けているようです。
その上、毒は完全に強化された大規模な攻撃(5ターン後に50ポイント以上)よりもすぐに強力になります。

毒で焼けたモンスターの平均寿命は、3回の回復でも8ターンを超えません。

マーティンのボットが示しているように見える、ゲームバランスはかなり良いです。
基本的には、純粋なスペルキャスターと純粋な攻撃者のバランスを崩すイニシアチブです。

コード

で呼び出す php campers.php

それは見苦しい混乱ですが、率直に言って、インターフェースも助けにはなりません。

適切に積極的な競争が登場したので、私は長い間計画されていた敵の動きの推測を実装しました。
攻撃の分析には、さまざまな曲技飛行の推論と最後のターン状態の永続的な保存が必要です。これは、偏執的なコントローラーインターフェイスとの全面的な戦争を意味します。
それはきれいなものでも6本足のジャックラビットでもありませんが、十分な仕事をします。

<?php

// ============================================================================
// Game
// ============================================================================
class G {
    static $code_type = array ("Normal", "Psychic", "Fire", "Water", "Grass", "?", "self"); 
    static $code_move = array    ("Punch", "Heal", "Slow", "Pain", "Sleep", "Weaken", "Fireball", "Burn", "Sharpen", "Watergun", "Confuse", "Shield", "Vine", "Poison", "Sap", "?", "self", "pass");
    static $move_uses = array (1000,3,5,1000,3,5,1000,3,5,1000,3,5,1000,3,5,   2000,2000);
    static $move_type      = array (0,0,0,1,1,1,2,2,2,3,3,3,4,4,4, 5,5,5);
    static $move_dmg       = array (20,0,10,20,0,10,20,0,10,20,0,10,20,0,10,  20,10,0);
    static $move_forbidden = array (1,1,1,0,0,0,4,4,4,2,2,2,3,3,3);
    static $code_effect = array ("N", "Poison", "Confuse", "Burn", "Sleep", "H", "Sharpen", "Weaken", "Shield", "Sap", "Slow"); 
    static $decode_type, $decode_move, $decode_effect;
    static $damage_multiplier = array (
        array (2, 0, 1, 1, 1, 0),
        array (0, 2, 1, 1, 1, 0),
        array (1, 1,.5, 2,.5, 0),
        array (1, 1,.5,.5, 2, 0),
        array (1, 1, 2,.5,.5, 0),
        array (2, 2, 2, 2, 2,-1),
        array (9, 9, 9, 9, 9, 9, 1));
    static $atk_score = array ("Poison"=> 1002, "Confuse"=>1001, "Burn"=>1000);
    static $status_field = "atk:def:spd:hp:type:Pturns";
    static $all_moves, $strong_moves, $medium_moves, $effect_moves, $possible_moves;

    function init()
    {
        self::$status_field = explode (":", self::$status_field);
        foreach (array ("type", "move", "effect") as $table) self::${"decode_$table"} = array_flip (self::${"code_$table"});
        foreach (self::$code_move as $c=>$m)
        {
            if ($m == "?") break;
            self::$all_moves[] = new Move($m);
            if (self::$move_uses[$c] >  5) self::$strong_moves[] = $m;
            if (self::$move_uses[$c] == 5) self::$medium_moves[] = $m;
            if (self::$move_uses[$c] == 3) self::$effect_moves[] = $m;
            for ($type = 0 ; $type != 5 ; $type++) if ((self::$move_uses[$c] >  5) && (self::$move_forbidden[$c] != $type)) self::$possible_moves[$type][] = $m;
        }
    }

    function __construct ($name, $team)
    {
        $this->turn = 0;
        $this->name = $name;
        $this->team = $team;
        $this->results_pending = false;
    }

    function parse_team ($tpack, $own_team)
    {
        $pack = explode ("|", $tpack);
        list ($name,$active) = explode (":", array_shift($pack));
        if ($own_team)
        {
            $team = $this->team;
        }
        else
        {
            if (!isset($this->enemies[$name])) $this->enemies[$name] = new Team(array (new Monster (), new Monster (), new Monster ()));
            $team = $this->foes = $this->enemies[$name];
        }
        $team->active = $active;
        foreach ($pack as $i=>$mpack) $team->monster[$i]->parse_monster ($own_team, $mpack);
    }

    function choose_active ()
    {
        // detect start of round
        $team = $this->team;
        $foes = $this->foes;
        foreach ($team->monster as $i=>$m) if ($m->hp > 0) $candidate[$i] = $m;
        if (count ($candidate) == 3)
        {
            $this->results_pending = false;
            $this->round++;

            // reinitialize all monsters
            foreach (array($team, $foes) as $t)
            foreach ($t->monster as $m)
                $m->start_round();

            // guess initial opponent
            $opponent = $foes->initial_opponent();
        }
        else
        {
            $this->analyze_last_round();
            $opponent = $foes->active();
        }
        return $this->do_switch ($opponent);
    }

    function choose_attacker ($foe)
    {
        foreach ($this->team->monster as $i=>$m) if ($m->can_attack($foe)) $candidate[$i] = $m;
        if (isset($candidate))
        {
            uasort ($candidate, function ($a,$b) use ($foe) { return ($a->atk_score != $b->atk_score) ? $b->atk_score - $a->atk_score : $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            return key($candidate);
        }
        return -1;
    }

    function do_switch ($foe)
    {
        $replacement = $this->choose_attacker ($foe);
        if ($replacement < 0)
        {
            $candidate =  $this->team->monster;
            uasort ($candidate, function ($a,$b) use ($foe) { return $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            $replacement = key($candidate);
        }

        $this->old_own = $this->team->monster[$replacement];
        $this->old_own->attack = "pass";
        return $replacement;
    }

    function choose_action ()
    {
        $this->analyze_last_round();
        $own = $this->team->active();
        $foe = $this->foes->active();
        $this->old_own = $own;

        if ($own->hp <= $own->max_damage($foe) && $own->can_do ("Heal")) return $own->execute("Heal");
        if ($attack = $own->can_attack($foe)) return $own->execute($attack);
        if ($own->hp <= 50 && $own->can_do ("Heal")) return $own->execute("Heal");

        return 10 + $this->do_switch ($foe);    
    }

    function choose_bonus()
    {
        foreach ($this->team->monster as $m)
        {
            if ($m->spd_b == 0) { $m->spd_b++; $res[] = 2; }
            else                { $m->def_b++; $res[] = 1; }
        }
        return implode (":", $res);
    }

    function parse ($parts)
    {
        self::parse_team ($parts[1], true);
        self::parse_team ($parts[2], false);    
    }

    function analyze_last_round()
    {
        if ($this->results_pending)
        {
            $this->results_pending = false;

            $foes = $this->foes;
            $foe = null;
            foreach ($foes->monster as $m) if ($m->hp != $m->old->hp) $foe = $m;
            if ($foe === null) $foe = $foes->monster[$foes->active];

            $this->old_own->guess_attack($foe);
        }
    }

    function process ($line)
    {
        $parts = explode ("#", $line);
        switch ($parts[0])
        {
        case "T": // register for tournament
            echo "$this->name|$this->team";
            break;
        case "C": // designate active monster
            $this->parse ($parts);
            echo $this->choose_active();
            break;
        case "A": // choose round action
            $this->parse ($parts);
            echo $this->choose_action();

            // save current state
            foreach (array($this->team, $this->foes) as $t)
            foreach ($t->monster as $m)
            {
                unset ($m->old);
                $m->old = clone ($m);
            }
            $this->results_pending = true;
            break;
        case "B": // distribute stat bonus
            echo $this->choose_bonus();
            break;
        }

    }
}
G::init();

// ============================================================================
// Move
// ============================================================================
class Move {
    function __construct ($move)
    {
        $this->register($move);
    }

    function register ($move)
    {
        $this->type = G::$decode_move[$move];
        $this->reinit();
    }

    function reinit()
    {
        $this->uses = G::$move_uses[$this->type];
    }

    function __tostring() { return G::$code_move[$this->type]."($this->uses)"; }
}

// ============================================================================
// Monster
// ============================================================================
class Monster { 
    function __construct ($name="?", $type="?", $atk=100, $def=100, $spd=100, $m0="?", $m1="?", $m2="?")
    {
        $this->name = $name;
        $this->type = G::$decode_type[$type];
        $this->atk  = $atk;
        $this->def  = $def;
        $this->spd  = $spd;
        $this->hp   = 100;
        $this->move = array (new Move($m0), new Move($m1), new Move($m2));
        $this->atk_b = 0;
        $this->def_b = 0;
        $this->spd_b = 0;
        foreach (G::$code_effect as $e) $this->$e = 0;
    }

    function __tostring ()
    {
        return implode (":", array (
            $this->name,
            $this->type,
            $this->atk,
            $this->def,
            $this->spd,
            $this->move[0]->type,
            $this->move[1]->type,
            $this->move[2]->type));
    }

    function start_round()
    {
        foreach ($this->move as $m) $m->reinit();
    }

    function parse_monster ($own_team, $spack)
    {
        $pack = explode (":", $spack);
        $name = array_shift ($pack); // get name
        array_shift ($pack); // skip id
        if ($this->name == "?") $this->name = $name; // get paranoid
        else if ($this->name != $name) die ("expected $this->name, got $name");

        // store updated values
        foreach (G::$status_field as $var) $this->$var = array_shift ($pack);
        if ($own_team)
        {
            foreach ($this->move as $m) $m->new_count = array_shift($pack);
            $pack = array_slice ($pack, 3); // these are maintained internally
        }
        $var = array();
        foreach ($pack as $e) @$var[G::$code_effect[$e]]++; 
        foreach (G::$code_effect as $e) $this->$e = @$var[$e]+0;
    }

    function damage_recieved ($attack, $foe=null)
    {
        if ($attack == "self") $foe = $this;
        $a = G::$decode_move[$attack];
        $type = G::$move_type[$a];
        $dmg = g::$move_dmg[$a];

        if ($dmg == 0) return 0;

        $atk = ($foe ->atk+$foe ->atk_b) * pow (.8, ($foe ->Weaken - $foe ->Sharpen));
        $def = ($this->def+$this->def_b) * pow (.8, ($this->Sap    - $this->Shield ));

        $boost = ($foe->type == $type) ? 1.2 : 1;
        return max (floor ($dmg * $atk / $def * $boost * G::$damage_multiplier[$this->type][$type]), 1);
    }

    function guess_attack_from_effect ($attacks)
    {
        foreach ($attacks as $status) if ($this->$status != $this->old->$status) return $status;
        return "?";
    }

    function guess_attack_from_damage ($foe, $damages)
    {
        $select = array();
        foreach (G::$possible_moves[$foe->type] as $attack)
        {
            $dmg = $this->damage_recieved ($attack, $foe);
            foreach ($damages as $damage) if ($damage != 0 && abs ($dmg/$damage-1) < 0.1) $select[$attack] = 1;
        }
        $res = array();
        foreach ($select as $a=>$x) $res[] = $a;
        return $res;
    }

    function guess_attack ($foe)
    {
        $attempt = G::$decode_move[$this->old->attack];
        $success = ($this->old->attack == "pass");
        foreach ($this->move as $m)
        {
            if ($m->type == $attempt)
            {
                if ($m->new_count == $m->uses-1)
                {
                    $m->uses--;
                    $success = true;
                }
                break;
            }
        }

        $possible = array();
        $attack = $this->guess_attack_from_effect (array("Burn", "Confuse", "Poison", "Sleep", "Slow", "Weaken", "Sap"));
        if ($attack == "?") $attack = $foe->guess_attack_from_effect (array("Sharpen", "Shield"));
        if ($attack == "?")
        {
            $foe_damage = $this->old->hp - $this->hp - (10 * $this->Burn + 5 * $this->Pturns*$this->Poison);
            if ($this->old->attack == "Heal" && $success) $foe_damage += 50;
            $possible_dmg[] = $foe_damage;
            //;!;if ($this->Confuse) $possible_dmg[] = $foe_damage + $this->damage_recieved ("self");
            $possible = $this->guess_attack_from_damage ($foe, $possible_dmg);
            if (count ($possible) == 1) $attack = $possible[0];
        }
        if ($attack == "?")
        {
            $own_damage = $foe->old->hp - $foe->hp 
                        - (10 * $foe->Burn + 5 * $foe->Pturns*$foe->Poison)
                        + $foe->damage_recieved ($this->attack);
            if (abs ($own_damage/50+1) < 0.1) $attack = "Heal";
        }
        if ($attack != "?")
        {
            $type = G::$decode_move[$attack];
            if ($attack != "?")
            {
                foreach ($foe->move as $m) if ($m->type == $type) goto found_old;
                foreach ($foe->move as $m) if ($m->type == 15) { $m->register($attack); goto found_new; }
            }
            found_new:
            found_old:
        }
    }

    function max_damage($foe)
    {
        $dmg = 0;
        foreach ($foe->move as $m) $dmg = max ($dmg, $this->damage_recieved (G::$code_move[$m->type], $foe));
        return $dmg;
    }

    function expected_damage ($foe)
    {
        return $this->max_damage($foe) + 10 * $this->Burn + 5 * ($this->Pturns+1);
    }

    function life_expectancy ($foe)
    {
        $hp = $this->hp;
        $poison = $this->Pturns;
        $heal = $this->can_do ("Heal");
        $dmg = $this->max_damage($foe);
        for ($turn = 0 ; $hp > 0 && $turn < 10; $turn++)
        {
            $hp -= 10 * $this->Burn + 5 * $poison;
            if ($poison > 0) $poison++;
            $hp -= $dmg;
            if ($hp <= 0 && $heal > 0) { $hp+=50; $heal--; }
        }
        return 100 * $turn + $this->hp;
    }

    function can_attack ($foe)
    {
        $attack = false;
        if ($this->hp > 0)
        {
            if      (!$foe->Poison  && $this->can_do ("Poison" )) $attack = "Poison";
            else if (!$foe->Confuse && $this->can_do ("Confuse")) $attack = "Confuse";
            else if (!$foe->Burn    && $this->can_do ("Burn"   )) $attack = "Burn";
        }
        $this->atk_score = ($attack === false) ? 0 : G::$atk_score[$attack];
        return $attack;
    }

    function can_do($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $m) if ($m->type == $type && $m->uses > 0) return $m->uses;
        return false;
    }

    function execute($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $i=>$m) if ($m->type == $type) 
        { 
            if ($m->uses > 0)
            {
//;!;               $m->uses--;
                $this->attack = $move;
            }
            else $this->attack = "pass";
            return $i; 
        }
        die ("$this asked to perform $move, available ".implode(",", $this->move));
    }
}

// ============================================================================
// Team
// ============================================================================
class Team {
    function __construct ($members)
    {
        $this->monster = $members;
    }

    function __tostring()
    {
        return implode ("|", $this->monster);
    }

    function active ()
    {
        return $this->monster[$this->active];
    }

    function initial_opponent()
    {
        return $this->monster[0];
    }
}

// ============================================================================
// main
// ============================================================================
$input = $argv[1];

$team_name = "H3C";
$mem_file = "$team_name/memory.txt";
$trc_file = "$team_name/trace.txt";
if (!file_exists($team_name)) mkdir($team_name, 0777, true) or die ("could not create storage directory '$team_name'");
if ($input == "T") array_map('unlink', glob("$team_name/*.txt"));

if (file_exists($mem_file)) $game = unserialize (file_get_contents ($mem_file));
else
{
    $team = new Team (
        array (
            new Monster ("Handy" , "Grass" , 50, 99, 81, "Confuse", "Poison", "Heal"),
            new Monster ("Nutty" , "Fire"  , 50, 99, 81, "Burn"   , "Poison", "Heal"),
            new Monster ("Flippy", "Water" , 50, 99, 81, "Confuse" , "Burn" , "Heal")));
    $game = new G($team_name,$team);
}

$game->process ($input);
file_put_contents ($mem_file, serialize($game));

結果

LittleKidはまだ威men的ですが、私のトリオは彼の有毒なフリークをかなりのマージンで打ち負かしました。

マーティンのボットは、イニシアチブの欠如によって運命づけられており、速度を上げるには攻撃を下げる必要があり、ダメージ処理能力の優位性が鈍くなります。

プラネットJavaScriptの新しい候補はチームと1対1で対等ですが、他の競合他社と比べて劣っています。彼らは実際にリトルキッドのスコアを下げるのに役立ちます:)。

それで、私のかわいい友人は丘の王のままであるようです-今のところ...

170             H3C
158             Nodemon
145             LittleKid
55              InsideYourHead
42              HardenedTrio
30              BitterRivals

また、私のPHPもありません。メタポッドはゆっくりとした戦略をたどり、毒殺されてしまうので、メタポッドで床を拭くことを期待しています。
Sp3000

... *そして*鮮明に焼き付けられます:D。それは複雑なルールの問題です。支配的な戦略が出現する可能性が非常に高いです。これらの呪文に対する保護はないので、それらはコデモンの太った男と小さな男の子かもしれません。

ハサミ、紙、岩のような非推移的なゲームと比較します。エフェクトには時間がかかるため、完全な攻撃チームがあなたを倒すことができるはずです:)
Sp3000

2
はい、これはPoison and Burnの改善策が見当たらないとすぐに想像したものです。私の夢を実現してくれてありがとう。
ちょうど半分

1
それは、同じ敵から3つ以上の異なる攻撃を検出したときに、彼の困惑を表現するランピー氏です。修正バージョンはほぼ完成していますが、現在他の作業を行っているため、修正は1日ほどで投稿されます。

7

HardenedTrio、Python 3

Geobitsは2つのサブミッションを提供するのに十分でしたので、最初のサブミッションについてはばかげたものをサブミットすると思いました。

パーティは、同じ統計と動きを持つ3つのCodemon(Metapod1、Metapod2、Metapod3)です。

  • 80の攻撃、100の防御、50の速度
  • パンチ、ヒール、シールド強化

すべてのボーナスポイントは防御にも割り当てられます。


from collections import namedtuple
import sys

BattleState = namedtuple("BattleState", ["us", "them"])
TeamState = namedtuple("TeamState", ["name", "active", "members"])
MemberState = namedtuple("MemberState", ["name", "id", "attack", "defense", "speed", "hp",
                                         "typeid", "poisonedturns", "otherstats"])

def parse_battle_state(state):
    return BattleState(*map(parse_team_state, state.split("#")))

def parse_team_state(state):
    na, *members = state.split("|")
    name, active = na.split(":")
    return TeamState(name, int(active), list(map(parse_member_state, members)))

def parse_member_state(state):
    name, id_, attack, defense, speed, hp, typeid, poisonedturns, *rest = state.split(":")
    return MemberState(name, int(id_), float(attack), float(defense), float(speed),
                       float(hp), int(typeid), int(poisonedturns), rest)

command = sys.argv[1].strip()

if command.startswith("T"):
    print("HardenedTrio|Metapod1:0:80:100:50:0:1:11|"
          "Metapod2:0:80:100:50:0:1:11|Metapod3:0:80:100:50:0:1:11")

elif command.startswith("C"):
    battle_state = parse_battle_state(command[2:])

    for i, codemon in enumerate(battle_state.us.members):
        if codemon.hp > 0:
            print(i)
            break

elif command.startswith("A"):
    battle_state = parse_battle_state(command[2:])
    current_codemon = battle_state.us.members[battle_state.us.active]

    if current_codemon.hp < 50 and int(current_codemon.otherstats[1]) > 0:
        print(1) # Heal up if low

    elif int(current_codemon.otherstats[2]) > 0:
        print(2) # Harden!

    else:
        print(0) # Punch!

elif command.startswith("B"):
    print("1:1:1")

で実行

py -3 <filename>

(またはインストールに応じてpython/のpython3代わりにpy




私はあなたのコードを読もうとしていますが、で混乱しましたint(current_codemon.otherstats[1])>0。彼にステータス効果がある場合、trueを返しますか?そして、彼は2つのステータス効果がある場合にのみhardenを使用しますか?
Mooingダック

@MooingDuckあなたのCodemonにはmoveCountsの前にeffectidsがあるので、Hardenをまだ使用できるかどうかをチェックしています。解析が面倒になったので、そこにまとめられています。
Sp3000

@ Sp3000:ああ!右!ははは!
Mooingダック

6

あなたの頭の中、ルビー

  • ブライアン:サイキック、攻撃:100、防御:50、速度:80、痛み、火の玉、ウォーターガン
  • Elemon1:サイキック、アタック:100、ディフェンス:50、スピード:80、ファイアボール、ウォーターガン、バイン
  • Elemon2:サイキック、攻撃:100、防御:50、速度:80、ファイアボール、ウォーターガン、バイン
TEAM_SPEC = "InsideYourHead"+
            "|Brian:1:100:50:80:3:6:9"+
            "|Elemon1:1:100:50:80:6:9:12"+
            "|Elemon2:1:100:50:80:6:9:12"

def parse_battle_state request
    request.map do |team_state|
        state = {}
        parts = team_state.split '|'
        state[:active] = parts.shift.split(':')[1].to_i
        state[:monsters] = parts.map do |monster_state|
            monster = {}
            parts = monster_state.split(':')
            monster[:name] = parts[0]
            monster[:hp] = parts[5].to_i
            monster[:type] = parts[6].to_i
            monster
        end
        state
    end
end

request = ARGV[0].split '#'
case request.shift
when 'T'
    puts TEAM_SPEC
when 'C'
    battle_state = parse_battle_state request
    my_state = battle_state[0]
    puts my_state[:monsters].find_index {|monster| monster[:hp] > 0}
when 'A'
    battle_state = parse_battle_state request
    my_state, their_state = *battle_state
    my_monster = my_state[:monsters][my_state[:active]]
    their_monster = their_state[:monsters][their_state[:active]]
    puts [1,0,1,2,0][their_monster[:type]]
when 'B'
    puts '0:0:0'
end

で実行

ruby InsideYourHead.rb

これはManuのボットに対してはあまり効果的ではありませんが、他の3つのボットよりも優れています。チームとモンスターの名前はかなりランダムです...もっと良いものを思いついたら変更するかもしれません

戦略は非常に単純です:攻撃!3匹のモンスターはすべて純粋な攻撃移動のみを持ち、相手のモンスターのタイプに基づいて移動を選択します。

後でヒールを投げて実験するかもしれません。


1
これはもっと面白くなります。マーティン:)

6

LittleKid、Java

小さな子供が3つの同一のコデモンを見つけて訓練しました。彼らはヒール+ポイズン攻撃で非常に迷惑です。毒はすべてのタイプに対してうまく機能するため、通常タイプのコデモンのみを使用すると、特定の敵に対してペアリングする必要がなくなります。

public class LittleKid {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("Geobits says you can't do this.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "LittleKid";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                break;
            case "B":
                out = "1:1:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];
                int pick = 0;

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = String.valueOf(pick);
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int enemyActive = getActive(them);
                if (getField(me, HP, active) < 50 && getField(me, MOVE1, active) != 0) {
                    out = "1";
                } else if (getEffectCount(them, POISON, enemyActive, false) < 1 && getField(me, MOVE2, active) != 0) {
                    out = "2";
                } else {
                    out = "0";
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6;
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10;

    final static int POISON =           1;
}

5
Geobitsはこれができないと言っている」:D
Geobits

毒はこのゲームの本当の原爆のようです:)

5

Nodémon-Javascript

ステータスが支配的な戦略であるように見えるため、このチームはスピードに焦点を当てて、最初に相手に毒や混乱などのステータスを取得し、その後、相手が無駄になっている間に回復や睡眠で失速します。

私はPHPをインストールしていないので、これはキャンパーに対してテストされていませんが、私の試用版ではLittleKidのまともな競争相手であるようです(そして、Bitter Rivalsを減らします)。

/*jshint node:true*/
'use strict';

var fs = require('fs');

var dataFile = 'Nodemon/data.json';
function getData(callback) {
  fs.readFile(dataFile, 'utf8', function(err, contents) {
    var data = {round: 0};

    if(!err) {
      data = JSON.parse(contents);
    }

    callback(data);
  });
}

function saveData(data, callback) {
  fs.mkdir('Nodemon', function() {    
    fs.writeFile(dataFile, JSON.stringify(data), callback);
  });
}

var effect = {
  poison: '1',
  confusion: '2',
  burn: '3',
  sleep: '4',
  heal: '5',
  attackUp: '6',
  attackDown: '7',
  defenseUp: '8',
  defenseDown: '9',
  speedDown: '10'
};

function parseMemberCommon(args) {
  return {
    name: args[0],
    id: args[1],
    baseAttack: +args[2],
    baseDefense: +args[3],
    baseSpeed: +args[4],
    hp: +args[5],
    typeId: args[6],
    poisonedTurns: +args[7],
    effects: args.slice(8)
  };
}

function parseOwnMember(arg) {
  var args = arg.split(':');

  var ownArgs = args.splice(8, 6);

  var member = parseMemberCommon(args);

  member.moveCount = [
    +ownArgs[0],
    +ownArgs[1],
    +ownArgs[2]
  ];

  member.bonusAttack = +ownArgs[3];
  member.bonusDefense = +ownArgs[3];
  member.bonusSpeed = +ownArgs[3];

  return member;
}

function parseOpponentMember(arg) {
  return parseMemberCommon(arg.split(':'));
}

function parseTeamStateCommon(arg, memberParse) {
  var args = arg.split(':');
  var state = {
    name: args[0],
    members: []
  };
  args = arg.substring(state.name.length + 1).split('|');
  var activeSlot = args[0];
  for(var index = 1; index < args.length; index++) {
    state.members.push(memberParse(args[index]));
  }
  state.activeMember = state.members[activeSlot];
  return state;
}

function parseOwnState(arg) {
  return parseTeamStateCommon(arg, parseOwnMember);
}

function parseOpponentState(arg) {
  return parseTeamStateCommon(arg, parseOpponentMember);
}

function parseBattleState(arg) {
  var args = arg.split('#');
  return {
    own: parseOwnState(args[0]),
    opponent: parseOpponentState(args[1])
  };
}

function teamData() {

  saveData({round:0}, function() {
    console.log('Nodemon|' + 
      'Charasaur:0:50:80:100:10:13:1|' +
      'Bulbtortle:4:50:80:100:10:13:1|' +
      'Squirtmander:1:50:80:100:10:13:4');
  });
}

function getActiveIndex(battleState) {
  for(var index = 0; index < battleState.own.members.length; index++) {
    var member = battleState.own.members[index];
    if(member.hp > 0) {
      return index;
    }
  }
}

function chooseActive(arg) {
  var battleState = parseBattleState(arg);

  getData(function(data) {
    var allFull = true;
    for(var index = 0; index < battleState.opponent.members.length; index++) {
      var member = battleState.opponent.members[index];
      if(!data.maxSpeed || member.baseSpeed > data.maxSpeed) {
        data.maxSpeed = member.baseSpeed;
      }
      if(member.hp < 100) {
        allFull = false;
      }
    }

    if(allFull) {
      data.round++;
    }

    saveData(data, function() {
      console.log(getActiveIndex(battleState));
    });    
  });
}

function useMove(moves, battleState) {
  var fighter = battleState.own.activeMember;

  for(var moveIndex = 0; moveIndex < moves.length; moveIndex++) {
    var move = moves[moveIndex];
    if(fighter.moveCount[move]) {
      return move;
    }

    for(var memberIndex = 0; memberIndex < battleState.own.members.length; memberIndex++) {
      var member = battleState.own.members[memberIndex];

      if(member.hp > 0 && member.moveCount[move] > 0) {
        return 10 + memberIndex;
      }
    }
  }

  return -1;  //do nothing
}

function battleAction(arg) {
  var battleState = parseBattleState(arg);

  var fighter = battleState.own.activeMember;
  var opponent = battleState.opponent.activeMember;

  var attemptedMoves = [];

  if(opponent.effects.indexOf(effect.poison) === -1) {
    attemptedMoves.push(1);
  }

  if(opponent.effects.indexOf(effect.confusion) === -1) {
    attemptedMoves.push(0);
  }

  if(fighter.name === 'Squirtmander') {
    //sleep
    if(opponent.effects.indexOf(effect.sleep) === -1) {
      attemptedMoves.push(2);
    }
  }
  else {
    //heal
    if(fighter.hp <= 60) {
      attemptedMoves.push(2);
    }
  }

  console.log(useMove(attemptedMoves, battleState));
}

function bonusStats(arg) {
  var teamState = parseOwnState(arg);

  getData(function(data) {
    var result = '1:';

    if(data.round % 4 === 0) {
      result += '1:';
    }
    else {
      result += '2:';
    }
    if(teamState.members[2].baseSpeed + teamState.members[2].bonusSpeed > data.maxSpeed + (data.round / 2)) {
      result += '1';
    }
    else {
      result += '2';
    }
    console.log(result);
  });
}

var actions = {
  'T': teamData,
  'C': chooseActive,
  'A': battleAction,
  'B': bonusStats
};

var arg = process.argv[2];
actions[arg[0]](arg.substring(2));

で実行

node nodemon

PS nodemonにおApび申し上げます。


これは、サーバー側スクリプトのグローバル戦争にエスカレートしています:D

4

苦いライバル-Java

切り替えるのが好きな草/火/水チーム。

緑竜

少なくとも誰に対しても中立的なカバレッジを持っています。防御の欠如を補うための高速。

Type: Grass
Attack:   80     Vine
Defense:  50     Punch
Speed:   100     Pain

ゼリザード

攻撃力の低い敵をSapしようとします。その後の火傷と火の玉。

Type: Fire
Attack:  100     Fireball
Defense:  50     Burn
Speed:    80     Sap

ブラストシールド

シールドを使用して、すでに高い防御力を強化します。必要に応じて回復します。

Type: Water
Attack:   80     Watergun
Defense: 100     Shield
Speed:    50     Heal

コード

これもコントローラーに含まれています。これ、DummyTeamとは異なり、競合するチームです。必要なコマンドplayers.confは次のとおりです。

java BitterRivals

public class BitterRivals {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You're not doing this right. Read the spec and try again.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "BitterRivals";
                out += "|Greenosaur:4:80:50:100:12:0:3";
                out += "|Searizard:2:100:50:80:6:7:14";
                out += "|Blastshield:3:80:100:50:9:11:1";
                break;
            case "B":
                out = "2:0:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];

                int pick = 0;
                switch(getField(them, TYPE, getActive(them))){
                    case 0:
                    case 1:
                    case 3:
                        pick = 0;
                        break;
                    case 2:
                        pick = 2;
                        break;
                    case 4:
                        pick = 1;
                        break;
                }

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = pick + "";
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int oType = getField(them, TYPE, getActive(them));
                switch(active){
                    case 0:         // Greenosaur
                        switch(oType){
                            case 0:
                            case 4:
                                out = "1";
                                break;
                            case 1:
                                out = "2";
                                break;
                            case 3:
                                out = "0";
                                break;
                            case 2:
                                if(isAlive(me, 2)){
                                    out = "12";
                                } else if(isAlive(me, 1)){
                                    out = "11";
                                } else {
                                    out = "1";
                                }
                                break;
                        }
                        break;
                    case 1:         // Searizard
                        if(oType == 3){
                            if(isAlive(me, 0)){
                                out = "10";
                                break;
                            } else if(isAlive(me, 2)){
                                out = "12";
                                break;
                            }
                            if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                out = "1";
                            } else if(getField(me, MOVE2, active) > 0){
                                out = "2";
                            } else {
                                out = "3";
                            }                           
                        } else {
                            if(getField(them, ATTACK, getActive(them)) < 80){
                                if(getEffectCount(them, DEFENSE_DOWN, getActive(them), false) < 1 && getField(me, MOVE2, active) > 0){
                                    out = "2";
                                    break;
                                } else if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                    out = "1";
                                    break;
                                }
                            }
                            out = "0";
                        }
                        break;
                    case 2:         // Blastshield
                        if(oType == 4){
                            if(isAlive(me, 1)){
                                out = "11";
                                break;
                            } else if(isAlive(me, 0)){
                                out = "10";
                                break;
                            }
                        }
                        if(getField(me, HP, active) < 50 && getField(me, MOVE2, active) > 0){
                            out = "2";
                        } else if(getEffectCount(me, DEFENSE_UP, active, true) < 3 && getField(me, MOVE1, active) > 0){
                            out = "1";
                        } else {
                            out = "0";
                        }
                        break;
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6; 
    final static int PTURNS =   7; 
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10; 
    final static int HA =       11; 
    final static int HD =       12; 
    final static int HS =       13; 

    final static int POISON =           1;
    final static int CONFUSION =        2;
    final static int BURN =             3;
    final static int SLEEP =            4;
    final static int ATTACK_UP =        6;
    final static int ATTACK_DOWN =      7;
    final static int DEFENSE_UP =       8;
    final static int DEFENSE_DOWN =     9;
    final static int SPEED_DOWN =       10;
}

4

エラー310:リダイレクトが多すぎる-C ++

毒の被害に対処するために高度に訓練され組織されたチーム

3週間、私はコデモンをほとんど訓練しませんでした。私はいくつかのチームを結成しました。そして最後に、私はこの挑戦に直面する準備ができています。私のすべてのポイズナーの敵に答えるために、私は非常に異なるコデモでチームを作りました。それぞれが特定の役割を持ちます。


解毒剤(画像)

Type : Normal - atk:50 def:100 spd:80 - Poison/Burn/Heal

解毒剤は毒が大好きです。彼が毒攻撃に突進するのを止めることはできません。


(画像)

Type : Fire - atk:100 def:80 spd:50 - Poison/Vine/Heal

禅は、すべての効果に対応する非常に驚くべきコデモンです。彼は敵が沈黙に対して努力し尽くすのを好む。


トライフォース(画像)

Type : Psychic - atk:88 def:60 spd:82 - Fireball/Watergun/Vine

トライフォースは常に戦う準備ができている古典的なコデモンです。これは彼の精神力を使って3つの要素を制御し、可能な限り多くの損害を与えます。


こちらからチームをダウンロードできます。

Linux:

http://dl.free.fr/iHYlmTOQ2

で起動 ./Error310TMR

Windows

http://dl.free.fr/vCyjtqo2s

で起動 ./Error310TMR.exe

コードは完全なc ++プロジェクトです。公開方法がわかりません。

$ wc -l src/*
    165 src/BruteForce.cpp
     26 src/BruteForce.h
    349 src/Codemon.cpp
     77 src/Codemon.h
     21 src/Logger.cpp
     35 src/Logger.h
    105 src/NoTimeToExplain.cpp
     27 src/NoTimeToExplain.h
    240 src/Recoverator.cpp
     31 src/Recoverator.h
     26 src/StrManip.cpp
     16 src/StrManip.h
    303 src/Team.cpp
     68 src/Team.h
     88 src/TooManyRedirects.cpp
     24 src/TooManyRedirects.h
     87 src/Unrecoverable.cpp
     27 src/Unrecoverable.h
     59 src/enums.cpp
    119 src/enums.h
     68 src/main.cpp
   1961 total

しかし、それは非常に効果的です。

------- Final Results -------

176     Error310TMR
131     H3C
130     LittleKid
121     Nodemon
58      InsideYourHead
47      HardenedTrio
37      BitterRivals

2

おとぎ話

かなり一般的な中道チーム。自分のことをしようとする3つのアーキタイプに基づいており、自分のことをまったくできない場合は切り替えます。

このチームは、poisonが新しいメタであると思われる前に作成されました。最初にチームを作成して以来、チームの変更に追いついていませんでした。私はまだトーナメントを実行してテストすることができませんでしたが、かなり忙しい週でした。これが実際に私のテストデータのように機能しない場合は、作業後にそれをさらに適用します。

#!/bin/perl
use 5.20.0;
use strict;

use constant MINE => 0;
use constant THEIRS => 1;

$_ = $ARGV[0];

if(/^T/){
    say 'FairyTale|Fairy:1:89:90:51:3:4:13|Dragon:2:100:50:80:6:1:8|Assassin:0:70:60:100:0:1:10';

} elsif(/^C#(.*)/){
    my $state = readBattleState($1);
    if($state->[MINE]->{$state->[MINE]->{slot}}{hp}){
        say $state->[MINE]->{slot};
    } elsif($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp}){
        say (($state->[MINE]->{slot}+1)%3);
    } else {
        say (($state->[MINE]->{slot}+2)%3);
    }

} elsif(/^A#(.*)/){
    my $state = readBattleState($1);
    my @actives = (
        $state->[MINE]->{$state->[MINE]->{slot}},
        $state->[THEIRS]->{$state->[THEIRS]->{slot}}
    );
    if($state->[MINE]->{slot} == 0){
        if(!exists($actives[THEIRS]{effects}{4}) && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif(!exists($actives[THEIRS]{effects}{1}) && $actives[MINE]{pp}->[2]) {
            say 2;
        } elsif(!$actives[THEIRS]{type}) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 1){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 2){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif($actives[THEIRS]{type} == 1) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    }

} elsif(/^B#(.*)/){
    my $state = readTeam($1, 1);
    say '1:0:2';
}

sub readBattleState {
    local $_ = $_[0];
    if(/^(.*?)#(.*?)$/){
        my @teams;
        $teams[0] = readTeam($1, 1);
        $teams[1] = readTeam($2, 0);
        return \@teams;
    }
}

sub readTeam {
    my $isMine = $_[1];
    local $_ = $_[0];
    if(/.*?:(?<slot>.*?)\|(.*?)\|(.*?)\|(.*?)$/){
        my %team;
        $team{slot} = $1;
        $team{0} = $isMine ? readYourMember($2) : readTheirMember($2);
        $team{1} = $isMine ? readYourMember($3) : readTheirMember($3);
        $team{2} = $isMine ? readYourMember($4) : readTheirMember($4);
        return \%team;
    }
    return 0;
}

sub readYourMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?):(?<move0>.*?):(?<move1>.*?):(?<move2>.*?):(?<batk>.*?):(?<bdef>.*?):(?<bspd>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk}+$+{batk},
            def    => $+{def}+$+{bdef},
            spd    => $+{spd}+$+{bspd},
            type   => $+{type},
            pp     => [$+{move0}, $+{move1}, $+{move2}],
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
}

sub readTheirMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk},
            def    => $+{def},
            spd    => $+{spd},
            type   => $+{type},
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
    return 0;
}

sub readEffects {
    local $_ = $_[0];
    my @retval = /:([^:]*)/g;
    if(!@retval){
        @retval = (0);
    }
    return @retval;
}

で実行

perl fairytale.pl

このボットは、最初の死後に「アクティブな」死んだメンバーを選択しようとして追い出されます。私が見ることができる最初の戦いを決して通過しません。
ジオビット

本当に?以前にバグが解決したと思っていたのですが、これはそのコードの古いバージョンかもしれません
...-mezzoEmrys

コードモンがノックアウトされると、彼のヘルスポイントが0 以下に減少することを忘れないでください。そのため、if($state->[MINE]->{$state->[MINE]->{slot}}{hp})ステートメントはなしでは正しく機能しません>0
-GholGoth21

ああ、そう、それでいい。
mezzoEmrys

0

ダミーチーム-Java

(非競合CW)

これは、練習するダミーのチームです。それはすべて通常のタイプで、各ターンで動き(パンチ、ヒール、スロー)をランダムに選択します。それを楽しんでください。

public class DummyTeam {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You need to run this from the tournament. Try to keep up.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String out = "";
        switch(sections[0]){
            // team data
            //      sends back all Normal types with minimum stats and Normal moves (randomized name suffixes to distinguish in tests)
            case "T":
                out = "DummyTeam";
                for(int i=0;i<3;i++)
                    out += "|Dummy"+((char)(Math.random()*26)+65) + i + ":0:50:50:50:0:1:2";
                break;
            // bonus points
            //      shoves them all in defense every time
            case "B":
                out = "1:1:1";
                break;
            // choose active
            //      picks last active if alive, otherwise loops to find first living member
            case "C":
                String[] team = sections[1].split("\\|");
                int current = Integer.parseInt(team[0].split(":")[1]);
                if(Integer.parseInt(team[current+1].split(":")[5]) > 0){
                    out = current + "";
                } else {
                    for(int i=1;i<team.length;i++){
                        if(Integer.parseInt(team[i].split(":")[5]) > 0){
                            out = (i - 1) + "";
                        }
                    }
                }               
                break;
            // choose action
            //      chooses a random move. does not check if it ran out of uses, so wastes turns quite often
            case "A":
                out = ((int)(Math.random()*3)) + "";
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }


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