The Rock, Paper, Scissors, Lizard, Spock Torneo di Epicness


98

Classifica più recente @ 2014-08-02 12:00

| Pos # | Author               | Name                    | Language   | Score | Win   | Draw  | Loss  | Avg. Dec. Time |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
| 1st   | Emil                 | Pony                    | Python2    | 064   | 064   | 000   | 005   | 0026.87 ms     |
| 2nd   | Roy van Rijn         | Gazzr                   | Java       | 062   | 062   | 001   | 006   | 0067.30 ms     |
| 2nd   | Emil                 | Dienstag                | Python2    | 062   | 062   | 001   | 006   | 0022.19 ms     |
| 4th   | ovenror              | TobiasFuenke            | Python2    | 061   | 061   | 001   | 007   | 0026.89 ms     |
| 5th   | PhiNotPi             | BayesianBot             | Perl       | 060   | 060   | 000   | 009   | 0009.27 ms     |
| 6th   | Claudiu              | SuperMarkov             | Python2    | 058   | 058   | 001   | 010   | 0026.77 ms     |
| 7th   | histocrat            | Alternator              | Ruby       | 057   | 057   | 001   | 011   | 0038.53 ms     |
| 8th   | histocrat            | LeonardShelby           | Ruby       | 053   | 053   | 000   | 016   | 0038.55 ms     |
| 9th   | Stretch Maniac       | SmarterBot              | Java       | 051   | 051   | 002   | 016   | 0070.02 ms     |
| 9th   | Martin Büttner       | Markov                  | Ruby       | 051   | 051   | 003   | 015   | 0038.45 ms     |
| 11th  | histocrat            | BartBot                 | Ruby       | 049   | 049   | 001   | 019   | 0038.54 ms     |
| 11th  | kaine                | ExcitingishBot          | Java       | 049   | 049   | 001   | 019   | 0065.87 ms     |
| 13th  | Thaylon              | UniformBot              | Ruby       | 047   | 047   | 001   | 021   | 0038.61 ms     |
| 14th  | Carlos Martinez      | EasyGame                | Java       | 046   | 046   | 002   | 021   | 0066.44 ms     |
| 15th  | Stretch Maniac       | SmartBot                | Java       | 045   | 045   | 001   | 023   | 0068.65 ms     |
| 16th  | Docopoper            | RoboticOboeBotOboeTuner | Python2    | 044   | 044   | 000   | 025   | 0156.55 ms     |
| 17th  | Qwix                 | Analyst                 | Java       | 043   | 043   | 001   | 025   | 0069.06 ms     |
| 18th  | histocrat            | Analogizer              | Ruby       | 042   | 042   | 000   | 027   | 0038.58 ms     |
| 18th  | Thaylon              | Naan                    | Ruby       | 042   | 042   | 004   | 023   | 0038.48 ms     |
| 20th  | Thaylon              | NitPicker               | Ruby       | 041   | 041   | 000   | 028   | 0046.21 ms     |
| 20th  | bitpwner             | AlgorithmBot            | Python2    | 041   | 041   | 001   | 027   | 0025.34 ms     |
| 22nd  | histocrat            | WereVulcan              | Ruby       | 040   | 040   | 003   | 026   | 0038.41 ms     |
| 22nd  | Ourous               | QQ                      | Cobra      | 040   | 040   | 003   | 026   | 0089.33 ms     |
| 24th  | Stranjyr             | RelaxedBot              | Python2    | 039   | 039   | 001   | 029   | 0025.40 ms     |
| 25th  | JoshDM               | SelfLoathingBot         | Java       | 038   | 038   | 001   | 030   | 0068.75 ms     |
| 25th  | Ourous               | Q                       | Cobra      | 038   | 038   | 001   | 030   | 0094.04 ms     |
| 25th  | Ourous               | DejaQ                   | Cobra      | 038   | 038   | 001   | 030   | 0078.31 ms     |
| 28th  | Luis Mars            | Botzinga                | Java       | 037   | 037   | 002   | 030   | 0066.36 ms     |
| 29th  | kaine                | BoringBot               | Java       | 035   | 035   | 000   | 034   | 0066.16 ms     |
| 29th  | Docopoper            | OboeBeater              | Python2    | 035   | 035   | 002   | 032   | 0021.92 ms     |
| 29th  | Thaylon              | NaanViolence            | Ruby       | 035   | 035   | 003   | 031   | 0038.46 ms     |
| 32nd  | Martin Büttner       | SlowLizard              | Ruby       | 034   | 034   | 004   | 031   | 0038.32 ms     |
| 33rd  | Kyle Kanos           | ViolentBot              | Python3    | 033   | 033   | 001   | 035   | 0032.42 ms     |
| 34th  | HuddleWolf           | HuddleWolfTheConqueror  | .NET       | 032   | 032   | 001   | 036   | 0029.86 ms     |
| 34th  | Milo                 | DogeBotv2               | Java       | 032   | 032   | 000   | 037   | 0066.74 ms     |
| 34th  | Timmy                | DynamicBot              | Python3    | 032   | 032   | 001   | 036   | 0036.81 ms     |
| 34th  | mccannf              | YAARBot                 | JS         | 032   | 032   | 002   | 035   | 0100.12 ms     |
| 38th  | Stranjyr             | ToddlerProof            | Java       | 031   | 031   | 010   | 028   | 0066.10 ms     |
| 38th  | NonFunctional User2..| IHaveNoIdeaWhatImDoing  | Lisp       | 031   | 031   | 002   | 036   | 0036.26 ms     |
| 38th  | john smith           | RAMBOBot                | PHP        | 031   | 031   | 002   | 036   | 0014.53 ms     |
| 41st  | EoinC                | SimpleRandomBot         | .NET       | 030   | 030   | 005   | 034   | 0015.68 ms     |
| 41st  | Martin Büttner       | FairBot                 | Ruby       | 030   | 030   | 006   | 033   | 0038.23 ms     |
| 41st  | Docopoper            | OboeOboeBeater          | Python2    | 030   | 030   | 006   | 033   | 0021.93 ms     |
| 44th  | undergroundmonorail  | TheGamblersBrother      | Python2    | 029   | 029   | 000   | 040   | 0025.55 ms     |
| 45th  | DrJPepper            | MonadBot                | Haskel     | 028   | 028   | 002   | 039   | 0008.23 ms     |
| 46th  | Josef E.             | OneBehind               | Java       | 027   | 027   | 007   | 035   | 0065.87 ms     |
| 47th  | Ourous               | GitGudBot               | Cobra      | 025   | 025   | 001   | 043   | 0053.35 ms     |
| 48th  | ProgramFOX           | Echo                    | .NET       | 024   | 024   | 004   | 041   | 0014.81 ms     |
| 48th  | JoshDM               | SelfHatingBot           | Java       | 024   | 024   | 005   | 040   | 0068.88 ms     |
| 48th  | Trimsty              | Herpetologist           | Python3    | 024   | 024   | 002   | 043   | 0036.93 ms     |
| 51st  | Milo                 | DogeBot                 | Java       | 022   | 022   | 001   | 046   | 0067.86 ms     |
| 51st  | William Barbosa      | StarWarsFan             | Ruby       | 022   | 022   | 002   | 045   | 0038.48 ms     |
| 51st  | Martin Büttner       | ConservativeBot         | Ruby       | 022   | 022   | 001   | 046   | 0038.25 ms     |
| 51st  | killmous             | MAWBRBot                | Perl       | 022   | 022   | 000   | 047   | 0016.30 ms     |
| 55th  | Mikey Mouse          | LizardsRule             | .NET       | 020   | 020   | 007   | 042   | 0015.10 ms     |
| 55th  | ja72                 | BlindForesight          | .NET       | 020   | 020   | 001   | 048   | 0024.05 ms     |
| 57th  | robotik              | Evolver                 | Lua        | 019   | 019   | 001   | 049   | 0008.19 ms     |
| 58th  | Kyle Kanos           | LexicographicBot        | Python3    | 018   | 018   | 003   | 048   | 0036.93 ms     |
| 58th  | William Barbosa      | BarneyStinson           | Lua        | 018   | 018   | 005   | 046   | 0005.11 ms     |
| 60th  | Dr R Dizzle          | BartSimpson             | Ruby       | 017   | 017   | 001   | 051   | 0038.22 ms     |
| 60th  | jmite                | IocainePowder           | Ruby       | 017   | 017   | 003   | 049   | 0038.50 ms     |
| 60th  | ArcticanAudio        | SpockOrRock             | PHP        | 017   | 017   | 001   | 051   | 0014.19 ms     |
| 60th  | Dr R Dizzle          | BetterLisaSimpson       | Ruby       | 017   | 017   | 000   | 052   | 0038.23 ms     |
| 64th  | Dr R Dizzle          | LisaSimpson             | Ruby       | 016   | 016   | 002   | 051   | 0038.29 ms     |
| 65th  | Martin Büttner       | Vulcan                  | Ruby       | 015   | 015   | 001   | 053   | 0038.26 ms     |
| 65th  | Dr R Dizzle          | Khaleesi                | Ruby       | 015   | 015   | 005   | 049   | 0038.29 ms     |
| 67th  | Dr R Dizzle          | EdwardScissorHands      | Ruby       | 014   | 014   | 002   | 053   | 0038.21 ms     |
| 67th  | undergroundmonorail  | TheGambler              | Python2    | 014   | 014   | 002   | 053   | 0025.47 ms     |
| 69th  | cipher               | LemmingBot              | Python2    | 011   | 011   | 002   | 056   | 0025.29 ms     |
| 70th  | Docopoper            | ConcessionBot           | Python2    | 007   | 007   | 000   | 062   | 0141.31 ms     |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
Total Players: 70
Total Matches Completed: 2415
Total Tourney Time: 06:00:51.6877573

