The Rock, Paper, Scissors, Lizard, Spock Tournament of Epicness

98

Clasificación más reciente @ 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

Notas del torneo

Bots excluidos

  • BashRocksBot - todavía no es divertido con .net ejecutando scripts cygwin bash
  • CounterPreferenceBot - esperando corrección de errores
  • RandomlyWeighted - en espera de corrección de errores
  • Casino Shakespeare: excluido porque requiere una conexión a Internet activa

Pregunta original publicada

Has girado hacia la casa de tus amigos para el enfrentamiento más épico de la historia de Rock, Paper, Scissors, Lizard, Spock. En el verdadero estilo nerd-tastic de BigBang, ninguno de los jugadores está jugando solo, pero ha creado bots de consola para jugar en su nombre. Sacas tu llave USB y se la entregas al Sheldor the Conqueror para que la incluya en el enfrentamiento. Penny se desmaya. O tal vez Howard se desmaya. No juzgamos aquí en el departamento de Leonard.

Reglas

Se aplican las reglas estándar de piedra, papel, tijera, lagarto y Spock.

  • Tijeras cortadas en papel
  • Cubiertas de papel Rock
  • Roca aplasta a lagarto
  • Veneno de lagarto Spock
  • Spock rompe tijeras
  • Tijeras decapitan a Lizard
  • Lagarto come papel
  • El papel refuta a Spock
  • Spock vaporiza roca
  • Tijeras de piedra

Reglas RPSLV

El bot de cada jugador jugará un partido contra el bot del torneo.

Cada partida constará de 100 iteraciones de un juego RPSLV.

Después de cada partido, el ganador es el jugador que ha ganado la mayor cantidad de juegos / manos de 100.

Si ganas un partido, se te asignará 1 punto en la tabla de la liga. En el resultado de un empate, ninguno de los jugadores ganará un punto.

Requisitos de bot

Su bot debe ser ejecutable desde la línea de comando.

Sheldor's * nix box ha muerto, por lo que lo estamos ejecutando desde su computadora portátil con Windows 8 Gaming, así que asegúrese de que su solución provista pueda ejecutarse en Windows. Sheldor se ha ofrecido gentilmente a instalar cualquier tiempo de ejecución requerido (dentro de lo razonable) para poder ejecutar su solución. (.NET, Java, Php, Python, Ruby, Powershell ...)

Entradas

En el primer juego de cada partida no se proporcionan argumentos a su bot. En cada juego posterior de cada partida: - Arg1 contendrá el historial de tus manos / decisiones de bots en esta partida. - Arg2 contendrá el historial de las manos / decisiones de tus oponentes en este partido.

La historia estará representada por una secuencia de letras mayúsculas que representan las posibles manos que puedes jugar.

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

P.ej

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

Salida

Su bot debe escribir una respuesta de un solo personaje que represente su "mano" para cada juego. El resultado debe escribirse en STDOUT y el bot debe salir. Las letras mayúsculas simples válidas están debajo.

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

En el caso de que su bot no devuelva una mano válida (es decir, 1 de las 5 letras mayúsculas anteriores), perderá automáticamente esa mano y la partida continuará.

En el caso de que ambos bots no devuelvan una mano válida, entonces el juego se considera un empate y el partido continúa.

Formato de partido

Cada bot enviado jugará un partido uno contra el otro en el torneo.

Cada partido durará exactamente 100 juegos.

Los partidos se jugarán de forma anónima, no tendrás un conocimiento avanzado del bot específico contra el que estás jugando, sin embargo, puedes usar toda la información que puedas obtener de su toma de decisiones durante el historial del partido actual para alterar tu estrategia contra tu adversario. También puede realizar un seguimiento del historial de sus juegos anteriores para construir patrones / heurística, etc. (consulte las reglas a continuación)

Durante un solo juego, el motor de orquestación ejecutará su bot y sus oponentes bot a 100 milisegundos de distancia y luego comparará los resultados para evitar cualquier colisión de PRNG en el mismo idioma / tiempo de ejecución. (Esto realmente me sucedió durante las pruebas).

Juicio y restricciones

