Gold Battle KoTH

44

Este desafío ha terminado. Para ver los puntajes finales de los competidores, haga clic aquí.

En este desafío, cada presentación es un bot. Cada bot debe ser una función Javascript. Los bots lucharán para obtener el mayor valor total en oro. El oro se puede cultivar o ganar matando a otros bots, y se usa para mejorar la curación, el ataque, el escudo y la agricultura.

Objetivo:

En una serie de rondas que contienen hasta 1000 turnos (finaliza cuando solo queda un bot), el bot con el valor total más alto (la suma de todo el oro obtenido) es el ganador.

Vueltas:

En cada turno, cada bot que esté vivo (> 0 HP) se ejecutará una vez. Puede devolver un movimiento, que puede ser uno de los siguientes:

  • Curar: recupera HP
  • Ataque: elimina HP de otro bot
  • Escudo: defiende contra ataques posteriores
  • Aturdir: se salta el siguiente turno de otro bot
  • Granja: gana oro a costa de HP
  • Actualización: mejora ciertos movimientos

Todos los bots devolverán su movimiento antes de que se ejecuten, por lo que un aturdimiento, curación, ataque, escudo, etc. no afectará a ningún bot que se mueva más tarde en ese turno. Por ejemplo, si el Bot A aturde al Bot B, y el Bot B está detrás del Bot A en el orden de turno, el Bot B aún se moverá más tarde en ese mismo turno y el aturdimiento ocurrirá en el siguiente turno.

Combate, agricultura y mejora:

Cada bot tiene un HP máximo de 100 y un UID asignado entre 0 y 99. Este UID cambia después de cada ronda, y es la forma en que los bots se siguen entre sí.

La curación es uno de los movimientos más simples, agregando una cantidad de HP determinada por su nivel (comienza en 5 HP). Un bot no puede curar más de 100 HP.

Atacar a un bot por su UID es otro movimiento posible, con un daño base de 5 HP en el nivel 0. Los bots también pueden aturdirse, omitiendo su próximo turno, que también usa UID.

Los bots tienen un escudo HP adicional, que no tiene límite. Este escudo HP absorberá el daño de los ataques directos de otros bots, y se agrega mediante escudo. En el nivel 0, el blindaje agrega 5 HP de escudo.

La agricultura ganará 5 de oro en el nivel 0, a un costo de 2 HP. Este 2 HP no se puede proteger. El único uso para el oro (más allá de ganar) es mejorar los movimientos. La curación, el ataque y la protección tienen un valor base de 5 HP, y la agricultura comienza en 5 de oro. Cada uno de esos movimientos tiene niveles individuales, que comienzan en 0. Estas fórmulas determinarán el valor en HP u oro de un movimiento, donde L es el nivel:

  • Curación: L + 5
  • Agresor: 1.25L + 5
  • Blindaje: 1.5L + 5
  • Agricultura: 2L + 5

El costo de actualizar cualquier movimiento es el mismo para cierto nivel, y está determinado por 2.5L² + 2.5L + 10dónde L es el nivel actual. Un bot puede usar la función cost(currentLevel)como un atajo para determinar esto.

Los bots comienzan con 25 de oro, lo que les permite actualizar rápidamente dos movimientos al nivel 1 o un movimiento al nivel 2. Este oro inicial no cuenta para el valor total de un bot. Matar a un bot te da la mitad de su valor total en oro, redondeado, y si dos bots matan a otro en el mismo turno, ambos obtienen la recompensa.

De entrada y salida:

Para comunicarse con el controlador, el valor de retorno de la función se utiliza para enviar información de movimiento. Uno de estos debe ser devuelto:

  • Sanar: heal()
  • Ataque: attack(uid)
  • Proteger: shield()
  • Aturdir: stun(uid)
  • Granja: farm()
  • Mejorar: upgrade("heal" / "attack" / "shield" / "farm")

Para omitir un turno (no hacer nada), no devolver nada o devolver un valor falso.

Para obtener el número de turno actual (comienza en 1), use turn().