Note di torneo

Bot esclusi

  • BashRocksBot - ancora nessuna gioia con .net che esegue script cygwin bash
  • CounterPreferenceBot - in attesa di correzione di bug
  • RandomlyWeighted - in attesa di correzione di bug
  • CasinoShakespeare - escluso perché richiede una connessione Internet attiva

Domanda postata originale

Ti sei girato a casa dei tuoi amici per lo scontro più epico di sempre tra Rock, Paper, Scissors, Lizard, Spock. Nel vero stile di BigBang nerd-tastic, nessuno dei giocatori sta giocando da solo, ma ha creato robot console per giocare per suo conto. Tiri fuori la tua chiave USB e la passi allo Sheldor the Conqueror per l'inclusione nello showdown. Penny svenisce. O forse Howard svenisce. Non giudichiamo qui nell'appartamento di Leonard.

Regole

Si applicano le regole Standard Rock, Paper, Scissors, Lizard, Spock.

  • Carta tagliata a forbice
  • Copertine di carta Rock
  • La roccia schiaccia la lucertola
  • La lucertola avvelena Spock
  • Spock rompe le forbici
  • Le forbici decapitano la lucertola
  • La lucertola mangia la carta
  • La carta smentisce Spock
  • Spock vaporizza il Rock
  • Forbici da schiacciamento

Regole RPSLV

Il bot di ogni giocatore giocherà una partita l' uno contro l'altro nel torneo.

Ogni incontro sarà composto da 100 iterazioni di un gioco RPSLV.

Dopo ogni partita, il vincitore è il giocatore che ha vinto il maggior numero di partite / mani su 100.

Se vinci una partita, ti verrà assegnato 1 punto nella classifica. Nel risultato di un pareggio, nessuno dei due giocatori guadagnerà un punto.

Requisiti del robot

Il bot deve essere eseguibile dalla riga di comando.

La scatola * nix di Sheldor è morta, quindi la stiamo eseguendo dal suo laptop da gioco Windows 8, quindi assicurati che la soluzione fornita possa essere eseguita su Windows. Sheldor si è gentilmente offerto di installare tutti i runtime richiesti (entro limiti ragionevoli) per poter eseguire la soluzione. (.NET, Java, Php, Python, Ruby, Powershell ...)

ingressi

Nella prima partita di ogni partita non vengono forniti argomenti al bot. In ogni gioco successivo di ogni incontro: - Arg1 conterrà la cronologia delle mani / decisioni dei tuoi robot in questo incontro. - Arg2 conterrà la cronologia delle mani / decisioni dei tuoi avversari in questa partita.

La storia sarà rappresentata da una sequenza di singole lettere maiuscole che rappresentano le possibili mani che puoi giocare.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

Per esempio

  • Gioco 1: MyBot.exe
  • Gioco 2: MyBot.exe SV
  • Gioco 3: MyBot.exe SS VL
  • Gioco 4: MyBot.exe SSR VLS

Produzione

Il tuo bot deve scrivere una risposta per singolo personaggio che rappresenta la sua "mano" per ogni gioco. Il risultato dovrebbe essere scritto su STDOUT e il bot dovrebbe quindi uscire. Di seguito sono riportati i caratteri maiuscoli validi.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

Nel caso in cui il tuo bot non restituisca una mano valida (ovvero 1 delle 5 maiuscole sopra indicate, allora perdi automaticamente quella mano e la partita continua.

Nel caso in cui entrambi i robot non restituiscano una mano valida, il gioco viene considerato un pareggio e la partita continua.

Formato partita

Ogni bot inviato giocherà una partita contro l'altro bot nel torneo.

Ogni partita durerà esattamente 100 partite.

Le partite si giocheranno in forma anonima, non avrai una conoscenza avanzata del bot specifico contro cui stai giocando, tuttavia puoi utilizzare tutte le informazioni che puoi ottenere dal suo processo decisionale durante la cronologia della partita corrente per modificare la tua strategia contro il tuo avversario. Puoi anche tenere traccia della cronologia dei tuoi giochi precedenti per creare schemi / euristiche ecc ... (Vedi le regole di seguito)

Durante una singola partita, il motore di orchestrazione eseguirà il bot e i bot degli avversari a una distanza di 100 millisecondi, quindi confronterà i risultati al fine di evitare eventuali collisioni del PRNG nella stessa lingua / runtime. (questo in realtà mi è successo durante i test).

Giudizio e vincoli

Il Dr. Sheldon Cooper nelle vesti di Sheldor il Conquistatore si è gentilmente offerto di supervisionare lo svolgimento del torneo. Sheldor the Conqueror è un sorvegliante giusto e giusto (per lo più). Tutte le decisioni di Sheldor sono definitive.

Il gioco si svolgerà in modo corretto e corretto:

  • Lo script / programma del bot verrà archiviato nel motore di orchestrazione in una sottocartella Players\[YourBotName]\
  • Puoi utilizzare la sottocartella Players\[YourBotName]\dataper registrare tutti i dati o la cronologia di gioco del torneo corrente mentre procede. Le directory dei dati verranno eliminate all'inizio di ogni torneo.
  • Non puoi accedere alla directory dei giocatori di un altro giocatore nel torneo
  • Il tuo bot non può avere un codice specifico che ha come target un altro comportamento specifico dei bot
  • Ogni giocatore può inviare più di un bot per giocare purché non interagiscano o si assistano a vicenda.

Modifica - Vincoli aggiuntivi

  • Per quanto riguarda i forfait, non saranno supportati. Il tuo bot deve giocare una delle 5 mani valide. Metterò alla prova ogni bot al di fuori del torneo con alcuni dati casuali per assicurarmi che si comportino bene. Tutti i bot che generano errori (ad es. Errori di perdita) saranno esclusi dal torneo fino a quando non verranno corretti.
  • I robot possono essere derivati ​​a condizione che siano succintamente diversi nel loro comportamento. I bot (anche in altre lingue) che svolgono esattamente lo stesso comportamento di un bot esistente verranno squalificati
  • Esistono già bot di spam per quanto segue, quindi non inviare nuovamente
    • Rock - BartSimpson
    • Carta - LisaSimpson
    • Scissor - Edward mani di forbice
    • Spock - Vulcan
    • Lucertola - Khaleesi
    • Pseudo casuale - SimpleRandomBot & FairBot
    • Psuedo Random RPS - ConservativeBot
    • Psuedo Random LV - Barney Stinson
  • I robot non possono chiamare servizi di terze parti o risorse Web (o qualsiasi altra cosa che rallenta in modo significativo la velocità / il tempo decisionale delle partite). CasinoShakespeareè l'unica eccezione in quanto il bot è stato inviato prima dell'aggiunta di questo vincolo.

Sheldor aggiornerà questa domanda il più spesso possibile con i risultati del Torneo, man mano che vengono inviati più robot.

Programma di orchestrazione / controllo

Il programma di orchestrazione, insieme al codice sorgente per ogni bot, è disponibile su github.

https://github.com/eoincampbell/big-bang-game

Dettagli di invio

Il tuo invio dovrebbe includere

  • Il nome del tuo Bot
  • Il tuo codice
  • Un comando a
    • esegui il tuo bot dalla shell ad es
    • ruby myBot.rb
    • python3 myBot.py
    • O
    • prima compilare entrambi e quindi eseguirlo. per esempio
    • csc.exe MyBot.cs
    • MyBot.exe

Invio campione

BotName: SimpleRandomBot
Compile: "C:\Program Files (x86)\MSBuild\12.0\Bin\csc.exe" SimpleRandomBot.cs
Run:     SimpleRandomBot [Arg1] [Arg2]

Codice:

using System;
public class SimpleRandomBot
{
    public static void Main(string[] args)
    {
        var s = new[] { "R", "P", "S", "L", "V" };
        if (args.Length == 0)
        {
            Console.WriteLine("V"); //always start with spock
            return;
        }
        char[] myPreviousPlays = args[0].ToCharArray();
        char[] oppPreviousPlays = args[1].ToCharArray();
        Random r = new Random();
        int next = r.Next(0, 5);
        Console.WriteLine(s[next]);
    }
}

Una precisazione

Per qualsiasi domanda, poni nei commenti qui sotto.


7
Che aspetto ha la storia quando un giocatore ha perso una mano?
istocrato,

1
Stavo per andare fuori di testa con un approccio analitico, ma la maggior parte dei robot qui sono abbastanza stupidi da sconfiggere l'IA intelligente.
soffice

1
Solo perché non sono mai in testa a nessuna sfida KotH a cui ho partecipato, ho preso uno screenshot come ricordo.
Kyle Kanos,

3
Farò un altro torneo stasera e pubblicherò i risultati della partita completa su pastebin ... il prossimo batch avrà circa 450 partite, ma dovrebbe essere un po 'più veloce da eseguire poiché ho implementato alcune cose di parallelismo nel programma di controllo
Eoin Campbell,

3
Se non sbaglio, sembra che ci sia un grave bug nello script dell'orchestrazione: le storie dei giocatori 1 e 2 sono sempre passate ai robot rispettivamente come primo e secondo argomento, mentre secondo le regole i robot dovrebbero sempre ottenere il loro prima la propria storia. Ora il giocatore 2 sta effettivamente cercando di battersi. (Sono diventato un po 'sospettoso perché il mio bot ha vinto ogni singola partita in cui era giocatore 1 mentre perdeva la metà delle altre partite.)
Emil,

Risposte:


26

Pony (Python 2)

Questo si basa su un robot con le forbici da roccia di carta che ho scritto qualche tempo fa per una sfida di programmazione alla fine di una lezione online di Udacity . L'ho cambiato per includere Spock e lucertola e ho apportato alcuni miglioramenti.

Il programma ha 11 diverse strategie semplici, ognuna con 5 varianti. Scegli tra questi in base a quanto si sarebbero esibiti negli ultimi round.

Ho rimosso una strategia di fallback che ha giocato casualmente contro avversari più forti. Immagino sia più divertente così.

import sys

# just play Spock for the first two rounds
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'V'; sys.exit()

# initialize and translate moves to numbers for better handling:
my_moves, opp_moves = sys.argv[1], sys.argv[2]
moves = ('R', 'P', 'S', 'V', 'L')   
history = zip([moves.index(i) for i in my_moves],
              [moves.index(i) for i in opp_moves])

# predict possible next moves based on history
def prediction(hist):
    N = len(hist)    

    # find longest match of the preceding moves in the earlier history
    cand_m = cand_o = cand_b = range(N-1)
    for l in xrange(1,min(N, 20)):
        ref = hist[N-l]
        cand_m = ([c for c in cand_m if c>=l and hist[c-l+1][0]==ref[0]]
                  or cand_m[-1:])
        cand_o = ([c for c in cand_o if c>=l and hist[c-l+1][1]==ref[1]]
                  or cand_o[-1:])
        cand_b = ([c for c in cand_b if c>=l and hist[c-l+1]==ref]
                  or cand_b[-1:])

    # analyze which moves were used how often
    freq_m, freq_o = [0]*5, [0]*5
    for m in hist:
        freq_m[m[0]] += 1
        freq_o[m[1]] += 1

    # return predictions
    return ([hist[-i][p] for i in 1,2 for p in 0,1]+   # repeat last moves
            [hist[cand_m[-1]+1][0],     # history matching of my own moves
             hist[cand_o[-1]+1][1],     # history matching of opponent's moves
             hist[cand_b[-1]+1][0],     # history matching of both
             hist[cand_b[-1]+1][1],
             freq_m.index(max(freq_m)), # my most frequent move
             freq_o.index(max(freq_o)), # opponent's most frequent move
             0])                        # good old rock (and friends)


# what would have been predicted in the last rounds?
pred_hist = [prediction(history[:i]) for i in xrange(2,len(history)+1)]

# how would the different predictions have scored?
n_pred = len(pred_hist[0])
scores = [[0]*5 for i in xrange(n_pred)]
for pred, real in zip(pred_hist[:-1], history[2:]):
    for i in xrange(n_pred):
        scores[i][(real[1]-pred[i]+1)%5] += 1
        scores[i][(real[1]-pred[i]+3)%5] += 1
        scores[i][(real[1]-pred[i]+2)%5] -= 1
        scores[i][(real[1]-pred[i]+4)%5] -= 1

# return best counter move
best_scores = [list(max(enumerate(s), key=lambda x: x[1])) for s in scores]
best_scores[-1][1] *= 1.001   # bias towards the simplest strategy    
if best_scores[-1][1]<0.4*len(history): best_scores[-1][1] *= 1.4
strat, (shift, score) = max(enumerate(best_scores), key=lambda x: x[1][1])
print moves[(pred_hist[-1][strat]+shift)%5]

Correre come:

python Pony.py

Modifica : ho apportato una piccola modifica inserendo una tendenza verso la strategia più semplice (ovvero giocando sempre la stessa mossa) in casi incerti. Questo aiuta un po 'a non provare a trovare schemi eccessivamente complicati dove non ce ne sono, ad esempio in robot come ConservativeBot.

Nota : ho cercato di spiegare la strategia di abbinamento della cronologia di base che questo bot utilizza nel post per il mio altro bot Dienstag .


3
Un rapporto di vincita del 96 percento è eccezionale.
AndoDaan,

Molto bella. Potrebbe piacerti la polvere di Iocaina , se non l'hai già vista.
wchargin,

@WChargin, ovviamente. :) Quando ho scritto il mio codice originale, avevo letto di Iocaina in polvere alcuni anni prima e ricordavo vagamente l'idea generale. Quindi, Pony ne è davvero ispirato, se non molto direttamente. A quanto pare, sono molto simili. Penso che il mio abbia un repertorio più ampio di strategie mentre l'Iocaine Powder ha un livello intelligente di ragionamento meta-meta che non ho incluso.
Emil,

20

Markov, Ruby

Guarda le ultime due mosse dell'avversario e determina i possibili (e molto probabilmente) follow-up. Se la combinazione non è stata scelta prima, usa invece tutte le mosse dell'avversario (finora). Quindi raccoglie tutte le possibili risposte per queste e ne sceglie una casuale.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

puts choices.sample

Corri come

markov.rb

E poi uso questo programma per determinare la mossa più possibile che farò dopo, poi scopro cosa farai e finalmente troverò un modo per battere quello che farai e ripetere all'infinito il tutto, ancora e ancora.
Jamie,

@Jamie Intendi come questo ragazzo? codegolf.stackexchange.com/a/35295/8478
Martin Ender

indovina. (il commento non è stato abbastanza lungo per essere pubblicato)
Jamie,

19

ConservativeBot, Ruby

Le cose nuove sono cose cattive.

puts ['R','P','S'].sample

Corri come

ruby conservative.rb

La versione OG è la migliore.
maxywb,

13

Star Wars Fan - Ruby

Fottiti, Spock

puts ['R','P','L','S'].sample

Eseguilo come:

ruby starwarsfan.rb

Aggiunto al controller
Eoin Campbell il

puoi eseguire il rollback con la modifica della risposta: ti faccio un commento qui quando li ho aggiunti.
Eoin Campbell,

Perché R e S? : P
cjfaure,

@mardavi È un fan di Star Wars perché non usa Spock.
William Barbosa,

ah, hai ragione (ovviamente). L'ho letto troppo in fretta, il mio errore (ma per fortuna senza conseguenze)
mardavi,

13

Barney Stinson - Lua

Ho solo una regola: il nuovo è sempre meglio. Fanculo il vecchio Jo Ken Po o come lo chiami.

math.randomseed(os.time())
print(math.random() > 0.5 and "V" or "L")

Eseguilo come:

lua legenwaitforitdary.lua

8

Boring Bot (Java)

Presume che tutti giochino sempre la stessa cosa e pianifichi di conseguenza. Di solito, però, raccoglie le pietre in un legame perché anche tutti gli altri hanno ragione?

