ゴールドバトルKoTH


43

この挑戦は終わりました。競合他社の最終スコアを見るには、ここをクリックしてください

この課題では、各サブミッションは1つのボットです。各ボットはJavaScript関数でなければなりません。ボットは、金で最高の合計価値を獲得するために戦います。金は養殖するか、他のボットを殺すことで獲得することができ、治癒、攻撃、シールド、および養殖のアップグレードに使用されます。

目的:

最大1000ターン(ボットが1つだけ残った時点で終了)を含む多くのラウンドで、合計の価値が最も高いボット(取得したすべての金の合計)が勝者です。

ターン:

各ターンで、生きているすべてのボット(> 0 HP)が1回実行されます。次のいずれかの動きを返すことができます。

  • 回復:HPを回復する
  • 攻撃:別のボットからHPを削除します
  • シールド:後の攻撃から守ります
  • スタン:別のボットの次のターンをスキップします
  • 農場:HPのコストでゴールドを獲得
  • アップグレード:特定の動きを改善する

すべてのボットは、実行される前に移動を戻すため、スタン、ヒール、攻撃、シールドなどは、そのターンの後半に移動するボットには影響しません。たとえば、ボットAがボットBをスタンし、ボットBがターン順でボットAの後にある場合、ボットBは同じターンの後半に移動し、スタンは次のターンに発生します。

戦闘、農業、およびアップグレード:

各ボットの最大HPは100で、割り当てられたUIDは0〜99です。このUIDはラウンドごとに変化し、ボットがお互いを追跡する方法です。

ヒーリングは最も単純な動きの1つであり、レベルによって決まるHPの量を追加します(5 HPから開始)。ボットは100 HPを超えて回復することはできません。

UIDでボットを攻撃することもできます。レベル0で5 HPの基本ダメージがあります。ボットは、UIDを使用する次のターンをスキップしてスタンすることもできます。

ボットには追加のシールドHPがあり、制限はありません。このシールドHPは、他のボットからの直接攻撃によるダメージを吸収し、シールドによって追加されます。レベル0では、シールドは5シールドHPを追加します。

ファーミングでは、レベル0で5 HPのコストで5ゴールドを獲得します。この2 HPはシールドできません。ゴールドの唯一の用途は(勝ちを超えて)移動をアップグレードすることです。回復、攻撃、およびシールドの基本値は5 HPであり、農業は5ゴールドから始まります。これらの動きのそれぞれには、0から始まる個別のレベルがあります。これらの式は、HPまたは動きのゴールドの値を決定します(Lはレベルです)。

  • 癒し: L + 5
  • 攻撃: 1.25L + 5
  • シールド: 1.5L + 5
  • 農業: 2L + 5

移動のアップグレードのコストは特定のレベルで同じであり、によって決定され2.5L² + 2.5L + 10ます。ここで、Lは現在のレベルです。ボットは、cost(currentLevel)これを決定するショートカットとして関数を使用できます。

ボットは25ゴールドから始まり、2移動をレベル1に、または1移動をレベル2にすばやくアップグレードできます。この開始ゴールドは、ボットの合計価値にはカウントされません。ボットを殺すと、その合計価値の半分が金になり、切り上げられます。2つのボットが同じターンに別のボットを殺すと、両方が報酬を受け取ります。

入出力:

コントローラと通信するために、関数の戻り値を使用して移動情報を送信します。次のいずれかが返されます。

  • 癒し: heal()
  • 攻撃: attack(uid)
  • シールド: shield()
  • スタン: stun(uid)
  • ファーム: farm()
  • アップグレード: upgrade("heal" / "attack" / "shield" / "farm")

ターンをスキップする(何もしない)、何も返さない、または偽の値を返す。

現在のターン番号(1から始まる)を取得するには、を使用しますturn()

関数の引数には、ボット、他のボットのUID、およびターン間ストレージに関する情報が含まれます。最初の引数は、次のプロパティを持つオブジェクトです:uidhpgold、とshield。これらは、ボットの現在の情報のコピーです。ネストされたオブジェクトがあるlevelsのレベル番号と、healattackshield、とfarm

2番目の引数は、自分以外のすべての生きているボットのシャッフルされた配列であり、プロパティuidhp(およびシールド)、、worthおよびattack(攻撃レベル)を含むオブジェクトとしてフォーマットされます。3番目の引数は、ターン間ストレージに使用できる空のオブジェクトです。

ボットの例:

このボットは、攻撃をレベル5にアップグレードできるようになるまでファーム化し、ターンごとにランダムボットを攻撃(または勝利)するまで攻撃します。ヒーリング/シールドがないため、あまり効果的ではありません。

function freeTestBotA(me, others, storage) {
    if (me.levels.attack < 5) {
        if (me.gold < cost(me.levels.attack))
            return farm();
        return upgrade("attack");
    }
    return attack(others[0].uid);
}

このボットには、攻撃モードと防御モードの2つのモードがあります。防御モードではランダムボットを気絶させるか回復し、攻撃モードでは攻撃またはシールドします。可能な限り攻撃をアップグレードしようとします。

function freeTestBotB(me, others, storage) {
    if (me.gold >= cost(me.levels.attack))
        return upgrade("attack");
    if (me.hp < 50)
        if (Math.random() < 0.5)
            return stun(others[0].uid);
        else
            return heal();
    else
        if (Math.random() < 0.5)
            return attack(others[0].uid);
        else
            return shield();
}

ルール:

  • 禁止されている標準的な抜け穴
  • ボットは、スコープ外の変数を読み取ったり、変更したり、追加したり、チートを試みたり、コントローラー定義またはDOM関数を呼​​び出したりすることはできません。
  • 戻り値は偽であるか、上記の関数出力のいずれかでなければなりません
  • ボットは特定のボットをターゲットとするように設計するべきではありませんが、一般的な戦略を活用するように設計することができます
  • ボットは自分自身を攻撃することはできません(@Nessのコメントにより発見)
  • ボットは、他のボットとは十分に異なっていなければならず、合理的に個別のエントリと見なすことができます
  • チーム化は現在許可されていません
  • コントローラーはここにあります
  • チャットルーム

新しいコントローラーのデバッグ:

ファイルを使用して、ボットgold-battle-log.jsdebugプロパティの値botDataを0(ロギングなし)、1(ログの移動)、または2(ログの移動、hp、ゴールド、レベルなど)に設定できます。

チャレンジは8月9日金曜日の1700 UTCに終了します


4
すべてのボットで要旨を作成しました。gist.github.com/Draco18s/2efbf95edcf98d6b1f264e26bbb669d1私はそれを更新し続けるよう努力します(しかし、そうでない場合はまともなスタートです)。
Draco18s

4
ボットを含む自動更新コントローラー:redwolfprograms.com/koth
プログラム

4
すでに事実上の新しい回答が閉じられているため、この質問を終了することに投票しています(「この課題は終了しました。最終スコアを見るには...」)
pppery

3
@ppperyできませんか?競争力のない答えは大丈夫です。[closed]最後に、カジュアルな視聴者は私の挑戦を読むことをスキップする可能性があります。
Redwolfプログラム

5
@pppery今日までに終了するための課題が解決されたことを聞いたことはありません。また、実施したい社会的制限は存在しないと主張します。閉じる必要はありませんし、閉じたくありません。私にとっては、サイトの利益のためではなく、閉鎖のために閉鎖しているように思えます。誰かが古い質問への回答を投稿したい場合、彼らはできるはずです。深刻な競争相手のルールの後に、それが投稿されたときに深刻な競争相手にならなければならないという注記はありません。答えは、たとえそれが勝つための競争相手でなくても、挑戦に対する重大な競争相手になる可能性がある
Redwolfプログラム

回答:


16

殺せない

Undyableから分岐しました

function UnkillableBot(me){
    if(me.hp <= 100 - (me.levels.heal + 5)){
        return heal()
    }else if(turn() % 10 == 0 && me.shield < 800) {
        return shield()
    }else{
        if(me.gold >= cost(me.levels.shield) && me.levels.shield <= 9){
            return upgrade("shield")
        }else if(me.gold >= cost(me.levels.farm)){
            return upgrade("farm")
        }else{
            if(me.shield < 500 && me.levels.shield > 4) {
                return shield()
            }
            return farm()
        }
    }
}

指数関数的なアップグレードのコストを考えると、ヒーリングをアップグレードできない場合、農業をアップグレードすることもできます。これにより、ボットがより効率的に金を収集できるようになります。


私のテストで絶対に競争相手を
打ち負かす

1
このボットは、最初のifステートメントが使用された場合、少し強力になると思います<=-現在、完全に回復することはありません。
スクート

@Scootsどれだけ重要かはわかりませんが、変更します。
Draco18s

2
@ Draco18sそれはごくわずかな問題だと確信していますが、このサイトは、実際には取るに足らない小さな改善に関するものではありませんか?:)
スクート

@Scoots最大の健康状態への回復は、実際の攻撃の脅威がないため、この課題ではあまり重要ではありません。真に不快なボットはbullybotのみであり、彼については何もできません。実際に完全な状態を維持すると、パフォーマンスが低下する場合があります。
B0RDERS

13

タノスボット