El Dr. Sheldon Cooper, disfrazado de Sheldor el Conquistador, se ha ofrecido amablemente a supervisar el funcionamiento del torneo. Sheldor the Conqueror es un supervisor justo y justo (en su mayoría). Todas las decisiones de Sheldor son finales.

Los juegos se realizarán de manera justa y adecuada:

  • Su script / programa bot se almacenará en el motor de orquestación en una subcarpeta Players\[YourBotName]\
  • Puede usar la subcarpeta Players\[YourBotName]\datapara registrar cualquier dato o historial del juego del torneo actual a medida que avanza. Los directorios de datos se eliminarán al comienzo de cada carrera del torneo.
  • No puedes acceder al directorio de jugadores de otro jugador en el torneo
  • Su bot no puede tener un código específico que apunte a otro comportamiento específico de bots
  • Cada jugador puede enviar más de un bot para jugar siempre que no interactúen o se ayuden entre sí.

Editar - Restricciones adicionales

  • En cuanto a los decomisos, no serán compatibles. Tu bot debe jugar una de las 5 manos válidas. Probaré cada bot fuera del torneo con algunos datos aleatorios para asegurarme de que se comporten. Cualquier bot que arroje errores (es decir, perderá errores) será excluido del torneo hasta que se corrijan.
  • Los bots pueden ser derivados siempre que sean sucintamente diferentes en su comportamiento. Los bots (incluso en otros idiomas) que realicen exactamente el mismo comportamiento que un bot existente serán descalificados
  • Ya hay bots de spam para lo siguiente, así que no vuelva a enviar
    • Rock - BartSimpson
    • Papel - LisaSimpson
    • Tijera - EdwardScissorhands
    • Spock - Vulcano
    • Lagarto - Khaleesi
    • Pseudoaleatorio - SimpleRandomBot y FairBot
    • Psuedo RPS aleatorio - ConservativeBot
    • Psuedo Random LV - Barney Stinson
  • Los bots no pueden llamar a servicios de terceros o recursos web (o cualquier otra cosa que disminuya significativamente la velocidad / tiempo de toma de decisiones de los partidos). CasinoShakespearees la única excepción, ya que ese bot se envió antes de que se agregara esta restricción.

Sheldor actualizará esta pregunta tan a menudo como pueda con los resultados del Torneo, a medida que se envíen más bots.

Programa de Orquestación / Control

El programa de orquestación, junto con el código fuente de cada bot, está disponible en github.

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

Detalles de envío

Su envío debe incluir

  • El nombre de tu bot
  • Tu codigo
  • Un comando para
    • ejecute su bot desde el shell, por ejemplo
    • ruby myBot.rb
    • python3 myBot.py
    • O
    • primero compila tus dos y luego ejecútalo. p.ej
    • csc.exe MyBot.cs
    • MyBot.exe

Envío de muestras

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

Código:

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

Aclaración

Cualquier pregunta, pregunte en los comentarios a continuación.

Eoin Campbell
fuente
77
¿Cómo se ve la historia cuando un jugador pierde una mano?
histocrat
1
Iba a hacer todo lo posible con un enfoque analítico, pero la mayoría de los bots aquí son lo suficientemente estúpidos como para derrotar a la inteligencia artificial inteligente.
esponjoso
1
Solo porque nunca estoy a la cabeza de ningún desafío de KotH en el que haya competido, tomé una captura de pantalla como recuerdo.
Kyle Kanos
3
Correré otro torneo esta noche y publicaré los resultados completos del partido en pastebin ... el próximo lote tendrá unos 450 juegos, pero debería ser un poco más rápido ya que he implementado algunas cosas de paralelización en el programa de control
Eoin Campbell
3
Si no me equivoco, parece que hay un error grave en el guión de orquestación: las historias de los jugadores 1 y 2 siempre se pasan a los bots como primer y segundo argumento respectivamente, mientras que de acuerdo con las reglas, los bots siempre deben obtener su propia historia primero. Ahora el jugador 2 está tratando efectivamente de superarse a sí mismo. (Sospeché un poco porque mi bot ganó todos los partidos donde era el jugador 1 y perdió la mitad de los otros partidos).
Emil