Los argumentos de su función incluirán información sobre su bot, los UID de otros bots y el almacenamiento entre turnos. El primer argumento es un objeto con las siguientes propiedades: uid, hp, gold, y shield. Estas son copias de la información actual de su bot. También hay un objeto anidado levels, con los números de nivel de heal, attack, shield, y farm.

El segundo argumento es un conjunto aleatorio de todos los bots vivos distintos al tuyo, formateado como un objeto que contiene propiedades uid, hp(más escudo) worthy attack(nivel de ataque). El tercer argumento es un objeto vacío que se puede usar para el almacenamiento entre turnos.

Bots de ejemplo:

Este bot cultivará hasta que pueda actualizar su ataque al nivel 5, luego atacará un bot aleatorio cada turno hasta que muera (o gane). No es muy efectivo debido a la falta de curación / blindaje.

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);
}

Este bot tiene dos modos: ofensivo y defensivo. Aturdirá a un bot aleatorio o sanará cuando esté en modo defensivo, y atacará o protegerá cuando esté en modo ofensivo. Intentará actualizar sus ataques siempre que sea posible.

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();
}

Reglas:

  • Lagunas estándar prohibidas
  • Los bots no pueden leer, modificar o agregar ninguna variable fuera de su alcance, no pueden intentar hacer trampa y no pueden llamar a ninguna función DOM o definida por el controlador
  • El valor de retorno debe ser falso o una de las salidas de funciones anteriores
  • Los bots no deben diseñarse para apuntar a un bot específico, sino que pueden diseñarse para aprovechar estrategias comunes
  • Los bots no pueden atacarse a sí mismos (descubiertos debido a un comentario de @Ness)
  • Los bots deben ser suficientemente diferentes de cualquier otro bots para que puedan considerarse razonablemente entradas separadas
  • Teaming ahora no está permitido
  • El controlador se puede encontrar aquí
  • Sala de chat

Nueva depuración del controlador:

Usando el archivo gold-battle-log.js, puede establecer el valor de la debugpropiedad de un bot en botData0 (sin registro), 1 (movimientos de registro) o 2 (movimientos de registro, hp, oro, niveles, etc.)

El desafío finaliza a las 1700 UTC del viernes 9 de agosto.

Programas Redwolf
fuente
44
Creó una esencia con todos los bots. gist.github.com/Draco18s/2efbf95edcf98d6b1f264e26bbb669d1 Me esforzaré por mantenerlo actualizado (pero si no es un buen comienzo).
Draco18s
44
Controlador de actualización automática con bots incluidos: redwolfprograms.com/koth
Programas Redwolf
44
Estoy votando para cerrar esta pregunta porque ya está cerrada de facto a nuevas respuestas ("Este desafío ha terminado. Para ver los puntajes finales ...")
pppery
3
@pppery ¿No podrías? Estaría bien con respuestas no competitivas, y [closed]al final es probable que los espectadores casuales se salten la lectura de mi desafío, ya que asumirían que es de baja calidad o fuera de tema.
Programas Redwolf
55
@pppery Nunca escuché que se cerrara un desafío por haber terminado hasta hoy, y diría que la restricción social que desea aplicar ni siquiera existe. No hay necesidad de cerrarlo, y no quiero que se cierre. Para mí, eso parece cerrar por cerrar, en lugar de por el bien del sitio. Si alguien quiere publicar una respuesta a una pregunta anterior, debería poder hacerlo. No hay una nota después de la regla del contendiente serio que dice que tiene que ser un contendiente serio cuando se publica; una respuesta todavía puede ser un serio contendiente para el reto, incluso si no es un competidor para ganar
Redwolf Programas

Respuestas:

16

Invencible

bifurcado de Undyable .

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

Dados los costos exponenciales de las actualizaciones, también podríamos mejorar la agricultura si no podemos mejorar la curación, permitiendo que el bot recolecte oro de manera más eficiente.