public class BoringBot
{
    public static void main(String[] args)
    {
        int Rock=0;
        int Paper=0;
        int Scissors=0;
        int Lizard=0;
        int Spock=0;

        if (args.length == 0)
        {
            System.out.print("P");
            return;
        }

        char[] oppPreviousPlays = args[1].toCharArray();

        for (int j=0; j<oppPreviousPlays.length; j++) {
            switch(oppPreviousPlays[j]){
                case 'R': Rock++; break;
                case 'P': Paper++; break;
                case 'S': Scissors++; break;
                case 'L': Lizard++; break;
                case 'V': Spock++;
            }
        }

        int Best = Math.max(Math.max(Lizard+Scissors-Spock-Paper,
                                     Rock+Spock-Lizard-Scissors),
                            Math.max(Math.max(Paper+Lizard-Spock-Rock,
                                              Paper+Spock-Rock-Scissors),
                                     Rock+Scissors-Paper-Lizard));

        if (Best== Lizard+Scissors-Spock-Paper){
            System.out.print("R"); return;
        } else if (Best== Rock+Spock-Lizard-Scissors){
            System.out.print("P"); return;
        } else if (Best== Paper+Lizard-Spock-Rock){
            System.out.print("S"); return;
        } else if(Best== Paper+Spock-Rock-Scissors){
            System.out.print("L"); return;
        } else {
            System.out.print("V"); return;
        }
    }
}

Nota che se questa è una strategia che qualcun altro sta già usando fammi sapere e cancellerò. Sembra proprio quello ovvio che non avevo già visto.
Kaine,

è questo C #. sei .length proprietà sono sbagliate. e non esiste alcun metodomax
Eoin Campbell,

@EoinCampbell È java, ho giocato con entrambi e apparentemente ho dimenticato a quali comandi appartengono.
Kaine,

Ah, bello. lascialo con me e lo includerò.
Eoin Campbell,

ancora rotto. in esecuzione jre8 - java BoringBot.java - Errore: Impossibile trovare o caricare la classe principale D: \ My Software Dev \ big-bang-game \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.java -
Eoin Campbell

8

IocainePowder, Ruby

inserisci qui la descrizione dell'immagine

Basato sulla (spudoratamente rubata) strategia RPS qui . Il bot sembra scegliere un'ipotesi identica al bot Markov, ma poi assume che l'avversario abbia indovinato cosa sceglierà e sceglie una mossa per battere quella di conseguenza.

Nota che ho appena adattato l'idea di base della strategia collegata, non l'ho seguita in dettaglio.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

myChoice = choices.sample 
theirChoice = responses[myChoice].sample
actualChoice = responses[theirChoice].sample
puts actualChoice

Corri come

iocaine.rb

5
Continui a usare quella parola. Non penso che significhi ciò che pensi significhi.
JoshDM,

2
Il vero potere della polvere di Iocaina era quello di passare dall'uso del markov al battito-markov. Inizia come smart markov, ma una volta che rileva (inizia a perdere) passa alla modalità beat-markov. Dovrebbe essere facile da aggiungere.
Roy van Rijn,

Ah, intelligente! Non mentirò, avevo solo sentito parlare di Iocaina, ma non l'ho guardato in dettaglio. Sentiti libero di modificare il mio codice se desideri o inviare il tuo e ottenere il credito!
jmite,

8

HuddleWolfTheConqueror - C #

HuddleWolf è tornato e migliore che mai. Batterà Sheldor il Conquistatore nel suo gioco stupido. HuddleWolf è abbastanza intelligente da identificare e contrastare gli spammerbot. Per avversari più intelligenti, HuddleWolf usa la sua conoscenza delle statistiche di base di quinta elementare e utilizza un lancio di dadi ponderato basato sulla storia dei giochi dell'opposizione.

using System;
using System.Collections.Generic;
using System.Linq;

public class HuddleWolfTheConqueror
{

    public static readonly char[] s = new[] { 'R', 'P', 'S', 'L', 'V' };

    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine(pickRandom());
            return;
        }

        char[] myPlays = args[0].ToCharArray();
        char[] oppPlays = args[1].ToCharArray();

        char tryPredict = canPredictCounter(oppPlays);
        if (tryPredict != '^')
        {
            Console.WriteLine(tryPredict);
        }
        else
        {
            Console.WriteLine(pickRandom());
        }
        return;
    }


    public static char canPredictCounter(char[] history)
    {
        // don't predict if insufficient data
        if (history.Length < 5)
        {
            return '^';
        }

        // calculate probability of win for each choice
        Dictionary<char, double> dic = getBestProabability(history);

        // get item with highest probability of win
        List<char> maxVals = new List<char>();
        char maxVal = '^';
        double mostFreq = 0;
        foreach (var kvp in dic)
        {
            if (kvp.Value > mostFreq)
            {
                mostFreq = kvp.Value;
            }
        }
        foreach (var kvp in dic)
        {
            if (kvp.Value == mostFreq)
            {
                maxVals.Add(kvp.Key);
            }
        }

        // return error
        if (maxVals.Count == 0)
        {
            return maxVal;
        }

        // if distribution is not uniform, play best play
        if (maxVals.Count <= 3)
        {
            Random r = new Random(Environment.TickCount);
            return maxVals[r.Next(0, maxVals.Count)];
        }

        // if probability is close to uniform, use weighted dice roll
        if (maxVals.Count == 4)
        {
            return weightedRandom(dic);
        }

        // if probability is uniform, use random dice roll
        if (maxVals.Count >= 5)
        {
            return pickRandom();
        }

        // return error
        return '^';
    }

    public static Dictionary<char, double> getBestProabability(char[] history)
    {
        Dictionary<char, double> dic = new Dictionary<char, double>();
        foreach (char c in s)
        {
            dic.Add(c, 0);
        }
        foreach (char c in history)
        {
            if (dic.ContainsKey(c))
            {
                switch(c)
                {
                    case 'R' : 
                        dic['P'] += (1.0/(double)history.Length);
                        dic['V'] += (1.0/(double)history.Length);
                        break;
                    case 'P' : 
                        dic['S'] += (1.0/(double)history.Length);
                        dic['L'] += (1.0/(double)history.Length);
                        break;
                    case 'S' : 
                        dic['V'] += (1.0/(double)history.Length);
                        dic['R'] += (1.0/(double)history.Length);
                        break;
                    case 'L' : 
                        dic['R'] += (1.0/(double)history.Length);
                        dic['S'] += (1.0/(double)history.Length);
                        break;
                    case 'V' : 
                        dic['L'] += (1.0/(double)history.Length);
                        dic['P'] += (1.0/(double)history.Length);
                        break;
                    default : 
                        break;

                }
            }
        }
        return dic;
    }

    public static char weightedRandom(Dictionary<char, double> dic)
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 100);
        int curVal = 0;
        foreach (var kvp in dic)
        {
            curVal += (int)(kvp.Value*100);
            if (curVal > next)
            {
                return kvp.Key;
            }
        }
        return '^';
    }

    public static char pickRandom()
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 5);
        return s[next];
    }
}

8

ToddlerProof

Questo bot abbastanza stupido presume che stia interpretando un bambino che "inseguirà" le sue mosse, cercando sempre di battere tutto ciò che è stato lanciato l'ultima volta. Se il bot viene battuto più volte di seguito, passa a un nuovo punto nel pattern. Si basa sulla mia strategia per battere sempre il mio fratello molto più giovane. :)

EDIT :: Modificata la lunghezza di una serie di perdite richiesta per saltare in tiri casuali. Risolto anche un bug importante con il salto casuale.

Salva come ToddlerProof.java, compila, quindi esegui conjava ToddlerProof [me] [them]

import java.util.HashMap;
public class ToddlerProof
{
    char[] moves = new char[]{'R', 'P', 'S', 'L', 'V'};
    public static void main(String[] args)
    {
        if(args.length<1) //first Round
        {
            System.out.print('V');//Spock is best
            return;
        }
        else
        {
            String them = args[1];
            String me = args[0];
            int streak = 0;

            HashMap<Character, Character> nextMove = new HashMap<Character, Character>();
            //Next move beats things that beat my last move
            nextMove.put('L', 'V');
            nextMove.put('V', 'S');
            nextMove.put('S', 'P');
            nextMove.put('P', 'R');
            nextMove.put('R', 'L');
            //Check if last round was a tie or the opponent beat me
            int lastResult = winner(me.charAt(me.length()-1), them.charAt(them.length()-1));
            if(lastResult == 0)
            {
                //tie, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));

                return;
            }
            else if(lastResult == 1)
            {
                //I won, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));


                return;
            }

            else{
                //I lost
                //find streak
                for(int i = 0; i<me.length(); i++)
                {
                    int a = winner(me.charAt(i), them.charAt(i));
                    if(a >= 0) streak = 0;
                    else streak++;
                }
                //check lossStreak
                //If the streak is 2, then a rotation will make it even.
                //if it is >2, something bad has happened and I need to adjust.
                if(streak>2)
                {
                    //if they are on to me, do something random-ish
                    int r = (((them.length()+me.length()-1)*13)/7)%4;
                    System.out.print(move[r]);
                    return;
                }
                //otherwise, go on with the plan
                System.out.print(nextMove.get(me.charAt(me.length()-1)));
                return;
            }
        }
    }
    public static int winner(char me, char them)
    {
        //check for tie
        if(me == them) return 0;
        //check if they won
        if(me=='V' && (them == 'L' || them == 'P')) return -1;
        if(me=='S' && (them == 'V' || them == 'R')) return -1;
        if(me=='P' && (them == 'S' || them == 'L')) return -1;
        if(me=='R' && (them == 'P' || them == 'V')) return -1;
        if(me=='L' && (them == 'R' || them == 'S')) return -1;
        //otherwise, I won
        return 1;
    }
}