Respuestas:

26

Pony (Python 2)

Esto se basa en un bot de piedra, papel o tijera que escribí hace algún tiempo para un desafío de programación al final de una clase en línea de Udacity . Lo cambié para incluir Spock y lagarto e hice algunas mejoras.

El programa tiene 11 estrategias simples diferentes, cada una con 5 variantes. Elige entre estos en función de qué tan bien se habrían desempeñado en las últimas rondas.

Eliminé una estrategia alternativa que solo jugó al azar contra oponentes más fuertes. Supongo que es más divertido así.

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]

Correr como:

python Pony.py

Editar : hice un pequeño cambio al poner un sesgo hacia la estrategia más simple (es decir, siempre jugar el mismo movimiento) en casos inseguros. Esto ayuda un poco a no tratar de encontrar patrones demasiado complicados donde no los hay, por ejemplo, en bots como ConservativeBot.

Nota : Traté de explicar la estrategia básica de coincidencia de historial que este bot usa en la publicación para mi otro bot Dienstag .

Emil
fuente
3
Un porcentaje de victorias del 96 por ciento es excepcional.
AndoDaan
Muy agradable. Es posible que le guste Iocaine Powder , si aún no lo ha visto.
wchargin
@WChargin, por supuesto. :) Cuando escribí mi código original, había leído sobre Iocaine Powder algunos años antes y recordaba vagamente la idea general. Entonces, Pony está inspirado en él, si no directamente. Resulta que son muy similares. Creo que el mío tiene un repertorio más amplio de estrategias, mientras que Iocaine Powder tiene un nivel inteligente de razonamiento meta-meta que no incluí.
Emil
20

Markov, Ruby

Mira los últimos dos movimientos del oponente y determina los posibles (y más probables) seguimientos. Si la combinación no se ha elegido antes, solo usa todos los movimientos del oponente (hasta ahora) en su lugar. Luego recoge todas las respuestas posibles para estas y elige una aleatoria.

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

Corre como

markov.rb
Martin Ender
fuente
Y luego uso este programa para determinar el movimiento más posible que haré a continuación, luego descubro lo que harás y finalmente encuentro una manera de vencer lo que harás y hacer un bucle infinito una y otra vez.
Jamie
@Jamie ¿Te refieres a este tipo? codegolf.stackexchange.com/a/35295/8478
Martin Ender
lo adivinas (el comentario no fue lo suficientemente largo como para ser publicado)
Jamie
19

ConservadorBot, Ruby

Las cosas nuevas son malas.

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

Corre como

ruby conservative.rb
Martin Ender
fuente
La versión OG es la mejor versión.
maxywb
13

Fan de Star Wars - Ruby

Jódete Spock

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

Ejecútalo como:

ruby starwarsfan.rb
William Barbosa
fuente
Añadido al controlador
Eoin Campbell
puede revertir mediante la edición de respuestas: solo comentaré aquí cuando los haya agregado.
Eoin Campbell
¿Por qué R y S? : P
cjfaure
@mardavi Es fanático de Star Wars porque no usa Spock.
William Barbosa
ah, tienes razón (por supuesto). Lo leí demasiado rápido, mi error (pero sin consecuencias afortunadamente)
mardavi
13

Barney Stinson - Lua

Solo tengo una regla: lo nuevo siempre es mejor. Al diablo con el viejo Jo Ken Po o como se llame.

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

Ejecútalo como:

lua legenwaitforitdary.lua
William Barbosa
fuente
8

Bot aburrido (Java)

Asume que todos siempre juegan lo mismo y planea en consecuencia. Sin embargo, por lo general, escoge rocas atadas porque todos los demás tienen razón

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;
        }
    }
}
kaine
fuente
Tenga en cuenta que si esta es una estrategia que otra persona ya está utilizando, avíseme y la eliminaré. Simplemente se siente como el obvio que ya no vi.
kaine
es este C #. sus propiedades .length están mal. y no hay métodomax
Eoin Campbell
@EoinCampbell Es Java, he estado jugando con ambos y aparentemente olvidé qué comandos pertenecen a cuáles.
kaine
Ah, guay. déjalo conmigo y lo incluiré.
Eoin Campbell
todavía roto. ejecutando jre8 - java BoringBot.java - Error: No se pudo encontrar o cargar la clase principal D: \ My Software Dev \ big-bang-game \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.java -
Eoin Campbell
8

