Simple Race KoTH

Aug 25 2020

Questa sfida è ufficialmente terminata. Ulteriori proposte non saranno competitive (ma sono comunque benvenute!). Visualizza i punteggi qui

In questa sfida, gli invii ("bot") dovrebbero essere funzioni Javascript che cercano di vincere il maggior numero di gare possibile. In ogni gara, i bot avranno una quantità limitata di energia che dovrebbe essere utilizzata per viaggiare il più rapidamente possibile su una distanza di 100 unità.

Meccanica

Ogni partita consisterà in un numero di gare, che si compongono di un numero di turni. In ogni turno, i bot sceglieranno una distanza non negativa da percorrere in avanti. La quantità di energia consumata è uguale al quadrato della distanza percorsa (e i robot viaggeranno solo fino a quando il loro livello di energia lo consente se tornano a una distanza maggiore).

All'inizio di ogni gara, le posizioni dei bot vengono ripristinate a 0. Una volta che uno o più bot raggiungono una distanza di 100 unità, la corsa terminerà. Nota che se un bot restituisce una distanza che lo collocherebbe a più di 100 unità dall'inizio, si muoverà solo per quanto gli serve per vincere. All'inizio di tutte le gare, i bot riceveranno 100 energia in aggiunta a quella rimanente dell'ultima gara. Riceveranno anche un bonus di 1 energia per ogni unità che hanno viaggiato nella gara precedente.

Punti

Alla fine di ogni gara, tutti i bot riceveranno un punto per ogni dieci unità che hanno viaggiato al termine del gioco (comprese le frazioni di punto). Alla fine di una partita, vince il bot con il maggior numero di punti.

Poiché è probabile che i bot saranno ottimizzati per un certo numero di gare, ci saranno 5 categorie in cui tutti i bot competeranno: 250 gare, 750 gare, 2500 gare, 7500 gare e 25000 gare. Il punteggio complessivo di un bot sarà la somma del punteggio medio per gara in ciascuna di queste categorie, ottenendo il punteggio più alto possibile 50.

Input Output