1
Dovremmo usare print o println? ... Non ne ero certo.
Kaine,

Hmmm. Immagino che entrambi funzionerebbero, ma potrei vedere un pasticcio se il programma di controllo afferrasse la nuova riga anziché il personaggio. Grazie per averlo sottolineato, modificherò il mio codice per ogni evenienza
Stranjyr,

@Stranjyr ci sono stati alcuni bug nella tua ultima corsa. Non ha bombardato il programma di controllo ma se cerchi la cronologia di "ToddlerProof gioca n" sembra che il tuo bot stia tornando nullo per certe mani e quindi autolosing la mano. Il gioco di esempio è "Echo & ToddlerProof" in cui Echo ha giocato a "LVSPRLV" prima che il bot iniziasse a schivare.
Eoin Campbell,

@Eion Campbell Grazie per averlo menzionato. L'ho visto prima quando hai pubblicato i registri del torneo fallito e penso di averlo corretto. Si è verificato un errore in cui se ha perso più di 5 rette, invece di saltare a una giocata casuale, ha generato un valore non valido. E poi, poiché ciò lo ha fatto perdere, ha lanciato un altro valore non valido. Un circolo vizioso.
Stranjyr,

Freddo. Ora aggiornalo nel controllo prog.
Eoin Campbell,

8

Bart Simpson

"Buon vecchio rock! Niente batte il rock!"

puts 'R'

Correre come

ruby DoTheBartman.rb

Lisa Simpson

"Povero, prevedibile Bart. Scegli sempre il rock."

puts 'P'

Correre come

ruby LisaSimpson.rb

Meglio Lisa Simpson

Mi sono sentito male nel rendere Lisa così stupida, così le ho permesso di scegliere casualmente una delle mani che battere il rock. Ancora stupida, ma dopo tutto è una Simpson. Forse un pastello si è bloccato nel suo cervello?

puts ['P','V'].sample

Correre come

ruby BetterLisaSimpson.rb


@ MartinBüttner Damn, non me ne sono accorto. I programmi sembrano comunque fare cose diverse - e almeno Lisa qui può sentirsi più superiore battendo due diverse versioni di suo fratello.
Dr R Dizzle,

1
Sheldor è d'accordo ... ci saranno un BartBot e un BartSimpson :)
Eoin Campbell,

3
Abbiamo solo BortBot.
JoshDM,

1
Questi saranno massacrati da Markov :)
Cruncher,

7

Eco

Scritto in C #. Compila con csc Echo.cs. Corri comeEcho.exe ARG1 ARG2 .

Alla prima esecuzione, Echo prende un'opzione casuale. Ad ogni corsa dopo la prima, Echo semplicemente ripete l'ultima azione dell'avversario.

using System;

namespace Echo
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Random r = new Random();
                string[] options = new string[] { "R", "P", "S", "L", "V" };
                Console.WriteLine(options[r.Next(0, options.Length)]);
            }
            else if (args.Length == 2)
            {
                string opponentHistory = args[1];
                Console.WriteLine(opponentHistory[opponentHistory.Length - 1]);
            }
        }
    }
}

7

Vulcaniano, Rubino

Le mie dita sono incollate insieme.

puts 'V'

Corri come

ruby vulcan.rb

(Penso che questa sia l'unica strategia in-character per la tua impostazione di sfondo.)


Devo guardare indietro agli episodi per vedere se qualcuno è nato con la lingua biforcuta. LizardMan FTW !!!
Eoin Campbell,

3
Ma non è così che suonano tutti nel big bang?
Kaine,

2
@anotherguest Questo è ciò che intendevo per "questa è l'unica strategia in-character".
Martin Ender,

6

Tyrannosaurus, Godzilla, Barney ... Regola delle lucertole. Di tanto in tanto si mettono nei guai e devono chiamare Spock o lanciare Rocks

using System;
public class LizardsRule
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("L");
            return;
        }
        char[] oppPreviousPlays = args[1].ToCharArray();
        var oppLen = oppPreviousPlays.Length;
        if (oppPreviousPlays.Length > 2
            && oppPreviousPlays[oppLen - 1] == 'R'
            && oppPreviousPlays[oppLen - 2] == 'R'
            && oppPreviousPlays[oppLen - 3] == 'R')
        {
            //It's an avalance, someone call Spock
            Console.WriteLine("V");
            return;
        }

        if (oppPreviousPlays.Length > 2
                && oppPreviousPlays[oppLen - 1] == 'S'
                && oppPreviousPlays[oppLen - 2] == 'S'
                && oppPreviousPlays[oppLen - 3] == 'S')
        {
            //Scissors, Drop your tail and pick up a rock
            Console.WriteLine("R");
            return;
        }

        //Unleash the Fury Godzilla
        Console.WriteLine("L");     
    }
}

6

BayesianBot, Perl (ora v2!)

Soprattutto, questo è un programma unico. In esso, vedrai la brillante fusione di statistiche e orribile modulo di programmazione. Inoltre, questo bot probabilmente infrange molte regole delle statistiche bayesiane, ma il nome sembra più interessante.

L'essenza principale di questo bot è la sua creazione di 250 diversi modelli predittivi. Ogni modello prende la forma di "Dato che ho giocato il rock nell'ultimo turno e il mio avversario ha giocato con le forbici due turni fa, questa è la distribuzione di probabilità per la prossima mossa del mio avversario." Ogni distribuzione di probabilità assume la forma di una distribuzione multidimensionale di Dirichlet.

Ad ogni turno, le previsioni di tutti i modelli applicabili (in genere 10) vengono moltiplicate insieme per formare una previsione complessiva, che viene quindi utilizzata per determinare quali mosse hanno il rendimento atteso più elevato.

Modifica 1: In questa versione, ho modificato la distribuzione precedente e ho reso il bot più casuale quando sta perdendo.

Vi sono alcune cose che possono essere soggette a miglioramenti, come il numero di modelli (250 è solo un numero di 3 cifre), la scelta della distribuzione precedente (attualmente Dir (3,3,3,3,3)) e il metodo di fusione delle previsioni. Inoltre, non mi sono mai preso la briga di normalizzare nessuna delle distribuzioni di probabilità, il che va bene per ora perché le sto moltiplicando.

Non ho aspettative molto alte, ma spero che questo bot possa fare bene.

my ($phist, $ohist) = @ARGV;

my %text2num = ('R',0,'V',1,'P',2,'L',3,'S',4);  #the RVPLS ordering is superior
my @num2text = ('R','V','P','L','S');