function ThanosBot(me, others, storage){
    if(turn()==1){
        storage.origPopulation = others.length;
        return upgrade("attack");
    }

    if (others.length < storage.origPopulation / 2)
    {
        if(me.hp <= 100 - (me.levels.heal + 5)){
            return heal();
        }
        else {
            return farm();
        }
    }

    if(me.hp <= 100 - (me.levels.heal + 5)){
        return heal()
    }else{
        if(me.gold >= cost(me.levels.attack)){
            return upgrade("attack")
        }else if(me.gold >= cost(me.levels.heal)){
            return upgrade("heal")
        }else if(me.gold >= cost(me.levels.farm)){
            return upgrade("farm")
        }else{
            if(Math.random() < 0.5){
                return attack(others[0].uid);
            }
            else{
                return farm();
            }
        }
    }
}

ボットが多すぎて、十分なゴールドがありません。このボットは解決策を提案します。

虐殺、はい、しかしランダムで、冷静で、公平から金持ち、貧乏人まで。

彼らは彼を狂人と呼んだ。

ThanosBotは、ボットコミュニティに最適なものを求めており、すべての方法で進んでいきます。最初は、攻撃、農業、治癒をアップグレードして、リソースをより効率的に収集し、戦いに勝ちます。今後の戦闘のために、リソースを集めながら、彼はランダムに人々を攻撃し始めます。彼は軍隊、武器、そして自分自身を改善し続けます。

人口の50%が除去されると、生まれたボットは満腹と晴天のみを知り、農業の生活に引退し、感謝の宇宙で太陽が昇るのを見ます。彼は完全に平和主義者になり、野菜スープと農業で自分自身を癒します。


6
私は、「スナップ」し「攻撃」をリネームする誘惑だ
Redwolfプログラム

11

スティーラーを殺す

function killStealer({hp, gold, attack:atck, shield:shld, levels:{heal:lHeal, shield:lShld, farm:lFarm, attack:lAtck}}, es, S) {
  let saneReduce = (a, f, n) => a.length? a.reduce(f) : n;
  let t = turn();
  if (t===1) {
    S.worth = 0;
    S.pHP = 100;
    S.pGold = 0;
    S.stat = {};
    S.pT = 0;
    for (let e of es) S.stat[e.uid] = {kills:0, seen:0};
  }

  let pT = S.pT;
  S.pT = t;

  let shp = shld+hp;

  let healP = lHeal      + 5;
  let shldP = lShld*1.5  + 5;
  let farmP = lFarm*2    + 5;
  let atckP = lAtck*1.25 + 5;
  let pheal = () => hp<5  ||  Math.min(100, hp+healP)-hp > shldP? heal() : shield();

  let attacked = S.pHP-hp-shld > 2;
  S.pHP = hp+shld;

  if (gold>S.pGold  &&  t!=1) S.worth+= gold-S.pGold;
  S.pGold = gold;

  let pes = S.pEs;
  let ces = {};
  for (let e of es) ces[e.uid] = {uid:e.uid, hp:e.hp, worth:e.worth};
  S.pEs = ces;

  if (t === 1) return shield(); // to not break things depending on previous frame

  if (t == pT+1) {
    for (let uidE in pes) {
      let e = pes[uidE];
      if (!ces[uidE]) { // dead
        if (e.worth < 30) continue; // don't bother, because others probably won't
        for (let a of es) {
          let pa = pes[a.uid];
          if (a.worth >= pa.worth + e.worth/2 - 2) {
            S.stat[a.uid].kills++;
          }
          if (a.worth != pa.worth || a.hp > pa.hp) S.stat[a.uid].seen++;
        }
      }
    }
  }


  let attackers = es.filter(c => {
    let k = S.stat[c.uid].kills;
    let s = S.stat[c.uid].seen;
    return k > 1  &&  k > s*.7;
  });
  let maxDmg = es.map(c=>c.attack).reduce((a, b) => Math.max(a, b), 0)*1.25 + 5;
  for (let e of es) {
    if (e.worth < farmP) continue;
    let p = pes[e.uid];
    let dmg = p.hp-e.hp;
    if (e.hp <= atckP) {
      return attack(e.uid);
    }
    if (e.hp-dmg-atckP <= 0) {
      return attack(e.uid);
    }
    if (e.hp-maxDmg-atckP <= 0) {
      return attack(e.uid);
    }
    if (e.hp-maxDmg-dmg <= 0) {
      return attack(e.uid);
    }
  }
  if (attackers.length>0 && t>50) {
    for (let e of es) {
      if (e.hp - maxDmg*2 - atckP <= 0  &&  e.worth > 200) {
        let worst = saneReduce(attackers.filter(c => c.hp > 80), (a, b)=>a.worth>b.worth? a : b, null);
        if (worst) return stun(worst.uid);
      }
    }
  }



  if (t < 60  &&  t%5 == 1) return shield();
  if (t === 2) return upgrade("heal");
  if (t === 3) return upgrade("farm");
  if (t%10 == 1) return shield();

  if (gold>=cost(lShld) && lFarm>-2) return upgrade("shield");
  if (gold>=cost(lFarm) && !attacked) return upgrade("farm");

  if (es.length > 2) {
    let notDead = es.filter(c => c.hp > 20);
    if (notDead.length !== 0) {
      notDead.sort((a, b) => a.hp-b.hp);
      if (notDead[Math.min(2, notDead.length-1)].hp > shp) {
        return pheal();
      }
    }
  }


  if (gold>=cost(lHeal)  &&  lHeal+5 < lFarm) return upgrade("heal");
  if (gold>=cost(lAtck)  &&  lAtck+5 < lFarm  &&  es.every(c=>c.attack<=lAtck+2)) return upgrade("attack");

  if (lShld>5  &&  shp < 205+healP+t  &&  shp < 600+t*5) return pheal();
  if (es.every(c => c.worth < S.worth+farmP) && es.length>2 && t<100 && lShld<6) return pheal();
  if (shp<=120  ||  hp<5) return pheal();
  return farm();
}

キルを盗むだけでなく、キルを盗むこともできます!

このボットは、農場以外にはほとんど何もしません。可能性に気づくと、死にかけている敵に最後の一撃を加えることに参加し、どうにかして非常に優れています。


殺害の一撃に関与するすべてのボットが完全な報酬を得るため、それは機能します。
Draco18s

@ Draco18sなぜそれが良いのか理解していますが、次の最高のボットのスコアを平均して2倍にするという単純なアイデアは期待していませんでした(作成時)。
dzaima

へへ、それは公平だ。可能な場合はすべてのボットをダウンロードし、別のソリューションが見つかるかどうかを確認する必要があります。
Draco18s

9

イコライザー

このボットは、ボットコミュニティの平和を取り戻そうとしています。彼は、ボットのヒーリングが自分の攻撃よりも優れている場合にのみ、最高の攻撃でボットを容赦なくターゲットにします。攻撃よりもひどい治癒をしたボットがいなくなると、彼は平和な農業の生活に引退します。

function equalizer(me, others, storage){
  if(storage.agroKilled == null)storage.agroKilled = false;
  if(!storage.agroKilled){
    if(storage.blacklist == null)storage.blacklist = [];
    if(storage.lastAttack == null)storage.lastAttack = -1;
    var maxAtk = 0;
    var maxAtkUid = -1;
    var maxAtkHealth = 0;
    for(var i = 0; i < others.length; i++)if(others[i].uid == storage.lastAttack){
      maxAtk = others[i].attack*1.25+5;
      maxAtkUid = storage.lastAttack;
      maxAtkHealth = others[i].hp;
    }
    for(var i = 0; i < others.length; i++){
      if(storage.lastAttack == others[i].uid && others[i].hp >= storage.lastHealth){
        maxAtk = 0;
        maxAtkUid = -1;
        maxAtkHealth = 0;
        storage.blacklist.push(others[i].uid);
      }
    }
    storage.lastAttack = -1;
    var willHeal;
    for(var i = 0; i < others.length; i++)if(others[i].attack*1.25+5 > maxAtk){
      willHeal = false
      for(var j = 0; j < storage.blacklist.length; j++)if(others[i].uid==storage.blacklist[j])willHeal = true;
      if(!willHeal){
        maxAtk = others[i].attack*1.25+5;
        maxAtkUid = others[i].uid;
        maxAtkHealth = others[i].hp;
      }
    }
    if(me.hp < maxAtk) return heal();
    if(me.hp <= 100 - me.levels.heal - 5) return heal();
    var target = -1;
    var targetWorth = me.levels.farm * 2 + 5;
    for(var i = 0; i < others.length; i++) {
      if (others[i].hp <= maxAtk && others[i].worth / 2 > targetWorth) {
        target= others[i].uid;
          targetWorth = others[i].worth / 2;
      }
    }
    if(target!=-1) return attack(target);
    if(me.gold >= cost(me.levels.attack)) return upgrade("attack");
    if(me.levels.heal + 7 < me.levels.attack && me.levels.heal < 9 && me.gold >= cost(me.levels.heal)) return upgrade("heal");
    if(maxAtkUid!=-1){
      storage.lastAttack = maxAtkUid;
      storage.lastHealth = maxAtkHealth;
      return attack(maxAtkUid);
    }
    storage.agroKilled = true;
  }
  if(me.hp < 30) return heal();
  if(me.gold > cost(me.levels.farm)) return upgrade("farm");
  return farm();
}

8

楽観主義者