I bot riceveranno i seguenti argomenti: dist(la distanza che hanno percorso nella gara in corso), energy(la quantità di energia che hanno), bots(una matrice delle distanze di tutti gli altri robot alla fine dell'ultimo turno, mescolata al fine di ogni gara) e storage, che per impostazione predefinita è un oggetto vuoto e può essere utilizzato per memorizzare le informazioni tra le razze.

Bot di esempio

Il follower proverà a stare al passo con il bot medio, della quantità media spostata per turno.

{
    "Follower": function(dist, energy, bots, storage) {
        storage.turns = storage.turns || 0;

        if (Math.max(...bots))
            storage.avg = ((storage.avg || 0) * storage.turns++ + bots.reduce((a, b, i) => a + (b - storage.last[i]), 0) / bots.length) / storage.turns;

        storage.last = bots;

        return (bots.reduce((a, b) => a + b, 0) / bots.length + (storage.avg || 1)) - dist;
    }
}

Controller

// Each bot should be placed in this object

var bot_data = {
    "Follower": function(dist, energy, bots, storage) {
        storage.turns = storage.turns || 0;

        if (Math.max(...bots))
            storage.avg = ((storage.avg || 0) * storage.turns++ + bots.reduce((a, b, i) => a + (b - storage.last[i]), 0) / bots.length) / storage.turns;

        storage.last = bots;

        return (bots.reduce((a, b) => a + b, 0) / bots.length + (storage.avg || 1)) - dist;
    }
};

var games = 0;
var records = {};

// races: Number of races
// log: Array of bot names to log information about, or null for no logging
//   Per-turn logging will only happen in games with less than 10 races
//   Per-race logging will only happen in games with less than 100 races
// bold: Whether to use bold text when logging information

var run_game = function(races, log = [], bold = true) {
    var perf_now = performance.now();
    
    var bots = [];
    
    games++;

    for (let bot in bot_data)
        bots.push({
            name: bot,
            run: bot_data[bot]
        });

    var uids = new Array(bots.length);

    for (let i = 0; i < uids.length; i++)
        uids[i] = i;

    var race = 0;
    var turn = 0;

    for (let r = 0; r < races; r++) {
        race++;

        for (let j, i = 0; i < uids.length; i++) {
            j = Math.random() * (i + 1) | 0;
            [uids[i], uids[j]][uids[j], uids[i]];
        }

        for (let b, i = 0; i < bots.length; i++) {
            b = bots[i];

            bots[i] = {
                name: b.name,
                run: b.run,

                uid: uids[i],
                dist: 0,
                energy: (b.energy || 0) + 100,
                points: b.points || 0,

                storage: b.storage || {},

                next: 0,
                inactive: 0
            };
        }

        turn = 0;

        while ((bots.every(b => b.dist < 100) && bots.some(b => b.energy > 0 && b.inactive < 3))) {
            turn++;

            for (let b, i = 0; i < bots.length; i++) {
                b = bots[i];

                try {
                    b.next = b.run(
                        b.dist, b.energy,
                        bots.filter(o => o.uid != b.uid).map(o => o.dist),
                        b.storage
                    );

                    if (log && log.includes(b.name) && races < 10)
                        console.log("[" + race + ":" + turn + "] " + b.name + "(" + (Math.round(b.dist * 1000) / 1000) + "," + (Math.round(b.energy * 1000) / 1000) + "):", b.next);
                } catch(e) {
                    if (log && races < 10)
                        console.warn("[" + race + ":" + turn + "] " + b.name + ":\n" + (e.stack || e.message));

                    b.next = 0;
                }

                b.next = Number(b.next);

                if (Number.isNaN(b.next))
                    b.next = 0;

                b.next = Math.max(Math.min(b.next, 100 - b.dist, Math.sqrt(b.energy)), 0);

                if (!b.next)
                    b.inactive++;
            }

            for (let b, i = 0; i < bots.length; i++) {
                b = bots[i];

                b.dist += b.next;
                b.energy = Math.max(b.energy - b.next ** 2, 0);
            }
        }

        for (let b, i = 0; i < bots.length; i++) {
            b = bots[i];

            b.energy = b.energy + b.dist;
            b.points += b.dist / 10;
        }

        if (log && races < 100)
            console.log(
                (bold ? "%c" : "") + "Race " + race + ":\n" +
                (bold ? "%c" : "") + bots.map(b => b).sort((a, b) => b.dist - a.dist).map(
                    b => b.name.slice(0, 16) + " ".repeat(20 - Math.min(b.name.length, 16)) + (Math.round(b.dist * 1000) / 10000)
                ).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
            );
    }

    for (let i = 0; i < bots.length; i++)
        records[bots[i].name] = (records[bots[i].name] || 0) + bots[i].points / races;
    
    if (log)
        console.log(
            (bold ? "%c" : "") + "Average Points/Race (" + races + " races, " + (Math.ceil((performance.now() - perf_now) * 1000) / 1000) + "ms):\n" +
            (bold ? "%c" : "") + bots.sort((a, b) => b.points - a.points).map(
                b => b.name.slice(0, 16) + " ".repeat(20 - Math.min(b.name.length, 16)) + (Math.round((b.points / races) * 10000) / 10000)
            ).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
        );
};

// Print and clear records for average scores

var print_records = function(bold = true) {
    console.log(
        (bold ? "%c" : "") + "Sum of Average Points/Game:\n" +
        (bold ? "%c" : "") + Object.entries(records).sort((a, b) => b[1] - a[1]).map(
            b => b[0].slice(0, 16) + " ".repeat(20 - Math.min(b[0].length, 16)) + (Math.round(b[1] * 10000) / 10000)
        ).join("\n"), ...(bold ? ["font-weight: bold;", ""] : [])
    );
};

var clear_records = function() {
    records = {};
};

// Default race categories

run_game(250);
run_game(750);
run_game(2500);
run_game(7500);
run_game(25000);

print_records();

Regole

  • Se nessun robot si è mosso per tre turni di fila, una gara terminerà (i punteggi verranno comunque conteggiati)

  • Se un bot commette errori, perderà un turno (cioè non si muoverà)

  • I bot non possono manomettere il controller o altri bot o essere altrimenti dannosi

  • I bot dovrebbero essere eseguiti in un ragionevole lasso di tempo

  • I bot devono essere deterministici; nessuna casualità a meno che non sia seminata dagli argomenti del bot

Chiacchierare: https://chat.stackexchange.com/rooms/112222/simple-race-koth

Bot in scadenza: venerdì 4 settembre, 12:00 UTC (08:00 EDT)

Risposte

3 Moogie Aug 31 2020 at 18:56

Compensatore

Derivato da "SubOptimal", Compensator non si adatta esplicitamente alla strategia "Horde / Burst", piuttosto compensa naturalmente con la consapevolezza che se non era il primo, potrebbe non aver utilizzato tutta la sua energia nel turno precedente e così potrebbe avere più energia del previsto. Per trarre vantaggio da questo eccesso di energia, questo robot utilizzerà metà dell'energia in eccesso per cercare di forzare una corsa più veloce, ma mantenendo l'altra metà di riserva per cercare di estendere l'effetto del surplus di energia su più razze.

Sembra funzionare leggermente meglio del suo fratello (SubOptimal) e, al momento di questa presentazione, è leggermente più avanti di tutti gli altri robot.

{
    "Compensator": function(dist, energy, bots, storage) {
        if ( dist == 0)
        {
          if (storage.targetStartingEnergy == undefined)
          {
            storage.targetStartingEnergy = energy;
            storage.nominalStartingEnergy = energy + 100;
          }
          else
          {
            if (energy <= storage.nominalStartingEnergy)
            {
              storage.targetStartingEnergy = energy;
            }
            else
            {
              storage.targetStartingEnergy = ((energy - storage.nominalStartingEnergy) * 0.5) +  storage.nominalStartingEnergy;
            }
          }

          if (storage.raceNumber == undefined)
          {
            storage.raceNumber = 1;
          }
          else
          {
            storage.raceNumber++;
          }

          storage.energyConsumptionRate = storage.targetStartingEnergy / 100;
        }

        let step = 0;

        if (storage.raceNumber == 1)
        {
          step = 1;
        }
        else
        {
          step = storage.energyConsumptionRate;
        }

        return step;
    }
}
6 Alion Aug 25 2020 at 21:11

Controllo della velocità

{
    "Rate control": function(distanceTravelled, energyLeft, _, s) {
        if (distanceTravelled === 0) {
            for (let i = 100; i > 0; --i) {
                if (10000 / i > energyLeft) {
                    s.travelSpeed = 100 / (i + 1);
                    break;
                }
            }
        }

        return s.travelSpeed;
    }
}

Ogni round consuma tutta la sua energia per raggiungere il traguardo. Strettamente migliore di "Lento e costante" in quanto questa voce utilizzerà sempre e solo 1 o più energia per turno, assicurandosi anche di arrivare sempre alla fine. Non ottimizzato, ma comunque abbastanza veloce.

4 Alion Aug 25 2020 at 20:19

Lento e costante

{
    "Slow and steady": function() {
        return 1;
    }
}

Baseline bot mentre cerco di capire cosa fare con questa sfida. Non si adatta affatto, quindi potrebbe iniziare a perdere costantemente se si sviluppa una sorta di meta.

3 jonatjano Aug 26 2020 at 19:56

precalcolato

{
    "precomputed": function(dist, energy, bots, storage) {
        if (dist === 0) {
            let movements = Array.from(new Array(100), _=>1)

            const totalEnergyConsumed = () => movements.reduce((a,c)=>a+c**2,0)
            let currentIndex = 0

            while(totalEnergyConsumed() < energy) {
                movements[currentIndex] += movements[currentIndex + 1]
                movements.splice(currentIndex + 1, 1)
                if (++currentIndex >= movements.length - 1) {
                    currentIndex = 0
                }
            }

            currentIndex = movements.length
            while(totalEnergyConsumed() > energy) {
                if(movements[currentIndex] > 1) {
                    movements[currentIndex]--
                    movements.push(1)
                } else {
                    currentIndex--
                }
            }

            storage.movements = {}
            movements.reduce((a,c)=>{storage.movements[a]=c;return a+c}, 0)
        }
        return storage.movements[dist]
    }
}

inizia la corsa calcolando il percorso completo fino alla fine in modo da muovere quasi alla stessa velocità per tutta la corsa, utilizzando comunque tutta l'energia disponibile

3 Spitemaster Aug 27 2020 at 02:06

Novanta

{
    "Ninety": function(dist, energy, bots, storage) {
        if (dist === 0) {
            for (let i = 90; i > 0; --i) {
                if (8100 / i > (energy - 10)) {
                    storage.travelSpeed = 90 / (i + 1);
                    break;
                }
            }
        }
        if (dist >= 89) {
            return 1;
        }

        return storage.travelSpeed;
    }
}

Mira a ottenere 9 punti per round. Non sono sicuro di quanto bene vada, ma è meno probabile che perda punti se i robot finiscono più velocemente di lui (rispetto a Rate Control, da cui è biforcuto).

3 SomoKRoceS Aug 29 2020 at 03:34

Pulse

"Pulse": function(dist, energy, bots, storage) {
    storage.round = storage.round ? storage.round+1 : 1;
    if(storage.round%500==0) return Math.max([...bots])+50
    return Math.floor(Math.sqrt(energy/100))
}

Ogni passaggio utilizza solo l'1% dell'energia. Ogni 500 giri, prende la distanza del primo posto in questo momento e aggiunge 50 passarla.

3 TheNumberOne Aug 30 2020 at 02:31

Jack in the Box

Risparmia energia fino a quando non riesce a completare il gioco in 40 mosse, riducendo il numero di mosse medie per partita.

{
    "Jack in the Box": function(dist, energy, bots, storage) {
        if (!dist) {
            if (energy >= 250) {
                storage.speed = energy / 100
            } else {
                storage.speed = .5
            }
        }
        return storage.speed
    }
}

Sempliciotto

Simpleton vuole solo vincere :(

{
    "Simpleton": function(dist, energy, bots, storage) {
        return energy / (100 - dist)
    }
}

Costante

Steady cerca di ottenere la stessa quantità ogni turno, ma non gli piace avere energia extra.

{
    "Steady": function(dist, energy, bots, storage) {
        storage.turns = storage.turns || 0
        storage.totalTurns = storage.totalTurns || 0
        storage.games = storage.games || 0
        storage.totalEnergyGained = storage.totalEnergyGained || 0
        storage.previousEnergy = storage.previousEnergy || 0
        if (!dist) {
            if (storage.games == 0) {
                storage.speed = 1
            } else {
                storage.totalTurns += storage.turns
                storage.turns = 0
                storage.speed = Math.sqrt(storage.totalEnergyGained / storage.totalTurns) + storage.previousEnergy / storage.totalTurns
            }
            storage.totalEnergyGained += energy - storage.previousEnergy
            storage.games++
        }
        storage.turns++;
        storage.previousEnergy = Math.max(energy - Math.max(Math.min(storage.speed, 100 - dist, Math.sqrt(energy)), 0) ** 2, 0)
        return storage.speed;
    }
}
3 Moogie Aug 30 2020 at 12:26

Non ottimale

La soluzione ottimale quando non c'è modo di influenzare gli altri corridori è usare tutta la tua energia per assicurarti di arrivare primo sia per ottenere la maggior parte delle energie nel round successivo sia per negare l'energia ai tuoi avversari. Questo può essere ottenuto spendendo 1,0 energia per turno nella prima gara e poi 2,0 per turno per le gare successive (a causa delle 100 energie extra date per vincere a 100 distanze)

Ciò può essere ottenuto calcolando l'energia del bot / la distanza da percorrere all'inizio di una gara, memorizzando questo valore e quindi restituendo questo valore ad ogni turno della gara.

Ora che conosciamo la soluzione ottimale senza gli effetti dell'avversario, dobbiamo considerare le azioni che gli avversari possono eseguire che possono influenzare gli altri. In questo gioco, l'unico vero effetto è la capacità di forzare la fine della gara in corso essendo il vincitore. Poiché ai bot è consentito accumulare e accumulare energia, possono decidere di ridurre al minimo il consumo di energia e massimizzare la produzione di energia, sacrificando la possibilità di guadagnare molti punti per una determinata razza e spendendo invece i punti accumulati in una gara per dominare gli altri robot e vincerla gara. Sebbene questa strategia non dia punti complessivamente elevati, ha un impatto sui robot che si aspettano che le gare finiscano dopo 100 turni. Il conteggio medio dei turni di una gara viene così ridotto. Quindi, per compensare questo effetto, una soluzione subottimale viene derivata dalla soluzione ottimale aggiungendo un fattore che emula l'effetto dei bot che usano questa strategia "hoard-burst".

Questo fattore non può essere calcolato a meno che il bot non incorpori tutte le altre strategie del bot e quindi esegua un'analisi per determinare il fattore. Questo non è proprio nello spirito delle sfide KoTH e potrebbe non essere consentito. Quindi, per questo bot, è stata eseguita una semplice analisi empirica per determinare il fattore al momento dell'invio e l'aggiunta di uno scalare in base al numero di invii che aumenterà il fattore come più invii presupponendo che i bot successivi possano interferire maggiormente.

In definitiva la formula è:

distance_per_turn = starting_energy / ((race_distance + hoard_burst_factor) * (1.0 + (number_of_bots - number_of_bots_at_submission) * 0.1))

{
    "Suboptimal": function(dist, energy, bots, storage) {
        if ( dist == 0)
        {
          storage.energyConsumptionRate = energy / ((100 + 10) * ( 1.0 + (bots.length - 26) * 0.1 ));
        }
        
        return storage.energyConsumptionRate;
    },
}
3 RedwolfPrograms Aug 26 2020 at 09:02

Robin Hood

{
    "Robin Hood": function(dist, energy, bots, storage) {
        if (!dist)
            storage.move = [
                [100, 1],
                [200, Math.sqrt(192 / 49) - 0.00695],
                [10000 / 49, (100 / 49)]
            ].sort((a, b) => Math.abs(a[0] - energy) - Math.abs(b[0] - energy))[0][1];

        return storage.move;
    }
}

Questo bot farà una delle tre cose in una gara:

  • Muovi un'unità per turno: questa operazione viene eseguita nella prima gara di ogni partita per garantire che abbia tutta l'energia di 200 di cui ha bisogno
  • Muoviti leggermente più lentamente di due unità per turno: questo viene fatto a turni alterni e risparmia energia sufficiente per consentirgli di ...
  • Muoviti leggermente più velocemente di due unità per turno: questo gli consente di finire un turno più velocemente rispetto ai concorrenti attuali, e solo di poco inferiore ad alcuni dei vincitori precedenti (sebbene il controllo della velocità sia avanti di un centesimo di punto al momento della pubblicazione)
2 RedwolfPrograms Aug 26 2020 at 01:37

Collettore

{
    "Collector": function(dist, energy, bots, storage) {
        if (!dist) {
            if ("turns" in storage) {
                storage.avg = ((storage.avg * Math.max(storage.races++, 0)) + storage.turns) / Math.max(storage.races, 1);
            } else {
                storage.avg = 100;
                storage.races = -1;
            }
            
            storage.turns = 0;
            
            storage.move = (energy >= 10000 / (storage.avg | 0)) ? (100 / (storage.avg | 0)) : 0.5;
        }
        
        storage.turns++;
        
        return storage.move;
    }
}

Il Collector si muoverà per impostazione predefinita a una velocità di 0,5 unità / turno. Questo è ottimale per raccogliere energia. Se prevede all'inizio di una gara che può pareggiare o battere la media con l'energia che ha, allora proverà a farlo.

Attualmente perde il controllo del tasso, ma potrebbe essere in grado di adattarsi meglio a nuove strategie.

2 Neil Aug 26 2020 at 06:37

Avido / avido

{
    "Greedy": function(dist, energy, bots, storage) {
        return energy > 100 ? 2 : 1;
    },
    "Greedier": function(dist, energy, bots, storage) {
        return dist + energy > 100 ? 2 : 1;
    },
}

Greedy si muoverà di 2 unità / turno se ha più di 100 energia, altrimenti 1 unità / turno. Greedier si muoverà di 2 unità / turno se pensa che probabilmente avrà abbastanza energia per ciascuna alla fine, altrimenti 1 unità / turno. Questi erano i modi più semplici in cui potevo pensare di utilizzare l'energia bonus che il bot potrebbe avere.

2 ATaco Aug 27 2020 at 15:12

Sprinter calcolato

Il velocista calcolato cerca di eseguire l'intero giro il più velocemente possibile con il carburante rimasto. Non abbastanza intelligente per pianificare le gare future, è solo felice di essere qui per la corsa.

{
    "Calculated Sprinter": function(dist, energy, bots, storage){
        var remaining = 100-dist;
        var energyLeftPerUnit = energy/remaining;
        return Math.sqrt(energyLeftPerUnit)
    }
}
2 null Aug 27 2020 at 13:35

(Nuovo) Accelera

{
    "Accelerate": function(dist, energy, bots, storage) {
        return dist * 0.21 + 0.001;
    },
}

Calmati, sto solo sperimentando robot estremamente semplici.

Questo bot è molto facile da capire. Inizialmente funziona alla velocità 0,001 e accelera in modo quadratico.

2 null Aug 27 2020 at 17:56

Amo la casualità

{
    "I love Randomness": function(dist, energy, bots, storage) {
        storage.rand = Math.abs(dist ^ energy ^ storage.rand) + 1;
        return Math.abs(dist ^ energy ^ storage.rand) + 1;
    }
}
2 histocrat Aug 29 2020 at 08:10

Sorpresa / Tempistica

"Timing": function(dist, energy, bots, storage) {
  storage.turns = storage.turns || 0;
  storage.games = storage.games || 0;
  storage.turns++;
  if(dist == 0) {
      storage.games++;
      estimated_game_length = Math.ceil( storage.turns / storage.games)+2;
      desired_speed = 100 / estimated_game_length;
      max_speed = Math.sqrt( energy / estimated_game_length);
      storage.speed = Math.min(desired_speed, max_speed);       
  }
  if(storage.games < 3)
      return storage.games;
  return storage.speed;
},
"Surprise": function(dist, energy, bots, storage) {
  storage.turns = storage.turns || 0;
  storage.games = storage.games || 0;
  storage.turns++;
  if(dist == 0) {
      storage.games++;
      estimated_game_length = Math.ceil( storage.turns / storage.games);
      desired_speed = 100 / (estimated_game_length - 3);
      max_speed = Math.sqrt( energy / estimated_game_length);
    if(desired_speed <= max_speed) {
      storage.speed = desired_speed;
    }
    else {
      storage.speed = Math.min(2, max_speed);
    }       
  }
  if(storage.games < 3)
       return storage.games;
  return storage.speed;
}

Calcola una velocità fissa in base alla durata dei giochi generalmente. Il tempismo cerca quindi di colpire nel segno, mentre Surprise cerca di batterlo.

Durante l'esecuzione dei test con entrambi, è diventato evidente che probabilmente abbiamo bisogno di regole sulla collusione in questo KotH, per quanto minime le interazioni. La sorpresa potrebbe migliorare notevolmente il Timing sacrificando il proprio punteggio per accorciare la durata della gara, e potrebbe aiutarlo ancora di più facendolo solo a intervalli fissi che il Timing conosce.

Non sto facendo questi scherzi adesso perché presumo che non siano nello spirito.

1 RedwolfPrograms Aug 27 2020 at 20:37

Imitare

{
    "Mimic": function(dist, energy, bots, storage) {
        if (!dist) {
            storage.last = bots;
            storage.rand = energy ** 3;
            
            return energy / (100 - dist);
        }
        
        storage.rand = Math.abs(dist ^ dist ** 2 ^ energy ^ energy ** 3 ^ energy ** 5 ^ bots.reduce((s, b) => s + b, 0) ^ storage.rand * (2 ** 31)) / (2 ** 31);
        
        var result = bots.map((b, i) => b - storage.last[i])[storage.rand * bots.length | 0]; // Fix RNG
        
        storage.last = bots;
        
        return Math.max(Math.min(result, Math.sqrt(energy / ((100 - dist) / 4))), Math.sqrt(energy / ((100 - dist))));
    }
}

Crea un elenco delle mosse (effettive) di ogni altro bot nell'ultimo turno e ne sceglie una pseudocasuale utilizzando una versione migliore del PRNG di HighlyRadioactive. Assicura che questi valori rientrino in un certo intervallo (cosa che accade circa la metà delle volte), quindi non fa nulla di stupido.

1 null Aug 26 2020 at 17:18

Veloce e non costante

{
    "Fast and not steady": function() {
        return 99999999;
    }
}
1 null Aug 28 2020 at 21:00

Più veloce che lento

{
    "Faster than Slow": function() {
        return 2;
    }
}

Se pensi che questo sia un cattivo bot, allora no.

Faster than Slow 48.951

1 alexberne Aug 29 2020 at 16:38

Totale

A Whole non piacciono le distanze frazionarie e si sposterà sempre di una distanza che è un numero intero.

    "Whole": function(dist, energy, bots, storage) {
        if (dist == 0) {
            if (energy < 110) {
                storage.lambda = function(distance) {return 100 - distance - 1;}
                storage.step = 1
            }
            else {
                storage.lambda = function(distance) {return 200 - distance - 2;}
                storage.step = 2
            }
        }
        let expEnergyPast = storage.lambda(dist);
        if (expEnergyPast + (storage.step + 1) ** 2 <= energy) {
            return storage.step + 1;
        }
        return storage.step;
    }

```
1 alexberne Aug 29 2020 at 16:48

Quarantanove

Fourty-Nine ha dato un'occhiata a Winner & Winner2 e ha riconosciuto che 49 turni per vincere è meglio di 48 turni per vincere. Ma Fourty-Nine vuole vincere secondo le tue regole. Quindi Fourty-Nine non sacrifica la sua distanza media per vincere molte gare. Ma non andrà mai più veloce di 49 giri per vincere.

    "fourty-nine": function(dist, energy, bots, storage) {
        if (dist == 0) {
            if (energy < 110) {
                storage.step = 1
            }
            else if(energy < 10000.0/49){
                storage.step = 2
            }
            else {
                storage.step = 100.0/49
            }
        }
        return storage.step;
    },
1 RedwolfPrograms Aug 30 2020 at 03:17

Predittore

{
    "Predictor": function(dist, energy, bots, storage) {
        if (!dist)
            if (energy == 100)
                storage.move = 1;
            else
                storage.move = (energy >= 10000 / (50 - bots.length * 0.25 | 0)) ? (100 / (50 - bots.length * 0.25 | 0)) : 1.3;

        return storage.move;
    }
}

Predictor presume che più bot vengono aggiunti, più velocemente deve andare per vincere. Raccoglie energia nel tempo, quindi scatta verso il traguardo in un modo simile a Collector o Jack nella scatola.

1 NoOorZ24 Sep 04 2020 at 17:07

DECISIONE3M8

Miglioramento su UWUTM8 che funziona in modo diverso

Cerca di prevedere quando qualcuno sta accelerando e cerca di usare più energia per guadagnare più punti

"DECISION3M8": function(dist, energy, bots, storage) {
    const checkpointPer = 5;
    if (storage.turn == undefined) {
        storage.turn = 0;
    } else {
        storage.turn = storage.turn + 1;
    }
    
    if (dist === 0) {
        if (storage.round == undefined) {
            storage.round = 0;
        }
        storage.round = storage.round + 1;
        storage.turn = 0;
        storage.maxAtPreviouscheckpoint = 0;
        storage.predictedTurnsLeft = 100;
        storage.travelSpeed = Math.sqrt(energy / 50);
        
        if (energy == 100) {
            return 1;
        }
    } else if (storage.turn % checkpointPer == 0) {
        let maxAtCurrentTurn = Math.max( ...bots );
        let speederCheck = maxAtCurrentTurn / (storage.turn / checkpointPer) - storage.maxAtPreviouscheckpoint / ((storage.turn / checkpointPer) - 1);
        let speedOfSpeederPerTurn = maxAtCurrentTurn / storage.turn;
        if ((Math.abs(speederCheck) < 0.01) && (maxAtCurrentTurn > dist)) {
            //console.log(speederCheck);
            storage.predictedTurnsLeft = Math.ceil(100 / speedOfSpeederPerTurn) - (100 - storage.turn);
            storage.travelSpeed = Math.sqrt(energy / (storage.turn - speedOfSpeederPerTurn));
            //console.log(storage.predictedTurnsLeft);
        }
    }
    
    return storage.travelSpeed;
}
alexberne Aug 29 2020 at 16:43

Vincitore

Il vincitore non si preoccupa delle tue regole. Il vincitore gioca secondo le proprie regole.

Il vincitore cerca di vincere (= termina alla distanza 100) nel maggior numero di gare possibile.

"Winner": function(dist, energy, bots, storage) {
        if (dist == 0) {
            if (energy < 10000.0/49) {
                storage.step= 0.5;
            }
            else {
                storage.step = 100.0/49;
            }
        }
        return storage.step;
    },
"Winner2": function(dist, energy, bots, storage) {
        if (dist == 0) {
            if (energy < 10000.0/48) {
                storage.step= 0.5;
            }
            else {
                storage.step = 100.0/48;
            }
        }
        return storage.step;
    },

```
NoOorZ24 Sep 03 2020 at 13:47

UWUTM8

Proprio come molti robot, cerco di finire il più velocemente possibile usando più energia possibile. Inoltre non cerca di finire affatto in punti specifici, ma cerca di raggiungere il punto 9

"UWUTM8": function(dist, energy, bots, storage) {
    if (dist === 0) {
        if (storage.round == undefined) {
            storage.round = 0;
        }
        storage.round = storage.round + 1;
        if (storage.round % 2500 == 0 || storage.round == 250 || storage.round == 750) {
            storage.travelSpeed = Math.sqrt(energy / 90)
        } else {
            storage.travelSpeed = Math.sqrt(energy / 100)
        }
    }

    return storage.travelSpeed;
}