¿Quién ganará un juego de Piedra, Papel, Tijera, Lagarto, Spock?

24

Hay varias preguntas con respecto a este juego , incluso un concurso de aquí . Pero creo que todos esos desafíos y concursos necesitan una forma de determinar automáticamente el ganador de un juego. Asi que:

Reto

Dadas dos entradas en el rango que ["rock", "paper", "scissors", "lizard", "spock"]representan las selecciones para el jugador 1 y el jugador 2, determinar el ganador del partido.

Reglas

[Winner] [action]    [loser]
-----------------------------
scissors cut         paper
paper    covers      rock
rock     crushes     lizard
lizard   poisons     spock
spock    smashes     scissors
scissors decapitates lizard
lizard   eats        paper
paper    disproves   spock
spock    vaporizes   rock
rock     crushes     scissors

Restricciones

  • La entrada será un par de cadenas en el rango dado (no se pueden usar otras cadenas). Puede usar matrices de caracteres si lo desea, siempre que representen cualquiera de los valores mencionados.
  • Puede elegir entre usar minúsculas, mayúsculas ( "ROCK") o camellas ( "Rock") para las cadenas de entrada, siempre que el caso elegido sea el mismo para todas las entradas.
  • La salida será un trío de valores que determinarán el ganador, que puede ser cualquier cosa que desee siempre que las respuestas sean consistentes. Ejemplo: 1si gana la primera entrada, 2si gana la segunda entrada, 0si hay un empate. O tal vez Asi gana la primera entrada, Bsi gana la segunda entrada, <empty string>si hay un empate.

Gol

Este es el , ¡así que puede ganar el programa / método / función / lambda más corto para cada idioma!

Pruebas

[Input 1] [Input 2] [Output: 1/2/0]
-----------------------------------
 rock      paper     2
 rock      scissors  1
 lizard    spock     1
 spock     rock      1
 spock     paper     2
 rock      rock      0
Charlie
fuente
Esto viene de la caja de arena .
Charlie
1
Muy relacionado .
Stewie Griffin
Lo cerré como un duplicado de la pregunta vinculada porque es la misma pregunta con 2 valores nuevos y una ligera variación en IO.
Wheat Wizard
44
@WheatWizard a veces un ligero cambio en la entrada produce salidas muy diferentes. Las preguntas pueden ser bastante similares, pero los dos nuevos valores crean más casos para considerar, por lo que los algoritmos utilizados aquí son lo suficientemente diferentes como para hacer que las personas piensen nuevamente (vea las respuestas con el caketruco).
Charlie
44
Estoy de acuerdo y voté para reabrir.
GB

Respuestas:

25

Python 3 , 68 50 48 bytes

EDITAR: Gracias a 3 trucos de Neil y 2 del Sr. Xcoder

Cada cadena de entrada tiene un cuarto carácter distinto, así que lo estoy usando para distinguirlos. Si organiza los elementos en el ciclo (tijeras, papel, piedra, lagarto, spock), cada elemento supera al elemento directamente después y el elemento 3 se coloca a la derecha, cíclicamente. Entonces restamos las posiciones de las entradas en el ciclo. Si ese número es 0, es un empate. Si es 1 o 3, es una victoria para el primer jugador. En mi solución original, la diferencia de ciclo se indexaría en la cadena "210100" para distinguir los resultados del juego. Neil de alguna manera descubrió que esto se puede lograr sin indexar agregando 7 y tomando el módulo por 3. Editar: Originalmente usé el segundo carácter para identificar la cadena, pero si usas el cuarto e inviertes el ciclo, obtienes pastel. Y todos podríamos usar más pastel.

lambda x,y,z="cake".find:(7+z(y[3])-z(x[3]))%5%3

Pruébalo en línea!

Versión antigua:

lambda x,y,z="caoip".index:(7+z(y[1])-z(x[1]))%5%3

Pruébalo en línea!

Versión original:

b="caoip"
def r(x,y):return"210100"[(b.index(y[1])-b.index(x[1]))%5]

Pruébalo en línea!

Qué hacer
fuente
1
50 bytes: ¡ Pruébelo en línea!
Neil
66
Bienvenido a PPCG!
Steadybox
1
49 bytes: ¡ Pruébelo en línea! (cambiando .indexa .find)
Sr. Xcoder
1
48 bytes: ¡ Pruébelo en línea! (no necesita p, "chaoi"basta)
Sr. Xcoder
14

JavaScript (ES6), 56 bytes

Toma entrada en la sintaxis de curry (a)(b). Devuelve 0si A gana, 1si B gana o falsepor un empate.

a=>b=>a!=b&&a>b^614>>((g=s=>parseInt(s,31)%9)(a)^g(b))&1

Manifestación

¿Cómo?

Definimos la función hash H () como:

H = s => parseInt(s, 31) % 9

Esto da:

s          | H(s)
-----------+-----
"rock"     |  2
"paper"    |  8
"scissors" |  1
"lizard"   |  3
"spock"    |  4

Dados dos entradas una y b , tenemos en cuenta las siguientes afirmaciones:

  1. ¿tenemos a> b ? (en orden lexicográfico)
  2. ¿ b gana el juego?
  3. ¿Cuál es el valor de N = H (a) XOR H (b) ?

A partir de (1) y (2), deducimos si el resultado de a> b debe invertirse para obtener el ganador correcto y almacenamos este indicador en el N-ésimo bit de una máscara de bits de búsqueda.

a        | H(a) | b        | H(b) | N  | a > b | b wins | invert
---------+------+----------+------+----+-------+--------+-------
rock     |   2  | paper    |   8  | 10 | Yes   | Yes    | No
rock     |   2  | scissors |   1  |  3 | No    | No     | No
rock     |   2  | lizard   |   3  |  1 | Yes   | No     | Yes
rock     |   2  | spock    |   4  |  6 | No    | Yes    | Yes
paper    |   8  | rock     |   2  | 10 | No    | No     | No
paper    |   8  | scissors |   1  |  9 | No    | Yes    | Yes
paper    |   8  | lizard   |   3  | 11 | Yes   | Yes    | No
paper    |   8  | spock    |   4  | 12 | No    | No     | No
scissors |   1  | rock     |   2  |  3 | Yes   | Yes    | No
scissors |   1  | paper    |   8  |  9 | Yes   | No     | Yes
scissors |   1  | lizard   |   3  |  2 | Yes   | No     | Yes
scissors |   1  | spock    |   4  |  5 | No    | Yes    | Yes
lizard   |   3  | rock     |   2  |  1 | No    | Yes    | Yes
lizard   |   3  | paper    |   8  | 11 | No    | No     | No
lizard   |   3  | scissors |   1  |  2 | No    | Yes    | Yes
lizard   |   3  | spock    |   4  |  7 | No    | No     | No
spock    |   4  | rock     |   2  |  6 | Yes   | No     | Yes
spock    |   4  | paper    |   8  | 12 | Yes   | Yes    | No
spock    |   4  | scissors |   1  |  5 | Yes   | No     | Yes
spock    |   4  | lizard   |   3  |  7 | Yes   | Yes    | No

De ahí los bits:

bit | value
----+-----------
 0  | 0 (unused)
 1  | 1
 2  | 1
 3  | 0
 4  | 0 (unused)
 5  | 1
 6  | 1
 7  | 0
 8  | 0 (unused)
 9  | 1
10  | 0
11  | 0
12  | 0

Leyendo esto de abajo hacia arriba e ignorando los ceros iniciales , esto da 1001100110 , o 614 en decimal.

Arnauld
fuente
6

05AB1E , 16 bytes

ε'³²s3èk}Æ7+5%3%

Pruébalo en línea! o como un conjunto de pruebas

Explicación

Utiliza el caketruco muy agradable del usuario 507295