Polvo de iocaína, rubí

ingrese la descripción de la imagen aquí

Basado en (descaradamente robado) la estrategia RPS aquí . El aspecto del bot elige una conjetura idéntica al bot de Markov, pero luego asume que el oponente ha adivinado lo que va a elegir, y elige un movimiento para vencer a ese en consecuencia.

Tenga en cuenta que acabo de adaptar la idea básica de la estrategia vinculada, no la seguí en detalle.

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

Corre como

iocaine.rb
jmite
fuente
55
Usted sigue usando esa palabra. No creo que signifique lo que tú piensas que significa.
JoshDM
2
El verdadero poder de Iocaine Powder es que cambia entre usar el markov y el beating-markov. Comienza como un markov inteligente, pero una vez que detecta (comienza a perder) salta al modo de markov. Debería ser fácil de agregar.
Roy van Rijn
Ahh, listo! No voy a mentir, solo escuché que Iocaine me lo describió, en realidad no lo miré en detalle. ¡Siéntase libre de modificar mi código si lo desea o enviar el suyo y obtener el crédito!
jmite
8

HuddleWolfTheConqueror - C #

HuddleWolf está de vuelta y mejor que nunca. Él vencerá a Sheldor el Conquistador en su propio juego tonto. HuddleWolf es lo suficientemente inteligente como para identificar y contrarrestar robots de spam. Para oponentes más inteligentes, HuddleWolf usa su conocimiento de estadísticas básicas de 5º grado y utiliza una tirada de dados ponderada basada en el historial de jugadas de la oposición.

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];
    }
}
HuddleWolf
fuente
8

Prueba para niños pequeños

Este bot bastante estúpido asume que está jugando a un niño pequeño que "perseguirá" sus movimientos, siempre tratando de vencer lo que se lanzó por última vez. Si el bot es golpeado varias veces seguidas, salta a un nuevo punto en el patrón. Se basa en mi estrategia para siempre vencer a mi hermano mucho más joven. :)

EDITAR :: Cambió la duración de una racha de pérdida requerida para saltar en lanzamientos aleatorios. También se solucionó un error importante con el salto aleatorio.

Guardar como ToddlerProof.java, compilar, luego ejecutar 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;
    }
}
Stranjyr
fuente
1
¿Deberíamos usar print o println? ... No estaba seguro.
kaine
Hmmm Me imagino que ambos funcionarían, pero podría ver que println se estropea si el programa de control toma la nueva línea en lugar del personaje. Gracias por señalarlo,
editaré
@Stranjyr hubo algunos errores en su última ejecución. No bombardeó el programa de control, pero si buscas en el historial "Jugadas a prueba de niños pequeños n", parece que tu bot regresó nulo para ciertas manos y luego perdió la mano automáticamente. El juego de ejemplo es "Echo & ToddlerProof", donde Echo jugó "LVSPRLV" antes de que tu bot comenzara a fallar.
Eoin Campbell
@Eion Campbell Gracias por mencionarlo. Lo vi antes cuando publicaste los registros del torneo fallido, y creo que lo solucioné. Se encontró con un error en el que si perdía más de 5 seguidas, en lugar de saltar a una jugada aleatoria, arrojaba un valor no válido. Y luego, porque eso lo hizo perder, arrojó otro valor no válido. Un circulo vicioso.
Stranjyr
Bueno. Tenlo actualizado en el programa de control ahora.
Eoin Campbell
8

Bart Simpson

"¡Buena roca vieja! ¡Nada supera a la roca!"

puts 'R'

Correr como

ruby DoTheBartman.rb

Lisa Simpson

"Pobre, predecible Bart. Siempre elige el rock".

puts 'P'

Correr como

ruby LisaSimpson.rb

Mejor Lisa Simpson

