[Question]
  [
> 
> This challenge has ended. To see the final scores of the competitors, [click here](https://chat.stackexchange.com/transcript/message/51317259#51317259)
> 
> 
> 
In this challenge, each submission is one bot. Each bot should be a Javascript function. Bots will fight to obtain the highest total worth in gold. Gold can be farmed, or earned from killing other bots, and is used to upgrade healing, attacking, shielding, and farming.
**Objective:**
Over a number of rounds containing up to 1000 turns (ends when only one bot is left), the bot with the highest total worth (the sum of all gold obtained) is the winner.
**Turns:**
In each turn, every bot which is alive (>0 HP) will be run once. It can return a move, which can be one of the following:
* Heal: Regains HP
* Attack: Removes HP from another bot
* Shield: Defends against later attacks
* Stun: Skips another bot's next turn
* Farm: Earns gold at the cost of HP
* Upgrade: Make certain moves better
All bots will return their move before any are executed, so a stun, heal, attack, shield, etc. will not affect any bots moving later in that turn. For example, if Bot A stuns Bot B, and Bot B is after Bot A in the turn order, Bot B will still move later in that same turn and the stun will occur on the next turn.
**Combat, Farming, and Upgrading:**
Each bot has a maximum HP of 100, and an assigned UID between 0 and 99. This UID changes after every round, and is how bots keep track of each other.
Healing is one of the simplest moves, adding an amount of HP determined by its level (starts at 5 HP). A bot cannot heal past 100 HP.
Attacking a bot by its UID is another possible move, with a base damage of 5 HP at level 0. Bots can also be stunned, skipping their next turn, which also uses UIDs.
Bots have additional shield HP, which has no limit. This shield HP will absorb damage from direct attacks from other bots, and is added by shielding. At level 0, shielding adds 5 shield HP.
Farming will earn 5 gold at level 0, at the cost of 2 HP. This 2 HP cannot be shielded. The only use for gold (beyond winning) is to upgrade moves. Healing, attacking, and shielding have a base value of 5 HP, and farming starts at 5 gold. Each of those moves have individual levels, which start at 0. These formulas will determine the value in HP or gold of a move, where L is the level:
* Healing: `L + 5`
* Attacking: `1.25L + 5`
* Shielding: `1.5L + 5`
* Farming: `2L + 5`
The cost of upgrading any move is the same for a certain level, and is determined by `2.5L² + 2.5L + 10`, where L is the current level. A bot can use the function `cost(currentLevel)` as a shortcut to determine this.
Bots start with 25 gold, allowing them to quickly upgrade either two moves to level 1, or one move to level 2. This beginning gold does not count towards a bots total worth. Killing a bot gives you half of its total worth in gold, rounded up, and if two bots kill another in the same turn, they both get the reward.
**Input/Output:**
In order to communicate with the controller, the return value of the function is used to send move information. One of these should be returned:
* Heal: `heal()`
* Attack: `attack(uid)`
* Shield: `shield()`
* Stun: `stun(uid)`
* Farm: `farm()`
* Upgrade: `upgrade("heal" / "attack" / "shield" / "farm")`
To skip a turn (do nothing), return nothing, or return a falsy value.
To get the current turn number (starts at 1), use `turn()`.
The arguments of your function will include information about your bot, UIDs of other bots, and between-turn storage. The first argument is an object with the following properties: `uid`, `hp`, `gold`, and `shield`. These are copies of your bot's current information. There is also an nested object `levels`, with the level numbers of `heal`, `attack`, `shield`, and `farm`.
The second argument is a shuffled array of all alive bots other than yours, formatted as an object containing properties `uid`, `hp` (plus shield), `worth`, and `attack` (attack level). The third argument is an empty object which can be used for between-turn storage.
**Example Bots:**
This bot will farm until it can upgrade its attack to level 5, then attack a random bot each turn until it dies (or wins). Not very effective due to lack of healing/shielding.
```
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);
}
```
This bot has two modes: offensive and defensive. It will either stun a random bot or heal when in defensive mode, and it will either attack or shield when in offensive mode. It will attempt to upgrade its attacks whenever possible.
```
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();
}
```
**Rules:**
* [Standard Loopholes](https://codegolf.meta.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) forbidden
* Bots may not read, modify, or add any variables outside of their scope, may not attempt to cheat, and may not call any controller-defined or DOM functions
* Return value must be falsy, or one of the above function outputs
* Bots should not be designed to target a specific bot, but can be designed to take advantage of common strategies
* Bots may not attack themselves (discovered due to a comment by @Ness)
* Bots must be sufficiently different from any other bots that they can be reasonably considered separate entries
* Teaming is **now not** allowed
* Controller can be found [here](https://gist.github.com/Radvylf/a8089fee5921b6118b92f429f8f60083)
* [Chatroom](https://chat.stackexchange.com/rooms/96920/gold-battle-koth)
**New Controller Debugging:**
Using the file `gold-battle-log.js`, you can set the value of the `debug` property of a bot in `botData` to 0 (no logging), 1 (log moves), or 2 (log moves, hp, gold, levels, etc.)
**Challenge ends at 1700 UTC on Friday, August 9th**
  
[Answer]
# Unkillable
forked from [Undyable](https://codegolf.stackexchange.com/a/189115/47990).
```
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()
        }
    }
}
```
Given the exponential costs of upgrades, may as well upgrade farming if we can't upgrade healing, allowing the bot to collect gold more efficiently.
[Answer]
# ThanosBot
```
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();
            }
        }
    }
}
```
There are too many bots, not enough gold to go around. This bot proposes a solution.
Genocide, yes, but random, dispassionate, fair to rich and poor alike.
They called him a madman.
ThanosBot wants the best for the bot community, and is willing to go all the way. In the beginning, he will upgrade his attack, farming and healing, to more efficiently gather resources and win battles. Prograssively, he will start attacking people randomly while still gathering resources, for upcoming battles. He will keep improving his army, his weapons and himself.
Once 50% of the population has been eliminated, bots born will only know full bellies and clear skies, he will retire to a life of farming, and watch the sun rise on a grateful universe. He will become completely pacifist, only healing himself with vegetable soups and farming.
[Answer]
# Kill Stealer
```
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();
}
```
Now not only steals kills, but steals stealing kills too!
This bot doesn't do much except farm, and when it notices the possibility, joins in doing the final blow to a dying enemy, and somehow manages to be very good.
[Answer]
# Optimist
```
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();
}
```
Assumes it will be able to spend 80% of its time peacefully farming, so it starts off by maxing out farming, and only then starts paying any attention to its combat skills. Surely nothing will go wrong!
[Answer]
# The Equalizer
This bot seeks to restore peace in the bot community. He relentlessly targets the bots with the highest attack, giving up only if the bot's healing is better than his own attack. Once no bots with healing worse than its attack are left, he will retire to a life of peaceful farming.
```
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();
}
```
[Answer]
# Kill Assist
```
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();
}
```
Why upgrade attack value when you can do plink damage and still get full credit?
Once more back to piggybacking off Kill Stealer. I was able to simplify several blocks of code where statements were always true and fiddle with some numbers that resulted in massive gains over the original.
I have to hand it to @dzaima for realizing that stunning a wealthy opponent that is likely to be involved in an assist the turn before a kill happens is quite clever. One of the (very) few times `Stun()` has a positive sum outcome. Once again I was able to improve upon the idea, as knowing that Kill Stealer will be running similar logic, Kill Assist looks for a "second best" target (with some discretion) and stuns them instead.
Minor update to prevent stunning the bot-about-to-die and prevent stunning the bot-most-likely-to-make-the-kill.
Sample results (truncated top 5 after 1000 games)
```
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
```
[Answer]
# The Bot That Farms, Attacks, Shields, And Even Heals But Never Stuns
*(Short name is **TBTFASAEHBNS**, not to be mistaken with [TBTPTGCBCBA](https://codegolf.stackexchange.com/a/170251/81663))*
```
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();
}
```
This bot basically:
* Builds up on farming at start
* Defends itself when needed
* Attacks when it can kill or when it thinks there is a chance to kill someone
* Upgrades here and then
* Farms the rest of the time
* Never stuns
**Edit 1:** Fixed an issue and improved some tiny things in the bot based on tests with lots of games.
**Edit 2:** Reduced shield upgrades.
[Answer]
## Undyable Bot (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()
            }
        }        
    }   
}
```
---
[Answer]
# FizzBuzz
```
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);
}
```
Mostly offensive bot. Extremely upset by the fact that it can't truly FizzBuzz so it just Buzzes angrily instead. When it's not Fizzing or Buzzing, it chips away at another bot for 30 turns and gives up and chooses another bot to target if it isn't making progress.
~~Performs extraordinarily inconsistently.~~ Never mind, updated the controller, now seems to always be around the middle of the pack.
[Answer]
# PatientStrategistBot
I tried to write a bot that starts out framing and defending as needed and then switches to killing other high value bots later in the game.
Currently this doesn't seem to work properly since its either killed by a gang of murder-bots in the start of the game or gets stuck somewhere in its offensive mode. 
Still pretty happy with this being my first JS code, so ...
(I did steal code snippets from here & there cause that was faster than googling all of the JS basic syntax)
```
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();
}
```
[Answer]
## JustFarm
I thought I'd start simple.
```
function justFarm(me, others){
    return farm();
}
```
[Answer]
# Switzerland
```
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()
    }
}
```
Like the name suggests, this bot is ~~neutral~~ mostly neutral(now it helps kill bots that are going to die) and just farms and heals, slowly building up its gold(~~just like switzerland~~)
[Answer]
# SniperBot
*This bot will only be effective if someone starts adding bots that actually attack on a regular basis. SmartFarmer is my current optimized solution*
1. heals if can get one-shot
2. heals if under 30
3. attacks bot if can pick it off and earn more money than farming
4. upgrades farming if can afford
5. upgrades healing if is under 80 health and can afford
6. farms
vultures don't need an attack
```
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();
}
```
[Answer]
# 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);
}
```
Mashup of BullyBot and some other bits. Optimist had a short and sweet opportunistic attack chunk that I yoinked (though other bots do similar calculations).
Instead of bullying the target by stunning them, *it murders them* for their sweet, sweet loot. It also targets the weakest in the herd for bullying, but it will give up and just go farming if the weakest target's HP is too high.
[Answer]
# 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);
}
```
[Try it online!](https://tio.run/##bVC7bsMwDNzzFewmIamRzq6WLvmBbkUHJaEdtbJUUJSBwsi3u7KstCkgLgRfd8f70KMOJzJf/Oj8Gee5i@7Exjs4Rmu/XzyLAXfg@YIUdhDYk@5RThtIYTrBkZyQSj3JiXApoNM0CNlebxvlpMl4r5p6ZKVcKuRUG61Mb/v3JppzQskwoybgPLdmxAAqsdiAbR52nsSyYFJ736b0XOQ2Fl3Pl9TabiWskldRIAqNyTSgFFS03N8s8V8BUywCbnEk1J9/rdWBXx8e7s6rryfM6vPF18DR1cyU7eY6U3QHPWDyff4B "JavaScript (Node.js) – Try It Online")
May not win but will certainly try his damndest to make sure his target doesn't either. bullyBot also farms on the first turn so that if there's no outside influence, he will beat his target 5-0 or tie them 5-5.
[Answer]
## ScavengerBot (V2)
Realized it wasn't much of a scavenger before. New strategy is wait until it can kill another bot. If no one can be killed, it sits and builds up shield.
```
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();
}
```
[Answer]
# Moody
```
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);   
}
```
Moody's default strategy is to upgrade farming and healing for a while, then take out the other bots in descending order of worth. However, if it's attacked, it'll get scared and refocus on healing for a bit. If it attacks and "fails", because the victim was healing or shielding more effectively than the attack, it'll get angry and go off to upgrade its attacking abilities.
[Answer]
# Bandit
```
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;
}
```
First attempt at a reinforcement learning bot. Purely defensive for now to narrow down the search space. Sort of a smarter spinoff of FizzBuzz -- it repeats a specific series of five actions over and over; the five actions are what are chosen by RL.
But it's mostly based off of enumeration for now -- I just generated all 3^5=243 permutations of series of five defensive actions that repeated itself over and over, and stored their average scores (divided by 200, to get the average gain over five turns) over 100 iterations in the `storage.prior` array. Then, during the game, it implements an epsilon-greedy approach to updating those score lists so it's more future-proof. (Also because using epsilon=0.3 did way better than epsilon=0.1 so I just kept it.)
It does okay, consistently placing between scavengerBot and Optimist. I'm currently doing some more training on real games, and looking for better ways to frame the strategy, to see if I can improve it.
[Answer]
# The Opportunist
This one borrows a bit from a few others (notably ScavengerBot (V2) and Unkillable) since they had the same ideas I had in mind, but I generally like well-roundedness and jack-of-all-trades styles more than focusing on only one or two things. This will likely mean that I will not win, but it should be in the middle somewhere (which happens to me most of the time in many things).
So it steals juicy kills; heals if necesssary; upgrades farm, attack, and heal in that order; and farms otherwise.
```
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();
    }
}
```
[Answer]
# ScaredBot
1. It finds other bots:
	* with the highest attack
	* with most wealth and HP lower than own attack
2. If its HP+shield is lower than the found `highest attack * (25% of bots)`, or it gets near the lower end of `HP + shield`, then it shields
3. If it found a bot with lower shield than its own attack, it attacks it.
4. If its health is `< 50`, it heals.
5. If it can upgrade any of shield, heal and farm, it upgrades the one with the lowest level
6. It farms
```
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();
    }
}
```
The idea is to stay alive the longest possible and otherwise try getting gold in a safe and cheap way to be able to upgrade.
Upgrade priorities should probably be tweaked, as well as the condition when determining on whether to shield.
[Answer]
# 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();
}
```
Here's the thing. It's gotten really dangerous out there. Farming at all increases your worth, making you a target. So it's really not safe to farm until you've built up a huge shield and all the violence has died down. Then you can poke your head out of your shell and start farming. Or kill-assisting. Whatever pays better.
[Answer]
# SmartFarmer
Farms, upgrades farming, heals if low health. Farming seemed overpowered until the truly offensive bots arrived. Now my bot gets killed :-(
```
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();
}
```
[Answer]
# Mort
```
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];
}
```
Each turn, compares the amortized profit of killing each bot to that of farming and healing and picks the best option. Really it should use state to figure out how long it'll take to kill a bot, but for now it just assumes every bot heals or shields an average of 5 points a turn net of damage other bots do.
[Answer]
# Friendly bot
```
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].hp` is `hp + shield` instead of `hp`...
[Answer]
# The Accountant
This practical bot calculates the most economically beneficial move, but he likes to keep his attack profile low to avoid trouble from all of the vigilante bots. He doesn't try to pick help the defenseless or prey on them. Rather, he does what helps him the most.
```
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();
}
```
[Answer]
# Guardian
I can have more than one submission, right?
A fork of CampBot. Doesn't shield, instead focusing on attacking. Shows a preference for attacking players with higher attack stats, rather than striking at random like CampBot. Focuses on upgrading its farming rather than healing.
```
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()
    }
}
```
[Answer]
# Rando
This silly guy will choose actions based on uniform randomness with some biases. If a randomly chosen action won't work, then it drops down to the next choice.
So on average, he should attack almost 2/9 of the time and farm almost 3/9 of the time. The rest are about 1/9 chance if he is able to upgrade, or if the healing/shielding is worth it, etc.
He will not likely perform well, but at least there's a small chance that he reigns supreme. And that's the whole purpose of Rando. He just needs to believe in himself! All the options are laid in front of him. He needs only choose what is needed for any given situation.
```
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
    }
}
```
(I know "default" is unnecessary, but I think it is good coding practice for robust code.)
[Answer]
# Kill Bot
```
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);
}
```
A simple bot, Kill Bot just wants to kill its enemies. Since shielding is much more efficient than healing (especially when levelled), Kill Bot just tries to always be an unappealing target by shielding itself whenever attacked. Kill Bot does quite well among the weak, pacifistic bots around here (you can feel its scorn for them).
[Answer]
# FarmHeal Bot
Forked from @Anonymous' JustFarm bot
```
function farmhealBot(me, others, storage) {
  if (me.hp <= 95)
    return heal();
  else return farm();
}
```
[Answer]
## Indestructible
A modification of Draco18's bot, using shields (more effective against other bots)
```
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();
        }
    }
}
```
]