function Optimist(me, others, storage) {
    if (me.hp < 10)
        return heal();
    if ( (me.hp + me.shield) < 50 )
        return shield();
    if (me.gold >= cost(me.levels.farm) && cost(me.levels.farm) < 0.8 * (1000 - turn()))
        return upgrade("farm");
    rich_bots = others.sort( (x,y) => y.worth - x.worth );
    potential_victim = rich_bots.find( bot => bot.hp <= me.levels.attack * 1.25 + 5 );
    if (potential_victim)
        return attack(potential_victim.uid);
    if (me.gold < rich_bots[0].worth + cost(me.levels.farm) + 25)
        return farm();
    if (me.levels.heal < me.levels.farm)
        return upgrade("heal");
    if (me.levels.shield < me.levels.heal)
        return upgrade("shield");
    if (me.levels.attack < me.levels.shield)
        return upgrade("attack");
    return shield();
}

その時間の80%を平和的に農業に費やすことができると想定しているため、農業を最大限に活用することから始めてから、戦闘スキルに注意を払い始めます。間違いなく何も悪いことはありません!


8

キルアシスト

function KillAssist(me, others, storage) {
  let t = turn();
  if (t===1) {
    storage.worth = 0;
    storage.pHP = 100;
    storage.pGold = 0;
  }
  let hp = me.hp;
  let gold = me.gold;
  let shld = me.shield;
  let lHeal = me.levels.heal+0.25;
  let lFarm = me.levels.farm;
  let lShld = me.levels.shield;
  let lAtck = me.levels.attack;
  let healPower = lHeal      + 4.75;
  let shldPower = lShld*1.5  + 5;
  let farmPower = lFarm*2    + 5;
  let atckPower = lAtck*1.25 + 5;

  let dmgTaken = storage.pHP-(hp+shld);
  let attacked = dmgTaken > 2;
  storage.pHP = (hp+shld);

  if (gold > storage.pGold) storage.worth+= gold-storage.pGold;
  if (gold-storage.pGold > farmPower+5)  storage.lastAtck = -10;
  storage.pGold = gold;
  let pOthers = storage.pOthers;
  storage.pOthers = {};
  for (let o of others) {
    storage.pOthers[o.uid] = {hp: o.hp, uid: o.uid, worth: o.worth};
  } 

  if (t === 1 || t === 2) return upgrade("shield");
  if (t === 3) return shield();

  let maxdmg = others.map(c=>c.attack).reduce((a, b) => Math.max(a, b))*1.25 + 5;
  let lowhp = others.map(c=>c.hp).reduce((a, b) => Math.min(a, b));
  let lowhpid = others.find(c=>c.hp == lowhp).uid;
  let maxAttacker = others.find(o => o.attack*1.25 + 5 == maxdmg).uid;
  for (let o of others) {
    if (o.hp < atckPower  &&  o.worth > farmPower) {
      storage.dead = o.uid;
      storage.deadWorth = o.worth;
      return attack(o.uid);
    }
    let pO = pOthers[o.uid];
    let dmg = pO.hp - o.hp;
    if (o.hp - dmg - atckPower <= atckPower && o.worth >= farmPower) {
      storage.dead = o.uid;
      storage.deadWorth = o.worth;
      return attack(o.uid);
    }
    if (o.hp - maxdmg - atckPower <= atckPower && o.worth >= farmPower) {
      storage.deadWorth = o.worth;
      return attack(o.uid); 
    }
  }
  let lowhpdiff = Math.max(pOthers[lowhpid].hp - others.find(o => o.uid == lowhpid).hp,0);
  if (others.some(o => o.hp > maxdmg && o.hp < lowhpdiff*2+atckPower+maxdmg && o.worth > farmPower)) {
    let bad = others.reduce((a, b) => a.worth>b.worth? a : b);
    let bad2 = others.reduce((a, b) => bad.uid == b.uid ? a : (bad.uid == a.uid ? b : (a.worth>b.worth ? a : b)));
    if(bad.worth < bad2.worth*3 && bad.hp >= (maxdmg+atckPower)*2 && bad.uid != maxAttacker && bad.uid != lowhpid) {
      return stun(bad.uid);
    }
    if(bad2.hp >= (maxdmg+atckPower)*2 && bad2.uid != maxAttacker && bad.uid != lowhpid) {
      return stun(bad2.uid);
    }
  }

  if (t%10 == 9  &&  lShld>4) return shield(); // slowly build up shield just in case
  if (shld+hp < 100) return shldPower>healPower || hp >= 100-healPower? shield() : heal();

  var bon = shldPower-maxdmg < 3 && t < 700 ? lShld/2 : 0;
  var bon2 = t/100;
  if (gold>=cost(lFarm) && lShld+2 > lFarm && bon == 0 && !attacked) return upgrade("farm"); // farm first, but make sure it doesn't get too far ahead
  if (gold>=cost(lShld) && t>20 && (lShld<10+bon || lShld+5+bon2 < lFarm+bon) && t < 900) return upgrade("shield");
  if (gold>=cost(lFarm)) return upgrade("farm"); // try upgrading farming again, because shield upgrading can be picky
  if (gold>=cost(lHeal) && (lHeal<3)) return upgrade("heal"); // healing isn't that important

  if (shld<200 && attacked || shld<500 && t>20 && others.filter(c=>c.hp>=100).every(o=>o.hp+10 > hp+shld)) return shldPower>healPower || hp >= 100-healPower? shield() : heal();

  let hpdelta = attacked ? dmgTaken+shldPower : maxdmg
  if (shld<lShld*60 && (1000-t)*(hpdelta) > shld+hp) return shield(); // we want to look impressive & terrifying
  if (hp<=100-healPower) return heal();

  return farm();
}

Plinkダメージを与えても完全なクレジットを得ることができるのに、なぜ攻撃値をアップグレードするのですか?

もう一度キル・スティーラーをおんぶすることに戻る。ステートメントが常に真であり、元のコードを大幅に上回る結果となったいくつかの数字をいじるコードのいくつかのブロックを単純化することができました。

キルが発生する前のターンでアシストに関与する可能性が高い裕福な相手を気絶させるのは非常に賢いことだと気付いたので、@ dzaimaにそれを渡さなければなりません。(非常に)数回のいずれかStun()は、プラスの合計結果になります。Kill Stealerが同様のロジックを実行することを知っているため、Kill Assistは「次善の」ターゲット(ある程度の裁量で)を探し、代わりにそれらをスタンします。

死ぬほどボットを気絶させないようにし、ボットを作る可能性が最も高いボットを気絶させることを防ぐためのマイナーアップデート。

サンプル結果(1000ゲーム後にトップ5を切り捨て)

VM2406:1629 Kill Assist: 39495.679
VM2406:1629 The Accountant: 29990.267
VM2406:1629 Kill Stealer: 23530.153
VM2406:1629 Unkillable: 12722.604
VM2406:1629 captFarmer: 12232.466

待って、キャプテン・ファーマーはどのような世界で14kゴールドを取得しますか?
Redwolfプログラム

これ:runGame(1) results: [...] captFarmer: 13768
Draco18s

それはかなり予想外に高いです...私のテストでは通常10k前後になります
Redwolfプログラム

* shrugh *わからない。すべてがクリーンであることを保証するために、自動化された要旨の更新を行います。
Draco18s

締め切りの終わりまでに私のお気に入りのボット。
ナイト2

7

Undyableボット(v3)

function undyableBot(me, others, storage){    

    if(me.hp < 100 - (me.levels.heal + 5)*2){
        return heal()
    }else{
        if(me.levels.heal < 10 && cost(me.levels.heal) / 2 < cost(me.levels.farm)){
            if(me.gold >= cost(me.levels.heal)){
                return upgrade("heal")
            }else{
                return farm()
            }
        }else{
            if(me.gold >= cost(me.levels.farm)){
                return upgrade("farm")
            }else{
                return farm()
            }
        }        
    }   
}


私を気にしないでください ...私はこれを借りるつもりです。
Draco18s

6

PatientStrategistBot

必要に応じてフレーミングと防御を開始し、ゲームの後半で他の価値の高いボットの殺害に切り替えるボットを作成しようとしました。

現在、これはゲームの開始時に殺人ボットのギャングによって殺されるか、攻撃モードでどこかで立ち往生するため、適切に機能していないようです。

これが私の最初のJSコードであることにまだかなり満足しているので...(私はここからコードスニペットを盗みました。これはすべてのJS基本構文をグーグルするよりも高速でした)