Me sentí mal por hacer que Lisa fuera tan estúpida, así que le permití elegir al azar entre cualquiera de las manos que vencerían al rock. Todavía estúpida, pero ella es una Simpson después de todo. Tal vez un crayón se atascó en su cerebro?

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

Correr como

ruby BetterLisaSimpson.rb
Dr R Dizzle
fuente
2
Menor choque de nombres . +1 de todos modos.
Martin Ender
@ MartinBüttner Maldición, no me di cuenta de eso. Sin embargo, los programas todavía parecen hacer cosas diferentes, y al menos Lisa aquí puede sentirse más superior al vencer a dos versiones diferentes de su hermano.
Dr. R Dizzle
1
Sheldor está de acuerdo ... habrá un BartBot y un BartSimpson :)
Eoin Campbell
3
Solo tenemos BortBot.
JoshDM
1
Estos serán asesinados por markov :)
Cruncher
7

Eco

Escrito en C #. Compilar con csc Echo.cs. Corre como Echo.exe ARG1 ARG2.

La primera ejecución, Echo toma una opción aleatoria. Cada carrera después de la primera, Echo simplemente repite la última acción del oponente.

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]);
            }
        }
    }
}
ProgramFOX
fuente
7

Vulcan, Ruby

Mis dedos están pegados.

puts 'V'

Corre como

ruby vulcan.rb

(Creo que esta es la única estrategia en personaje para su configuración de fondo).

Martin Ender
fuente
Necesito mirar hacia atrás en los episodios para ver si alguien nació con una lengua bífida. LizardMan FTW !!!
Eoin Campbell
3
¿Pero no es así como todos en el Big Bang juegan de todos modos?
kaine
2
@anotherguest Eso es lo que quise decir con "esta es la única estrategia en el personaje".
Martin Ender
6

Tyrannosaurus, Godzilla, Barney ... Regla de los lagartos. De vez en cuando se meten en problemas y necesitan llamar a Spock o tirar rocas

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");     
    }
}
Mikey Mouse
fuente
6

BayesianBot, Perl (¡ahora v2!)

Por encima de todo lo demás, este es un programa único. En él, verás la brillante fusión de estadísticas y la horrible forma de programación. Además, este bot probablemente rompe muchas reglas de estadísticas bayesianas, pero el nombre suena mejor.

La esencia central de este bot es su creación de 250 modelos predictivos diferentes. Cada modelo toma la forma de "Dado que jugué piedra el último turno y mi oponente jugó tijeras hace dos turnos, esta es la distribución de probabilidad para el próximo movimiento de mi oponente".Cada distribución de probabilidad toma la forma de una distribución de Dirichlet multidimensional.

Cada turno, las predicciones de todos los modelos aplicables (generalmente 10) se multiplican para formar una predicción general, que luego se utiliza para determinar qué movimientos tienen el mayor rendimiento esperado.

Edición 1: en esta versión, cambié la distribución anterior e hice que el bot fuera más aleatorio cuando está perdiendo.

Hay algunas cosas que pueden estar sujetas a mejoras, como el número de modelos (250 es solo un número de 3 dígitos), la elección de la distribución previa (actualmente Dir (3,3,3,3,3)) y El método de fusionar las predicciones. Además, nunca me molesté en normalizar ninguna de las distribuciones de probabilidad, lo cual está bien por ahora porque las estoy multiplicando.

No tengo expectativas muy altas, pero espero que este bot pueda hacerlo bien.

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

He estado ejecutando este programa así:

perl BayesianBot.plx
PhiNotPi
fuente
5

DynamicBot

El bot dinámico casi siempre está cambiando. Realmente odia repetirse

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))])

Lenguaje: Python 3.4.1

Comando: python dynamicbot.py <history>o python3 dynamicbot.py <history>dependiendo de su sistema

Tímbrico
fuente
Sí, pensé en eso.
seequ
5

SmartBot - Java

¡Mi primera entrada para algo en este sitio!

Aunque no es un nombre muy creativo ...

SmartBot encuentra secuencias de movimientos donde los movimientos del oponente y / o de sí mismo son similares a los movimientos realizados por última vez y planifica en consecuencia.

name = SmartBot

Creo ejecutarlo, corregirme si me equivoco.

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

Asigna una puntuación para cada posible próximo movimiento por la cantidad de veces que han ocurrido patrones similares.

Favorece ligeramente lagarto.

Estiramiento maniaco
fuente
Creo que así es como lo ejecutas si lo sacas primero. Si simplemente lo compila primero, entonces java ABotdebería funcionar (recuerde nombrar el archivo igual que la clase pública)
Justin
¡Gracias! Como programador relativamente nuevo, no estaba al tanto de esto.
Stretch Maniac
5

SpockOrRock - PHP

SpockOrRock

Cuando se juega en el mundo real, la mayoría de las personas instintivamente escogen tijeras. Este bot elige Spock o Rock para vencer al jugador promedio. No le molestan las rondas anteriores.

corre con php spockorrock.php

<?php

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


?>
ArcticanAudio
fuente
4

SlowLizard, Ruby

Después de comenzar con Lizard, siempre elige un movimiento aleatorio que supera el movimiento anterior del oponente.

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

Corre como

ruby slowlizard.rb
Martin Ender
fuente
4

LexicographicBot

A este bot le gusta ordenar sus letras, por lo que elegirá una respuesta que sea 1 mayor que la que le dio su oponente en la ronda anterior; a menos que el oponente haya elegido Vulcan, entonces elige una respuesta al azar.

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])

Esto espera que la mano del oponente se reparta en segundo lugar:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent
Kyle Kanos
fuente
@ MartinBüttner: ¡Comando agregado! He estado bastante ocupado en el trabajo tratando de publicar algo, de ahí la desaparición.
Kyle Kanos
se rompe en la primera carrera sin args. Rastreo (la última llamada más reciente): Archivo "LexicographicBot \ LexicographicBot.py", línea 10, en <module> adversnt = sys.argv [2] IndexError: índice de lista fuera de rango
Eoin Campbell
@EoinCampbell: Olvidé la cláusula de salida en la primera ejecución, se agregó y debería funcionar bien ahora.
Kyle Kanos
4

Werevulcan - Ruby

Correr como 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

El hombre se ve normal durante el día, pero cuando sale la luna, sus orejas se vuelven puntiagudas y sus movimientos se vuelven más lógicos.

histocrat
fuente
4

Analizador - Ruby

Corre con ruby analogizer.rb. He hecho una corrección lógica al código, pero no tengo idea de por qué hubo errores con esto.

@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

Asume que el bot contrario siempre está reaccionando a mi movimiento anterior, y ya sea eligiendo algo que lo venza, algo que lo pierda, o el mismo movimiento, posiblemente de un conjunto restringido de movimientos posibles. Luego escoge el mejor movimiento dado ese supuesto.

Excepto que los primeros diez movimientos están codificados: primero pretendo que solo conozco lagarto, luego asumo que mi oponente siempre lanza algo para vencer lo último que lancé hasta que tenga suficientes datos para un análisis adecuado.

histocrat
fuente
4

Java - SelfLoathingBot

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

Bot comienza al azar, luego ~ 33% para ir al azar, o ~ 33% para jugar una táctica ganadora contra cualquiera de las jugadas inmediatamente anteriores, con un 50% de elección de táctica ganadora.

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;
    }
}
JoshDM
fuente
4

El analista

El analista analiza algunas cosas y hace algunas cosas para intentar vencerlo.

compilar javac Analyst.javay ejecutar comojava 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;
        }
    }
}
Qwix
fuente
4

El jugador - 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 nombre, la única aleatoriedad de tiempo que se usa en este programa es en la primera ronda, cuando no hay información. En cambio, lleva el nombre de la falacia del jugador, la creencia de que si un evento aleatorio ha sucedido con menos frecuencia en el pasado, es más probable que ocurra en el futuro. Por ejemplo, si lanzas una moneda justa 20 veces, y las primeras 15 son caras, la falacia del jugador establece que las probabilidades de que las tiras restantes sean colas aumentan. Por supuesto, esto no es cierto; Independientemente de los lanzamientos anteriores, las probabilidades de una moneda justa de salir de colas siempre son del 50%.

