Last active
August 7, 2019 16:26
-
-
Save Draco18s/2efbf95edcf98d6b1f264e26bbb669d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Copy and paste bot functions here: | |
function justFarm(me, others){ | |
return farm(); | |
} | |
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() | |
} | |
} | |
} | |
} | |
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() | |
} | |
} | |
} | |
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(); | |
} | |
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); | |
} | |
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(); | |
} | |
} | |
} | |
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(); | |
} | |
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(); | |
} | |
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); | |
} | |
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(); | |
} | |
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(); | |
} | |
function pacifistWinnerBot(me, others, storage) { | |
if(!storage.start){ | |
storage.start=true; | |
storage.others = others; | |
} | |
others.map(bot => | |
storage.others.map( | |
bot2 => {if(bot2.uid==bot.uid)bot=bot2}//update worth, hp, attack level | |
) | |
); | |
const maxAtk = 5+1.25*Math.max(storage.others.map(bot => bot.attack)); | |
if(storage.win || ((me.gold > Math.max(storage.others.map(bot => bot.worth))+25) && storage.others.reduce((bot,x) => x+(bot.hp<=0),0)==1)){ | |
storage.win=true; | |
return stun(storage.others.filter(bot => bot.hp>0)[0].uid); | |
} | |
if(me.hp < 2+maxAtk) return heal(); | |
if(me.hp < 2+maxAtk*2) return shield(); | |
if(me.levels.healing<1 && me.gold>cost(me.levels.healing)) return upgrade("heal"); | |
if((me.gold > cost(me.levels.shield)) && (1.5*me.levels.shield+5 < 2*maxAtk)) return upgrade("shield"); | |
if(me.gold > 50+cost(me.levels.farm)) return upgrade("farm"); | |
return farm(); | |
} | |
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); | |
} | |
function campBot(self,others,storage){ | |
if(!storage.victimBlacklist){ | |
storage.victimBlacklist=[] | |
} | |
let turnsLeft=999-turn() | |
function findVictim(){ | |
let potentialVictims=others.filter(bot=>bot.worth>70&&((bot.attack>1&&bot.hp<200)||bot.hp<80)&&!storage.victimBlacklist.includes(bot.uid)) | |
if(potentialVictims.length>0){ | |
let victim=potentialVictims[Math.floor(Math.random()*potentialVictims.length)] | |
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.shield<=50){ | |
return shield() | |
} else if(self.gold>=cost(self.levels.attack)&&turnsLeft>100&&self.levels.attack<=3){ | |
storage.prevMove="upgrade" | |
return upgrade("attack") | |
} else if(self.gold>=cost(self.levels.farm)&&cost(self.levels.farm)<turnsLeft*(2*(self.levels.farm+1)+5)){ | |
storage.prevMove="upgrade" | |
return upgrade("farm") | |
}else if(self.gold>=cost(self.levels.heal)&&cost(self.levels.heal)<turnsLeft/(self.levels.heal+6)*(2*self.levels.farm+5)&&self.levels.heal<=2){ | |
storage.prevMove="upgrade" | |
return upgrade("heal") | |
}else if(self.gold>=cost(self.levels.shield)&&self.levels.shield<=3){ | |
return upgrade("shield") | |
}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() | |
} | |
} | |
function switzerland(self,others,storage){ | |
let turnsLeft=999-turn() | |
let lowestHpBots=others.sort((a,b)=>a.hp-b.hp) | |
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){ | |
return attack(lowestHpBots[0].uid) | |
} else if(self.shield<=50||self.shield<=4500/others.length&&self.shield<=500&&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() | |
} | |
} | |
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() | |
} | |
} | |
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(); | |
} | |
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); | |
} | |
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(); | |
} | |
} | |
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); | |
} | |
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; | |
} | |
function serialKiller(self,others,storage){ | |
let turnsLeft=999-turn() | |
if(self.shield<50){ | |
return shield() | |
} else if(self.gold>=cost(self.levels.attack)&&turnsLeft>20){ | |
return upgrade("attack") | |
}else if(self.gold>=cost(self.levels.shield)&&self.levels.shield<=4&&turnsLeft>20){ | |
return upgrade("shield") | |
}else{ | |
return attack(others.sort((a,b)=>a.hp-b.hp)[0].uid) | |
} | |
} | |
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 | |
} | |
} | |
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]; | |
} | |
function farmhealBot(me, others, storage) { | |
if (me.hp <= 95) | |
return heal(); | |
else return farm(); | |
} | |
function killStealer(me, others, storage) { | |
let t = turn(); | |
if (t===1) { | |
storage.worth = 0; | |
storage.pHP = 100; | |
storage.pGold = 0; | |
storage.bad = {}; | |
for (let o of others) storage.bad[o.uid] = 0; | |
} | |
let hp = me.hp; | |
let gold = me.gold; | |
let shld = me.shield; | |
let lHeal = me.levels.heal; | |
let lFarm = me.levels.farm; | |
let lShld = me.levels.shield; | |
let lAtck = me.levels.attack; | |
let healPower = lHeal + 5; | |
let shldPower = lShld*1.5 + 5; | |
let farmPower = lFarm*2 + 5; | |
let atckPower = lAtck*1.25 + 5; | |
let attacked = storage.pHP-hp > 2; | |
storage.pHP = hp; | |
if (gold > storage.pGold) storage.worth+= gold-storage.pGold; | |
if (gold-storage.pGold > farmPower+5) storage.lastAtck = -10; | |
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 (storage.dead !== undefined) { | |
if (!others.some(c=>c.uid == storage.dead)) { | |
for (let o of others) { | |
if (o.worth >= pOthers[o.uid]+storage.deadWorth) storage.bad[o.uid]++; | |
} | |
} | |
// else console.log("I MISJUDGED"); | |
storage.dead = undefined; | |
} | |
let maxdmg = others.map(c=>c.attack).reduce((a, b) => Math.max(a, b))*1.25 + 5; | |
if (t > 2) { | |
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 <= 0 && o.worth > farmPower) { | |
storage.dead = o.uid; | |
storage.deadWorth = o.worth; | |
return attack(o.uid); | |
} | |
if (o.hp - maxdmg - atckPower <= 0 && o.worth > farmPower) { | |
storage.deadWorth = o.worth; | |
return attack(o.uid); | |
} | |
if (o.hp < 70 && o.hp - maxdmg*2 - atckPower <= 0) { | |
let maxBad = others.map(c => storage.bad[c.uid]).reduce((a, b) => Math.max(a, b)); | |
let bad = others.filter(c => storage.bad[c.uid] >= maxBad/2).reduce((a, b) => a.worth>b.worth? a : b); | |
return stun(bad.uid); | |
} | |
} | |
} | |
if (others.length == 1 && others[0].worth < storage.worth && attacked) return stun(others[0].uid); // stun-lock hehe | |
if (t === 1) return upgrade("shield"); | |
if (t === 2) return shield(); | |
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(); | |
if (gold>=cost(lFarm) && lShld+2 > lFarm) return upgrade("farm"); // farm first, but make sure it doesn't get too far ahead | |
if (gold>=cost(lShld) && t>20 && (lShld<10 || lShld+5 < lFarm)) 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+2 < lFarm && lHeal<10 || 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(); | |
if (lShld>1 && shld<lShld*50) return shield(); // we want to look impressive & terrifying | |
if (hp<=100-healPower) return heal(); | |
if (gold >= cost(lAtck) && (lAtck+5 < lFarm)) return upgrade("attack"); // upgrade attack when it's cheap at the start, we wouldn't be able to do much anyways | |
return farm(); | |
} | |
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(); | |
} | |
} | |
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(); | |
} | |
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(); | |
} | |
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(); | |
} | |
} | |
} | |
} | |
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 maxAttack = 0; | |
for (var i = 0; i < others.length; i++) if (1.25 * others[i].attack + 5 > maxAttack) maxAttack = 1.25 * others[i].attack + 5; | |
var storageIndex; | |
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; | |
} | |
} | |
var isUrgent = false; | |
for (var i = 0; i < others.length; i++) if (others[i].hp <= maxAttack) { | |
isUrgent = true; | |
maxProfitTurn = others[i].worth / 2; | |
victimID = others[i].uid; | |
} | |
if (maxProfitTurn > (2 * me.levels.farm + 5) && (maxProfitTurn > me.gold || isUrgent)) { | |
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() < 100 / (me.hp + me.shield)) { | |
storage.lastHP += 1.5 * me.levels.shield + 5; | |
return shield(); | |
} | |
} | |
else { | |
if (Math.random() < .5 || me.hp + me.shield - storage.hisAttack - maxAttack <= 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(); | |
} | |
function captFarmer(me, others, storage) { | |
if (!storage.mode) | |
storage.mode = "prep"; | |
var weak = others.find(el => el.hp < me.levels.attack * 1.25 + Math.max(...others.map(el => el.attack)) * 1.75 + 10 && Math.ceil(el.worth / 2) > me.levels.farm * 2 + 5); | |
if (weak && storage.weak >= 0) { | |
storage.weak += 1; | |
return attack(weak.uid); | |
} | |
if (storage.weak < 0) | |
storage.weak += 1; | |
else if (storage.weak > 3) | |
storage.weak = -3; | |
else if (!storage.weak) | |
storage.weak = 0; | |
if (me.hp + me.shield < 90) | |
storage.mode = "lowhp"; | |
if (storage.mode == "prep") { | |
if (turn() < 5) | |
return shield(); | |
if (turn() == 5) | |
return upgrade("attack"); | |
if (turn() == 6) | |
return upgrade("attack"); | |
storage.modeTimer = 0; | |
storage.mode = "farm"; | |
} else if (storage.mode == "lowhp") { | |
let last = storage.lastHp; | |
let hp = me.hp + me.shield; | |
storage.lastHp = hp; | |
if (!last) | |
return shield(); | |
if (me.hp == 100) { | |
if (me.shield >= 25) { | |
storage.mode = "farm"; | |
storage.modeTimer = 0; | |
} | |
return shield(); | |
} | |
if (last > hp) { | |
if (last - hp + me.levels.heal + 5 <= me.levels.shield * 1.5 + 5) | |
return shield(); | |
else | |
return farm(); | |
} else { | |
return shield(); | |
} | |
} else if (storage.mode == "farm") { | |
if (me.gold >= cost(me.levels.shield)) | |
return upgrade("shield"); | |
if (me.gold >= cost(me.levels.farm)) | |
return upgrade("farm"); | |
if (me.gold >= cost(me.levels.attack)) | |
return upgrade("attack"); | |
if (me.hp > 80 && !storage.healMode) | |
return farm(); | |
storage.healMode = true; | |
if (me.hp < 97) | |
return heal(); | |
storage.healMode = false; | |
return shield(); | |
} | |
return shield(); | |
} | |
function barbarianMan(me, others, storage) { | |
if (!storage.mode) { | |
storage.mode = "prep"; | |
storage.prep = 0; | |
} | |
if (me.hp + me.shield < 100) | |
storage.mode = "lowhp"; | |
var weak = others.find(el => el.hp < me.levels.attack * 1.25 + Math.max(...others.map(el => el.attack)) * 2.5 + 10 && Math.ceil(el.worth / 2) >= 5); | |
if (weak && storage.weak >= 0) { | |
storage.weak += 1; | |
return attack(weak.uid); | |
} | |
if (storage.weak < 0) | |
storage.weak += 1; | |
else if (storage.weak > 3) | |
storage.weak = -3; | |
else if (!storage.weak) | |
storage.weak = 0; | |
if (storage.mode == "prep") { | |
storage.prep += 1; | |
if (storage.prep < 3) | |
return upgrade("shield"); | |
if (storage.prep < 7) | |
return shield(); | |
if (storage.prep < 10) | |
return farm(); | |
if (storage.prep < 11) | |
return heal(); | |
if (storage.prep < 13) | |
return farm(); | |
if (storage.prep < 14) | |
return heal(); | |
if (storage.prep < 16) | |
return upgrade("attack"); | |
storage.mode = "kill"; | |
} else if (storage.mode == "lowhp") { | |
if ((me.hp + me.shield) > 150) { | |
if (me.hp >= 95) | |
storage.mode = "kill"; | |
return heal(); | |
} | |
return shield(); | |
} else if (storage.mode == "kill") { | |
if (!storage.badTargs) { | |
storage.badTargs = []; | |
storage.testHp = []; | |
} | |
storage.lastHp = null; | |
if (me.gold >= cost(me.levels.attack) && me.levels.attack < 5) | |
return upgrade("attack"); | |
if (me.gold >= cost(me.levels.shield)) | |
return upgrade("shield"); | |
if (me.gold >= cost(me.levels.farm)) | |
return upgrade("farm"); | |
if (storage.gTarg && attack(storage.gTarg)[0]) | |
return attack(storage.gTarg); | |
if (storage.test == "attack1" && attack(storage.tTarg)[0]) { | |
storage.test = "attack2"; | |
storage.testHp[0] = others.find(el => el.uid == storage.tTarg).hp; | |
return attack(storage.tTarg); | |
} | |
if (storage.test == "attack2" && attack(storage.tTarg)[0]) { | |
storage.test = "exam"; | |
storage.testHp[1] = others.find(el => el.uid == storage.tTarg).hp; | |
return attack(storage.tTarg); | |
} | |
if (storage.test == "exam" && attack(storage.tTarg)[0]) { | |
if (storage.testHp[1] - storage.testHp[0] > 3) { | |
storage.gTarg = storage.tTarg; | |
storage.test = null; | |
} else { | |
storage.badTargs.push(storage.tTarg); | |
storage.test = null; | |
} | |
return heal(); | |
} | |
let targs = []; | |
let scores = []; | |
for (let o, i = 0; i < others.length; i++) { | |
o = others[i]; | |
if (storage.badTargs.includes(o.uid)) | |
continue; | |
targs.push(o.uid); | |
scores.push((-(o.worth ** 2) / 5000 + 4 * (o.worth) / 15) / o.hp); | |
} | |
if (!targs.length) | |
storage.mode = "farm"; | |
storage.tTarg = targs[scores.indexOf(Math.max(...scores))]; | |
storage.test = "attack1"; | |
return heal(); | |
} else if (storage.mode == "farm") { | |
if (me.gold >= cost(me.levels.shield)) | |
return upgrade("shield"); | |
if (me.gold >= cost(me.levels.farm)) | |
return upgrade("farm"); | |
if (me.hp > 80 && !storage.healMode) | |
return farm(); | |
storage.healMode = true; | |
if (me.hp < 97) | |
return heal(); | |
storage.healMode = false; | |
return shield(); | |
} | |
return shield(); | |
} | |
function TheHalfHalf(me, others, storage){ | |
if (turn() == 0) { | |
return upgrade("heal"); | |
} | |
if(turn() % 2 == 0) { | |
if(me.hp <= 50 - (me.levels.heal + 5)){ | |
return heal() | |
} else { | |
if(me.gold >= cost(me.levels.farm)){ | |
return upgrade("farm") | |
} else { | |
return farm(); | |
} | |
} | |
} else { | |
if(me.hp <= 50){ | |
return shield(); | |
} else { | |
return attack(others[Math.floor(Math.random() * Math.floor(others.length))].uid); | |
} | |
} | |
} | |
function TeacherBot(self, others, storage){//10979.913 | |
var maxAtk = others.map(c=>c.attack).reduce((a, b) => Math.max(a, b)); | |
var maxDmg = maxAtk * 1.25 + 5; | |
var myDmg = self.levels.attack * 1.25 + 5; | |
var potential_victim = others.find( bot => bot.hp <= Math.max(maxDmg, myDmg) ); | |
if (potential_victim) { | |
return attack(potential_victim.uid); | |
} | |
let turnsLeft=999-turn() | |
if(self.shield<50 && turn() > 5){ | |
return shield() | |
}else if(self.gold>=cost(self.levels.attack)&&turnsLeft>20){ | |
return upgrade("attack") | |
}else if(self.gold>=cost(self.levels.shield)&&self.levels.shield<=4&&turnsLeft>50){ | |
return upgrade("shield") | |
}else{ | |
return attack(others.sort((a,b)=>b.attack-a.attack)[0].uid) | |
} | |
} | |
var botData = [ | |
{ | |
name: "justFarm", | |
debug: 0, | |
run: justFarm | |
}, | |
{ | |
name: "undyableBot", | |
debug: 0, | |
run: undyableBot | |
}, | |
{ | |
name: "Unkillable", | |
debug: 0, | |
run: UnkillableBot | |
}, | |
{ | |
name: "scavengerBot", | |
debug: 0, | |
run: scavengerBot | |
}, | |
{ | |
name: "bullyBot", | |
debug: 0, | |
run: bullyBot | |
}, | |
{ | |
name: "indestructible", | |
debug: 0, | |
run: indestructible | |
}, | |
{ | |
name: "SniperBot", | |
debug: 0, | |
run: sniperBot | |
}, | |
{ | |
name: "Optimist", | |
debug: 0, | |
run: Optimist | |
}, | |
{ | |
name: "BullyDozerBot", | |
debug: 0, | |
run: BullyDozerBot | |
}, | |
{ | |
name: "Friendly bot", | |
debug: 0, | |
run: menShengFaDaCai | |
}, | |
{ | |
name: "SmartFarmer", | |
debug: 0, | |
run: smartFarmer | |
}, | |
{ | |
name: "PacifistBot", | |
debug: 0, | |
run: pacifistWinnerBot | |
}, | |
{ | |
name: "FizzBuzz", | |
debug: 0, | |
run: FizzBuzz | |
}, | |
{ | |
name: "CampBot", | |
debug: 0, | |
run: campBot | |
}, | |
{ | |
name: "Switzerland", | |
debug: 0, | |
run: switzerland | |
}, | |
{ | |
name: "Guardian", | |
debug: 0, | |
run: guardian | |
}, | |
{ | |
name: "The Equalizer", | |
debug: 0, | |
run: equalizer | |
}, | |
{ | |
name: "Moody", | |
debug: 0, | |
run: Moody | |
}, | |
{ | |
name: "The Opportunist", | |
debug: 0, | |
run: Opportunist | |
}, | |
{ | |
name: "Kill Bot", | |
debug: 0, | |
run: killBot | |
}, | |
{ | |
name: "Bandit", | |
debug: 0, | |
run: Bandit | |
}, | |
{ | |
name: "Serial Killer", | |
debug: 0, | |
run: serialKiller | |
}, | |
{ | |
name: "Rando", | |
debug: 0, | |
run: Rando | |
}, | |
{ | |
name: "Mort", | |
debug: 0, | |
run: Mort | |
}, | |
{ | |
name: "FarmHeal Bot", | |
debug: 0, | |
run: farmhealBot | |
}, | |
{ | |
name: "Kill Stealer", | |
debug: 0, | |
run: killStealer | |
}, | |
{ | |
name: "ScaredBot", | |
debug: 0, | |
run: ScaredBot | |
}, | |
{ | |
name: "PatientStrategistBot", | |
debug: 0, | |
run: PatientStratgistBot | |
}, | |
{ | |
name: "Kill Assist", | |
debug: 0, | |
run: KillAssist | |
}, | |
{ | |
name: "ThanosBot", | |
debug: 0, | |
run: ThanosBot | |
}, | |
{ | |
name: "The Accountant", | |
debug: 0, | |
run: accountant | |
}, | |
{ | |
name: "captFarmer", | |
debug: 0, | |
run: captFarmer | |
}, | |
{ | |
name: "barbarianMan", | |
debug: 0, | |
run: barbarianMan | |
}, | |
{ | |
name: "TheHalfHalf", | |
debug: 0, | |
run: TheHalfHalf | |
}, | |
{ | |
name: "TeacherBot", | |
debug: 0, | |
run: TeacherBot | |
} | |
]; | |
function freeTestBotA(me, others) { | |
if (me.levels.attack < 5) { | |
if (me.gold < cost(me.levels.attack)) | |
return farm(); | |
return upgrade("attack"); | |
} | |
return attack(others[0].uid); | |
} | |
function freeTestBotB(me, others) { | |
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(); | |
} | |
//Put bot names and functions below. Set debug to 1 or 2 for event log. | |
//Just call this function to test. Errors will not stop the game. Max turns: 1000. Event logger included, set log to false to disable | |
function runGame(rounds = 1, log = true) { | |
records = []; | |
for (let i = 0; i < rounds; i++) | |
runRound(log); | |
var ids = []; | |
for (let i = 0; i < records.length; i++) | |
ids[i] = i; | |
ids = ids.sort((a, b) => records[b] - records[a]); | |
var results = "Results: "; | |
for (let b, i = 0; i < ids.length; i++) { | |
b = ids[i]; | |
results += "\n " + (i < 9 ? " " : "") + (i + 1) + ". " + botData[b].name + ": " + (records[b] / rounds); | |
} | |
console.log(results); | |
} | |
//Ignore everything under this, it's internal stuff | |
var records = []; | |
var bots = []; | |
var turns = 0; | |
var heal = () => ["heal"]; | |
var attack = bot => { | |
var index = bots.findIndex(el => el.uid == bot && el.hp > 0); | |
if (index == -1) | |
return [null, "attack", bot]; | |
return ["attack", index]; | |
}; | |
var shield = () => ["shield"]; | |
var stun = bot => { | |
var index = bots.findIndex(el => el.uid == bot && el.hp > 0); | |
if (index == -1) | |
return [null]; | |
return ["stun", index]; | |
}; | |
var farm = () => ["farm"]; | |
var upgrade = item => { | |
if (["heal", "attack", "shield", "farm"].includes(item)) | |
return ["upgrade", item]; | |
return [null, "upgrade", item]; | |
}; | |
var cost = lvl => 2.5 * (lvl ** 2) + 2.5 * lvl + 10; | |
var turn = () => turns; | |
var move = code => { | |
if (!Array.isArray(code)) | |
return "Invalid [" + code + "]"; | |
else if (code[0] == "heal") | |
return "Healed"; | |
else if (code[0] == "attack") | |
return "Attacked " + botData[code[1]].name; | |
else if (code[0] == "shield") | |
return "Shielded"; | |
else if (code[0] == "stun") | |
return "Stunned " + botData[code[1]].name; | |
else if (code[0] == "farm") | |
return "Farmed"; | |
else if (code[0] == "upgrade") | |
return "Upgraded " + code[1]; | |
else if (!code[0] && !code[1]) | |
return "Skipped"; | |
else if (!code[0] && code[1] == "attack") | |
return "Attacked unknown UID [" + code[2] + "]"; | |
else if (!code[0] && code[1] == "upgrade") | |
return "Upgraded unknown move [" + code[2] + "]"; | |
else | |
return "Unknown [" + code[0] + "]"; | |
}; | |
function runRound(log) { | |
var uids = []; | |
for (let i = 0; i < 100; i++) | |
uids[i] = i; | |
for (let j, i = 99; i > 0; i--) { | |
j = Math.floor(Math.random() * (i + 1)); | |
[uids[i], uids[j]] = [uids[j], uids[i]]; | |
} | |
for (let i = 0; i < botData.length; i++) { | |
bots[i] = { | |
uid: uids[i], | |
hp: 100, | |
gold: 25, | |
shield: 0, | |
stun: false, | |
worth: 0, | |
lvl: { | |
heal: 0, | |
attack: 0, | |
shield: 0, | |
farm: 0 | |
}, | |
storage: {} | |
}; | |
records[i] = records[i] || 0; | |
} | |
turns = 0; | |
while (bots.filter(el => el.hp > 0).length > 1 && turns < 1000) { | |
turns += 1; | |
runTurn(log); | |
} | |
} | |
function runTurn(log) { | |
var moves = []; | |
var uids = bots.filter(el => el.hp > 0).map(el => ({ | |
uid: el.uid, | |
hp: el.hp + el.shield, | |
worth: el.worth, | |
attack: el.lvl.attack | |
})); | |
for (let j, i = uids.length - 1; i > 0; i--) { | |
j = Math.floor(Math.random() * (i + 1)); | |
[uids[i], uids[j]] = [uids[j], uids[i]]; | |
} | |
for (let ls, u, m, r, b, i = 0; i < bots.length; i++) { | |
b = bots[i]; | |
b.attackers = []; | |
if (log && botData[i].debug == 1) | |
ls = JSON.stringify(b.storage); | |
if (b.hp > 0 && !b.stun) { | |
try { | |
r = botData[i].run(m = { | |
uid: b.uid, | |
hp: b.hp, | |
gold: b.gold, | |
shield: b.shield, | |
levels: { | |
heal: b.lvl.heal, | |
attack: b.lvl.attack, | |
shield: b.lvl.shield, | |
farm: b.lvl.farm | |
} | |
}, u = uids.filter(el => el.uid != b.uid), b.storage) || [null]; | |
} catch (e) { | |
console.error("Error in " + botData[i].name + ":\n" + e.stack); | |
r = [null]; | |
} | |
} else { | |
b.stun = false; | |
r = [null]; | |
} | |
if (log && botData[i].debug == 1 && b.hp > 0 && !b.stun) { | |
console.log("[" + turns + "] " + botData[i].name + ":\n Self: " + JSON.stringify(m) + "\n Others: " + JSON.stringify(u) + "\n Storage: " + ls + "\n Move: " + move(r)); | |
} | |
if (r[0] == "heal") | |
b.hp = Math.min(100, b.hp + b.lvl.heal + 5); | |
moves[i] = r; | |
} | |
for (let m, b, n, i = 0; i < moves.length; i++) { | |
m = moves[i]; | |
b = bots[i]; | |
n = botData[i].name; | |
if (log && botData[i].debug == 2 && b.hp > 0) { | |
if (b.stun) | |
console.log("[" + turns + "] " + n + ": Stunned by " + b.stun); | |
else | |
console.log("[" + turns + "] " + n + ":\n HP/SHP: " + b.hp + "/" + (b.hp + b.shield) + "\n Gold/Worth: " + b.gold + "/" + b.worth + "\n Levels: " + b.lvl.heal + "/" + b.lvl.attack + "/" + b.lvl.shield + "/" + b.lvl.farm + "\n Move: " + move(moves[i])); | |
} | |
if (!m) | |
continue; | |
if (m[0] == "attack") { | |
bots[m[1]].hp = bots[m[1]].hp - Math.max(0, b.lvl.attack * 1.25 + 5 - bots[m[1]].shield); | |
bots[m[1]].shield = Math.max(0, bots[m[1]].shield - b.lvl.attack * 1.25 - 5); | |
bots[m[1]].attackers.push(i); | |
} else if (m[0] == "stun") { | |
if (bots[m[1]].stun) | |
bots[m[1]].stun += ", " + n; | |
else | |
bots[m[1]].stun = n; | |
} else if (m[0] == "farm") { | |
b.gold += b.lvl.farm * 2 + 5; | |
b.worth += b.lvl.farm * 2 + 5; | |
records[i] += b.lvl.farm * 2 + 5; | |
b.hp -= 2; | |
if (log && b.hp < 0) | |
console.log("%c[" + turns + "] " + n + " died of overfarming", "font-weight: bold"); | |
} else if (m[0] == "upgrade" && b.gold >= cost(b.lvl[m[1]])) { | |
b.lvl[m[1]] += 1; | |
b.gold -= cost(b.lvl[m[1]] - 1); | |
} | |
} | |
for (let m, b, n, i = 0; i < moves.length; i++) { | |
m = moves[i]; | |
b = bots[i]; | |
n = botData[i].name; | |
if (m[0] == "shield") { | |
b.shield += b.lvl.shield * 1.5 + 5; | |
} | |
if (b.hp < 0) { | |
for (let a, j = 0; j < b.attackers.length; j++) { | |
a = bots[b.attackers[j]]; | |
a.gold += Math.ceil(b.worth / 2); | |
a.worth += Math.ceil(b.worth / 2); | |
records[b.attackers[j]] += Math.ceil(b.worth / 2); | |
if (log) | |
console.log("%c[" + turns + "] " + botData[b.attackers[j]].name + " killed " + n, "font-weight: bold"); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment