Codémon, io scelgo te!


55

Il tuo gentile vicino, Doctor Tree, ti ha appena dato tre creature magiche chiamate Codémon. C'è un torneo di battaglia nella vicina città di Colorville. Sei il migliore, come nessuno lo è mai stato?

Panoramica

Questo è un torneo di battaglia. Ogni giocatore controlla una squadra di tre mostri e l'obiettivo è quello di eliminare (uccidere) l'altra squadra. Ci sono 100 round, con punti assegnati per vittorie e pareggi. Vince la squadra con più punti!

mostri

Un Codémon è una piccola creatura complicata. Esistono cinque tipi (elementi) tra cui scegliere, tre statistiche e tre slot di spostamento su ciascuno.

tipi

A ciascun Codémon viene assegnato un tipo. I cinque tipi sono Normale, Psichico, Fuoco, Acqua ed Erba. Ognuno ha i suoi punti di forza e di debolezza. Il danno si basa sulla seguente tabella:

tipo-chart

I numeri sono moltiplicatori di danno. Ad esempio, Acqua che attacca il fuoco ha un modificatore 0,5 (metà danno), mentre raddoppia l'erba che attacca il fuoco (2).

Statistiche

Ogni mostro ha tre statistiche che determinano le sue abilità di battaglia. L'attacco aumenta il danno che fa. La difesa riduce il danno che subisce. La velocità gli consente di muoversi prima di quelli con velocità inferiore.

Ogni mostro ha un valore iniziale di 50 per ogni stat e un massimo di 100. Quando crei i tuoi mostri, sarai in grado di assegnare 80 punti stat aggiuntivi (ciascuno). Ricorda che nessuna singola statistica può superare 100. Quindi, potresti avere una distribuzione 100/80/50, 90/80/60 o 65/65/100, ma 120/50/60 è illegale. Qualsiasi squadra con statistiche illegali viene squalificata. Non è necessario utilizzare tutti gli 80 punti, ma probabilmente non si dovrebbe andare con il minimo 50/50/50.

Puoi anche considerare HP come stat, ma ogni Codémon ha 100 HP non modificabili. Quando HP scende a zero, non sono in grado di continuare a combattere. HP viene ricaricato a 100 prima di ogni battaglia.

Si sposta

Ogni mostro conosce tre mosse di battaglia. I tre scelti devono essere distinti, quindi nessun Punch / Punch / Punch.

Ci sono 15 mosse, tre per ogni tipo. Ogni tipo ha un attacco diretto, un attacco più debole con un effetto e una sola mossa effetto.

id  name        type    power   uses    usable  effect

0   Punch       N       20      -       NFWG
1   Heal        N        0      3       NFWG    Heals 50 HP
2   Slow        N       10      5       NFWG    Enemy speed x0.8
3   Pain        P       20      -       PFWG
4   Sleep       P        0      3       PFWG    No enemy action until wake
5   Weaken      P       10      5       PFWG    Enemy Atk x0.8
6   Fireball    F       20      -       NPFW
7   Burn        F        0      3       NPFW    Enemy -10 HP each turn
8   Sharpen     F       10      5       NPFW    Own Atk x1.25
9   Watergun    W       20      -       NPWG    
10  Confuse     W        0      3       NPWG    Enemy may strike itself (10 power)
11  Shield      W       10      5       NPWG    Own Def x1.25
12  Vine        G       20      -       NPFG
13  Poison      G        0      3       NPFG    Enemy -5xTurns HP each turn
14  Sap         G       10      5       NPFG    Enemy Def x0.8

typesi riferisce al tipo di mossa. powerè il suo potere sorprendente. usesindica quante volte può essere usato per battaglia ( -è illimitato). usablemostra da quali tipi può essere utilizzato (ad esempio, Punch non può essere assegnato a un tipo Psichico, poiché non esiste P). effectmostra quali effetti hanno le mosse. C'è una probabilità del 75% di ogni effetto, tranne Heal, che funziona sempre.

Per gli effetti che cambiano le statistiche di un mostro, gli effetti possono essere raggruppati . Ad esempio, l'uso di Weaken due volte può ridurre l'attacco del tuo avversario a 0,64 di efficacia. Gli effetti che non cambiano le statistiche di un mostro (Sleep, Burn, ecc.) Non si accumulano .

Il sonno mette l'avversario a dormire, con una probabilità del 60% di svegliarsi all'inizio di ogni turno. Nessuna azione sarà intrapresa dai mostri addormentati.

Bruciare danneggia l'avversario di 10 HP alla fine di ogni turno quando è attivo . Il veleno funziona in modo simile, ma ne prende una quantità crescente ogni turno. Al primo turno, è 5 e guadagna 5 ogni turno successivo. Quindi, al quarto turno, sarà dannoso per 20. Questi sono danni piatti, non influenzati dal tipo di mostro o soggetti a bonus.

La confusione può far attaccare un mostro stesso invece di fare ciò che gli è stato detto di fare. Questo attacco ha il potere 10 e ha una probabilità del 30% di accadere in un dato turno.

Per essere chiari, gli effetti durano fino alla fine della battaglia (tranne Sleep, come notato sopra).

Le mosse ricevono anche un potenziamento del 20% in potenza se utilizzate da un mostro del tipo corrispondente. Ad esempio, un mostro Erba che usa Vine è potenziato, mentre usando Punch non lo è.

Statistiche segrete

Le statistiche e il tipo (ma non le mosse) di ogni mostro sono di dominio pubblico. I tuoi avversari saranno in grado di vedere cosa stanno combattendo, al fine di scegliere l'azione migliore. Tuttavia, ci sono anche dei bonus disponibili che sono nascosti.

In particolare, dopo ogni due battaglie, ti verrà assegnato un punto stat "bonus" per ogni mostro della tua squadra. I punti vengono assegnati a tutti i mostri, vivi o morti, vincitori o perdenti. Puoi assegnarlo a qualunque delle tre statistiche che scegli. Non puoi impilarli su un singolo mostro; ogni mostro ne prende uno ogni volta. Questi punti sono immuni al limite di 100. Dal momento che ci saranno 100 round di battaglia, questo significa che puoi ottenere una singola statistica fino a 149 se assegni tutti i tuoi bonus. Ancora una volta, l'avversario vedrà solo le tue statistiche "base", quindi più sei lontano nel torneo, più la loro conoscenza diverge dalla verità.

Battaglia

La battaglia si svolge tra squadre di tre, con una attiva su ogni squadra alla volta. All'inizio, ti verrà mostrato il team dell'avversario e ti verrà chiesto di scegliere quale mostro sarà il tuo primo giocatore "attivo".

Successivamente, le svolte avvengono con i seguenti passaggi:

  • Switch: si verificano gli switch monster obbligatori (se presenti)
  • Scegli l'azione di battaglia
  • Switch: qualsiasi switch monster opzionale (scelto come azione di battaglia) ha luogo
  • Controllo del sonno: possibilità di svegliarsi dal sonno
  • Attacco 1: se possibile, il mostro più veloce usa la sua mossa selezionata
  • Attacco 2: se possibile, l'altro mostro usa la sua mossa selezionata
  • Danno dell'effetto: applica danni da ustione / avvelenamento ai mostri viventi

"Speedier" indica il mostro con la velocità più alta. Se entrambe le statistiche di velocità sono uguali, viene scelto dal lancio della moneta PRNG ogni turno.

Alla fine di ogni turno in cui muore il tuo mostro attivo, ti verrà chiesto di scegliere un nuovo attivo. Puoi anche scegliere di cambiare mostri attivi come mossa per ogni turno (a condizione che tu ne abbia più di uno vivo). Ancora una volta, se cambi come mossa, non farai una mossa di battaglia in quel turno.

I mostri non vengono "elaborati" quando inattivi. Ciò significa che non subiscono danni da bruciatura / avvelenamento, i segnalini veleno non si accumulano, nessuna veglia dal sonno, ecc. Nessun effetto viene rimosso o modificato quando si cambia . Questo non è l' altro gioco di battaglie tra mostri. Se esci con l'attacco sollevato e bruciato, saranno ancora lì quando torni.

Il danno da effetto si verifica indipendentemente dal fatto che tu uccida o meno il tuo avversario attivo. In questo modo, i membri di entrambe le squadre possono morire in un solo turno.

Quando una squadra esaurisce i mostri utilizzabili, perde. Se entrambe le squadre si esauriscono nello stesso turno, è un pareggio. Se la battaglia dura 1000 turni, è un pareggio.

La formula per determinare il danno è:

floor((effAttack / effDefense) * movePower * typeMultiplier * moveBoost)

effAttacke effDefensesono le statistiche efficaci per i mostri. L'attacco efficace si ottiene aggiungendo Attacco e Attacco Bonus, quindi moltiplicando (per 0,8 o 1,25) se qualche effetto lo altera. Ricorda che questi effetti possono accumularsi.

Il danno può essere 0 solo quando il modificatore del tipo è 0 (Normale <--> Psichico) o la Potenza della mossa è 0 (Guarigione, Brucia, ecc.). Altrimenti il ​​minimo viene applicato a 1.

Torneo

I tornei durano per 100 round. In ogni round, le squadre vengono mescolate e accoppiate l'una contro l'altra in modo casuale. Se c'è un numero dispari di squadre, il rimanente riceve un arrivederci (segna come pareggio). Vincere una battaglia guadagna 2 punti per la squadra , i legami valgono 1 e nulla perde. Vince la squadra con il maggior numero di punti alla fine!

Se le squadre sono in parità, un torneo con solo le squadre in parità per il primo posto avrà luogo per determinare l'ordine dei tiebreaker.

Protocollo

Il controller invierà al tuo programma uno dei quattro comandi. Il primo carattere determina il tipo di comando, con i dati che seguono se necessario.

Il tuo programma accetterà il comando come argomento e risponderà su STDOUT entro un secondo . Non rimanere in vita ascoltando STDIN, non ci sarà. Ogni comando genererà un nuovo processo.

È possibile scrivere dati / stato su disco. Metti tutti i file in una sottocartella con lo stesso nome del tuo team. Non scrivere più di 32 kilobyte di dati, altrimenti verrai squalificato. I dati persistono tra i round, ma verranno cancellati tra i tornei.

comandi

Dati del team

Questo viene inviato una volta all'inizio del torneo per registrare la tua squadra. La tua risposta dovrebbe essere costante , non diversa per ogni torneo.

Query:

T

Risposta:

name|member0|member1|member2

nameè una stringa con il nome della tua squadra. Si prega di utilizzare solo alfanumerico, per facilitare l'analisi. memberNè una stringa membro, che fornisce i dettagli di ciascun mostro:

Stringa membro:

name:typeid:attack:defense:speed:moveid0:moveid1:moveid2

Ancora una volta, "name" è una stringa, questa volta con il nome di questo mostro. typeidè il suo tipo. Gli ID di tipo sono nell'ordine mostrato nella tabella sopra, con Normale = 0 e Grass = 4.

I prossimi tre campi sono le tue statistiche di base. Tieni presente i limiti descritti nella sezione delle statistiche sopra.

Le ultime tre sono le mosse del tuo mostro. Gli ID sono mostrati nella tabella delle mosse sopra.

Un esempio di risposta dei dati del team può apparire così:

DummyTeam|DummyA:0:50:60:70:0:1:2|DummyB:0:50:60:70:0:1:2|DummyC:0:50:60:70:0:1:2

Qualsiasi squadra che rispedisca qui dati inutili, non formattati o illegali non parteciperà fino a quando non verrà risolto.

Scegli Attivo

Viene inviato all'inizio di ogni battaglia e quando un mostro muore e deve essere cambiato.

Query:

C#battleState

battleStatemostra lo stato della battaglia attuale. Abbi pazienza qui, è brutto:

yourTeamState#theirTeamState

Dove XteamStateappare:

name:activeSlot|member0state|member1state|member2state

activeSlotmostra quale mostro è attualmente attivo (0-2). Gli stati membri hanno due gusti. Se è la tua squadra, fornisce ulteriori informazioni. Così,

Il tuo membroXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:moveCount0:moveCount1:moveCount2:bonusAttack:bonusDefense:bonusSpeed:effectid:effectid:effectid

Il loro membroXstate:

name:id:attack:defense:speed:hp:typeid:poisonedturns:effectid:effectid:effectid

idè semplicemente un identificatore intero che puoi usare per tenere traccia dei mostri se non ti piace usare name.

attack:defense:speedsono le tue statistiche di base .

poisonedturns ti dice per quanti turni sei stato avvelenato.

moveCountXindica quanti usi ti rimangono per ogni mossa. Se 0, non può essere utilizzato. Per mosse illimitate, questo sarà negativo.

bonus(stat) è la quantità di punti bonus assegnati a ciascuna statistica.

effectidè un elenco di effetti di dimensioni variabili che sono stati applicati al tuo mostro. Ci sarà non essere una finale :sulla corda, se ci sono effetti attivi presenti o meno. Se sono presenti effetti sovrapposti, verranno visualizzati come effetti multipli nell'elenco.

Gli ID effetto sono:

0  NONE           (should not appear, internal use)
1  POISON
2  CONFUSION 
3  BURN 
4  SLEEP 
5  HEAL           (should not appear, internal use)
6  ATTACK_UP
7  ATTACK_DOWN
8  DEFENSE_UP
9  DEFENSE_DOWN
10 SPEED_DOWN

Risposta:

memberSlot

L'unica risposta richiesta è un singolo numero 0,1,2, che indica quale membro si desidera essere attivo. Questo deve essere un membro in grado di combattere. Non rispedire 1se il membro 1 è morto.

Azione di battaglia

Ad ogni turno, devi decidere cosa fare.

Query:

A#battleState

Il battleStatequi è esattamente come descritto sopra.

Risposta:

Per usare una mossa, rispedire lo slot in cui si trova la mossa. Ad esempio, se ho assegnato Punch allo slot 0, l'invio 0esegue Punch.

Per passare a un altro membro, invia lo slot del membro più dieci . Quindi per passare al membro 2, invia 12.

Qualunque cosa non in [0,1,2,10,11,12] è considerata non valida e non comporterà alcuna azione in questo turno.

Statistiche bonus

Dopo ogni due battaglie, ricevi un punto bonus segreto per ogni membro della squadra.

Query:

B#yourTeamState

Lo stato della tua squadra è lo stesso mostrato sopra, non farmi ripetere.

Risposta:

stat0:stat1:stat2

La tua risposta rappresenterà quale stat aumentare per ciascun membro del team. L'attacco è 0, la difesa è 1, la velocità è 2.

Quindi, per aumentare la velocità del membro, l'attacco del membro due e la difesa del membro tre, risponderesti con:

2:0:1

controllore

Il controller può essere trovato su BitBucket: https: //Geobits@bitbucket.org/Geobits/codemon.git

Basta lanciare tutti i file della classe compilati, i contributi e il player.conf in una cartella ed eseguire.

Viene chiamata la classe principale del controller Tournament. L'utilizzo è:

java Tournament [LOG_LEVEL]

I livelli di registro da 0 a 4 forniscono informazioni crescenti. Il livello 0 esegue il torneo in silenzio e fornisce solo i risultati, mentre il livello 3 fornisce commenti passo-passo. Il livello 4 è l'output di debug.

Puoi aggiungere invii al torneo in players.confAggiungi semplicemente la stringa della riga di comando necessaria per eseguire il programma, uno per riga. Le righe che iniziano con #sono commenti.

Nel tuo post, includi il comando che dovrò aggiungere al mio players.confe tutti i passaggi della compilazione (se necessario).

È inclusa una squadra fittizia composta da tutti i membri normali con le tre mosse normali. Scelgono le mosse in modo casuale e hanno statistiche terribili. Divertiti a picchiarli.

Regole varie

  • Non è possibile leggere o scrivere su risorse esterne (tranne nella propria sottocartella, fino a 32 kB come indicato sopra).

  • La tua squadra deve andare al torneo "alla cieca". Ciò significa che non puoi analizzare la fonte di altre persone per capire cosa farà una specifica squadra / mostro in una determinata situazione. Puoi analizzare le mosse / le statistiche del tuo avversario e tenere traccia dell'avanzamento del torneo, ma non puoi inserire queste informazioni.

  • Non interferire con altri processi / invii. Non invocarli, usare reflection per ottenere i loro dati, ecc. Non scherzare con il mio computer. Basta non provarlo. Questo è a mia discrezione. I trasgressori potrebbero essere esclusi da ingressi futuri.

  • I concorrenti sono limitati a un massimo di due iscrizioni. Se invii di più, segnerò solo i primi due inviati. Se si desidera revocarne uno, eliminarlo.

  • Le voci non possono esistere esclusivamente per sostenere altre voci. Inoltre, non puoi provare a squalificare indirettamente altri concorrenti (ad esempio, usando un nome di squadra di 27 milioni di caratteri per i giocatori DQ che provano a scrivere questo su disco). Ogni sottomissione dovrebbe giocare per vincere per il proprio merito.

  • Il tuo programma può generare un massimo di un processo figlio alla volta (discendenti totali, non diretti). Entrambi i processi principali e secondari devono terminare direttamente dopo aver fornito l'output. Ad ogni modo, assicurati di non andare oltre il timeout.

  • Il torneo si terrà sul mio computer con Ubuntu in esecuzione con un processore Intel i7 3770K.

risultati

Questi sono i risultati degli attuali giocatori. È molto vicino tra i migliori contendenti e sto pensando di aumentare il numero di round fino a 500 (e regolare la spaziatura dei punti bonus in modo che corrispondano). Eventuali obiezioni, commenti?

------- Final Results -------

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

Risultati play-by-play completi su Google Drive


62
Voglio essere il migliore / Come nessun codice è mai stato / Non crash è il mio test / Debug è la mia causa! / Viaggerò attraverso la LAN / Scripting in lungo e in largo / Sto cercando di capire / Perché il mio BIOS ha funzionato! / Codémon, siamo io e te / Giocare a golf tutto ciò che l'occhio può vedere / Codémon, sei il mio migliore amico / Al termine del programma! / Codémon, una lingua così vera / Nessun segreto ci trascinerà / Tu mi insegni e io ti insegnerò / Codémon, devo giocare a golf!
Kaz Wolfe,

1
Invece di aumentare i round a 500, sarebbe bello se un round consistesse nel fatto che tutti combattono tutti. Quindi non più byeper un numero irregolare di concorrenti e verrebbe assicurato che le coppie di match siano eque e distribuite uniformemente.
foobar,

@foobar Volevo evitarlo perché ridimensiona le battaglie n^2invece di n. Con solo gli attuali 7 concorrenti e 100 round, sono 2100 battaglie (contro 300 così com'è e 1500 con 500 round). Peggiora solo con l'ingresso di più voci. Potrei ridimensionare il numero di round, ma esito a farlo a causa della variabilità intrinseca (per quanto riguarda gli stati esp), e avere un multiplo di 50 (per punti bonus) è più facile.
Geobits il

Questa sfida non richiede un aggiornamento? :)
GholGoth21

@ GholGoth21 Sì, credo di si. Probabilmente non ci riesco oggi, ma forse domani o il giorno seguente. Esegui il ping in chat se non aggiornato entro giovedì o così, se lo desideri.
Geobits

Risposte:


16

Happy 3 camper - PHP

Un gruppo di codardi a cui piace respingere l'opposizione con incantesimi debilitanti e vederli marcire.

EDIT : Mr. Lumpy è stato severamente castigato e non dirà più parolacce


ManeggevoleManeggevoleGrass - atk:50 def:99 spd:81 Confuse Poison Heal

Un castoro velenoso senza braccia a cui piace confondere le persone con problematiche strette di mano


flippyflippyWater - atk:50 def:99 spd:81 Confuse Burn Heal

Un veterano della bacheca con un debole per discorsi noiosi e sciocche e guerre di fiamma.


ricco di nociricco di nociFire - atk:50 def:99 spd:81 Burn Poison Heal

Le armi di distruzione di massa sono le sue caramelle preferite.


granulosogranulosoPhp - lines:500 clarity:05 spd:01 Gather Guess Store

Grazie al suo QI di quasi 2 cifre e alla sua memoria fenomenale, Lumpy può indovinare le mosse nemiche. Bene, soprattutto.


Strategia

La strategia è di far avvelenare, bruciare e confondere gli avversari il prima possibile.
Il sonno non è stato usato poiché sembrava meno potente dei 3 incantesimi sopra.
La confusione è mortale a lungo termine, poiché riduce gli attacchi del 30% (sia infliggendo danni che lanciando incantesimi), impedisce ai guaritori di curarsi da soli e danneggia gravemente i colpi pesanti (un mostro 50 dif / 100 atk infliggerà 20 punti danno su se stesso ).

Una volta che un nemico è completamente incollato, i miei campeggiatori semplicemente lo guardano sfrigolare, marcire e pugnalarsi a morte.

Alta difesa e cura sono usate per mitigare il danno in arrivo durante l'agonia.

Mentre i miei 3 campeggiatori stanno combattendo, Lumpy il cervo magico osserva i nemici ogni mossa e talvolta riesce a identificarli. Le informazioni vengono restituite ai nostri combattenti, che fanno del loro meglio per trarne vantaggio.

Dopo la difesa, la velocità è la statistica più importante da potenziare.
L'iniziativa è cruciale per applicare la guarigione prima che arrivi il colpo successivo.

L'attacco non è usato affatto.

Gli incantesimi sono l'arma definitiva?

Incantesimi come veleno, bruciore e confusione sfuggono alla logica generale di roccia / carta / forbice di altri attacchi.

Una volta che un mostro è interessato, continuerà a perdere PS anche dopo che l'incantatore è morto. È come se il fantasma dell'incantatore continuasse ad attaccarlo.
Inoltre, il veleno diventa rapidamente più potente di un attacco massiccio completamente potenziato (sopra i 50 punti dopo 5 turni).

L'aspettativa di vita di un mostro avvelenato e bruciato non va oltre gli 8 turni, anche con 3 cure.

Come sembrano indicare i robot di Martin , il bilanciamento del gioco è piuttosto buono.
Fondamentalmente è un'iniziativa che farà pendere l'equilibrio tra incantatori puri e attaccanti puri.

Il codice

Invocare con php campers.php

È un brutto pasticcio, ma francamente anche l'interfaccia non aiuta.

Ora che è apparsa una competizione opportunamente aggressiva, ho implementato le mie mosse nemiche pianificate da tempo.
L'analisi degli attacchi richiede varie detrazioni acrobatiche e una memorizzazione persistente dello stato dell'ultimo turno, il che significa una guerra su vasta scala con l'interfaccia del controller paranoico.
Non è roba carina né jackrabbit a sei zampe, ma fa un lavoro adeguato.

<?php

// ============================================================================
// Game
// ============================================================================
class G {
    static $code_type = array ("Normal", "Psychic", "Fire", "Water", "Grass", "?", "self"); 
    static $code_move = array    ("Punch", "Heal", "Slow", "Pain", "Sleep", "Weaken", "Fireball", "Burn", "Sharpen", "Watergun", "Confuse", "Shield", "Vine", "Poison", "Sap", "?", "self", "pass");
    static $move_uses = array (1000,3,5,1000,3,5,1000,3,5,1000,3,5,1000,3,5,   2000,2000);
    static $move_type      = array (0,0,0,1,1,1,2,2,2,3,3,3,4,4,4, 5,5,5);
    static $move_dmg       = array (20,0,10,20,0,10,20,0,10,20,0,10,20,0,10,  20,10,0);
    static $move_forbidden = array (1,1,1,0,0,0,4,4,4,2,2,2,3,3,3);
    static $code_effect = array ("N", "Poison", "Confuse", "Burn", "Sleep", "H", "Sharpen", "Weaken", "Shield", "Sap", "Slow"); 
    static $decode_type, $decode_move, $decode_effect;
    static $damage_multiplier = array (
        array (2, 0, 1, 1, 1, 0),
        array (0, 2, 1, 1, 1, 0),
        array (1, 1,.5, 2,.5, 0),
        array (1, 1,.5,.5, 2, 0),
        array (1, 1, 2,.5,.5, 0),
        array (2, 2, 2, 2, 2,-1),
        array (9, 9, 9, 9, 9, 9, 1));
    static $atk_score = array ("Poison"=> 1002, "Confuse"=>1001, "Burn"=>1000);
    static $status_field = "atk:def:spd:hp:type:Pturns";
    static $all_moves, $strong_moves, $medium_moves, $effect_moves, $possible_moves;

    function init()
    {
        self::$status_field = explode (":", self::$status_field);
        foreach (array ("type", "move", "effect") as $table) self::${"decode_$table"} = array_flip (self::${"code_$table"});
        foreach (self::$code_move as $c=>$m)
        {
            if ($m == "?") break;
            self::$all_moves[] = new Move($m);
            if (self::$move_uses[$c] >  5) self::$strong_moves[] = $m;
            if (self::$move_uses[$c] == 5) self::$medium_moves[] = $m;
            if (self::$move_uses[$c] == 3) self::$effect_moves[] = $m;
            for ($type = 0 ; $type != 5 ; $type++) if ((self::$move_uses[$c] >  5) && (self::$move_forbidden[$c] != $type)) self::$possible_moves[$type][] = $m;
        }
    }

    function __construct ($name, $team)
    {
        $this->turn = 0;
        $this->name = $name;
        $this->team = $team;
        $this->results_pending = false;
    }

    function parse_team ($tpack, $own_team)
    {
        $pack = explode ("|", $tpack);
        list ($name,$active) = explode (":", array_shift($pack));
        if ($own_team)
        {
            $team = $this->team;
        }
        else
        {
            if (!isset($this->enemies[$name])) $this->enemies[$name] = new Team(array (new Monster (), new Monster (), new Monster ()));
            $team = $this->foes = $this->enemies[$name];
        }
        $team->active = $active;
        foreach ($pack as $i=>$mpack) $team->monster[$i]->parse_monster ($own_team, $mpack);
    }

    function choose_active ()
    {
        // detect start of round
        $team = $this->team;
        $foes = $this->foes;
        foreach ($team->monster as $i=>$m) if ($m->hp > 0) $candidate[$i] = $m;
        if (count ($candidate) == 3)
        {
            $this->results_pending = false;
            $this->round++;

            // reinitialize all monsters
            foreach (array($team, $foes) as $t)
            foreach ($t->monster as $m)
                $m->start_round();

            // guess initial opponent
            $opponent = $foes->initial_opponent();
        }
        else
        {
            $this->analyze_last_round();
            $opponent = $foes->active();
        }
        return $this->do_switch ($opponent);
    }

    function choose_attacker ($foe)
    {
        foreach ($this->team->monster as $i=>$m) if ($m->can_attack($foe)) $candidate[$i] = $m;
        if (isset($candidate))
        {
            uasort ($candidate, function ($a,$b) use ($foe) { return ($a->atk_score != $b->atk_score) ? $b->atk_score - $a->atk_score : $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            return key($candidate);
        }
        return -1;
    }

    function do_switch ($foe)
    {
        $replacement = $this->choose_attacker ($foe);
        if ($replacement < 0)
        {
            $candidate =  $this->team->monster;
            uasort ($candidate, function ($a,$b) use ($foe) { return $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            $replacement = key($candidate);
        }

        $this->old_own = $this->team->monster[$replacement];
        $this->old_own->attack = "pass";
        return $replacement;
    }

    function choose_action ()
    {
        $this->analyze_last_round();
        $own = $this->team->active();
        $foe = $this->foes->active();
        $this->old_own = $own;

        if ($own->hp <= $own->max_damage($foe) && $own->can_do ("Heal")) return $own->execute("Heal");
        if ($attack = $own->can_attack($foe)) return $own->execute($attack);
        if ($own->hp <= 50 && $own->can_do ("Heal")) return $own->execute("Heal");

        return 10 + $this->do_switch ($foe);    
    }

    function choose_bonus()
    {
        foreach ($this->team->monster as $m)
        {
            if ($m->spd_b == 0) { $m->spd_b++; $res[] = 2; }
            else                { $m->def_b++; $res[] = 1; }
        }
        return implode (":", $res);
    }

    function parse ($parts)
    {
        self::parse_team ($parts[1], true);
        self::parse_team ($parts[2], false);    
    }

    function analyze_last_round()
    {
        if ($this->results_pending)
        {
            $this->results_pending = false;

            $foes = $this->foes;
            $foe = null;
            foreach ($foes->monster as $m) if ($m->hp != $m->old->hp) $foe = $m;
            if ($foe === null) $foe = $foes->monster[$foes->active];

            $this->old_own->guess_attack($foe);
        }
    }

    function process ($line)
    {
        $parts = explode ("#", $line);
        switch ($parts[0])
        {
        case "T": // register for tournament
            echo "$this->name|$this->team";
            break;
        case "C": // designate active monster
            $this->parse ($parts);
            echo $this->choose_active();
            break;
        case "A": // choose round action
            $this->parse ($parts);
            echo $this->choose_action();

            // save current state
            foreach (array($this->team, $this->foes) as $t)
            foreach ($t->monster as $m)
            {
                unset ($m->old);
                $m->old = clone ($m);
            }
            $this->results_pending = true;
            break;
        case "B": // distribute stat bonus
            echo $this->choose_bonus();
            break;
        }

    }
}
G::init();

// ============================================================================
// Move
// ============================================================================
class Move {
    function __construct ($move)
    {
        $this->register($move);
    }

    function register ($move)
    {
        $this->type = G::$decode_move[$move];
        $this->reinit();
    }

    function reinit()
    {
        $this->uses = G::$move_uses[$this->type];
    }

    function __tostring() { return G::$code_move[$this->type]."($this->uses)"; }
}

// ============================================================================
// Monster
// ============================================================================
class Monster { 
    function __construct ($name="?", $type="?", $atk=100, $def=100, $spd=100, $m0="?", $m1="?", $m2="?")
    {
        $this->name = $name;
        $this->type = G::$decode_type[$type];
        $this->atk  = $atk;
        $this->def  = $def;
        $this->spd  = $spd;
        $this->hp   = 100;
        $this->move = array (new Move($m0), new Move($m1), new Move($m2));
        $this->atk_b = 0;
        $this->def_b = 0;
        $this->spd_b = 0;
        foreach (G::$code_effect as $e) $this->$e = 0;
    }

    function __tostring ()
    {
        return implode (":", array (
            $this->name,
            $this->type,
            $this->atk,
            $this->def,
            $this->spd,
            $this->move[0]->type,
            $this->move[1]->type,
            $this->move[2]->type));
    }

    function start_round()
    {
        foreach ($this->move as $m) $m->reinit();
    }

    function parse_monster ($own_team, $spack)
    {
        $pack = explode (":", $spack);
        $name = array_shift ($pack); // get name
        array_shift ($pack); // skip id
        if ($this->name == "?") $this->name = $name; // get paranoid
        else if ($this->name != $name) die ("expected $this->name, got $name");

        // store updated values
        foreach (G::$status_field as $var) $this->$var = array_shift ($pack);
        if ($own_team)
        {
            foreach ($this->move as $m) $m->new_count = array_shift($pack);
            $pack = array_slice ($pack, 3); // these are maintained internally
        }
        $var = array();
        foreach ($pack as $e) @$var[G::$code_effect[$e]]++; 
        foreach (G::$code_effect as $e) $this->$e = @$var[$e]+0;
    }

    function damage_recieved ($attack, $foe=null)
    {
        if ($attack == "self") $foe = $this;
        $a = G::$decode_move[$attack];
        $type = G::$move_type[$a];
        $dmg = g::$move_dmg[$a];

        if ($dmg == 0) return 0;

        $atk = ($foe ->atk+$foe ->atk_b) * pow (.8, ($foe ->Weaken - $foe ->Sharpen));
        $def = ($this->def+$this->def_b) * pow (.8, ($this->Sap    - $this->Shield ));

        $boost = ($foe->type == $type) ? 1.2 : 1;
        return max (floor ($dmg * $atk / $def * $boost * G::$damage_multiplier[$this->type][$type]), 1);
    }

    function guess_attack_from_effect ($attacks)
    {
        foreach ($attacks as $status) if ($this->$status != $this->old->$status) return $status;
        return "?";
    }

    function guess_attack_from_damage ($foe, $damages)
    {
        $select = array();
        foreach (G::$possible_moves[$foe->type] as $attack)
        {
            $dmg = $this->damage_recieved ($attack, $foe);
            foreach ($damages as $damage) if ($damage != 0 && abs ($dmg/$damage-1) < 0.1) $select[$attack] = 1;
        }
        $res = array();
        foreach ($select as $a=>$x) $res[] = $a;
        return $res;
    }

    function guess_attack ($foe)
    {
        $attempt = G::$decode_move[$this->old->attack];
        $success = ($this->old->attack == "pass");
        foreach ($this->move as $m)
        {
            if ($m->type == $attempt)
            {
                if ($m->new_count == $m->uses-1)
                {
                    $m->uses--;
                    $success = true;
                }
                break;
            }
        }

        $possible = array();
        $attack = $this->guess_attack_from_effect (array("Burn", "Confuse", "Poison", "Sleep", "Slow", "Weaken", "Sap"));
        if ($attack == "?") $attack = $foe->guess_attack_from_effect (array("Sharpen", "Shield"));
        if ($attack == "?")
        {
            $foe_damage = $this->old->hp - $this->hp - (10 * $this->Burn + 5 * $this->Pturns*$this->Poison);
            if ($this->old->attack == "Heal" && $success) $foe_damage += 50;
            $possible_dmg[] = $foe_damage;
            //;!;if ($this->Confuse) $possible_dmg[] = $foe_damage + $this->damage_recieved ("self");
            $possible = $this->guess_attack_from_damage ($foe, $possible_dmg);
            if (count ($possible) == 1) $attack = $possible[0];
        }
        if ($attack == "?")
        {
            $own_damage = $foe->old->hp - $foe->hp 
                        - (10 * $foe->Burn + 5 * $foe->Pturns*$foe->Poison)
                        + $foe->damage_recieved ($this->attack);
            if (abs ($own_damage/50+1) < 0.1) $attack = "Heal";
        }
        if ($attack != "?")
        {
            $type = G::$decode_move[$attack];
            if ($attack != "?")
            {
                foreach ($foe->move as $m) if ($m->type == $type) goto found_old;
                foreach ($foe->move as $m) if ($m->type == 15) { $m->register($attack); goto found_new; }
            }
            found_new:
            found_old:
        }
    }

    function max_damage($foe)
    {
        $dmg = 0;
        foreach ($foe->move as $m) $dmg = max ($dmg, $this->damage_recieved (G::$code_move[$m->type], $foe));
        return $dmg;
    }

    function expected_damage ($foe)
    {
        return $this->max_damage($foe) + 10 * $this->Burn + 5 * ($this->Pturns+1);
    }

    function life_expectancy ($foe)
    {
        $hp = $this->hp;
        $poison = $this->Pturns;
        $heal = $this->can_do ("Heal");
        $dmg = $this->max_damage($foe);
        for ($turn = 0 ; $hp > 0 && $turn < 10; $turn++)
        {
            $hp -= 10 * $this->Burn + 5 * $poison;
            if ($poison > 0) $poison++;
            $hp -= $dmg;
            if ($hp <= 0 && $heal > 0) { $hp+=50; $heal--; }
        }
        return 100 * $turn + $this->hp;
    }

    function can_attack ($foe)
    {
        $attack = false;
        if ($this->hp > 0)
        {
            if      (!$foe->Poison  && $this->can_do ("Poison" )) $attack = "Poison";
            else if (!$foe->Confuse && $this->can_do ("Confuse")) $attack = "Confuse";
            else if (!$foe->Burn    && $this->can_do ("Burn"   )) $attack = "Burn";
        }
        $this->atk_score = ($attack === false) ? 0 : G::$atk_score[$attack];
        return $attack;
    }

    function can_do($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $m) if ($m->type == $type && $m->uses > 0) return $m->uses;
        return false;
    }

    function execute($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $i=>$m) if ($m->type == $type) 
        { 
            if ($m->uses > 0)
            {
//;!;               $m->uses--;
                $this->attack = $move;
            }
            else $this->attack = "pass";
            return $i; 
        }
        die ("$this asked to perform $move, available ".implode(",", $this->move));
    }
}

// ============================================================================
// Team
// ============================================================================
class Team {
    function __construct ($members)
    {
        $this->monster = $members;
    }

    function __tostring()
    {
        return implode ("|", $this->monster);
    }

    function active ()
    {
        return $this->monster[$this->active];
    }

    function initial_opponent()
    {
        return $this->monster[0];
    }
}

// ============================================================================
// main
// ============================================================================
$input = $argv[1];

$team_name = "H3C";
$mem_file = "$team_name/memory.txt";
$trc_file = "$team_name/trace.txt";
if (!file_exists($team_name)) mkdir($team_name, 0777, true) or die ("could not create storage directory '$team_name'");
if ($input == "T") array_map('unlink', glob("$team_name/*.txt"));

if (file_exists($mem_file)) $game = unserialize (file_get_contents ($mem_file));
else
{
    $team = new Team (
        array (
            new Monster ("Handy" , "Grass" , 50, 99, 81, "Confuse", "Poison", "Heal"),
            new Monster ("Nutty" , "Fire"  , 50, 99, 81, "Burn"   , "Poison", "Heal"),
            new Monster ("Flippy", "Water" , 50, 99, 81, "Confuse" , "Burn" , "Heal")));
    $game = new G($team_name,$team);
}

$game->process ($input);
file_put_contents ($mem_file, serialize($game));

risultati

LittleKid è ancora minaccioso, ma il mio trio ha battuto i suoi mostri velenosi con un discreto margine.

I robot di Martin sono condannati dalla loro mancanza di iniziativa e aumentare la loro velocità richiederebbe un attacco inferiore, il che ridurrebbe il loro vantaggio nella capacità di infliggere danni.

I nuovi contendenti del pianeta JavaScript sono alla pari con il team in uno contro uno, ma se la cavano peggio con gli altri concorrenti. Aiutano effettivamente a ridurre il punteggio di LittleKid :).

Quindi sembra che i miei amici coccolosi rimangano re della collina - per ora ...

170             H3C
158             Nodemon
145             LittleKid
55              InsideYourHead
42              HardenedTrio
30              BitterRivals

E non ho neanche PHP sul mio. Mi aspetto che tu pulisca il pavimento con i Metapodi, dato che vanno per uno strat lento e sarebbero avvelenati a morte.
Sp3000,

... * e * bruciati in modo nitido: D. Questo è il problema con regole complicate: è molto probabile che emerga una strategia dominante. Dal momento che non esiste alcuna protezione contro questi incantesimi, potrebbero essere l'uomo grasso e il ragazzino di Codémon.

Lo paragonerei di più a un gioco non transitivo come forbici, carta, roccia - dal momento che gli effetti richiedono un po 'di tempo, una squadra di attacco completo dovrebbe essere in grado di
buttarti

2
Sì, questo è quello che ho immaginato non vedendo alcun rimedio per Poison and Burn. Grazie per aver realizzato il mio sogno.
solo

1
Questo è il signor Lumpy che esprime la sua perplessità quando rileva più di 3 attacchi diversi dallo stesso avversario :). Ho una versione fissa quasi completa, ma sono nel bel mezzo di qualche altra cosa in questo momento, quindi la correzione verrà pubblicata tra circa un giorno.

7

HardenedTrio, Python 3

Dato che Geobits è stato abbastanza gentile da darci due invii, ho pensato di presentare qualcosa di stupido per il primo: P

La festa è composta da tre Codemon (Metapod1, Metapod2, Metapod3) con le stesse statistiche e mosse:

  • 80 attacchi, 100 difese, 50 velocità
  • Punch, Heal, Shield Harden

Tutti i punti bonus sono anche assegnati alla difesa.


from collections import namedtuple
import sys

BattleState = namedtuple("BattleState", ["us", "them"])
TeamState = namedtuple("TeamState", ["name", "active", "members"])
MemberState = namedtuple("MemberState", ["name", "id", "attack", "defense", "speed", "hp",
                                         "typeid", "poisonedturns", "otherstats"])

def parse_battle_state(state):
    return BattleState(*map(parse_team_state, state.split("#")))

def parse_team_state(state):
    na, *members = state.split("|")
    name, active = na.split(":")
    return TeamState(name, int(active), list(map(parse_member_state, members)))

def parse_member_state(state):
    name, id_, attack, defense, speed, hp, typeid, poisonedturns, *rest = state.split(":")
    return MemberState(name, int(id_), float(attack), float(defense), float(speed),
                       float(hp), int(typeid), int(poisonedturns), rest)

command = sys.argv[1].strip()

if command.startswith("T"):
    print("HardenedTrio|Metapod1:0:80:100:50:0:1:11|"
          "Metapod2:0:80:100:50:0:1:11|Metapod3:0:80:100:50:0:1:11")

elif command.startswith("C"):
    battle_state = parse_battle_state(command[2:])

    for i, codemon in enumerate(battle_state.us.members):
        if codemon.hp > 0:
            print(i)
            break

elif command.startswith("A"):
    battle_state = parse_battle_state(command[2:])
    current_codemon = battle_state.us.members[battle_state.us.active]

    if current_codemon.hp < 50 and int(current_codemon.otherstats[1]) > 0:
        print(1) # Heal up if low

    elif int(current_codemon.otherstats[2]) > 0:
        print(2) # Harden!

    else:
        print(0) # Punch!

elif command.startswith("B"):
    print("1:1:1")

Corri con

py -3 <filename>

(o con python/ python3invece di pydipendere dall'installazione)



1
@FryAmTheEggman Metapod, HARDEN!
Sp3000,

Sto cercando di leggere il tuo codice, ma mi sono confuso int(current_codemon.otherstats[1])>0. Ciò ritorna vero se ha un effetto di stato? E usa harden solo se ha due effetti di stato?
Mooing Duck,

@MooingDuck Per il tuo Codemon hai le moveCounts prima delle effectids, quindi sta controllando se può ancora usare Harden. Sono diventato pigro con l'analisi, motivo per cui è ammucchiato lì.
Sp3000,

@ Sp3000: Oh! Giusto! HAHAHA!
Mooing Duck,

6

Dentro la tua testa, Ruby

  • Brian : Psychic, Attack: 100, Defense: 50, Speed: 80, Pain, Fireball, Watergun
  • Elemon1 : Psychic, Attack: 100, Defense: 50, Speed: 80, Fireball, Watergun, Vine
  • Elemon2 : Psychic, Attack: 100, Defense: 50, Speed: 80, Fireball, Watergun, Vine
TEAM_SPEC = "InsideYourHead"+
            "|Brian:1:100:50:80:3:6:9"+
            "|Elemon1:1:100:50:80:6:9:12"+
            "|Elemon2:1:100:50:80:6:9:12"

def parse_battle_state request
    request.map do |team_state|
        state = {}
        parts = team_state.split '|'
        state[:active] = parts.shift.split(':')[1].to_i
        state[:monsters] = parts.map do |monster_state|
            monster = {}
            parts = monster_state.split(':')
            monster[:name] = parts[0]
            monster[:hp] = parts[5].to_i
            monster[:type] = parts[6].to_i
            monster
        end
        state
    end
end

request = ARGV[0].split '#'
case request.shift
when 'T'
    puts TEAM_SPEC
when 'C'
    battle_state = parse_battle_state request
    my_state = battle_state[0]
    puts my_state[:monsters].find_index {|monster| monster[:hp] > 0}
when 'A'
    battle_state = parse_battle_state request
    my_state, their_state = *battle_state
    my_monster = my_state[:monsters][my_state[:active]]
    their_monster = their_state[:monsters][their_state[:active]]
    puts [1,0,1,2,0][their_monster[:type]]
when 'B'
    puts '0:0:0'
end

Corri con

ruby InsideYourHead.rb

Questo non funziona molto bene contro il bot di Manu, ma batte gli altri tre. I nomi delle squadre e dei mostri sono piuttosto casuali ... Potrei cambiarli se trovo qualcosa di meglio

La strategia è piuttosto semplice: l' attacco! Tutti e tre i mostri hanno solo mosse di attacco e scelgono la loro mossa in base al tipo di mostro dell'avversario.

Potrei sperimentare con il lancio di un Heal in seguito.


1
Hehe questo diventa più interessante. Sapevo di poter contare su di te per questo, Martin :)

6

LittleKid, Java

Un bambino ha trovato 3 codici identici e li ha addestrati. Sono molto fastidiosi con i loro attacchi di cura + veleno. L'uso di solo codemoni di tipo normale elimina la necessità di accoppiarli a nemici specifici, poiché il veleno funziona bene contro tutti i tipi.

public class LittleKid {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("Geobits says you can't do this.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "LittleKid";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                break;
            case "B":
                out = "1:1:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];
                int pick = 0;

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = String.valueOf(pick);
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int enemyActive = getActive(them);
                if (getField(me, HP, active) < 50 && getField(me, MOVE1, active) != 0) {
                    out = "1";
                } else if (getEffectCount(them, POISON, enemyActive, false) < 1 && getField(me, MOVE2, active) != 0) {
                    out = "2";
                } else {
                    out = "0";
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6;
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10;

    final static int POISON =           1;
}

5
" Geobits dice che non puoi farlo ": D
Geobits il

Sembra che il veleno sia la vera bomba atomica in questo gioco :)

5

Nodémon - Javascript

Poiché lo status sembra essere la strategia dominante, questa squadra si concentra sulla velocità per ottenere prima gli stati come il veleno e la confusione sugli avversari, quindi si blocca con cure e / o sonno mentre l'avversario si perde.

Non ho PHP installato, quindi questo non è testato contro i campeggiatori, ma sembra essere un discreto concorrente di LittleKid nelle mie prove (e decima Bitter Rivals).

/*jshint node:true*/
'use strict';

var fs = require('fs');

var dataFile = 'Nodemon/data.json';
function getData(callback) {
  fs.readFile(dataFile, 'utf8', function(err, contents) {
    var data = {round: 0};

    if(!err) {
      data = JSON.parse(contents);
    }

    callback(data);
  });
}

function saveData(data, callback) {
  fs.mkdir('Nodemon', function() {    
    fs.writeFile(dataFile, JSON.stringify(data), callback);
  });
}

var effect = {
  poison: '1',
  confusion: '2',
  burn: '3',
  sleep: '4',
  heal: '5',
  attackUp: '6',
  attackDown: '7',
  defenseUp: '8',
  defenseDown: '9',
  speedDown: '10'
};

function parseMemberCommon(args) {
  return {
    name: args[0],
    id: args[1],
    baseAttack: +args[2],
    baseDefense: +args[3],
    baseSpeed: +args[4],
    hp: +args[5],
    typeId: args[6],
    poisonedTurns: +args[7],
    effects: args.slice(8)
  };
}

function parseOwnMember(arg) {
  var args = arg.split(':');

  var ownArgs = args.splice(8, 6);

  var member = parseMemberCommon(args);

  member.moveCount = [
    +ownArgs[0],
    +ownArgs[1],
    +ownArgs[2]
  ];

  member.bonusAttack = +ownArgs[3];
  member.bonusDefense = +ownArgs[3];
  member.bonusSpeed = +ownArgs[3];

  return member;
}

function parseOpponentMember(arg) {
  return parseMemberCommon(arg.split(':'));
}

function parseTeamStateCommon(arg, memberParse) {
  var args = arg.split(':');
  var state = {
    name: args[0],
    members: []
  };
  args = arg.substring(state.name.length + 1).split('|');
  var activeSlot = args[0];
  for(var index = 1; index < args.length; index++) {
    state.members.push(memberParse(args[index]));
  }
  state.activeMember = state.members[activeSlot];
  return state;
}

function parseOwnState(arg) {
  return parseTeamStateCommon(arg, parseOwnMember);
}

function parseOpponentState(arg) {
  return parseTeamStateCommon(arg, parseOpponentMember);
}

function parseBattleState(arg) {
  var args = arg.split('#');
  return {
    own: parseOwnState(args[0]),
    opponent: parseOpponentState(args[1])
  };
}

function teamData() {

  saveData({round:0}, function() {
    console.log('Nodemon|' + 
      'Charasaur:0:50:80:100:10:13:1|' +
      'Bulbtortle:4:50:80:100:10:13:1|' +
      'Squirtmander:1:50:80:100:10:13:4');
  });
}

function getActiveIndex(battleState) {
  for(var index = 0; index < battleState.own.members.length; index++) {
    var member = battleState.own.members[index];
    if(member.hp > 0) {
      return index;
    }
  }
}

function chooseActive(arg) {
  var battleState = parseBattleState(arg);

  getData(function(data) {
    var allFull = true;
    for(var index = 0; index < battleState.opponent.members.length; index++) {
      var member = battleState.opponent.members[index];
      if(!data.maxSpeed || member.baseSpeed > data.maxSpeed) {
        data.maxSpeed = member.baseSpeed;
      }
      if(member.hp < 100) {
        allFull = false;
      }
    }

    if(allFull) {
      data.round++;
    }

    saveData(data, function() {
      console.log(getActiveIndex(battleState));
    });    
  });
}

function useMove(moves, battleState) {
  var fighter = battleState.own.activeMember;

  for(var moveIndex = 0; moveIndex < moves.length; moveIndex++) {
    var move = moves[moveIndex];
    if(fighter.moveCount[move]) {
      return move;
    }

    for(var memberIndex = 0; memberIndex < battleState.own.members.length; memberIndex++) {
      var member = battleState.own.members[memberIndex];

      if(member.hp > 0 && member.moveCount[move] > 0) {
        return 10 + memberIndex;
      }
    }
  }

  return -1;  //do nothing
}

function battleAction(arg) {
  var battleState = parseBattleState(arg);

  var fighter = battleState.own.activeMember;
  var opponent = battleState.opponent.activeMember;

  var attemptedMoves = [];

  if(opponent.effects.indexOf(effect.poison) === -1) {
    attemptedMoves.push(1);
  }

  if(opponent.effects.indexOf(effect.confusion) === -1) {
    attemptedMoves.push(0);
  }

  if(fighter.name === 'Squirtmander') {
    //sleep
    if(opponent.effects.indexOf(effect.sleep) === -1) {
      attemptedMoves.push(2);
    }
  }
  else {
    //heal
    if(fighter.hp <= 60) {
      attemptedMoves.push(2);
    }
  }

  console.log(useMove(attemptedMoves, battleState));
}

function bonusStats(arg) {
  var teamState = parseOwnState(arg);

  getData(function(data) {
    var result = '1:';

    if(data.round % 4 === 0) {
      result += '1:';
    }
    else {
      result += '2:';
    }
    if(teamState.members[2].baseSpeed + teamState.members[2].bonusSpeed > data.maxSpeed + (data.round / 2)) {
      result += '1';
    }
    else {
      result += '2';
    }
    console.log(result);
  });
}

var actions = {
  'T': teamData,
  'C': chooseActive,
  'A': battleAction,
  'B': bonusStats
};

var arg = process.argv[2];
actions[arg[0]](arg.substring(2));

Corri con

node nodemon

PS si scusa con nodemon .


Questo si sta intensificando verso una guerra globale di script lato server: D

4

Bitter Rivals - Java

Un team di Grass / Fire / Water a cui piace cambiarlo.

Greenosaur

Ha una copertura almeno neutrale su chiunque. Alta velocità per compensare la mancanza di difesa.

Type: Grass
Attack:   80     Vine
Defense:  50     Punch
Speed:   100     Pain

Searizard

Prova i nemici Sap con attacco basso. Burns e Fireballs dopo.

Type: Fire
Attack:  100     Fireball
Defense:  50     Burn
Speed:    80     Sap

Scudo distrutto

Usa Shield per migliorare la sua già alta difesa. Guarisce quando necessario.

Type: Water
Attack:   80     Watergun
Defense: 100     Shield
Speed:    50     Heal

Codice

Questo è incluso anche con il controller. Questa è una squadra in competizione, a differenza di DummyTeam. Il comando necessario per players.confè:

java BitterRivals

public class BitterRivals {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You're not doing this right. Read the spec and try again.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "BitterRivals";
                out += "|Greenosaur:4:80:50:100:12:0:3";
                out += "|Searizard:2:100:50:80:6:7:14";
                out += "|Blastshield:3:80:100:50:9:11:1";
                break;
            case "B":
                out = "2:0:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];

                int pick = 0;
                switch(getField(them, TYPE, getActive(them))){
                    case 0:
                    case 1:
                    case 3:
                        pick = 0;
                        break;
                    case 2:
                        pick = 2;
                        break;
                    case 4:
                        pick = 1;
                        break;
                }

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = pick + "";
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int oType = getField(them, TYPE, getActive(them));
                switch(active){
                    case 0:         // Greenosaur
                        switch(oType){
                            case 0:
                            case 4:
                                out = "1";
                                break;
                            case 1:
                                out = "2";
                                break;
                            case 3:
                                out = "0";
                                break;
                            case 2:
                                if(isAlive(me, 2)){
                                    out = "12";
                                } else if(isAlive(me, 1)){
                                    out = "11";
                                } else {
                                    out = "1";
                                }
                                break;
                        }
                        break;
                    case 1:         // Searizard
                        if(oType == 3){
                            if(isAlive(me, 0)){
                                out = "10";
                                break;
                            } else if(isAlive(me, 2)){
                                out = "12";
                                break;
                            }
                            if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                out = "1";
                            } else if(getField(me, MOVE2, active) > 0){
                                out = "2";
                            } else {
                                out = "3";
                            }                           
                        } else {
                            if(getField(them, ATTACK, getActive(them)) < 80){
                                if(getEffectCount(them, DEFENSE_DOWN, getActive(them), false) < 1 && getField(me, MOVE2, active) > 0){
                                    out = "2";
                                    break;
                                } else if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                    out = "1";
                                    break;
                                }
                            }
                            out = "0";
                        }
                        break;
                    case 2:         // Blastshield
                        if(oType == 4){
                            if(isAlive(me, 1)){
                                out = "11";
                                break;
                            } else if(isAlive(me, 0)){
                                out = "10";
                                break;
                            }
                        }
                        if(getField(me, HP, active) < 50 && getField(me, MOVE2, active) > 0){
                            out = "2";
                        } else if(getEffectCount(me, DEFENSE_UP, active, true) < 3 && getField(me, MOVE1, active) > 0){
                            out = "1";
                        } else {
                            out = "0";
                        }
                        break;
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6; 
    final static int PTURNS =   7; 
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10; 
    final static int HA =       11; 
    final static int HD =       12; 
    final static int HS =       13; 

    final static int POISON =           1;
    final static int CONFUSION =        2;
    final static int BURN =             3;
    final static int SLEEP =            4;
    final static int ATTACK_UP =        6;
    final static int ATTACK_DOWN =      7;
    final static int DEFENSE_UP =       8;
    final static int DEFENSE_DOWN =     9;
    final static int SPEED_DOWN =       10;
}

4

Errore 310: troppi reindirizzamenti - C ++

Una squadra altamente qualificata e organizzata per contrastare le devastazioni del veleno

Per tre settimane, ho appena addestrato i miei codici. Ho formato diverse squadre. E infine, sono pronto per affrontare questa sfida. Per rispondere a tutti i miei avversari avvelenatori, ho formato una squadra con codici molto diversi, ognuno con un ruolo specifico.


Antidoto(Immagine)

Type : Normal - atk:50 def:100 spd:80 - Poison/Burn/Heal

L'antidoto ama il veleno. Tanto che non posso impedirgli di precipitarsi in attacchi di avvelenamento.


zen(Immagine)

Type : Fire - atk:100 def:80 spd:50 - Poison/Vine/Heal

Lo Zen è un codice molto sorprendente che si adatta a tutti gli effetti. Preferisce guardare i suoi nemici lottare e sfinirsi contro il suo silenzio.


Triforce(Immagine)

Type : Psychic - atk:88 def:60 spd:82 - Fireball/Watergun/Vine

Triforce è un classico codice, sempre pronto a combattere. Questo usa la sua forza psichica per controllare i tre elementi e infliggere quanti più danni possibile.


Puoi scaricare il team qui:

Linux:

http://dl.free.fr/iHYlmTOQ2

avviare con ./Error310TMR

Finestre :

http://dl.free.fr/vCyjtqo2s

avviare con ./Error310TMR.exe

Il codice è un progetto c ++ completo. Non so come pubblicarlo.

$ wc -l src/*
    165 src/BruteForce.cpp
     26 src/BruteForce.h
    349 src/Codemon.cpp
     77 src/Codemon.h
     21 src/Logger.cpp
     35 src/Logger.h
    105 src/NoTimeToExplain.cpp
     27 src/NoTimeToExplain.h
    240 src/Recoverator.cpp
     31 src/Recoverator.h
     26 src/StrManip.cpp
     16 src/StrManip.h
    303 src/Team.cpp
     68 src/Team.h
     88 src/TooManyRedirects.cpp
     24 src/TooManyRedirects.h
     87 src/Unrecoverable.cpp
     27 src/Unrecoverable.h
     59 src/enums.cpp
    119 src/enums.h
     68 src/main.cpp
   1961 total

Ma è molto efficace:

------- Final Results -------

176     Error310TMR
131     H3C
130     LittleKid
121     Nodemon
58      InsideYourHead
47      HardenedTrio
37      BitterRivals

2

Fiaba

Un team di metà strada abbastanza generico. Basato su tre archetipi che provano a fare le loro cose e cambiano se non riescono affatto a fare le loro cose.

Questa squadra è stata creata prima che sembrasse che il veleno fosse la nuova meta, non ho davvero tenuto il passo con il cambio della mia squadra da quando l'ho fatto originariamente, la maggior parte del tempo è stato impiegato solo per cercare di abbattere. Non sono ancora riuscito a far funzionare il torneo per provarlo, ma è stata una settimana piuttosto impegnativa. Se questo in realtà non funziona come sembra con i miei dati di test, applicherò un po 'più di lucentezza dopo il lavoro.

#!/bin/perl
use 5.20.0;
use strict;

use constant MINE => 0;
use constant THEIRS => 1;

$_ = $ARGV[0];

if(/^T/){
    say 'FairyTale|Fairy:1:89:90:51:3:4:13|Dragon:2:100:50:80:6:1:8|Assassin:0:70:60:100:0:1:10';

} elsif(/^C#(.*)/){
    my $state = readBattleState($1);
    if($state->[MINE]->{$state->[MINE]->{slot}}{hp}){
        say $state->[MINE]->{slot};
    } elsif($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp}){
        say (($state->[MINE]->{slot}+1)%3);
    } else {
        say (($state->[MINE]->{slot}+2)%3);
    }

} elsif(/^A#(.*)/){
    my $state = readBattleState($1);
    my @actives = (
        $state->[MINE]->{$state->[MINE]->{slot}},
        $state->[THEIRS]->{$state->[THEIRS]->{slot}}
    );
    if($state->[MINE]->{slot} == 0){
        if(!exists($actives[THEIRS]{effects}{4}) && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif(!exists($actives[THEIRS]{effects}{1}) && $actives[MINE]{pp}->[2]) {
            say 2;
        } elsif(!$actives[THEIRS]{type}) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 1){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 2){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif($actives[THEIRS]{type} == 1) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    }

} elsif(/^B#(.*)/){
    my $state = readTeam($1, 1);
    say '1:0:2';
}

sub readBattleState {
    local $_ = $_[0];
    if(/^(.*?)#(.*?)$/){
        my @teams;
        $teams[0] = readTeam($1, 1);
        $teams[1] = readTeam($2, 0);
        return \@teams;
    }
}

sub readTeam {
    my $isMine = $_[1];
    local $_ = $_[0];
    if(/.*?:(?<slot>.*?)\|(.*?)\|(.*?)\|(.*?)$/){
        my %team;
        $team{slot} = $1;
        $team{0} = $isMine ? readYourMember($2) : readTheirMember($2);
        $team{1} = $isMine ? readYourMember($3) : readTheirMember($3);
        $team{2} = $isMine ? readYourMember($4) : readTheirMember($4);
        return \%team;
    }
    return 0;
}

sub readYourMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?):(?<move0>.*?):(?<move1>.*?):(?<move2>.*?):(?<batk>.*?):(?<bdef>.*?):(?<bspd>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk}+$+{batk},
            def    => $+{def}+$+{bdef},
            spd    => $+{spd}+$+{bspd},
            type   => $+{type},
            pp     => [$+{move0}, $+{move1}, $+{move2}],
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
}

sub readTheirMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk},
            def    => $+{def},
            spd    => $+{spd},
            type   => $+{type},
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
    return 0;
}

sub readEffects {
    local $_ = $_[0];
    my @retval = /:([^:]*)/g;
    if(!@retval){
        @retval = (0);
    }
    return @retval;
}

Corri con

perl fairytale.pl

Questo bot viene espulso per aver tentato di "scegliere membri morti attivi" dopo la prima morte. Non passa mai la prima battaglia che posso vedere.
Geobits il

Veramente? Pensavo di aver risolto quel bug prima, forse questa è una versione precedente di quel codice ...
mezzoEmrys,

Non dimenticare che quando un codemon viene eliminato, i suoi punti di cura diminuiscono a 0 o meno . Quindi la if($state->[MINE]->{$state->[MINE]->{slot}}{hp})dichiarazione non funzionerà correttamente senza >0.
GholGoth21

Ah, sì, lo farebbe.
mezzoEmrys

0

Squadra fittizia - Java

(CW non in competizione)

Questa è una squadra fittizia su cui esercitarsi. Sono tutti tipi normali, che scelgono casualmente tra le loro mosse (Pugno, Guarigione, Lenta) ogni turno. Divertiti con esso.

public class DummyTeam {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You need to run this from the tournament. Try to keep up.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String out = "";
        switch(sections[0]){
            // team data
            //      sends back all Normal types with minimum stats and Normal moves (randomized name suffixes to distinguish in tests)
            case "T":
                out = "DummyTeam";
                for(int i=0;i<3;i++)
                    out += "|Dummy"+((char)(Math.random()*26)+65) + i + ":0:50:50:50:0:1:2";
                break;
            // bonus points
            //      shoves them all in defense every time
            case "B":
                out = "1:1:1";
                break;
            // choose active
            //      picks last active if alive, otherwise loops to find first living member
            case "C":
                String[] team = sections[1].split("\\|");
                int current = Integer.parseInt(team[0].split(":")[1]);
                if(Integer.parseInt(team[current+1].split(":")[5]) > 0){
                    out = current + "";
                } else {
                    for(int i=1;i<team.length;i++){
                        if(Integer.parseInt(team[i].split(":")[5]) > 0){
                            out = (i - 1) + "";
                        }
                    }
                }               
                break;
            // choose action
            //      chooses a random move. does not check if it ran out of uses, so wastes turns quite often
            case "A":
                out = ((int)(Math.random()*3)) + "";
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }


}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.