Draco18s
fuente
Absolutamente aplastando a la competencia en mis pruebas
Programas Redwolf
1
Siento que este bot podría ser un poco más fuerte si se ifusara esa primera declaración <=, actualmente nunca se curará por completo.
Scoots
@Scoots No estoy seguro de cuánto importará, pero lo cambiaré.
Draco18s
2
@ Draco18s Estoy seguro de que importa muy poco, pero ¿este sitio no se trata de pequeñas mejoras prácticamente insignificantes? :)
Scoots
@Scoots La curación para maximizar la salud no importa mucho en este desafío porque no hay amenazas de ataque reales. El único bot verdaderamente ofensivo es el bullybot, y realmente no puedes hacer nada al respecto. En realidad, podría disminuir el rendimiento para mantenerse en plena salud.
B0RDERS
13

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();
            }
        }
    }
}

Hay demasiados bots, no hay suficiente oro para todos. Este bot propone una solución.

Genocidio, sí, pero aleatorio, desapasionado, justo para ricos y pobres por igual.

Lo llamaron loco.

ThanosBot quiere lo mejor para la comunidad de bots y está dispuesto a llegar hasta el final. Al principio, mejorará su ataque, agricultura y curación, para reunir recursos de manera más eficiente y ganar batallas. Progresivamente, comenzará a atacar a las personas al azar mientras sigue reuniendo recursos para las próximas batallas. Seguirá mejorando su ejército, sus armas y él mismo.

Una vez que el 50% de la población haya sido eliminada, los bots nacidos solo conocerán vientres llenos y cielos despejados, se retirará a una vida de agricultura y verá salir el sol en un universo agradecido. Se volverá completamente pacifista, solo se curará con sopas de verduras y agricultura.

niño Kaito
fuente
66
Estoy tentado a cambiar el nombre de "ataque" a "complemento"
Programas Redwolf
11

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();
}

¡Ahora no solo roba asesinatos, sino que también roba robos mata!

Este bot no hace mucho, excepto la granja, y cuando se da cuenta de la posibilidad, se une para dar el golpe final a un enemigo moribundo, y de alguna manera se las arregla para ser muy bueno.

dzaima
fuente
Funciona porque todos los bots involucrados en un golpe mortal obtienen la recompensa completa.
Draco18s
@ Draco18s Entiendo por qué podría ser bueno, simplemente no esperaba que una idea tan simple obtuviera en promedio el doble del puntaje del siguiente mejor bot (al momento de hacerlo).
dzaima
Jeje, eso es justo. Tendré que descargar todos los bots cuando pueda y ver si puedo encontrar otra solución.
Draco18s
9

El Equalizador

Este bot busca restaurar la paz en la comunidad bot. Ataca implacablemente a los bots con el ataque más alto, rindiéndose solo si la curación del bot es mejor que su propio ataque. Una vez que no queden bots con una curación peor que su ataque, se retirará a una vida de agricultura pacífica.

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();
}
B0RDERS
fuente
8

Optimista

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();
}

Asume que podrá pasar el 80% de su tiempo cultivando pacíficamente, por lo que comienza maximizando la agricultura y solo entonces comienza a prestar atención a sus habilidades de combate. ¡Seguramente nada saldrá mal!

histocrat
fuente
8

Asesinato

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();
}

¿Por qué actualizar el valor de ataque cuando puedes hacer daño por plink y aún así obtener crédito completo?

Una vez más volviendo a llevar a Kill Stealer. Pude simplificar varios bloques de código donde las declaraciones siempre eran verdaderas y jugar con algunos números que resultaron en ganancias masivas sobre el original.

Tengo que dárselo a @dzaima para darme cuenta de que aturdir a un oponente rico que probablemente esté involucrado en una asistencia el turno antes de que ocurra una muerte es bastante inteligente. Una de las (muy) pocas veces Stun()tiene un resultado de suma positiva. Una vez más pude mejorar la idea, ya que sabiendo que Kill Stealer ejecutará una lógica similar, Kill Assist busca un "segundo mejor" objetivo (con cierta discreción) y los aturde en su lugar.

Actualización menor para evitar aturdir al bot a punto de morir y evitar aturdir al bot que tiene más probabilidades de matar.