ε       }          # apply to each in the input pair
    s3è            # get the 4th letter
 '³²   k           # get its cake-index
         Æ         # reduce by subtraction
          7+       # add 7
            5%3%   # mod by 5 and then 3
Emigna
fuente
4

Ruby , 36 bytes

->a,b{(2+a.sum%88%6-b.sum%88%6)%5%3}

Devuelve 0si el primer jugador gana, 1si el segundo jugador gana, y 2por un empate.

Basado en la respuesta del usuario 507295, pero utiliza una fórmula matemática para realizar el hash. a.sumes la suma de todos los códigos ASCII de la cadena a, mod 1<<16y está pensada como una suma de control rudimentaria. El hash se encontró usando el siguiente código:

1.upto(99){|j|p j,["scissors","paper","rock","lizard","spock"].map{|i|i.sum%j%6}}

Esto produjo dos valores jque dieron un hash adecuado para letras minúsculas, a saber, 88 y 80, los cuales dieron la secuencia descendente [3,2,1,0,4](o [4,3,2,1,0]si el ciclo se inicia al principio).

Como se explica en otras respuestas, se necesita un hash que proporcione una diferencia constante del módulo 5 para elementos consecutivos en la secuencia anterior para que la (h[a]-h[b])%5fórmula funcione. Cada elemento vence al elemento 1 o 3 lugares a la derecha y pierde al elemento 2 o 4 lugares a la derecha.

Pruébalo en línea!

Level River St
fuente
4

JavaScript (ES6), 63 54 53 49 bytes

f=
(l,r,g=s=>"cake".search(s[3]))=>(7+g(r)-g(l))%5%3
<div onchange=o.textContent=`RLT`[f(a.selectedOptions[0].value,b.selectedOptions[0].value)]>L: <select id=a><option>Rock<option>Paper<option>Scissors<option>Lizard<option>Spock</select> R: <select id=b><option>Rock<option>Paper<option>Scissors<option>Lizard<option>Spock</select> Winner: <span id=o>T

Puerto de mi golf a la respuesta de @ WhatToDo. Nota: el fragmento decodifica el resultado numérico en algo un poco menos ilegible. Editar: guardado 1 byte gracias a @Arnauld. Guardado 4 bytes gracias a @ovs.

Neil
fuente
@ovs Ugh, no porté mi golf a la respuesta de WhatToDo con suficiente fuerza ...
Neil
3

C, 53bytes

a="FÈ..J..ÁE";
z=*++y==*++x?0:a[*y&47>>1]>>*++x&7&1+1;

He tratado este problema como una máquina de estados, de los cuales hay 25 estados definidos por las dos, cinco entradas de estado.

Al definir los resultados de los estados dentro de una matriz de bits. Miro los resultados utilizando marcadores únicos dentro de las entradas.

Como se señaló en otras soluciones, los caracteres 2, 3 y 4 son únicos entre las posibles entradas. He concentrado el uso en los caracteres 2 y 3 que uso para seleccionar el bit apropiado dentro de mi matriz de respuestas.

Dentro del Carácter 2, los bits 1 a 4 identifican claramente la entrada. Al enmascarar estos bits y desplazarlos adecuadamente [ese es el "* y & 47 >> 1"], la entrada puede observarse como 0, 1, 4, 7 u 8. Por lo tanto, mi cadena de respuesta tiene 9 caracteres. (partes interesantes separadas)

character 2:
a 61   011 0000 1
c 63   011 0001 1
i 69   011 0100 1
p 70   011 1000 0
o 6f   011 0111 1

Dentro del carácter 3, los bits 0, 1 y 2 identifican claramente la entrada. Al enmascarar estos bits (no se requiere desplazamiento) [ese es el "* x & 7"], la entrada puede anotarse como 0, 1, 2, 3 o 7. (partes interesantes separadas)

character 3
p 70   01110 000
i 69   01101 001
z 7a   01111 010
o 6f   01101 111
c 63   01100 011