Este programa analiza la historia del oponente, encuentra los 2 movimientos que menos ha usado hasta ahora y asume que el movimiento del oponente esta vez será uno de esos dos. Asignando 2 a una victoria, 1 a un empate y 0 a una pérdida, encuentra el movimiento con el puntaje máximo en contra de estos dos movimientos predichos y lanza eso.

El hermano del jugador - 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)

Al cambiar el MODE variable a 0, este programa funcionará en función de una falacia relacionada, también conocida a veces como falacia del jugador. Establece que si un evento aleatorio ha sucedido con más frecuencia en el pasado, es más probable que ocurra en el futuro. Por ejemplo, si lanzas una moneda 20 veces y las primeras 15 son caras, esta falacia indica que las tiradas restantes tienen más probabilidades de ser caras, ya que actualmente hay una racha. En el modo 0, este programa funciona de la misma manera, excepto que supone que el oponente lanzará uno de los dos movimientos que ha lanzado con mayor frecuencia hasta el momento.

Entonces sí, estos dos programas están separados por un solo personaje. :)

metro subterráneo
fuente
¿Con qué condición cambia TheGambler MODE?
Dr R Dizzle
@DrRDizzle No lo hace, parece que esto es un envío de dos bots en uno.
Paŭlo Ebermann
2
¿Este programa no sería más efectivo si MODE cambiara si pierde más de una cierta cantidad de veces seguidas?
Dr R Dizzle
4

Dienstag (Python 2)

A mi primera entrada, Pony parece irle bastante bien con todas sus segundas suposiciones (triples conjeturas, ...) y meta razonamiento. ¿Pero es eso incluso necesario?

Entonces, aquí está Dienstag, el pequeño amigo de Pony, con solo una de las 55 estrategias: predecir el próximo movimiento del oponente y vencerlo.

A la larga, Dienstag gana o empata con cada Bot entre los diez primeros de la clasificación actual. Excepto por Pony que es.

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]

Correr como:

python Dienstag.py

Admito que el código está un poco ofuscado. Si alguien quisiera saber más al respecto, podría agregar explicaciones.

Editar: Aquí hay un breve ejemplo para explicar la idea:

  • El programa obtiene la historia propia y los movimientos del oponente:

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

  • El historial se combina en una lista de pares y los movimientos se traducen a números (R = 0, ...):

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

  • Se determina el número de rondas jugadas hasta el momento:

    N = 7

  • La idea básica ahora es buscar la cadena ininterrumpida más larga de exactamente los últimos movimientos en la historia anterior. El programa realiza un seguimiento de dónde termina dicha cadena en la lista cand(para 'candidatos'). Al principio, sin verificar, se considera cada posición en el historial, excepto la última:

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

  • Ahora la longitud de las posibles cadenas aumenta paso a paso. Para la longitud de la cadena l = 1, busca ocurrencias anteriores del último par de movimientos [4, 1]. Esto se puede encontrar en la posición de historia 1y 3. Solo estos se mantienen en la candlista:

    cand = [1, 3]

  • A continuación, para l = 2comprobar cuál de los posibles candidatos fue precedido por el penúltimo par de movimientos [3, 2]. Este es solo el caso de la posición 3:

    cand = [3]

  • Para l = 3y más no hay cadenas anteriores de esa longitud y candestarían vacías. En este caso candse guarda el último elemento de :

    cand = [3]

  • El bot ahora supone que la historia se repetirá. La última vez que [3, 2], [4, 1]ocurrió el caín , fue seguido por [4, 2]. Entonces, el oponente jugó 2(tijeras) que puede ser golpeado por (2+1)%5 = 3(Spock) o (2+3)%5 = 0(piedra). El bot responde, con la primera o segunda alternativa dependiendo de si Nes impar o incluso para introducir alguna variación.

  • Aquí 3se elige el movimiento que luego se traduce de nuevo:

    print 'V'