Resultados de muestra (top 5 truncado después de 1000 juegos)

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
Draco18s
fuente
Espera, ¿en qué mundo el Capitán Farmer obtiene 14k de oro?
Programas Redwolf
Éste:runGame(1) results: [...] captFarmer: 13768
Draco18s
Eso es bastante inesperadamente alto ... por lo general obtiene alrededor de 10k en mis pruebas
Programas Redwolf
* encogerse de hombros * No tengo idea. Haré una actualización de GIS automatizada solo para asegurar que todo esté limpio.
Draco18s
Mi bot favorito al final de la fecha límite.
Noche2
7

Bot indescriptible (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()
            }
        }        
    }   
}

Luis felipe De jesus Munoz
fuente
No te preocupes por mí ... voy a pedir prestado esto.
Draco18s
6

PacienteEstrategiaBot

Traté de escribir un bot que comience a enmarcar y defender según sea necesario y luego cambie a matar a otros bots de alto valor más adelante en el juego.

Actualmente, esto no parece funcionar correctamente ya que es asesinado por una pandilla de robots asesinos al comienzo del juego o queda atrapado en algún lugar en su modo ofensivo.

Todavía estoy bastante contento con que este sea mi primer código JS, así que ... (robé fragmentos de código de aquí y de allá porque fue más rápido que buscar en Google toda la sintaxis básica de JS)

function PatientStratgistBot(me, others, storage) {

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

        return upgrade("farm");
    }

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

    //defensive Actions

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

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

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

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

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

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

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

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


    if (turn() >= 600) {


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


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

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

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

        }

    }

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

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

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

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

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

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

        //storage.attackMode = true;


    }

    }

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

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

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

    }

    return attack(storage.targetUid)

    }



    //otherwise farm

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

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

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


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

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

}
Nicolai
fuente
6

Suiza

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()
    }
}

Como su nombre lo indica, este bot es neutral en su mayoría neutral (ahora ayuda a matar a los bots que van a morir) y solo cultiva y cura, construyendo lentamente su oro ( al igual que Suiza )

SuperStormer
fuente
6

El bot que cultiva, ataca, protege e incluso cura pero nunca aturde

(El nombre corto es TBTFASAEHBNS , que no debe confundirse con TBTPTGCBCBA )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Este bot básicamente:

  • Se acumula en la agricultura al comienzo
  • Se defiende cuando es necesario
  • Ataca cuando puede matar o cuando cree que existe la posibilidad de matar a alguien
  • Actualizaciones aquí y luego
  • Granjas el resto del tiempo
  • Nunca aturde

Edición 1: se corrigió un problema y se mejoraron algunas cosas pequeñas en el bot basadas en pruebas con muchos juegos.

Edición 2: Mejoras de escudo reducidas.

Noche2
fuente
2
Tan pronto como vi el nombre, supe que sería su bot (:
Programas Redwolf
Lamento los nombres largos, ¡pero soy adicto a ellos!
Noche2
1
Tal vez sea una señal de un buen robot ... mis pruebas muestran que está en el quinto lugar
Programas Redwolf
5

SniperBot

Este bot solo será efectivo si alguien comienza a agregar bots que realmente atacan de forma regular. SmartFarmer es mi solución optimizada actual

  1. cura si puede obtener un disparo
  2. cura si es menor de 30
  3. ataca al bot si puede recogerlo y ganar más dinero que la agricultura
  4. mejora la agricultura si puede permitirse
  5. mejora la curación si tiene menos de 80 de salud y puede pagar
  6. granjas

los buitres no necesitan un ataque

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();
}
B0RDERS
fuente
Identificador inesperado ( int) en la línea 2. ReferenceError: el estado no está definido.
Draco18s
Debe ser me.hp?
mbomb007
lo siento. nuevo en javascript. gracias por la ayuda
B0RDERS
Se if(me.hp <30 && ...)podría simplificar a la primera cláusula debido a la necesidad de un nivel absurdo de curación para que
tenga
@Veskah Gracias por señalar eso. Eso fue un remanente de cuando el CV mínimo era mayor
B0RDERS
5