@phist = map($text2num{$_},split(//,$phist));
@ohist = map($text2num{$_},split(//,$ohist));

$lowerlimit = 0;
for($lowerlimit..~~@phist-3){$curloc=$_;
 $result = $ohist[$curloc+2];
 @moveset = ($ohist[$curloc],$ohist[$curloc+1],$phist[$curloc],$phist[$curloc+1]);
 for(0..3){$a=$_;
  for(0..$a){$b=$_;
   $predict[$a][$b][$moveset[$a]][$moveset[$b]][$result]++;
  }
 }
}

@recentmoves = ($ohist[-2],$ohist[-1],$phist[-2],$phist[-1]);

@curpred = (1,1,1,1,1);

for(0..3){$a=$_;
 for(0..$a){$b=$_;
  for(0..4){$move=$_;
   $curpred[$move] *= $predict[$a][$b][$recentmoves[$a]][$recentmoves[$b]][$move]/3+1;
  }
 }
}

@bestmove = (0,0,0,0,0);
for(0..4){
 $bestmove[$_] = $curpred[$_]/2+$curpred[$_-1]+$curpred[$_-2];
}

$max = 0;
for(0..4){
 if($bestmove[$_]>$max){
  $max = $bestmove[$_];
 }
}
@options=();
$offset=0;
if(($ohist[-1] - $phist[-1])%5 < 2 && ($ohist[-2] - $phist[-2])%5 < 2 && ($ohist[-3] - $phist[-3])%5 < 2){  #frequentist alert!
 $offset=int(rand(3));
}
for(0..4){
 if($bestmove[$_] == $max){
  push(@options,$num2text[($_+$offset)%5]);
 }
}
$outputb = $options[int(rand(~~@options))];

print "$outputb";

Ho eseguito questo programma in questo modo:

perl BayesianBot.plx

5

DynamicBot

Il robot dinamico è quasi sempre in evoluzione. Odia davvero ripetersi

import sys, random
choices = ['L','V','S','P','R'] * 20
if len(sys.argv) > 1:
    my_history = sys.argv[1]
    [choices.remove(my_history[-1]) for i in range(15)]
print(choices[random.randrange(len(choices))])

Lingua: Python 3.4.1

Comando: python dynamicbot.py <history>o in python3 dynamicbot.py <history>base al tuo sistema


Sì, ci ho pensato.
Seequ,

5

SmartBot - Java

La mia prima entrata in assoluto per qualsiasi cosa su questo sito!

Sebbene non sia un nome molto creativo ...

SmartBot trova sequenze di mosse in cui l'avversario e / o le mosse di se stesso sono simili alle mosse effettuate per ultime e pianificano di conseguenza.

name = SmartBot

Penso di eseguirlo, correggimi se sbaglio.

java -jar SmartBot.jar

import java.util.ArrayList;
public class SmartBot {
    public static void main(String[] args) {
        if(args.length ==0){
            System.out.print("L");
            return;
        }
        if(args[0].length()<3){
            String[] randLetter = new String[]{"R","P","S","L","V"};
            System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
            return;
        }
        String myHistory = args[0];
        String otherHistory = args[1];

        double rScore,pScore,sScore,lScore,vScore;//score - highest = highest probability of next opponent move
        rScore = pScore = sScore = lScore = vScore = 0;
        lScore = .001;
        ArrayList<ArrayList<Integer>> moveHits = new ArrayList<ArrayList<Integer>>();
        for(int g = 0;g<2;g++){
            for(int i=1;i<(myHistory.length() / 2) + 1;i++){
                if(g==0){
                    moveHits.add(findAll(myHistory.substring(myHistory.length() - i),myHistory));
                }
                else{
                    moveHits.add(findAll(otherHistory.substring(otherHistory.length() - i),otherHistory));
                }
            }
            for(int i = 0; i < moveHits.size();i++){
                int matchingMoves = i+1;
                ArrayList<Integer> moveIndexes = moveHits.get(i);
                for(Integer index:moveIndexes){
                    if(index+matchingMoves +1<= otherHistory.length()){
                        char nextMove = otherHistory.charAt(index + matchingMoves-1);
                        if(nextMove=='R'){rScore = rScore + matchingMoves;}
                        if(nextMove=='P'){pScore = pScore + matchingMoves;}
                        if(nextMove=='S'){sScore = sScore + matchingMoves;}
                        if(nextMove=='L'){lScore = lScore + matchingMoves;}
                        if(nextMove=='V'){vScore = vScore + matchingMoves;}
                    }
                }
            }
        }
        if(rScore >= pScore && rScore >= sScore && rScore >= lScore && rScore >= vScore){
            System.out.print("V");
            return;
        }
        if(pScore >= rScore && pScore >= sScore && pScore >= lScore && pScore >= vScore){
            System.out.print("L");
            return;
        }
        if(sScore >= pScore && sScore >= rScore && sScore >= lScore && sScore >= vScore){
            System.out.print("R");
            return;
        }
        if(vScore >= pScore && vScore >= sScore && vScore >= lScore && vScore >= rScore){
            System.out.print("L");
            return;
        }
        if(lScore >= pScore && lScore >= sScore && lScore >= rScore && lScore >= vScore){
            System.out.print("S");
        }
        return;
    }
    public static ArrayList<Integer> findAll(String substring,String realString){
        ArrayList<Integer> ocurrences = new ArrayList<Integer>();
        Integer index = realString.indexOf(substring);
        if(index==-1){return ocurrences;}
        ocurrences.add(index+1);
        while(index!=-1){
            index = realString.indexOf(substring,index + 1);
            if(index!=-1){
                ocurrences.add(index+1);
            }
        }
        return ocurrences;
    }
}

Assegna un punteggio per ogni possibile mossa successiva per il numero di volte in cui si sono verificati schemi simili.

Favorisce leggermente la lucertola.


Credo che sia così che lo fai se lo fai prima. Se lo compili semplicemente prima, allora java ABotdovrebbe funzionare (ricordati di nominare il file come la classe pubblica)
Giustino,

Grazie! Come programmatore relativamente nuovo, non ne ero a conoscenza.
Stretch Maniac,

5

SpockOrRock - PHP

SpockOrRock

Quando si gioca nel mondo reale, molte persone scelgono istintivamente le forbici. Questo bot sceglie Spock o Rock per battere il giocatore medio. Non si preoccupa dei round precedenti.

Corri con php spockorrock.php

<?php

//Pick either Spock or Rock
if (rand(0,1) == 0)     echo("R\n");
else                    echo("V\n");


?>

4

SlowLizard, Ruby

Dopo aver iniziato con Lizard, sceglie sempre una mossa casuale che batte la mossa precedente dell'avversario.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0
  puts 'L'
else
  puts responses[ARGV[1][-1]].sample
end

Corri come

ruby slowlizard.rb

4

LexicographicBot

A questo bot piace ordinare le sue lettere, quindi sceglierà una risposta che è 1 in più di quella data dal suo avversario nel round precedente - a meno che l'avversario non abbia scelto Vulcan, quindi sceglie in modo casuale una risposta.

import sys
import random

choices = ["L", "P", "R", "S", "V"]

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

if opponent_last == choices[-1]:
    print(random.choice(choices))
else:
    next = choices.index(opponent_last)+1
    print(choices[next])

Questo si aspetta che la mano dell'avversario venga distribuita per seconda:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent

@ MartinBüttner: comando aggiunto! Sono stato piuttosto impegnato al lavoro nel tentativo di pubblicare qualcosa, da cui la scomparsa.
Kyle Kanos,

si interrompe al primo avvio senza args. Traceback (ultima chiamata più recente): file "LexicographicBot \ LexicographicBot.py", linea 10, in <modulo> avversario = sys.argv [2] IndexError: indice elenco fuori portata
Eoin Campbell

@EoinCampbell: ho dimenticato la clausola di uscita al primo avvio, è stata aggiunta e ora dovrebbe funzionare correttamente.
Kyle Kanos,

4

Werevulcan - Ruby

Correre come ruby werevulcan.rb

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  # For the first 30 rounds, pick a random move that isn't Spock
  if player.to_s.size < 30
    %w[L P R S].sample
  elsif opponent.chars.to_a.uniq.size < 5
    exploit(opponent)
  else
    # Pick a random move that's biased toward Spock and against lizards
    %w[L P P R R S S V V V].sample
  end

end

def exploit(opponent)
  @moves.shuffle.max_by{ |m| opponent.chars.map{|o| score(m,o) }.reduce(:+) }
end

puts move

Il licantropo sembra normale di giorno, ma quando la luna sorge, le sue orecchie diventano appuntite e le sue mosse diventano più logiche.


4

Analogizer - Ruby

Corri con ruby analogizer.rb. Ho apportato una correzione logica al codice, ma non ho idea del perché si siano verificati errori in questo.

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  # Throw six lizards in the beginning to confuse opponent
  when 0..5
    'L'
  when 6
    'V'
  when 7
    'S'
  when 8
    'P'
  when 9
    'R'
  else
    analyze_history(player.chars.to_a, opponent.chars.to_a)
  end

end

def analyze_history(player, opponent)
  my_last_move = player.last
  predicted_moves = Hash.new {0}
  opponent_reactions = player.zip(opponent.drop(1))

  # Check whether opponent tended to make a move that would've beaten, lost, or tied my last move
  opponent_reactions.each do |my_move, reaction|
    score = score(reaction, my_move)
    analogous_moves = @moves.select { |move| score == score(move, my_last_move) }
    analogous_moves.each { |move| predicted_moves[move] += 1 }
  end

  # Assume if an opponent has never made a certain move, it never will
  @moves.each { |m| predicted_moves[m] = 0 unless opponent.include?(m) }

  # Pick the move with the best score against opponent's possible moves, weighted by their likelihood, picking randomly for ties
  @moves.shuffle.max_by{ |m| predicted_moves.map { |predicted, freq| score(m, predicted) * freq }.reduce(0,:+) }

end

puts move

Suppone che il robot avversario reagisca sempre alla mia mossa precedente e scelga qualcosa che lo batterebbe, qualcosa che perderebbe ad esso, o la stessa mossa, probabilmente da una serie ristretta di possibili mosse. Quindi seleziona la mossa migliore dato quel presupposto.

Tranne che le prime dieci mosse sono codificate: prima faccio finta di conoscere solo lucertola, quindi presumo che il mio avversario lancia sempre qualcosa per battere l'ultima cosa che ho lanciato fino a quando non ho abbastanza dati per un'analisi corretta.


4

Java - SelfLoathingBot

BotName: SelfLoathingBot
Compile: Save as 'SelfLoathingBot.java'; compile.
Run:     java SelfLoathingBot [me] [them]

Il bot inizia in modo casuale, quindi ~ 33% per diventare casuale, o ~ 33% per giocare una tattica vincente contro una delle giocate immediatamente precedenti, con una scelta del 50% di tattica vincente.

import java.util.Random;

public class SelfLoathingBot {

    static final Random RANDOM = new Random();

    private static char randomPlay() {

        switch (RANDOM.nextInt(5)) {

            case 0 : return 'R';

            case 1 : return 'P';

            case 2 : return 'S';

            case 3 : return 'L';

            default : return 'V';
        }
    }

    private static char antiPlay(String priorPlayString) {

        char[] priorPlays = priorPlayString.toCharArray();

        int choice = RANDOM.nextInt(2);

        switch (priorPlays[priorPlays.length - 1]) {

            case 'R' : return choice == 0 ? 'P' : 'V'; 

            case 'P' : return choice == 0 ? 'S' : 'L';

            case 'S' : return choice == 0 ? 'V' : 'R';

            case 'L' : return choice == 0 ? 'R' : 'S';

            default : return choice == 0 ? 'L' : 'P'; // V        
        }
    }

    public static void main(String[] args) {

        int choice = args.length == 0 ? 0 : RANDOM.nextInt(3);

        char play;

        switch (choice) {

            case 1 :

                // 33.3% chance Play myself
                play = antiPlay(args[0]);
                break;

            case 2 :

                // 33.3% chance Play opponent just in case opponent is screwy like that
                play = antiPlay(args[1]);
                break;

            default :

                // 33.3% chance 100% Random
                play = randomPlay();
        }

        System.out.print(play);
        return;
    }
}

4

L'analista

L'analista analizza alcune cose e fa alcune cose per cercare di picchiarti.

compilare javac Analyst.javaed eseguire comejava Analyst

import java.util.Random;

public class Analyst{
    public static void main(String[] args){
        char action = 'S';

        try{
            char[] enemyMoves = null, myMoves = null;

            //first move is random
            if(args.length == 0){
                System.out.print(randomMove());
                System.exit(0);
            //moves 2-3 will beat their last move
            }else if(args[0].length() < 8){
                System.out.print(counterFor(args[1].charAt(args[1].length()-1)));
                System.exit(0);
            //following moves will execute some analyzation stuff
            }else{
                //get previous moves
                myMoves = args[0].toCharArray();
                enemyMoves = args[1].toCharArray();
            }

            //test if they're trying to beat our last move
            if(beats(enemyMoves[enemyMoves.length-1], myMoves[myMoves.length-2])){
                action = counterFor(counterFor(myMoves[myMoves.length-1]));
            }
            //test if they're copying our last move
            else if(enemyMoves[enemyMoves.length-1] == myMoves[myMoves.length-2]){
                action = counterFor(myMoves[myMoves.length-1]);
            }
            //else beat whatever they've done the most of
            else{
                action = counterFor(countMost(enemyMoves));
            }

            //if they've beaten us for the first 40 moves, do the opposite of what ive been doing
            if(theyreSmarter(myMoves, enemyMoves)){
                action = counterFor(action);
            }

        //if you break my program do something random
        }catch (Exception e){
            action = randomMove();
        }

        System.out.print(action);
    }

    private static char randomMove(){
        Random rand = new Random(System.currentTimeMillis());
        int randomMove = rand.nextInt(5);

        switch (randomMove){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static char counterFor(char move){
        Random rand = new Random(System.currentTimeMillis());
        int moveSet = rand.nextInt(2);

        if(moveSet == 0){
            switch (move){
                case 'R': return 'P'; 
                case 'P': return 'S'; 
                case 'S': return 'R'; 
                case 'L': return 'R'; 
                default: return 'P';
            }
        }else{
            switch (move){
                case 'R': return 'V'; 
                case 'P': return 'L'; 
                case 'S': return 'V'; 
                case 'L': return 'S'; 
                default: return 'L';
            }
        }
    }

    private static boolean beats(char move1, char move2){
        if(move1 == 'R'){
            if((move2 == 'S') || (move2 == 'L')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'P'){
            if((move2 == 'R') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'S'){
            if((move2 == 'L') || (move2 == 'P')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'L'){
            if((move2 == 'P') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else{
            if((move2 == 'R') || (move2 == 'S')){
                return true;
            }else{
                return false;
            }
        }
    }

    private static char countMost(char[] moves){
        int[] enemyMoveList = {0,0,0,0,0};

        for(int i=0; i<moves.length; i++){
            if(moves[i] == 'R'){
                enemyMoveList[0]++;
            }else if(moves[i] == 'P'){
                enemyMoveList[1]++;
            }else if(moves[i] == 'S'){
                enemyMoveList[2]++;
            }else if(moves[i] == 'L'){
                enemyMoveList[3]++;
            }else if(moves[i] == 'V'){
                enemyMoveList[4]++;
            }
        }

        int max = 0, maxIndex = 0;
        for(int i=0; i<5; i++){
            if(enemyMoveList[i] > max){
                max = enemyMoveList[i];
                maxIndex = i;
            }
        }

        switch (maxIndex){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static boolean theyreSmarter(char[] myMoves, char[] enemyMoves){
        int loseCounter = 0;

        if(enemyMoves.length >= 40){
            for(int i=0; i<40; i++){
                if(beats(enemyMoves[i],myMoves[i])){
                    loseCounter++;
                }
            }
        }else{
            return false;
        }

        if(loseCounter > 20){
            return true;
        }else{
            return false;
        }
    }
}

4

The Gambler - Python 2

import sys
import random

MODE = 1

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

Contrariamente al nome, l'unica volta che la casualità viene utilizzata in questo programma è al primo turno, quando non ci sono informazioni. Invece, prende il nome dall'errore del giocatore, la convinzione che se un evento casuale è accaduto meno spesso in passato, è più probabile che accada in futuro. Ad esempio, se lanci una moneta giusta 20 volte, e le prime 15 sono teste, l'errore del giocatore afferma che le probabilità che le lancette rimanenti siano code aumentano. Certo, questo non è vero; a prescindere dai lanci precedenti, la probabilità che una moneta giusta salga la coda è sempre del 50%.

Questo programma analizza la storia dell'avversario, trova le 2 mosse che ha usato finora finora e presume che questa volta la mossa dell'avversario sarà una di quelle due. Assegnando 2 a una vittoria, 1 a un pareggio e 0 a una perdita, trova la mossa con il punteggio massimo rispetto a queste due mosse previste e la lancia.

The Gambler's Brother - Python 2

import sys
import random

MODE = 0

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

Commutando il MODE variabile su 0, questo programma funzionerà in base a un errore correlato, a volte indicato anche come errore del giocatore. Afferma che se un evento casuale è accaduto più spesso in passato, è più probabile che accada in futuro. Ad esempio, se lanci una moneta 20 volte e le prime 15 sono teste, questo errore afferma che le lancette rimanenti hanno più probabilità di essere teste, poiché al momento c'è una striscia. Nella modalità 0, questo programma funziona allo stesso modo, tranne per il fatto che supponga che l'avversario lanci una delle due mosse lanciate più spesso finora.

Quindi sì, questi due programmi sono separati da un solo personaggio. :)


A quali condizioni TheGambler cambia MODE?
Dr R Dizzle,

@DrRDizzle No, sembra che questo sia un invio di due robot in uno.
Paŭlo Ebermann,

2
Questo programma non sarebbe più efficace se MODE fosse commutato se perdessi più di un certo numero di volte di seguito?
Dr R Dizzle,

4

Dienstag (Python 2)

La mia prima voce, Pony, sembra andare abbastanza bene con tutte le sue seconde ipotesi (triplice ipotesi, ...) e meta ragionamento. Ma è anche necessario?

Quindi, ecco Dienstag, il piccolo amico di Pony, con solo una delle 55 strategie: prevedi la prossima mossa dell'avversario e battila.

A lungo termine Dienstag vince o lega con ogni Bot nella top ten della classifica attuale. Tranne Pony che è.

import sys
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'L'; sys.exit()
hist = [map('RPSVL'.index, p) for p in zip(sys.argv[1], sys.argv[2])]
N = len(hist)
cand = range(N-1)
for l in xrange(1,N):
    cand = ([c for c in cand if c>=l and hist[c-l+1]==hist[-l]] or cand[-1:])
print 'RPSVL'[(hist[cand[-1]+1][1]+(1,3)[N%2==0])%5]

Correre come:

python Dienstag.py

Ammetto che il codice è un po 'offuscato. Se qualcuno si preoccupasse di saperne di più, potrei aggiungere delle spiegazioni.

Modifica: ecco un breve esempio per spiegare l'idea:

  • Il programma prende la sua storia e le mosse dell'avversario:

    sys.arg[1] = 'LLVLLVL', sys.arg[2] = 'RPSPSSP'

  • La cronologia viene combinata in un elenco di coppie e le mosse vengono tradotte in numeri (R = 0, ...):

    hist = [[4, 0], [4, 1], [3, 2], [4, 1], [4, 2], [3, 2], [4, 1]]

  • Il numero di round giocati finora è determinato:

    N = 7

  • L'idea di base ora è quella di cercare la catena ininterrotta più lunga esattamente delle ultime mosse della storia precedente. Il programma tiene traccia di dove una tale catena termina nell'elenco cand(per "candidati"). All'inizio, senza controllo, vengono considerate tutte le posizioni nella storia tranne l'ultima:

    cand = [0, 1, 2, 3, 4, 5]

  • Ora la lunghezza delle possibili catene viene aumentata gradualmente. Per la lunghezza della catena l = 1cerca le occorrenze precedenti dell'ultima coppia di mosse [4, 1]. Questo può essere trovato nella posizione della cronologia 1e 3. Solo questi sono mantenuti candnell'elenco:

    cand = [1, 3]

  • Successivamente, l = 2controlla quale dei possibili candidati è stato preceduto dalla penultima coppia di mosse [3, 2]. Questo è solo il caso della posizione 3:

    cand = [3]

  • Per l = 3e altro ancora non ci sono catene precedenti di quella lunghezza e candsarebbero vuote. In questo caso candviene mantenuto l'ultimo elemento di :

    cand = [3]

  • Il bot ora presuppone che la storia si ripeterà. L'ultima volta che [3, 2], [4, 1]si è verificato il Caino , è stato seguito da [4, 2]. Quindi, l'avversario ha giocato 2(forbici) che può essere battuto da (2+1)%5 = 3(Spock) o (2+3)%5 = 0(rock). Il bot risponde, con la prima o la seconda alternativa a seconda che Nsia dispari o anche solo per introdurre una varianza.

  • Qui 3viene scelta la mossa che viene poi tradotta di nuovo:

    print 'V'

Nota: Dienstag ha una complessità temporale O ( N 2 ) per restituire la mossa successiva dopo N round. Pony ha una complessità temporale O ( N 3 ). Quindi in questo aspetto sono probabilmente molto peggio della maggior parte delle altre voci.


per favore fallo. questa è una fantastica esperienza di apprendimento per me. Di solito vivo in terra C # / Java, quindi tutta la follia di lua, ruby, python e haskell è molto interessante per me.
Eoin Campbell,

Sono anche tentato di aggiungere un'istanza extra di Pony ai giochi. Sarà come dover combattere il tuo sé specchio nel terzo o ultimo livello di combattimento mortale ;-)
Eoin Campbell

@EoinCampbell :-) Almeno la partita diretta Pony vs. Pony sarebbe un pareggio perfetto. Non c'è alcun elemento di casualità in entrambi i miei robot.
Emil

3

Bash Rocks

Cygwin è troppo da chiedere come runtime?

bashrocks.sh:

#!/bin/bash
HAND=(R P S L V)
RAND=`od -A n -t d -N 1 /dev/urandom | xargs`
echo ${HAND[ $RAND  % 5 ]}

ed eseguilo in questo modo:

sh bashrocks.sh

5
Dopo aver letto il titolo, sono leggermente deluso dal fatto che tu faccia qualsiasi cosa R. ;)
Martin Ender il

@mccannf. problemi con questo ... Ho installato cygwin e modificato i tuoi script con percorsi completi per C: \ Cygwin \ bin per od.exe, xargs.exe ed echo.exe. continua a ricevere il seguente errore. C: / Cygwin / bin / xargs: echo: nessun file o directory di questo tipo% 5 ") errore di sintassi: operando previsto (token di errore è"
Eoin Campbell,

@EoinCampbell: quando si crea il file in Windows, è possibile eseguire dos2unixil file in Cygwin prima di eseguirlo?
McCannf,

sicuro. Ci proverò.
Eoin Campbell,

Penso che il problema potrebbe essere con l'affermazione / dev / urandom
Eoin Campbell,

3

Algoritmo

Un algoritmo per il gusto di averne uno.

Perché è sempre più sicuro fare qualcosa, più è complicato, meglio è.

Non ho ancora fatto un po 'di matematica seria, quindi questo algoritmo potrebbe non essere così efficace.

import random, sys

if __name__ == '__main__':

    # Graph in adjacency matrix here
    graph = {"S":"PL", "P":"VR", "R":"LS", "L":"VP", "V":"SR"}
    try:
        myHistory = sys.argv[1]
        opHistory = sys.argv[2]
        choices = ""

        # Insert some graph stuff here. Newer versions may include advanced Math.
        for v in graph:
            if opHistory[-1] == v:
                for u in graph:
                    if u in graph[v]:
                        choices += graph[u]

        print random.choice(choices + opHistory[-1])

    except:
        print random.choice("RPSLV")

Programma Python 2: python algorithm.py


1
Riepilogo di questo algoritmo: osserva l'ultimo gioco giocato dall'avversario, quindi gioca a caso una delle due mosse che perderebbe contro l'ultima mossa dell'avversario se la giocasse di nuovo. Quindi è meglio contro i robot che non giocano la stessa mossa due volte di seguito.
Rory O'Kane,

Haha. Non so davvero se l'ho fatto in quel modo. Se non sbaglio, in realtà è solo un modo contorto di selezionare casualmente una delle 5 mosse. ;)
Vectorized

3

FairBot, Ruby

Cominciamo semplice.

puts ['R','P','S','L','V'].sample

Corri come

ruby fairbot.rb

piccolo errore di battitura sull'ultimo parametro 'V'. l'ho risolto su myside se vuoi aggiornarlo per completezza
Eoin Campbell,

@EoinCampbell grazie, riparato!
Martin Ender,

1
La cosa interessante è che questo ha esattamente le stesse probabilità di vincere contro TUTTE le strategie.
Cruncher,

3

ViolentBot

Questo bot sceglie l'opzione più violenta in base alla scelta precedente degli avversari:

import sys

choice_dict = {"L" : "S", "P" : "S", "R" : "V", "S" : "V", "V" : "L"}

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

print(choice_dict[opponent_last])

Correre come

python ViolentBot.py (me) (opp)

si rompe senza parametri. Traceback (ultima chiamata più recente): file "ViolentBot \ ViolentBot.py", riga 9, in <modulo> avversario = sys.argv [2] IndexError: indice elenco fuori portata
Eoin Campbell

si rompe con i parametri. Traceback (ultima chiamata più recente): File "ViolentBot \ ViolentBot.py", riga 12, in <module> print (choice_dict [opponente_ast]) KeyError: 'S'
Eoin Campbell

@EoinCampbell: ho aggiunto una clausola di uscita per la prima esecuzione, dovresti essere in grado di eseguirla ora.
Kyle Kanos,

3

Haskell - MonadBot

Non so se ghc sia considerato "entro limiti ragionevoli", ma supponiamo che lo sia. La strategia di questo bot è di contrastare la mossa più popolare dell'avversario.

Compile: ghc monadbot.hs
Run:     ./monadbot [Arg1] [Arg2]

Codice:

import System.Environment
import Data.List
import Data.Ord

main :: IO ()
main = do
  args <- getArgs
  let moves = if not (null args) then args !! 1 else ""
      fave = if not (null moves) then head $ maximumBy (comparing length) (group $ sort moves) else 'V'
  putChar $ case fave of 'R' -> 'P'
                         'P' -> 'S'
                         'S' -> 'R'
                         'L' -> 'R'
                         'V' -> 'P'
                         _   -> 'V'
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.