La cadena de respuesta se puede calcular simplemente completando los bits para los caracteres apropiados.

0th char represents X=paper
1st char represents X=scissors
4th char represents X=Lizard
7th char represents X=Rock
8th char represents X=Spock

0th bit represents Y=Paper
1st bit represents Y=Scissors
2nd bit represents Y=Lizard
3rd bit represents Y=Rock
7th bit represents Y=Spock

Entonces, pon un bit en char donde Y gana

char  7654 3210   in hex    in ascii
0     0100 0110    46         F
1     1100 1000    c8         È
2     0100 0000    d/c        .
3     0100 0000    d/c        .
4     0100 1010    4a         J
5     0100 0000    d/c        .
6     0100 0000    d/c        .
7     1100 0001    c1         Á
8     0100 0101    45         E

Entonces la lógica es simple: si el segundo carácter es el mismo, dibuje; de ​​lo contrario, obtenga un carácter ascii basado en el segundo carácter de y, cambie los bits por el tercer carácter de x y agregue uno. Esto hace que las respuestas sean 0 para empatar, 1 para x ganar y 2 para y ganar.

meismich
fuente
Bienvenido a PPCG! Esta es una gran respuesta bien pensada.
FantaC
1

Clojure, 130 118 bytes

-12 bytes al deshacerme de mi extraño uso de comp.

(fn[& m](let[[p q](map #(apply +(map int(take 2 %)))m)d(- p q)](cond(= d 0)0(#{5 -16 12 -14 13 1 4 -18 2 11}d)1 1 2)))

Pensé que estaba siendo inteligente, pero esto terminó siendo ingenuo en comparación con otras respuestas, y mucho más.

Toma las primeras 2 letras de cada cadena de movimiento, obtiene los códigos de caracteres y los suma. Luego resta las sumas para obtener d. Si des 0, es un empate (0), si está en el conjunto de #{5 -16 12 -14 13 1 4 -18 2 11}, p1 gana (1), de lo contrario, p2 gana (2).

(defn decide [& moves] ; Using varargs so I don't need to duplicate the steps.
  ; Pop the first 2 chars of each string, convert them to their ASCII code, and sum them.
  (let [[p1 p2] (map #(apply + (map int (take 2 %))) moves)
        d (- p1 p2)]

    (cond
      (= d 0) ; A tie
      0

      (#{5 -16 12 -14 13
         1 4 -18 2 11} d) ; P1 Wins
      1

      :else ; P2 Wins
      2)))

Para obtener los "números mágicos" que definen si P1 gana, corrí

(let [ms ["rock", "paper", "scissors", "lizard", "spock"]]
  (for [p1 ms
        p2 ms]

    ; Same as above
    (let [[p q] (map #(apply + (map int (take 2 %))) [p1 p2])
          d (- p q)]

      [p1 p2 d])))

Lo que genera una lista de dvalores para cada escenario posible:

(["rock" "rock" 0]
 ["rock" "paper" 16]
 ["rock" "scissors" 11]
 ["rock" "lizard" 12]
 ["rock" "spock" -2]
 ["paper" "rock" -16]
 ["paper" "paper" 0]
 ["paper" "scissors" -5]
 ["paper" "lizard" -4]
 ["paper" "spock" -18]
 ["scissors" "rock" -11]
 ["scissors" "paper" 5]
 ["scissors" "scissors" 0]
 ["scissors" "lizard" 1]
 ["scissors" "spock" -13]
 ["lizard" "rock" -12]
 ["lizard" "paper" 4]
 ["lizard" "scissors" -1]
 ["lizard" "lizard" 0]
 ["lizard" "spock" -14]
 ["spock" "rock" 2]
 ["spock" "paper" 18]
 ["spock" "scissors" 13]
 ["spock" "lizard" 14]
 ["spock" "spock" 0])

Luego comparé el gráfico de victorias con este resultado. Afortunadamente, no hubo ninguna "colisión" que no sea 0.

Carcigenicate
fuente