BullyDozerBot

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

Mashup de BullyBot y algunos otros bits. Optimist tenía un corto y dulce trozo de ataque oportunista que yo hice (aunque otros bots hacen cálculos similares).

En lugar de intimidar al objetivo aturdiéndolo, lo asesina por su dulce, dulce botín. También se dirige a los más débiles de la manada por intimidación, pero se dará por vencido e irá a la agricultura si el HP del objetivo más débil es demasiado alto.

Draco18s
fuente
te estás cultivando hasta la muerte. Aceptar mi edición :)
B0RDERS
1
@ AndrewBorders Ha, ni siquiera lo pensé. Gracias.
Draco18s
Este bot fue genial hasta que aparecieron esos bots protectores.
B0RDERS
@ B0RDERS Shield es muy fuerte, incluso si pierde tiempo.
Draco18s
5

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);
}

Mayormente ofensivo bot. Extremadamente molesto por el hecho de que no puede realmente FizzBuzz, por lo que solo zumba enojado. Cuando no es efervescente o zumbido, se dispara a otro bot durante 30 turnos y se da por vencido y elige otro bot para apuntar si no está progresando.

Realiza extraordinariamente inconsistente. No importa, actualizó el controlador, ahora parece estar siempre a la mitad del paquete.

Transformada de Fourier de Rin
fuente
Me gusta este concepto Independientemente de la situación actual, sigue avanzando a su propio ritmo.
Ness
5

bullyBot

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

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

    return stun(storage.bullyTarget);
}

Pruébalo en línea!

Puede que no gane, pero ciertamente hará todo lo posible para asegurarse de que su objetivo tampoco lo haga. bullyBot también trabaja en el primer turno para que si no hay influencia externa, superará a su objetivo 5-0 o los empatará 5-5.

Veskah
fuente
5

JustFarm

Pensé que comenzaría simple.

function justFarm(me, others){
    return farm();
}
Anónimo
fuente
13
Este bot se suicidará debido al costo de 2HP de la agricultura.
Draco18s
@ Draco18s Aunque la ronda puede terminar antes de eso, dependiendo del número de bots
Programas Redwolf
1
Aunque técnicamente es cierto, un temporizador de 50 rondas es muy muy corto cuando el tiempo de finalización predeterminado es 1000.
Draco18s
Venció a los dos bots de ejemplo, pero ahora hay algunas presentaciones más que podría intentar encontrar algo mejor.
Anónimo
@ Anónimo Quizás sea suficiente incluir actualizaciones de curación y agricultura. Dado que obtener la mayor cantidad de oro es el objetivo final, mantenerlo como el trabajo principal del bot podría funcionar. Hasta ahora no ha habido bots que tengan "modos" como el modo de curación y el modo de granja, podría ser un enfoque interesante
Redwolf Programs
4

ScavengerBot (V2)

Me di cuenta de que no era un carroñero antes. La nueva estrategia es esperar hasta que pueda matar a otro bot. Si nadie puede ser asesinado, se sienta y acumula escudo.

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();
}
reffu
fuente
1
me.levels.attacl?
Draco18s
Buena captura, arreglada
refu
4

temperamental

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);   
}

La estrategia predeterminada de Moody's es mejorar la agricultura y la curación por un tiempo, luego eliminar a los otros bots en orden descendente de valor. Sin embargo, si es atacado, se asustará y se centrará en la curación por un tiempo. Si ataca y "falla", porque la víctima se estaba curando o protegiendo más efectivamente que el ataque, se enojará y se irá para mejorar sus habilidades de ataque.

histocrat
fuente
4

Bandido

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;
}

Primer intento de un robot de aprendizaje de refuerzo. Puramente defensivo por ahora para reducir el espacio de búsqueda. Una especie de spin-off más inteligente de FizzBuzz: repite una serie específica de cinco acciones una y otra vez; Las cinco acciones son las elegidas por RL.