Nota: Dienstag tiene una complejidad de tiempo O ( N 2 ) para devolver el siguiente movimiento después de N rondas. Pony tiene complejidad de tiempo O ( N 3 ). Entonces, en este aspecto, probablemente sean mucho peores que la mayoría de las otras entradas.

Emil
fuente
Por favor, hazlo. Esta es una experiencia de aprendizaje increíble para mí. Por lo general, vivo en C # / Java, por lo que toda la locura lua, ruby, python, haskell es muy interesante para mí.
Eoin Campbell
También estoy tentado de agregar una instancia adicional de Pony a los juegos. Será como tener que luchar contra tu espejo en el tercer y último nivel de Mortal Combat ;-)
Eoin Campbell
@EoinCampbell :-) Al menos el partido directo Pony vs. Pony sería un empate perfecto. No hay ningún elemento de aleatoriedad en mis dos bots.
Emil
3

Bash Rocks

¿Cygwin es demasiado pedir como tiempo de ejecución?

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

y ejecutarlo así:

sh bashrocks.sh
mccannf
fuente
55
Después de leer el título, estoy un poco decepcionado de que hagas cualquier cosa menos R. ;)
Martin Ender
@mccannf. teniendo algunos problemas con este ... Instalé cygwin y modifiqué sus scripts con rutas completamente calificadas a C: \ Cygwin \ bin para od.exe, xargs.exe y echo.exe. Todavía obteniendo el siguiente error. C: / Cygwin / bin / xargs: echo: No existe tal archivo o directorio% 5 ") error de sintaxis: operando esperado (token de error es"
Eoin Campbell
@EoinCampbell: cuando crea el archivo en Windows, ¿puede ejecutarlo dos2unixen Cygwin antes de ejecutarlo?
mccannf
seguro. Lo intentaré.
Eoin Campbell
Creo que el problema podría estar con la declaración / dev / urandom
Eoin Campbell
3

Algoritmo

Un algoritmo en aras de tener uno.

Porque siempre se siente más seguro hacer algo, cuanto más complicado, mejor.

Todavía no he hecho algunas matemáticas serias, por lo que este algoritmo puede no ser tan efectivo.

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")

Programa Python 2: python algorithm.py

Vectorizado
fuente
1
Resumen de este algoritmo: mira lo que el oponente jugó por última vez, y luego juega aleatoriamente uno de los dos movimientos que perderían contra el último movimiento del oponente si lo volvieran a jugar. Por lo tanto, es mejor contra los robots que no juegan el mismo movimiento dos veces seguidas.
Rory O'Kane
Jaja. Realmente no sé si lo hice así. Si no me equivoco, en realidad es solo una forma complicada de seleccionar aleatoriamente cualquiera de los 5 movimientos. ;)
Vectorizado
3

FairBot, Ruby

Comencemos simple.

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

Corre como

ruby fairbot.rb
Martin Ender
fuente
pequeño error tipográfico en el último parámetro 'V'. lo he arreglado en myside si quieres actualizar para completarlo
Eoin Campbell
@EoinCampbell gracias, arreglado!
Martin Ender
1
Lo interesante es que esto tiene exactamente las mismas probabilidades de ganar contra TODAS las estrategias.
Cruncher
3

ViolentoBot

Este bot elige la opción más violenta según la elección previa de los oponentes:

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])

Correr como

python ViolentBot.py (me) (opp)
Kyle Kanos
fuente
rompe sin params. Rastreo (última llamada más reciente): Archivo "ViolentBot \ ViolentBot.py", línea 9, en <module> oposnt = sys.argv [2] IndexError: índice de lista fuera de rango
Eoin Campbell
rompe con los params. Rastreo (última llamada más reciente): Archivo "ViolentBot \ ViolentBot.py", línea 12, en <module> print (choice_dict [oponent_last]) KeyError: 'S'
Eoin Campbell
@EoinCampbell: agregué una cláusula de salida para la primera ejecución, ahora debería poder ejecutarla.
Kyle Kanos
3

Haskell - MonadBot

No sé si ghc se considera "dentro de lo razonable", pero supongamos que lo es. La estrategia de este bot es contrarrestar el movimiento más popular de su oponente.

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

Código:

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'
DrJPepper
fuente