function PatientStratgistBot(me, others, storage) {

    //set up some stuff in first turn
    if (turn() == 1) {
    storage.selfWorth = 0;
    storage.attackMode = false;
    storage.expectHP = 100;
    storage.expectShield = 0;
    storage.shieldTarget = 0;
    storage.targetUid = "None";
    storage.attackRounds = 0;
    storage.targetStartHP = 100;

        return upgrade("farm");
    }

    let farmPower = me.levels.farm * 2 + 5;

    //defensive Actions

    var maxAtk = Math.max(...others.map(o => o.attack));

    storage.shieldTarget = Math.ceil(maxAtk * 1.25 / 1.5) + 1;

    if (me.levels.shield < storage.shieldTarget && me.gold >= cost(me.levels.shield) && me.levels.shield < me.levels.farm)
        return upgrade("shield");

    if (turn() >= 7 && me.shield < 10 && me.levels.shield * 1.5 >= me.levels.heal) return shield();

    if (turn() >= 15 && me.shield < 15 && me.levels.shield * 1.5 >= me.levels.heal) return shield();

    if (turn() >= 30 && me.shield < 20 && me.levels.shield * 1.5 >= me.levels.heal) return shield();

    //attack mode
    // check if there any targets worth to go for

    function findTarget(potentialTargets, baseR){
    var targetUID = "None";
    var best = 0;
    for( var i = 0; i < potentialTargets.length; i++) {
        //We upgrade to attack lvl12, so 20 dmg; assume an enemy can heal/shield up to 15 per round
        var killRounds = Math.ceil(potentialTargets[i].hp / 5)
        var gain = potentialTargets[i].worth / ( 2 * ( killRounds + baseR) )
        //console.log(me, turn(), potentialTargets[i], killRounds, baseR, gain, farmPower)
        if (gain > farmPower * ( killRounds + baseR ) && gain > best)
            targetUID = potentialTargets[i].uid;
            storage.targetStartHP =  potentialTargets[i].hp;
    }
    return targetUID;
    }


    if (turn() >= 600) {


    //check if a current target is dead
    const uids = others.map(x=>x.uid);
        if(storage.targetUid != "None" && !uids.includes(storage.targetUid)) {
        storage.targetUid = "None";
        storage.attackMode = false;
        storage.attackRounds = 0;
    }


    // check if we are doing enough damage to current target
    if (storage.targetUid != "None" && storage.attackRounds >= 3) {

        var deltaHP = storage.targetStartHP - others[storage.targetUid].hp

        if (deltaHP / storage.attackRounds < 5) {
            storage.targetUid = "None";
            storage.attackMode = false;
            storage.attackRounds = 0;

        }

    }

    var investCost = 0
    for( var i = me.levels.attack; i < 12; i++) investCost += cost(i);

    if (storage.attackMode == true && me.gold >= investCost && me.levels.attack < 12) return upgrade("attack");

    if (storage.attackMode == false) {
        baseRounds = investCost / farmPower * 1.2; //overestimation with the heal level we should have at this point

        if (findTarget(others, baseRounds) != "None")
            storage.attackMode = true;

        var betterThanMe = others.filter(o => o.worth >= storage.selfWorth);

        if (betterThanMe.length > 0)
            storage.attackMode = true;

        //storage.attackMode = true;


    }

    }

    if (storage.attackMode == true && me.levels.attack == 12) {

    if (storage.targetUid == "None") {

        var target = findTarget(others, 0)
        storage.targetUid = target;
        storage.attackRounds = 0;
        return attack(target);

    }

    return attack(storage.targetUid)

    }



    //otherwise farm

    if (me.hp < 50) {
    storage.expectHP += 5 + me.levels.heal;
        return heal();
    }

    if (me.gold >= cost(me.levels.farm) && storage.attackMode == false)
        return upgrade("farm");

    //upgrade heal, so we can farm more, but increase farm ability faster
    if (me.levels.farm > 5 && me.levels.heal < 10 && me.gold >= 2*cost(me.levels.heal))
        return upgrade("heal");


   //be opportunistic - check if killing someone is more profitable than farming
    killable = others.filter(o => o.hp < me.levels.attack * 1.25 + 5 && o.worth / 2 > farmPower);
    if (killable.length > 0){
    //ideally check for the most worth target here
        return attack(killable[0].uid);
    }

    storage.expectHP -= 2;
    storage.selfWorth += farmPower;
    return farm();

}

6

スイス

function switzerland(self,others,storage){
    let turnsLeft=999-turn()
    let lowestHpBots=others.sort((a,b)=>a.hp-b.hp)
    if(!storage.worth){
        storage.worth=0
        storage.prevGold=25
    }else if(self.gold>storage.prevGold){
        storage.worth+=self.gold-storage.prevGold
    }
    if(others.length===1&&storage.worth>others[0].worth){
        //stun lock the other bot if there are only 2 left and I can win
        return stun(others[0].uid)
    }else if(self.hp<=(95-self.levels.heal)){
        return heal()
    }else if(lowestHpBots[0]&&lowestHpBots[0].hp<20&&lowestHpBots[0].worth/2>2*self.levels.farm+5&&self.hp+self.shield>=110){
        //kill assist
        return attack(lowestHpBots[0].uid)
    } else if(self.shield<=50||self.shield<=5500/others.length&&self.shield<=1200&&turn()>=20||lowestHpBots[1]&&lowestHpBots[1].hp>self.hp+self.shield){
        return shield()
    }else if(self.gold>=cost(self.levels.shield)&&self.levels.shield<=8){
        return upgrade("shield")
    } else if(self.gold>=cost(self.levels.farm)&&(turnsLeft+1)*(2*(self.levels.farm)+5)<turnsLeft*(2*(self.levels.farm+1)+5)){
        return upgrade("farm")
    } else if(self.gold>=cost(self.levels.heal)&&(turnsLeft+1)/(self.levels.heal+5)*(2*self.levels.farm+5)<turnsLeft/(self.levels.heal+6)*(2*self.levels.farm+5)&&self.levels.heal<=2){
        return upgrade("heal")
    }else{
        return farm()
    }
}

