Qui gagnera un jeu Rock, Paper, Scissors, Lizard, Spock?

24

Il y a plusieurs questions concernant ce jeu , même un concours de ici . Mais je pense que tous ces défis et concours nécessitent un moyen de déterminer automatiquement le vainqueur d'un match. Alors:

Défi

Étant donné deux entrées dans la plage ["rock", "paper", "scissors", "lizard", "spock"]représentant les sélections pour le joueur 1 et le joueur 2, déterminez le vainqueur du match.

Règles

[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

Restrictions

  • L'entrée sera une paire de chaînes dans la plage donnée (aucune autre chaîne ne peut être utilisée). Vous pouvez utiliser des tableaux de caractères si vous le souhaitez, tant qu'ils représentent l'une des valeurs mentionnées.
  • Vous pouvez choisir d'utiliser des minuscules, des majuscules ( "ROCK") ou des majuscules ( "Rock") pour les chaînes d'entrée, tant que la casse choisie est la même pour toutes les entrées.
  • La sortie sera un trio de valeurs qui détermineront le gagnant, qui peut être tout ce que vous voulez tant que les réponses sont cohérentes. Exemple: 1si la première entrée gagne, 2si la deuxième entrée gagne, 0s'il y a égalité. Ou peut A- être si la première entrée gagne, Bsi la deuxième entrée gagne, <empty string>s'il y a égalité.

Objectif

C'est , donc le programme / méthode / fonction / lambda le plus court pour chaque langue peut gagner!

Les tests

[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
la source
Cela vient du bac à sable .
Charlie
1
Très lié .
Stewie Griffin
Je l'ai fermé en tant que doublon de la question liée, car c'est juste la même question avec 2 nouvelles valeurs et une légère variation sur IO.
Wheat Wizard
4
@WheatWizard parfois un léger changement dans l'entrée produit des sorties très différentes. Les questions peuvent être assez similaires, mais les deux nouvelles valeurs créent plus de cas à considérer, donc les algorithmes utilisés ici sont suffisamment différents pour faire réfléchir à nouveau (voir les réponses avec l' cakeastuce).
Charlie
4
Je suis d'accord et j'ai voté pour la réouverture.
GB

Réponses:

25

Python 3 , 68 50 48 octets

EDIT: Merci à 3 tours de Neil, et 2 de M. Xcoder

Chaque chaîne d'entrée a un quatrième caractère distinct, donc je l'utilise pour les distinguer. Si vous organisez les éléments dans le cycle (ciseaux, papier, roche, lézard, spock), chaque élément bat l'élément directement après lui et l'élément 3 se place à droite, cycliquement. Nous soustrayons donc les positions des entrées dans le cycle. Si ce nombre est 0, c'est une égalité. Si c'est 1 ou 3, c'est une victoire pour le premier joueur. Dans ma solution d'origine, la différence de cycle serait indexée dans la chaîne "210100" pour distinguer les résultats du jeu. Neil a en quelque sorte compris que cela peut être accompli sans indexation en ajoutant 7 et en prenant le module par 3. Edit: À l'origine, j'ai utilisé le deuxième caractère pour identifier la chaîne, mais si vous utilisez le quatrième et inversez le cycle, vous obtenez un gâteau. Et nous pourrions tous utiliser plus de gâteau.

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

Essayez-le en ligne!

Ancienne version:

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

Essayez-le en ligne!

Version originale:

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

Essayez-le en ligne!

Que faire
la source
1
50 octets: essayez-le en ligne!
Neil
6
Bienvenue chez PPCG!
Steadybox
1
49 octets: essayez-le en ligne! (passage .indexà .find)
M. Xcoder
1
48 octets: essayez-le en ligne! (vous n'avez pas besoin du p, "chaoi"suffit)
M. Xcoder
14

JavaScript (ES6), 56 octets

Prend une entrée dans la syntaxe de curry (a)(b). Renvoie 0si A gagne, 1si B gagne ou falsepour une égalité.

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

Démo

Comment?

Nous définissons la fonction de hachage H () comme:

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

Cela donne:

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

Étant donné deux entrées a et b , nous considérons les déclarations suivantes:

  1. avons-nous un> b ? (par ordre lexicographique)
  2. ne b gagner le jeu?
  3. quelle est la valeur de N = H (a) XOR H (b) ?

De (1) et (2), nous déduisons si le résultat de a> b doit être inversé pour obtenir le bon gagnant et nous stockons cet indicateur dans le N-ème bit d'un masque de bits de recherche.

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

D'où les 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

En lisant ceci de bas en haut et en ignorant les zéros en tête, cela donne 1001100110 , ou 614 en décimal.

Arnauld
la source
6

05AB1E , 16 octets

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

Essayez-le en ligne! ou comme suite de tests

Explication

Utilise la très belle cakeastuce de user507295

ε       }          # 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
la source
4

Rubis , 36 octets

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

Renvoie 0si le 1er joueur gagne, 1si le 2ème joueur gagne et 2pour un match nul.

Basé sur la réponse de user507295 mais utilise une formule mathématique pour effectuer le hachage. a.sumest la somme de tous les codes ASCII de la chaîne a, mod 1<<16et est conçu comme une somme de contrôle rudimentaire. Le hachage a été trouvé à l'aide du code suivant:

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

Cela a produit deux valeurs jqui ont donné un hachage approprié pour les lettres minuscules, à savoir 88 et 80, qui ont toutes deux donné la séquence décroissante [3,2,1,0,4](ou [4,3,2,1,0]si spock est cyclé au début.)

Comme expliqué dans d'autres réponses, un hachage qui donne une différence constante modulo 5 pour les éléments consécutifs dans la séquence ci-dessus est nécessaire pour faire fonctionner la (h[a]-h[b])%5formule. Chaque élément bat l'élément 1 ou 3 places à droite et perd à l'élément 2 ou 4 places à droite.

Essayez-le en ligne!

Level River St
la source
4

JavaScript (ES6), 63 54 53 49 octets

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

Port de mon golf à la réponse de @ WhatToDo. Remarque: l'extrait de code décode le résultat numérique en quelque chose d'un peu moins illisible. Edit: 1 octet enregistré grâce à @Arnauld. 4 octets enregistrés grâce à @ovs.

Neil
la source
@ovs Ugh, je n'ai pas porté mon golf sur la réponse de WhatToDo assez durement ...
Neil
3

C, 53 octets

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

J'ai traité ce problème comme une machine à états, dont 25 états sont définis par les deux, cinq entrées d'état.

En définissant les résultats des états dans un tableau de bits. Je regarde les résultats à l'intérieur en utilisant des marqueurs uniques dans les entrées.

Comme indiqué dans d'autres solutions, les caractères 2, 3 et 4 sont uniques entre les entrées possibles. J'ai concentré l'utilisation sur les caractères 2 et 3 que j'utilise pour sélectionner le bit approprié dans mon tableau de réponses.

Dans le caractère 2, les bits 1 à 4 identifient clairement l'entrée. En masquant ces bits et en décalant de façon appropriée [c'est le "* y & 47 >> 1"], l'entrée peut être notée comme 0, 1, 4, 7 ou 8. Par conséquent, ma chaîne de réponse a 9 caractères. (bits intéressants séparés)

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