Pero por ahora se basa principalmente en la enumeración: acabo de generar las 3 ^ 5 = 243 permutaciones de series de cinco acciones defensivas que se repitieron una y otra vez, y almacenaron sus puntajes promedio (dividido por 200, para obtener el aumento promedio sobre cinco turnos) más de 100 iteraciones en la storage.priormatriz. Luego, durante el juego, implementa un enfoque codicioso de epsilon para actualizar esas listas de puntajes para que esté más preparado para el futuro. (También porque usar epsilon = 0.3 fue mucho mejor que epsilon = 0.1, así que simplemente lo guardé).

Lo hace bien, colocando constantemente entre scavengerBot y Optimist. Actualmente estoy entrenando un poco más en juegos reales, y estoy buscando mejores formas de enmarcar la estrategia, para ver si puedo mejorarla.

Transformada de Fourier de Rin
fuente
4

El oportunista

Este toma prestado un poco de algunos otros (notablemente ScavengerBot (V2) e Unkillable) ya que tenían las mismas ideas que tenía en mente, pero en general me gustan más los estilos bien redondeados y todo en vez de centrarme solo en una o dos cosas Esto probablemente significará que no ganaré, pero debería estar en el medio en algún lugar (lo que me sucede la mayoría del tiempo en muchas cosas).

Entonces roba asesinatos jugosos; cura si es necesario; mejora la granja, ataca y sana en ese orden; y granjas de lo contrario.

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();
    }
}
Ness
fuente
1
El segundo argumento debería serothers
SuperStormer
4

ScaredBot

  1. Encuentra otros bots:
    • con el mayor ataque
    • con más riqueza y HP más bajo que el propio ataque
  2. Si su escudo HP + es más bajo que el encontrado highest attack * (25% of bots), o se acerca al extremo inferior de HP + shield, entonces protege
  3. Si encuentra un bot con un escudo más bajo que su propio ataque, lo ataca.
  4. Si su salud es < 50, sana.
  5. Si puede mejorar cualquiera de los escudos, curar y cultivar, actualiza el que tenga el nivel más bajo
  6. Cultiva
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();
    }
}

La idea es mantenerse con vida el mayor tiempo posible e intentar obtener oro de una manera segura y económica para poder actualizar.

Las prioridades de actualización probablemente deberían modificarse, así como la condición al determinar si se debe proteger.

usuario24343
fuente
3

SmartFarmer

Granjas, mejora la agricultura, sana si tiene poca salud. La agricultura parecía dominada hasta que llegaron los bots realmente ofensivos. Ahora mi bot es asesinado :-(

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();
}
B0RDERS
fuente
1
Estaba probando (manualmente) esencialmente la misma estrategia para ver cuál es el valor máximo obtenible y los mejores números que pude obtener, se retrasó ligeramente cuando se actualizó la curación (usé oro> = costo * 2) y subí a lvl10 curación .
Nicolai
Ese multiplicador de precios es una buena idea. Agregué algo similar. Me interesaría ver qué números tienes
B0RDERS
3

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];
}

Cada turno, compara el beneficio amortizado de matar a cada bot con el de la agricultura y la curación y elige la mejor opción. Realmente debería usar el estado para determinar cuánto tiempo tomará matar a un bot, pero por ahora solo supone que cada bot cura o protege un promedio de 5 puntos por turno neto de daño que otros bots hacen.

histocrat
fuente
3

Bot amigable

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].hpes en hp + shieldlugar de hp...

tsh
fuente
44
¿Alguien puede ayudarme a traducir el nombre de la función al inglés? ^ _ ^
tsh
44
Según el traductor de Google, "闷声 发大财" significa "amortiguado". Estoy bastante seguro de que eso no es lo que quieres y de hecho es otra falla épica del Traductor de Google ... Busqué más y todos los resultados parecen mencionar que no hay una sola palabra en inglés que se pueda usar aquí, por lo que sería mejor mantenerla como es, en realidad, ya que parece ser una preposición china que generalmente significa que uno debe trabajar en silencio y dejar que los resultados hablen por sí mismos y logren una filosofía tradicional. Desafortunadamente, no sé chino para traducirlo directamente. : D
Erik the Outgolfer
1
como hablante nativo de chino, significa algo así como "hacer una gran fortuna en silencio": v 闷声 también connota intencionalmente ser silencioso, literalmente "encubriendo el sonido"
transformada de Fourier de Rin el
1
¿Furtivo? ¿Bajo el radar? DontMindMe? ¿Atención Deflector?
Peter Taylor
3