名前が示すように、このボットは、中立ゆっくりとその金を構築し、主にニュートラル(今は助けキル死ぬしようとしているボット)とちょうど農場や治癒、(ちょうどスイスのような


6

ファーム、攻撃、シールド、さらには回復するが決して気絶しないボット

(短縮名はTBTFASAEHBNSであり、TBTPTGCBCBAと間違えないでください

function TBTFASAEHBNS(me, others, storage) {
    this.getLevel = function (type) {
        return (typeof me.levels[type] === 'undefined' ? 0 : me.levels[type]);
    };

    this.getPower = function (type, level) {
        if (typeof level === 'undefined') level = this.getLevel(type);
        if (type === 'heal') return level + 5;
        if (type === 'attack') return (level * 1.25) + 5;
        if (type === 'shield') return (level * 1.5) + 5;
        if (type === 'farm') return (level * 2) + 5;
    };

    this.canUpgrade = function (type) {
        return myGold >= cost(this.getLevel(type));
    };

    this.farmOrUpgradeFarm = function () {
        if (this.canUpgrade('farm')) return upgrade('farm');
        if (myHp < 3) return heal();
        return farm();
    };

    let currentTurn = turn(),
        myGold = me.gold,
        myHp = me.hp,
        myShield = me.shield,
        myTotalHp = myHp + myShield,
        myHealPower = this.getPower('heal'),
        myShieldPower = this.getPower('shield'),
        myAttackPower = this.getPower('attack'),
        myFarmPower = this.getPower('farm'),
        topAttackPower = 0,
        attackOptions1 = [],
        attackOptions3 = [],
        attackOptions2 = [],
        finalTurns = 980;

    if (currentTurn === 1) {
        storage.othersInfo = {};
    }

    others.sort((a, b) => b.attack - a.attack);
    for (let i = 0; i < others.length; i++) {
        let other = others[i];

        if (i < 3) topAttackPower += this.getPower('attack', other.attack);

        if (other.worth > myFarmPower) {
            if (other.hp <= myAttackPower) {
                attackOptions1.push(other);
            } else {
                if (typeof storage.othersInfo[other.uid] !== 'undefined') {
                    let otherHpChange = storage.othersInfo[other.uid].hp - other.hp;

                    if (other.hp - otherHpChange <= 0) {
                        attackOptions2.push(other);
                    } else if (other.hp - (otherHpChange * 3) <= 0) {
                        attackOptions3.push(other);
                    }
                }
            }
        }

        storage.othersInfo[other.uid] = {hp: other.hp};
    }

    if (myTotalHp < (topAttackPower * 7) + 5) return shield();
    if (currentTurn <= 10) return this.farmOrUpgradeFarm();

    if (attackOptions1.length > 0) {
        attackOptions1.sort((a, b) => b.worth - a.worth);
        return attack(attackOptions1[0].uid);
    } else if (attackOptions2.length > 0) {
        attackOptions2.sort((a, b) => b.worth - a.worth);
        return attack(attackOptions2[0].uid);
    } else if (attackOptions3.length > 0) {
        attackOptions3.sort((a, b) => b.worth - a.worth);
        return attack(attackOptions3[0].uid);
    }

    if (currentTurn <= 20) return this.farmOrUpgradeFarm();
    if (currentTurn < finalTurns && myShieldPower < topAttackPower / 2 && Math.random() * 15 < 1 && this.canUpgrade('shield')) return upgrade('shield');
    if (currentTurn < finalTurns && this.canUpgrade('farm')) return upgrade('farm');
    if (currentTurn < finalTurns && myHealPower < 10 && this.canUpgrade('heal')) return upgrade('heal');
    if (myHp < 3) return heal();
    return farm();
}

このボットは基本的に:

  • 開始時に農業に蓄積
  • 必要なときに自分自身を守る
  • 殺すことができる場合、または誰かを殺す可能性があると考える場合に攻撃する
  • ここでアップグレードします
  • 残りの時間は農場
  • 決して気絶しない

編集1:問題を修正し、多くのゲームでのテストに基づいてボットのいくつかの小さなものを改善しました。

編集2:シールドのアップグレードの削減。


2
名前がわかるとすぐに、それがあなたのボットであることがわかりました(:
Redwolfプログラム

長い名前については申し訳ありませんが、私はそれに夢中です!
ナイト2

1
多分それは良いボットの兆候だ...私のテストは、それが5位でのショー
Redwolfプログラム

5

SniperBot

このボットは、誰かが実際に定期的に攻撃するボットの追加を開始した場合にのみ有効になります。SmartFarmerは現在最適化されているソリューションです

  1. ワンショットを得ることができれば癒す
  2. 30歳未満の場合は治癒します
  3. ボットを攻撃し、農業よりも多くのお金を稼ぐことができる場合
  4. 余裕があれば農業をアップグレードする
  5. ヘルスが80未満で、余裕がある場合は、ヒーリングをアップグレードします
  6. 農場

ハゲタカは攻撃を必要としません

function sniperBot(me, others){
    if(me.hp < 30) return heal();
    for(var i = 0; i < others.length; i++)if(others[i].attack > me.hp)return heal();
    var target = -1;
    var targetWorth = me.levels.farm * 2 + 5;
    for(var i = 0; i < others.length; i++) {
        if (others[i].hp <= 1.25 * me.levels.attack + 5 && others[i].worth / 2 > targetWorth) {
            target= others[i].uid;
            targetWorth = others[i].worth / 2;
        }
    }
    if(target!=-1) return attack(target);
    if(me.gold >= cost(me.levels.farm)) return upgrade("farm");
    if(me.hp < 50 && me.gold >= cost(me.levels.heal)) return upgrade("heal");
    return farm();
}

int2行目の予期しない識別子()。ReferenceError:正常性が定義されていません。
Draco18s

あるべきme.hp
mbomb007

ごめんなさい。javascriptの新機能。ヘルプをありがとう
B0RDERS

あなたif(me.hp <30 && ...)はそれが重要であるために不条理なレベルのヒールを必要とするために最初の節に単純化されるかもしれません(レベル65)
Veskah

@Veskahそれを指摘してくれてありがとう。それは、最小馬力が高かったときの残骸でした
B0RDERS

5

BullyDozerBot

function BullyDozerBot(me, others, storage){
    if(me.gold >= cost(me.levels.attack) && (storage.bullyTarget && storage.bullyTarget.hp < 500)) {
        return upgrade("attack");
    }
    if(storage.bullyTarget==null){
        storage.bullyTarget=others.sort((a,b) => a.hp - b.hp)[0];
    }
    potential_victim = others.find( bot => bot.hp <= me.levels.attack * 1.25 + 5 );
    if (potential_victim) {
        return attack(potential_victim.uid);
    }
    var targetlives = false;
    for(var i = 0; i < others.length; i++) {
        if (others[i] == storage.bullyTarget) {
            targetlives = true;
            break;
        }
    }
    if(!targetlives){
        storage.bullyTarget=others.sort((a,b) => a.hp - b.hp)[0];
    }
    if(storage.bullyTarget.hp >= 500) {
        if(me.gold >= cost(me.levels.farm)) {
            return upgrade("farm");
        }
        for(var i = 0; i < others.length; i++){
          if(others[i].attack*1.25+10 > me.hp){
            return heal();
          }
        }
        return farm();
    }
    return attack(storage.bullyTarget.uid);
}

BullyBotおよびその他のビットのマッシュアップ。オプティミストには、短くて日和見的な攻撃的なチャンクがありましたが、他のボットも同様の計算を行います。

それらを気絶させることによってターゲットをいじめる代わりに、それは彼らの甘い、甘い戦利品のためにそれらを殺します。また、いじめのために群れの中で最も弱いものをターゲットにしますが、最も弱いターゲットのHPが高すぎる場合、それはあきらめて農業に行きます。


あなたは死ぬまで自分で耕作しています。私の編集を受け入れます:)
B0RDERS

1
@AndrewBordersハ、考えさえしなかった。ありがとう。
Draco18s

これらのプロテクターボットが登場するまで、このボットは素晴らしかったです。
B0RDERS

@ B0RDERSシールドは、時間を浪費しても非常に強力です。
Draco18s

5

FizzBu​​zz

function FizzBuzz(me, others, storage) {
    if (!storage.target) storage.target = others[0].uid;
    const uids = others.map(x=>x.uid);
    if(!uids.includes(storage.target) || (turn() % 30 === 0 
        && others[uids.indexOf(storage.target)].hp>30))
        storage.target = others[0].uid;

    if (cost(me.levels.farm) < me.gold) return upgrade("farm");
    if (turn() % 15 === 0) return heal();
    if (turn() % 3 === 0) return farm();
    if (turn() % 5 === 0) return heal();

    if (cost(me.levels.attack) < me.gold) return upgrade("attack");
    return attack(storage.target);
}

主に攻撃的なボット。本当にFizzBu​​zzができないという事実に非常に腹を立て、代わりに怒ってただBuzzsします。FizzingまたはBuzzingでない場合、30ターンの間、別のボットにチップを投げかけ、進行していない場合は、ターゲットとして別のボットをあきらめて選択します。

非常に一貫性のないパフォーマンス。気にせず、コントローラーを更新しましたが、現在は常にパックの真ん中にいるようです。


私はこのコンセプトが好きです。現在の状況に関係なく、独自のペースで動き続けます。
ネス

5

bullyBot

function bullyBot(me, others, storage){
    if(turn()==1){return farm();}
    if(storage.bullyTarget==null){storage.bullyTarget=others[0].uid;}

    var targetlives = false;
    for(var i = 0; i < others.length; i++) {
        if (others[i].uid == storage.bullyTarget) {
            targetlives = true;
            break;
        }
    }
    if(!targetlives){storage.bullyTarget = others[0].uid;}

    return stun(storage.bullyTarget);
}

オンラインでお試しください!

勝つことはできないかもしれませんが、確かに彼の気の毒なことを試みて、彼のターゲットも同様にしないようにします。bullyBotはまた、最初のターンに農場を作るので、外部からの影響がなければ、ターゲットを5-0で倒すか、5-5で結びます。


5

JustFarm

シンプルに始めようと思った。

function justFarm(me, others){
    return farm();
}

13
このボットは、農業の2HPのコストのために自殺します。
Draco18s

ラウンドは、ボットの数に応じて、その前に終了しても良いが、Draco18s @
Redwolfプログラム

1
一方で、技術的に真のデフォルトの終了時刻が1000のとき、50ラウンドタイマーは非常に非常に短いです
Draco18s

これは2つのボットの例に勝りましたが、さらにいくつかのサブミッションがあり、より良いものを考え出そうとします。
匿名

癒しや農業のアップグレードを含む@Anonymous Maybeで十分でしょう。最も多くの金を獲得することが究極の目標であるため、ボットの主な仕事が機能するようにそれを維持します。これまでのところ、ヒーリングモードやファームモードなどの「モード」を備えたボットはありません。興味深いアプローチかもしれません
Redwolfプログラム

4

ScavengerBot(V2)

以前はあまりスカベンジャーではなかったことに気付きました。新しい戦略は、別のボットを殺すことができるまで待つことです。誰も殺すことができない場合、座ってシールドを構築します。

function scavengerBot(me, others) {
    if (me.shield < (me.levels.shield * 1.5 + 5)) {
        return shield();
    }
    var currentAttack = 1.25 * me.levels.attack + 5;
    var hasVictim = false;
    var victimUid = 0;
    var maxWorth = 0;
    for (var i = 0; i < others.length; i++) {
        var hp = others[i].hp;
        var worth = others[i].worth;
        if (hp <= currentAttack && worth > maxWorth) {
            hasVictim = true;
            victimUid = others[i].uid;
            maxWorth = worth;
        }
    }

    if (hasVictim) {
        return attack(victimUid);
    }

    if (me.gold >= cost(me.levels.attack)) {
        return upgrade("attack");
    }

    if (me.gold >= cost(me.levels.shield)) {
        return upgrade("shield");
    }
    return shield();
}

1
me.levels.attacl
Draco18s

良いキャッチ、修正
reffu

4

ムーディー

function Moody(me, others, storage) {
    health = me.hp + me.shield;
    damage = storage.previous_health - health;
    storage.previous_health = health;
    if( damage > 2 ) {
        storage.fear = 2;
    }
    if( storage.fear ) {
        storage.fear -= 1;
        if( me.gold >= cost(me.levels.heal) )
            return upgrade("heal");
        return heal();
    }
    if ( me.hp <= 50 ) {
        return heal();
    }
    if (cost(me.levels.farm) < 0.15 * (1000 - turn())) {
        if( me.gold >= cost(me.levels.farm) )
            return upgrade("farm");
        if( me.gold >= cost(me.levels.heal) )
            return upgrade("heal");
        return farm();
    }
    rich_bots = others.sort( (x,y) => y.worth - x.worth );
    richest_enemy = rich_bots[0];
    if (richest_enemy.hp >= storage.target_hp) {
        storage.anger = true;
    }
    storage.target_hp = NaN;
    if (storage.anger) {
        if( me.gold >= cost(me.levels.attack) ) {
            storage.anger = 0;
            return upgrade("attack");
        }
        return farm();
    }
    storage.target_hp = richest_enemy.hp;   
    return attack(richest_enemy.uid);   
}

ムーディーズのデフォルトの戦略は、しばらくの間ファーミングとヒーリングをアップグレードしてから、価値の高い順に他のボットを取り出します。ただし、攻撃された場合は怖くなり、少しの間ヒーリングに集中します。攻撃されて「失敗」した場合、被害者は攻撃よりも効果的に治癒または遮蔽しているため、怒り、攻撃能力をアップグレードするために立ち去ります。


4

盗賊

function Bandit(me, others, storage) {
    // stuff we need
    const epsilon = 0.3; // really high epsilon
    function argmax(xs) {
        var max = 0;
        var argmax = 0;
        for (var i=0; i<xs.length; i++) {
            if (xs[i]>max) {
                max = xs[i];
                argmax = i;
            }
        }
        return argmax;
    }
    function base3ToActionSeries(strategy) {
        const actions = [shield(), farm(), heal()];
        var idxs = []
        var strategy_cut = strategy;
        for (var i = 81; i >= 1; i /= 3) {
            if (strategy_cut >= 2 * i) {idxs.push(2); strategy_cut -= 2*i}
            else if (strategy_cut >= i) {idxs.push(1); strategy_cut -= i}
            else idxs.push(0);
        }
        return idxs.map(idx => actions[idx]);
    }

    // actual logic starts here
    // current strategy and info to calculate reward
    if (!storage.prior)
        storage.prior = [0,0.03325,0,0.0361,0.0361,0.2372,0,0.2372,0,0.00035,0.0361,0.23555,0.01305,0.0361,0.5798,0.23555,0.62065,0.23555,0,0.2372,0,0.20965,0.5841,0.2372,0,0.21905,0,0.0361,0.0361,0.2081,0.0361,0.0361,0.01455,0.000350,0.62065,0.205,0.000350,0.0361,0.3708,0.0361,0.0323,1.018050,0.5798,0.04495,0.5798,0.23555,0.62065,0.23555,0.62065,1.06395,0.62065,0.23555,0.62065,0.23555,0,0.2372,0,0.2372,0.5841,0.2372,0,0.2372,0,0.23555,0.62065,0.13775,0.5798,1.0257,0.5798,0.23555,0.62065,0.23555,0,0.2339,0,0.2372,0.5841,0.2339,0,0.2372,0,0.0342,0.0361,0.2372,0.03515,0.03325,0.6228,0.2372,0.5841,0.2372,0.0361,0.0130599,0.62065,0.03515,0.0361,1.0665,0.62065,0.24050,0.62065,0.23555,0.51465,0.2372,0.6228,1.0257,0.6228,0.2372,0.5841,0.2372,0.0361,0.0361,0.58195,0.0361,0.0313596,1.0614,0.58195,1.02315,0.58195,0.0342,0.0361,1.0206,0.02255,0.0183,0.02595,1.0206,1.5526,1.0206,0.58195,1.02315,0.58195,0.02765,0.0251,1.0614,0.0007,0.02085,0.3088,0.2372,0.5841,0.2273,0.6185,0.02255,0.6228,0.2372,0.5841,0.2372,0.62065,1.06395,0.62065,1.0665,0.0917,1.0665,0.62065,0,0.62065,0.2372,0.5841,0.2372,0.6228,1.0257,0.6228,0.2372,0.5841,0.2372,0,0.2372,0,0.23225,0.5841,0.2372,0,0.2372,0,0.23555,0.62065,0.23555,0.5798,1.0257,0.5798,0.23555,0.6142,0.23555,0,0.22235,0,0.2372,0.5841,0.2372,0,0.2372,0,0.23555,0,0.21905,0.62065,0.02255,0.62065,0.23555,0.61205,0.23555,0.5798,1.05885,0.5798,1.018050,0.03895,1.018050,0.5798,1.05885,0.5798,0.23555,0.62065,0.23555,0.62065,0.0361,0.62065,0.23555,0.62065,0.23555,0,0.2372,0,0.2372,0.3745,0.2372,0,0.2372,0,0.23555,0.62065,0.23555,0.5798,0.9452,0.5798,0.23555,0.5626,0.23555,0,0.2372,0,0.18175,0.5841,0.0138,0,0.2372,0]
    if (storage.lastScore == null)
        storage.lastScore = 0;
    if (storage.bestStrategy == null)
        storage.bestStrategy = argmax(storage.prior);

    if (cost(me.levels.heal) < me.gold) return upgrade("heal");
    if (cost(me.levels.farm) < me.gold) return upgrade("farm");

    // This barely explores and mostly exploits.
    if (turn() % 5 === 0) {
        // update
        const reward = me.gold/2 - storage.lastScore;
        // biased a bit towards later learned rewards
        storage.prior[storage.bestStrategy] += reward*0.01
        storage.prior[storage.bestStrategy] *= 100/101

        // explore
        if (Math.random() < epsilon) {
            storage.bestStrategy = Math.floor(Math.random()*243);
        }
        else { // exploit
            storage.bestStrategy = argmax(storage.prior);
        } 
        storage.lastScore = me.gold/2;
    }

    var action = base3ToActionSeries(storage.bestStrategy)[turn() % 5];
    return action;
}

強化学習ボットの最初の試み。今のところ純粋に防御的で、検索スペースを絞り込みます。FizzBu​​zzのよりスマートなスピンオフのようなもの-特定の一連の5つのアクションを繰り返し繰り返します。5つのアクションがRLによって選択されます。

しかし、現時点ではほとんど列挙に基づいています-繰り返し繰り返される一連の5つの防御アクションのすべての3 ^ 5 = 243の順列を生成し、平均スコア(200で除算して平均ゲインを取得する)を保存しました5ターン)storage.prior配列内で100回を超える反復。次に、ゲーム中に、これらのスコアリストを更新するイプシロングリーディアプローチを実装して、より将来性のあるものにします。(epsilon = 0.3を使用した方がepsilon = 0.1よりもずっと良かったので、そのままにしておきました。)

scavengerBotとOptimistの間に常に配置して、大丈夫です。私は現在、実際のゲームでさらにいくつかのトレーニングを行っており、戦略を組み立てるより良い方法を探して、それを改善できるかどうかを確認しています。


4

日和見主義者

これは他の少数の人(特にScavengerBot(V2)とUnkillable)から少し借りたものです。彼らは私が思い描いていたのと同じアイデアを持っていたからです。 1つまたは2つのこと。これはおそらく私が勝てないことを意味しますが、それはどこかの真ん中にあるはずです(多くの場合、ほとんどの場合私に起こります)。

そのため、ジューシーなキルを盗みます。必要に応じて回復します。ファームをアップグレードし、攻撃し、その順序で回復します。それ以外の農場。

function Opportunist(me, others, storage) {

    // Initializing and keeping track of selfWorth
    if (turn() == 1) {
        storage.selfWorth = 0;
    }
    else if (storage.previousGold < me.gold) {
        storage.selfWorth += (me.gold - storage.previousGold);
    }
    storage.previousGold = me.gold;

    // Me stats
    var me_attack = 1.25 * me.levels.attack + 5;
    var me_heal = me.levels.heal + 5;

    // Look for the juiciest hunk of loot
    // If there are multiple of the highest worth, the last is chosen
    var choice = others[0].uid;
    var mostWorthy = -1;
    for (var i = 0; i < others.length; i++) {
        worth = others[i].worth
        if (others[i].hp <= me_attack && worth >= mostWorthy) {
            choice = others[i].uid;
            mostWorthy = worth;
        }
    }

    // Actions in order of priority
    // The juicy targets must be worth the action
    if (mostWorthy > (storage.selfWorth * 0.25) ) {
        return attack(choice);
    }
    else if (me.hp <= 100 - me_heal) {
        return heal()
    }
    else if (me.gold >= cost(me.levels.farm)) {
        return upgrade("farm");
    }
    else if (me.gold >= cost(me.levels.attack)) {
        return upgrade("attack");
    }
    else if (me.gold >= cost(me.levels.heal)) {
        return upgrade("heal");
    }
    else {
        return farm();
    }
}

1
2番目の引数はothers
SuperStormer

4

ScaredBot

  1. 他のボットを見つけます:
    • 最高の攻撃で
    • ほとんどの富とHPは自身の攻撃よりも低い
  2. そのHP +シールドが見つかったよりも低い場合highest attack * (25% of bots)、またはの下端に近づくと、HP + shieldシールドします
  3. 自身の攻撃よりもシールドが低いボットを見つけた場合、攻撃します。
  4. 体力が< 50であれば、回復します。
  5. シールド、ヒール、ファームのいずれかをアップグレードできる場合、最も低いレベルのものをアップグレードします
  6. それは農場
function ScaredBot(me, others) {
    const my_attack = me.levels.attack * 1.25 + 5;
    const my_defense = me.hp + me.shield;

    var max_attack_val = 0;
    var min_hp_worth = 0;
    var min_hp_id = null;
    var hp_under_me = 0;
    for (var i=0; i<others.length; i++){
        if (others[i].hp < my_attack && others[i].worth > min_hp_worth){
            min_hp_id = others[i].uid;
            min_hp_worth = others[i].worth;
        }
        if (others[i].attack*1.25+5 > max_attack_val){
            max_attack_val = others[i].attack*1.25+5;
        }
        if (others[i].hp < my_defense && others[i].hp > 0){
            hp_under_me++;
        }
    }
    if (max_attack_val*0.25*others.length > my_defense || hp_under_me < 0.25*others.length){
        return shield();
    }
    else if (min_hp_id != null){
        return attack(min_hp_id);
    }
    else if (me.hp < 50){
        return heal();
    }
    else {
        var min_lvl = NaN;
        var min_name = null;
        const vals = [me.levels.heal, me.levels.shield, me.levels.farm];
        const names = ["heal", "shield", "farm"];
        for (var i=0; i<vals.length; i++){
            if (!(min_lvl < vals[i])){
                min_lvl = vals[i];
                min_name = names[i];
            }
        }
        if (me.gold > cost(min_lvl)){
            return upgrade(min_name);
        }
        return farm();
    }
}

考えは可能な限り長く生き続け、そうでなければアップグレードできるように安全で安価な方法で金を得ることを試みることです。

アップグレードの優先順位と、シールドするかどうかを決定する条件を調整する必要があります。


3

SmartFarmer

農場、農業のアップグレード、健康が低下すると回復します。真に攻撃的なボットが到着するまで、農業は圧倒的でした。今、私のボットは殺されます:-(

function smartFarmer(me, others){
    if(me.hp < 13) return heal();
    for(var i = 0; i < others.length; i++)if(others[i].attack * 1.25 + 5 > me.hp)return heal();
    if(me.gold >= cost(me.levels.farm)) return upgrade("farm");
    if(me.levels.heal < 9 && me.levels.farm > me.levels.heal + 7 && me.gold >= cost(me.levels.heal)) return upgrade("heal");
    return farm();
}

1
私は(手作業で)基本的に同じ戦略をテストして、獲得可能な最大の価値と得ることができる最高の数字を確認しました。これは、ヒールがアップグレードされたときにわずかに遅延し(ゴールド> =コスト* 2を使用)、レベル10まで回復しました。
ニコライ

その価格乗数は良いアイデアです。同様のものを追加しました。あなたが得た数字を見て
みたい

3

モート

function Mort(me, others, storage) {
    if (me.hp <= 100 - (me.levels.heal + 5))
        return heal();
    actions = ["farm", "heal", "attack"].filter(action => cost(me.levels[action]) <= me.gold).map( action => [upgrade(action), 1000 - turn() - cost(me.levels[action]) ] )
    my_damage = me.levels.attack * 1.25 + 5;
    actions = actions.concat(others.map( bot => [ attack(bot.uid), (bot.worth/2)/Math.max(bot.hp/(my_damage-(bot.hp > my_damage ? 5 : 0)),1) ] ));
    actions.push( [farm(), (2 * me.levels.farm + 5)*(1-2/(me.levels.heal+5))] );
    return actions.sort( (x,y) => y[1] - x[1] )[0][0];
}

各ターンで、各ボットを殺したことによる償却利益を農業と癒しの利益と比較し、最良の選択肢を選びます。本当に状態を使用してボットを殺すのにかかる時間を計算する必要がありますが、今のところは、すべてのボットが他のボットが与えるダメージの正味平均5ポイントを回復またはシールドすることを想定しています。


3

フレンドリーボット

function menShengFaDaCai(me, others) {
  // heal if needed
  const maxAttack = Math.max(...others.map(bot => bot.attack));
  const maxAttackCost = maxAttack * maxAttack + 5;
  const othersHp = others.map(bot => bot.hp).sort();
  const targetHp = othersHp[Math.ceil(othersHp.length / 2)];
  if (me.hp < 95 && me.hp < Math.max(maxAttackCost * 2, targetHp, 50)) return heal();

  // upgrade heal and farm if possible
  const { heal: healLevel, farm: farmLevel } = me.levels;
  const gain = (heal, farm) => ((5 + heal) / 2) * (2 * farm + 5) / ((5 + heal) / 2 + 1);
  const gain0 = gain(healLevel, farmLevel);
  const gainUpgradeHeal = gain(healLevel + 1, farmLevel);
  const gainUpgradeFarm = gain(healLevel, farmLevel + 1);
  const gainUpgradeHealPerGold = (gainUpgradeHeal - gain0) / cost(healLevel);
  const gainUpgradeFarmPerGold = (gainUpgradeFarm - gain0) / cost(farmLevel);
  const preferUpgradeHeal = gainUpgradeHealPerGold > gainUpgradeFarmPerGold;
  const mayOffer = type => me.gold >= cost(me.levels[type]);
  if (preferUpgradeHeal && mayOffer('heal')) return upgrade('heal');
  if (!preferUpgradeHeal && mayOffer('farm')) return upgrade('farm');

  // keep farming
  return farm();
}

others[0].hphp + shield代わりにhp...


4
関数名を英語に翻訳するのを手伝ってくれる人はいますか?^ _ ^
tsh

4
Google翻訳によると、「闷声发大财」は「くぐもった」という意味です。それはあなたが望むものではなく、実際には別のGoogle翻訳の叙事詩の失敗です...私はさらに検索し、すべての結果はここで使用できる単一の英語の単語がないことを言及しているようですので、そのままにしておく方が良いかもしれません実際、それは中国の前置詞であるように思われ、一般的には静かに働き、結果を自分自身で語り、伝統的な哲学に到達することを意味します。残念なことに、私は中国語を直接翻訳することをまったく知りません。:D
エリック・ザ・アウトゴルファー

1
ネイティブスピーカーとして、それは「黙って巨大な財産」のようなものを意味します:v闷声は意図的に静かであることを暗示し、文字通り「音を隠す」
リンのフーリエ変換

1
卑劣な?秘密裏に?DontMindMe?注意デフレクター?
ピーターテイラー

3

会計士

この実用的なボットは、最も経済的に有利な動きを計算しますが、自警団のすべてのボットからのトラブルを避けるために、攻撃プロファイルを低く保つことを好みます。彼は彼らを無防備にしたり、餌食にしたりしません。むしろ、彼は彼を最も助けるものをします。

function accountant(me, others, storage) {
    if (turn() == 1) {
        storage.lastHP = me.hp + me.shield;
        storage.hisAttack = 5;
        storage.timesAttacked = 0;
        storage.lastAttack = -1;
        storage.healths = [], storage.uids = [], storage.heals = [];
        for (var i = 0; i < others.length; i++) {
            storage.healths.push(others[i].hp);
            storage.uids.push(others[i].uid);
            storage.heals.push(5);
        }
    }
    storage.timesAttacked++;
    if (storage.lastHP == me.hp + me.shield) storage.timesAttacked = 0;
    else storage.hisAttack = storage.lastHP - me.hp - me.shield;
    storage.lastHP = me.hp + me.shield;
    var attacks = [];
    for (var i = 0; i < others.length; i++) if (others[i].uid != me.uid) attacks[i] = 1.25 * others[i].attack + 5;
    attacks.sort();
    for (var i = 0; i < others.length; i++) {
        storageIndex = storage.uids.indexOf(others[i].uid);
        if (storage.heals[storageIndex] < others[i].hp - storage.healths[storageIndex] + (others[i].uid == storage.lastAttack ? 1.25 * me.levels.attack + 5 : 0)) others[i].hp - storage.healths[storageIndex] + (others[i].uid == storage.lastAttack ? 1.25 * me.levels.attack + 5 : 0);
    }
    var maxProfitTurn = 2 * me.levels.farm + 5, victimID = -1, tempProfit;
    for (var i = 0; i < others.length; i++) {
        storageIndex = storage.uids.indexOf(others[i].uid);
        tempProfit = others[i].worth / 2 * (1.25 * me.levels.attack + 5 - storage.heals[storageIndex]) / others[i].hp;
        if (tempProfit > maxProfitTurn) {
            victimID = others[i].uid;
            maxProfitTurn = tempProfit;
        }
    }
    maxUrgentProfit = 0;
    for (var i = 0; i < others.length; i++) if (maxUrgentProfit < others[i].worth / 2 && others[i].hp <= attacks.slice(0, 4).reduce((a, b) => a + b) + 1.25 * me.levels.attack + 5) {
        maxUrgentProfit = others[i].worth / 2;
        victimID = others[i].uid;
    }
    if (maxUrgentProfit > 0) {
        storage.lastAttack = victimID;
        return attack(victimID);
    }
    storage.lastAttack = -1;
    if (storage.timesAttacked == 0) {
        if (me.levels.shield < 20 && me.gold >= cost(me.levels.shield)) return upgrade("shield");
        if (me.levels.heal < 5 && me.levels.shield >= me.levels.heal + 5 && me.gold >= cost(me.levels.heal)) return upgrade("heal");
        if (Math.random() < Math.pow((me.hp + me.shield) / 100, -2)) {
            storage.lastHP += 1.5 * me.levels.shield + 5;
            return shield();
        }
    }
    else {
        if (Math.random() < .5 || me.hp + me.shield - storage.hisAttack - attacks[0] <= 10) {
            storage.lastHP += 1.5 * me.levels.shield + 5;
            return shield();
        }
        if (me.levels.shield < 20 && me.gold >= cost(me.levels.shield)) return upgrade("shield");
        if (me.hp <= 2) {
            storage.lastHP += me.levels.shield + 5;
            return heal();
        }
        storage.lastHP -= 2;
        return farm();
    }
    if (me.gold >= cost(me.levels.farm)) return upgrade("farm");
    storage.lastAttack = victimID;
    if (victimID != -1) return attack(victimID);
    if (me.hp <= 2) {
        storage.lastHP += me.levels.shield + 5;
        return heal();
    }
    storage.lastHP -= 2;
    return farm();
}

3

reallyCommittedTurtle

function reallyCommittedTurtle(me, others, storage) {
    if( storage.previousHP ) {
        others.forEach ( o => {storage.deltaHP[o.uid] = o.hp - storage.previousHP[o.uid]; storage.previousHP[o.uid] = o.hp } );
    }
    else {
        storage.previousHP = {};
        storage.deltaHP = {};
        others.forEach ( o => storage.previousHP[o.uid] = o.hp );
    }
    if (turn() < 3)
        return upgrade("shield");
    if ( me.shield < 400 || others.find( o=> o.deltaHP < -2 ) )
        return shield();
    if (me.hp <= 95 - me.levels.heal) {
        if (me.gold >= cost(me.levels.heal))
            return upgrade("heal");
        return heal();
    }
    rich_bots = others.sort( (x,y) => y.worth - x.worth );
        potential_victim = rich_bots.find( bot => bot.hp + storage.deltaHP[bot.uid] <= me.levels.attack * 1.25 + 5 );
        if (potential_victim && potential_victim.worth/2 > me.levels.farm*2 + 5)
            return attack(potential_victim.uid);
    if (me.gold >= cost(me.levels.farm))
        return upgrade("farm");
    return farm();
}

つまりね。本当に危険になっています。農業はすべてあなたの価値を高め、あなたをターゲットにします。したがって、巨大なシールドを構築し、すべての暴力が消滅するまで、農業することは本当に安全ではありません。次に、頭を殻から突き出して農業を始めます。またはキルアシスト。良いものは何でも。


2

守護者

複数の提出物を作成できますか?

CampBotのフォーク。シールドせず、代わりに攻撃に集中します。CampBotのようにランダムに攻撃するのではなく、攻撃統計が高いプレイヤーを攻撃することを好みます。癒しではなく農業の改善に焦点を当てています。

function guardian(self,others,storage){
    if(!storage.victimBlacklist){
        storage.victimBlacklist=[]
    }
    let turnsLeft=999-turn()
    function findVictim(){
        let potentialVictims=others.filter(bot=>!storage.victimBlacklist.includes(bot.uid))
        if(potentialVictims.length>0){
            let victim=potentialVictims.reduce((el, em) => el.attack > em.attack ? el : em);
            storage.victimUid=victim.uid
            storage.victimPrevHp=victim.hp
            storage.prevMove="attack"
            return attack(victim.uid)
        }else{
            storage.prevMove="farm"
            return farm()
        }   
    }
    if(self.hp<=(95-self.levels.heal)){
        storage.prevMove="heal"
        return heal()
    } else if(self.gold>=cost(self.levels.attack)){
        storage.prevMove="upgrade"
        return upgrade("attack")
    } else if(self.gold>=cost(self.levels.farm)&&turnsLeft>100&&self.levels.heal<=1){
        storage.prevMove="upgrade"
        return upgrade("farm")
    } else if(!storage.victimUid){
        return findVictim()
    }else if(Object.values(others).map(bot=>bot.uid).includes(storage.victimUid)){
        let victimCurrHp=Object.values(others).filter(bot=>bot.uid==storage.victimUid)[0].hp
        if(storage.victimPrevHp<victimCurrHp&&storage.prevMove==="attack"){
            storage.victimBlacklist.push(storage.victimUid)
            storage.victimUid=undefined
            return findVictim()
        }else{  
            storage.victimPrevHp=victimCurrHp
            storage.prevMove="attack"
            return attack(storage.victimUid)
        }
    }else{
        storage.victimUid=undefined
        return findVictim()
    }
}

私のボットdoesntのは、ランダムに...攻撃
SuperStormer

投稿は何回でもできますが、もっと楽しいと思います
プログラム

@SuperStormer私はあなたのものが完全にランダムではないことを理解していますが、:let victim=potentialVictims[Math.floor(Math.random()*potentialVictims.length)]
匿名

しかし、最初に攻撃する価値のないものを除外します
SuperStormer

あなたがこれを投稿したとき、私はイコライザーと呼ばれる同様のボットに取り組んでいました。私はまだそれを微調整していますが、あなたのアイデアのいくつかが好きです。
B0RDERS

2

ランド

この愚かな男は、一定の偏りのある一様なランダム性に基づいてアクションを選択します。ランダムに選択されたアクションが機能しない場合、次の選択肢にドロップダウンします。

そのため、平均して、彼は時間のほぼ2/9を攻撃し、時間のほぼ3/9をファームする必要があります。彼がアップグレードできる場合、またはヒーリング/シールドがそれだけの価値がある場合など、残りは約1/9のチャンスです。

彼はおそらくうまくいかないでしょうが、少なくとも彼が最高の君臨する可能性はわずかです。それがRandoの全体的な目的です。彼は自分自身を信じる必要があります!すべてのオプションが彼の前に置かれています。彼は、特定の状況に必要なものを選択するだけです。

function Rando(me, others, storage) {

    var rnum = Math.floor(Math.random() * 9);
    switch (rnum) {
        case 0:
            if (me.gold >= cost(me.levels.shield)) {
                return upgrade("shield");
            }
        case 1:
            if (me.hp >= 100 - (me.levels.heal + 5) && me.levels.shield >= me.levels.heal) {
                return shield();
            }
        case 2:
            if (me.hp < 100 - (me.levels.heal + 5)) {
                return heal();
            }
        case 3:
            if (me.gold >= cost(me.levels.farm)) {
                return upgrade("farm");
            }
        case 4:
            if (me.gold >= cost(me.levels.heal)) {
                return upgrade("heal");
            }
        case 5:
            if (me.hp > 2) {
                return farm();
            }
        case 6:
            // Beat down the leader!
            var currentLeader = others[0].uid;
            var leaderWorth = -1;
            for (var i = 0; i < others.length; i++) {
                worth = others[i].worth;
                if (worth > leaderWorth) {
                    currentLeader = others[i].uid;
                    leaderWorth = worth;
                }
            }
            return stun(currentLeader);
        case 7:
            if (me.gold >= cost(me.levels.attack)) {
                return upgrade("attack");
            }
        case 8:
            // Find the juiciest kill (if any), or attack the strongest
            var choice = others[0].uid;
            var choiceWorth = -1;
            var currentLeader = others[0].uid;
            var leaderWorth = -1;
            for (var i = 0; i < others.length; i++) {
                worth = others[i].worth
                if (worth > leaderWorth) {
                    currentLeader = others[i].uid;
                    leaderWorth = worth;
                }
                if (others[i].hp <= (1.25 * me.levels.attack + 5) && worth >= choiceWorth) {
                    choice = others[i].uid;
                    choiceWorth = worth;
                }
            }
            if (choice > -1) {
                return attack(choice);
            }
            else {

                return attack(currentLeader);
            }
        default:
            return false
    }
}

(「デフォルト」は不要ですが、堅牢なコードを作成するための適切なコーディング方法だと思います。)


2
私はそんなに今笑ってよ...「彼はただ自分自身を信じる必要がある」
Redwolfプログラム

2

ボットを殺す

function killBot(me, others, storage) {
    // If I lost health since my last check, shield.
    if (me.hp < storage.hp){
        storage.hp = me.hp;
        return shield();
    }

    storage.hp = me.hp;

    health = Math.min(...others.map(o => o.hp));
    // If I have the least health or can be one-shot, shield.
    if (others.some(o => o.attack * 1.25 + 5 >= me.hp + me.shield) || (health > me.hp + me.shield && health < 500)) return shield();

    // If I can kill someone, kill them!
    targets = others.filter(o => o.hp < me.attack);
    if (targets.length > 0){
        wealth = Math.max(...targets.map(o => o.worth));
        targets = targets.filter(o => o.worth == wealth);
        target = targets[Math.floor(Math.random()*targets.length)];
        return attack(targets[0].uid);
    }

    // If I have the money, upgrade shielding or attack
    if (me.levels.shield <= me.levels.attack){
        if (cost(me.levels.shield) < me.gold) return upgrade("shield");
    } else {
        if (cost(me.levels.attack) < me.gold) return upgrade("attack");
    }

    // Otherwise, attack the weakest!
    targets = others.filter(o => o.hp == health);
    // And if there's a tie, attack the wealthiest.
    wealth = Math.max(...targets.map(o => o.worth));
    targets = targets.filter(o => o.worth == wealth);
    target = targets[Math.floor(Math.random()*targets.length)];
    return attack(targets[0].uid);
}

単純なボット、キルボットは敵を殺したいだけです。シールドは治癒よりもはるかに効率的であるため(特にレベル調整時)、Kill Botは攻撃されるたびにシールドすることで常に魅力のないターゲットになろうとします。キルボットは、この辺りの弱い、平和主義的なボットの間で非常によく機能します(その軽cornを感じることができます)。


3
o.attackダメージではなく攻撃レベルであることに注意してください
Redwolfプログラム

2

FarmHealボット

@Anonymous 'JustFarmボットから分岐

function farmhealBot(me, others, storage) {
  if (me.hp <= 95)
    return heal();
  else return farm();
}

2

不滅

シールドを使用したDraco18のボットの変更(他のボットに対してより効果的)

function indestructible(me){
    if (me.hp < 100) {
        return heal();
    } else if (me.shield < 15) {
        return shield();
    } else {
        if (me.gold >= cost(me.levels.shield)) {
            return upgrade("shield");
        } else if (me.gold >= cost(me.levels.farm)) {
            return upgrade("farm");
        } else {
            return farm();
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.