Dans le caractère 3, les bits 0, 1 et 2 identifient clairement l'entrée. En masquant ces bits (décalage non requis) [c'est le "* x & 7"], l'entrée peut être notée comme 0, 1, 2, 3 ou 7. (bits intéressants séparés)

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

La chaîne de réponse peut ensuite être calculée en remplissant simplement les bits pour les caractères appropriés.

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

Donc, mettez le bit dans le caractère où Y gagne

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

Ensuite, la logique est simple: si le deuxième caractère est le même, dessinez, sinon, obtenez le caractère ascii basé sur le deuxième caractère de y et décalez les bits par le troisième caractère de x et ajoutez-en un. Cela rend les réponses 0 pour le tirage au sort, 1 pour x victoire et 2 pour y victoire.

meismich
la source
Bienvenue chez PPCG! C'est une excellente réponse bien pensée.
FantaC
1

Clojure, 130 118 octets

-12 octets en se débarrassant de mon utilisation bizarre 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)))

Je pensais que j'étais intelligent, mais cela a fini par être naïf par rapport à d'autres réponses, et beaucoup plus longtemps.

Prend les 2 premières lettres de chaque chaîne de déplacement, obtient les codes de caractères et les additionne. Il soustrait ensuite les sommes à obtenir d. Si dest 0, c'est une égalité (0), s'il est dans l'ensemble de #{5 -16 12 -14 13 1 4 -18 2 11}, p1 gagne (1), sinon, p2 gagne (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)))

Pour obtenir les "nombres magiques" qui définissent si P1 gagne, j'ai couru

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

Ce qui génère une liste de dvaleurs pour chaque scénario possible:

(["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])

J'ai ensuite comparé le graphique des gains avec cette sortie. Heureusement, il n'y a pas eu de "collisions" autres que 0.

Carcigenicate
la source