El contador

Este práctico bot calcula el movimiento más beneficioso económicamente, pero le gusta mantener bajo su perfil de ataque para evitar problemas de todos los bots vigilantes. Él no trata de elegir ayudar a los indefensos o aprovecharse de ellos. Más bien, hace lo que más le ayuda.

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();
}
B0RDERS
fuente
3

realmenteCompettedTurtle

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();
}

Aquí está la cosa. Se ha vuelto realmente peligroso por ahí. La agricultura aumenta tu valor, convirtiéndote en un objetivo. Así que no es seguro cultivar hasta que hayas construido un escudo enorme y toda la violencia haya desaparecido. Entonces puedes sacar tu cabeza de tu caparazón y comenzar a cultivar. O asesinando. Lo que sea mejor paga

histocrat
fuente
2

guardián

Puedo tener más de una presentación, ¿verdad?

Un tenedor de CampBot. No protege, sino que se centra en atacar. Muestra una preferencia por atacar a jugadores con estadísticas de ataque más altas, en lugar de atacar al azar como CampBot. Se enfoca en mejorar su agricultura en lugar de curarlo.

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()
    }
}
Anónimo
fuente
mi bot no ataca al azar ...
SuperStormer
Puedes publicar tantas veces como quieras, cuanto más mejor, supongo
Redwolf Programs
@SuperStormer Me doy cuenta de que el tuyo no es completamente aleatorio, pero:let victim=potentialVictims[Math.floor(Math.random()*potentialVictims.length)]
Anónimo
pero primero filtra los que no vale la pena atacar
SuperStormer
Estaba trabajando en un bot similar llamado ecualizador cuando publicaste esto. Todavía lo estoy afinando, pero me gustan algunas de sus ideas.
B0RDERS
2

Rando

Este tipo tonto elegirá acciones basadas en aleatoriedad uniforme con algunos prejuicios. Si una acción elegida al azar no funciona, entonces se despliega a la siguiente opción.

Entonces, en promedio, debería atacar casi 2/9 de las veces y cultivar casi 3/9 de las veces. El resto tiene una probabilidad de aproximadamente 1/9 si es capaz de actualizar, o si la curación / protección lo vale, etc.

Probablemente no tendrá un buen desempeño, pero al menos hay una pequeña posibilidad de que él reine supremo. Y ese es todo el propósito de Rando. ¡Solo necesita creer en sí mismo! Todas las opciones se ponen delante de él. Solo necesita elegir lo que se necesita para una situación dada.

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
    }
}

(Sé que "default" es innecesario, pero creo que es una buena práctica de codificación para código robusto).

Ness
fuente
2
"Solo necesita creer en sí mismo" ... Me estoy riendo mucho en este momento
Programas Redwolf
2

Matar 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);
}

Un bot simple, Kill Bot solo quiere matar a sus enemigos. Dado que el escudo es mucho más eficiente que la curación (especialmente cuando está nivelado), Kill Bot solo trata de ser siempre un objetivo poco atractivo al protegerse cada vez que es atacado. Kill Bot funciona bastante bien entre los robots débiles y pacifistas de por aquí (puedes sentir su desprecio por ellos).

Spitemaster
fuente
3
Tenga en cuenta que o.attackes el nivel de ataque, no su daño
Programas Redwolf
2

FarmHeal Bot

Bifurcado del bot de @Anonymous 'JustFarm

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

Indestructible

Una modificación del bot de Draco18, usando escudos (más efectivo contra otros 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();
        }
    }
}
Programas Redwolf
fuente