Rock, Paper, Scissors, Lizard, Spock [fermé]


16

Créez une fonction qui prendra deux chaînes en entrée et renverra une seule sortie pour le résultat. La réponse la plus populaire l'emporte.

Les règles de Rock-paper-scissors-lizard-Spock sont:

  • Ciseaux papier découpé
  • Papier couvre rock
  • Lézard écrase la roche
  • Lézard empoisonne Spock
  • Spock fracasse les ciseaux
  • Des ciseaux décapitent le lézard
  • Lézard mange du papier
  • Le papier réfute Spock
  • Spock vaporise la roche
  • Rock brise des ciseaux

La sortie pour chaque cas d'entrée possible est:

winner('Scissors', 'Paper') -> 'Scissors cut Paper'
winner('Scissors', 'Rock') -> 'Rock breaks Scissors'
winner('Scissors', 'Spock') -> 'Spock smashes Scissors'
winner('Scissors', 'Lizard') -> 'Scissors decapitate Lizard'
winner('Scissors', 'Scissors') -> 'Scissors tie Scissors'
winner('Paper', 'Rock') -> 'Paper covers Rock'
winner('Paper', 'Spock') -> 'Paper disproves Spock'
winner('Paper', 'Lizard') -> 'Lizard eats Paper'
winner('Paper', 'Scissors') -> 'Scissors cut Paper'
winner('Paper', 'Paper') -> 'Paper ties Paper'
winner('Rock', 'Spock') -> 'Spock vaporizes Rock'
winner('Rock', 'Lizard') -> 'Rock crushes Lizard'
winner('Rock', 'Scissors') -> 'Rock breaks Scissors'
winner('Rock', 'Paper') -> 'Paper covers Rock'
winner('Rock', 'Rock') -> 'Rock ties Rock'
winner('Lizard', 'Rock') -> 'Rock crushes Lizard'
winner('Lizard', 'Spock') -> 'Lizard poisons Spock'
winner('Lizard', 'Scissors') -> 'Scissors decapitate Lizard'
winner('Lizard', 'Paper') -> 'Lizard eats Paper'
winner('Lizard', 'Lizard') -> 'Lizard ties Lizard'
winner('Spock', 'Rock') -> 'Spock vaporizes Rock'
winner('Spock', 'Lizard') -> 'Lizard poisons Spock'
winner('Spock', 'Scissors') -> 'Spock smashes Scissors'
winner('Spock', 'Paper') -> 'Paper disproves Spock'
winner('Spock', 'Spock') -> 'Spock ties Spock'

Défi supplémentaire suggéré par @Sean Cheshire: Autoriser les listes personnalisées, telles que celles de ce site. Avec la liste des n éléments, l'élément perd au (n-1) / 2 précédent et gagne le (n-1) / 2 suivant


7
La création d'une table de recherche à 25 éléments n'est pas un défi, et être populaire n'est pas un défi de code .
Peter Taylor

6
Et quand je dis qu'être populaire n'est pas un défi de code : l'explication de cette balise commence Un défi de code est une compétition pour des façons créatives de résoudre un puzzle de programmation pour un critère objectif autre que la taille du code. "La réponse la plus populaire gagne" n'est pas un critère objectif: vous ne pouvez pas donner le texte de deux réponses à quelqu'un et lui demander quelle est la plus populaire.
Peter Taylor

1
@PeterTaylor, dansalmo a raison, tant que cette table de recherche est dans une boucle: c'est un célèbre théorème de Conway: en.wikipedia.org/wiki/FRACTRAN
boothby

1
@dansalmo Le défi auquel vous créez un lien a été créé avant l'existence du tag de concours de popularité .
primo

1
Une suggestion à ajouter au défi - Autoriser les listes personnalisées, telles que celles de ce site, qui peuvent contenir jusqu'à 101 éléments. Avec la liste des n éléments, l'élément perd au (n-1) / 2 précédent et gagne le (n-1) / 2 suivant
SeanC

Réponses:


13

APL

vs←{
    n←'Scissors' 'Paper' 'Rock' 'Lizard' 'Spock'
    x←n⍳⊂⍺ ⋄ y←n⍳⊂⍵ ⋄ X←⍺ ⋄ Y←⍵ ⋄ r←{X,⍵,⊂Y}
    x=y:     r (-x=0)↓'ties'
    y=5|1+x: r x⌷'cut' 'covers' 'crushes' 'poisons' 'smashes'
    y=5|3+x: r x⌷'decapitate' 'disproves' 'breaks' 'eats' 'vaporizes'
    ⍵∇⍺
}

Sortie exactement comme requis dans tous les cas, y compris les cravates / cravates. Aucune table de recherche, sauf pour les mots réels.

Vous pouvez l'essayer sur http://ngn.github.io/apl/web/

'Spock' vs 'Paper'
Paper  disproves  Spock

APL sait juste!


+1, jamais remarqué APL jusqu'à présent. Envoûtant. Votre structure est également cool. J'aime mieux la dernière ligne.
dansalmo

@dansalmo Merci :) Je l'aime beaucoup. Et maintenant, grâce à github.com/ngn/apl, nous avons un interprète open source et prêt pour le Web (pendant des décennies, il n'y avait que des interprètes commerciaux)
Tobia

@dansalmo btw, APL est parfaitement adapté au type de codage fonctionnel que vous semblez faire en Python (ce que j'aime aussi faire)
Tobia

10

SED

#!/bin/sed
#expects input as 2 words, eg: scissors paper

s/^.*$/\L&/
s/$/;scissors cut paper covers rock crushes lizard poisons spock smashes scissors decapitates lizard eats paper disproves spock vaporizes rock breaks scissors/
t a
:a
s/^\(\w\+\)\s\+\(\w\+\);.*\1 \(\w\+\) \2.*$/\u\1 \3 \u\2/
s/^\(\w\+\)\s\+\(\w\+\);.*\2 \(\w\+\) \1.*$/\u\2 \3 \u\1/
t b
s/^\(\w\+\)\s\+\1;\(\1\?\(s\?\)\).*$/\u\1 tie\3 \u\1/
:b

1
C'est ... diabolique.
Wayne Conrad

4

Voici une solution générale basée sur une chaîne de règles de n'importe quelle taille. Il effectue une mise en majuscules correcte pour le nom propre "Spock" et permet également des règles pour spécifier "cravate" au lieu de "cravates" pour plusieurs objets.

def winner(p1, p2):
    rules = ('scissors cut paper covers rock crushes lizard poisons Spock'
    ' smashes scissors decapitate lizard eats paper disproves Spock vaporizes'
    ' rock breaks scissors tie scissors'.split())

    idxs = sorted(set(i for i, x in enumerate(rules) 
                      if x.lower() in (p1.lower(), p2.lower())))
    idx = [i for i, j in zip(idxs, idxs[1:]) if j-i == 2]
    s=' '.join(rules[idx[0]:idx[0]+3] if idx 
          else (rules[idxs[0]], 'ties', rules[idxs[0]]))
    return s[0].upper()+s[1:]

Résultats:

>>> winner('spock', 'paper')
'Paper disproves Spock'
>>> winner('spock', 'lizard')
'Lizard poisons Spock'
>>> winner('Paper', 'lizard')
'Lizard eats paper'
>>> winner('Paper', 'Paper')
'Paper ties paper'
>>> winner('scissors',  'scissors')
'Scissors tie scissors'    

Lors de la définition, rulesvous pouvez utiliser une chaîne multiligne au lieu d'une concaténation littérale. Cela vous permet de supprimer les parenthèses redondantes.
Bakuriu

3

Python

class Participant (object):
    def __str__(self): return str(type(self)).split(".")[-1].split("'")[0]
    def is_a(self, cls): return (type(self) is cls)
    def do(self, method, victim): return "%s %ss %s" % (self, method, victim)

class Rock (Participant):
        def fight(self, opponent):
                return (self.do("break", opponent)  if opponent.is_a(Scissors) else
                        self.do("crushe", opponent) if opponent.is_a(Lizard)   else
                        None)

class Paper (Participant):
        def fight(self, opponent):
                return (self.do("cover", opponent)    if opponent.is_a(Rock)  else
                        self.do("disprove", opponent) if opponent.is_a(Spock) else
                        None)

class Scissors (Participant):
        def fight(self, opponent):
                return (self.do("cut", opponent)       if opponent.is_a(Paper)  else
                        self.do("decaitate", opponent) if opponent.is_a(Lizard) else
                        None)

class Lizard (Participant):
        def fight(self, opponent):
                return (self.do("poison", opponent) if opponent.is_a(Spock) else
                        self.do("eat", opponent)    if opponent.is_a(Paper) else
                        None)

class Spock (Participant):
        def fight(self, opponent):
                return (self.do("vaporize", opponent) if opponent.is_a(Rock)     else
                        self.do("smashe", opponent)    if opponent.is_a(Scissors) else
                        None)

def winner(a, b):
    a,b = ( eval(x+"()") for x in (a,b))
    return a.fight(b) or b.fight(a) or a.do("tie", b)

Les ciseaux sont au pluriel, donc le papier "cut s " et le "lizard" decaitate s est faux (le dernier manque aussi un P). Et "Spock smashs " devrait être "smashes";)
daniero

@daniero, merci. J'ai remarqué le problème des ciseaux, mais le réparer complique les choses. Correction des "smashes" maintenant.
ugoren

@Daniel "Scissors" est pluriel. "Ciseaux" est également singulier. Voir en.wiktionary.org/wiki/scissors
DavidC

Si subtil. Aimer.
kaoD

2

Python

def winner(p1, p2):
    actors = ['Paper', 'Scissors', 'Spock', 'Lizard', 'Rock']
    verbs = {'RoLi':'crushes', 'RoSc':'breaks', 'LiSp':'poisons',
             'LiPa':'eats', 'SpSc':'smashes', 'SpRo':'vaporizes', 
             'ScPa':'cut', 'ScLi':'decapitate', 'PaRo':'covers', 
             'PaSp':'disproves', 'ScSc':'tie'}
    p1, p2 = actors.index(p1), actors.index(p2)
    winner, loser = ((p1, p2), (p2, p1))[(1,0,1,0,1)[p1 - p2]]
    return ' '.join([actors[winner],
                     verbs.get(actors[winner][0:2] + actors[loser][0:2],
                               'ties'),
                     actors[loser]])

1
Soit dit en passant, "plus lâche" est l'opposé de "plus serré". "Perdant" est l'opposé de "gagnant". Et cela vous fera économiser quelques caractères dans votre code.
Joe

2

Ruby, approche arithmétique

Les acteurs peuvent être disposés dans un tableau de telle manière que chaque acteur a[i]gagne contre les acteurs a[i+1]et a[i+2], modulo 5, par exemple:

%w(Scissors Lizard Paper Spock Rock)

Ensuite, pour un acteur Aavec index, inous pouvons voir comment il correspond à un acteur Bavec index jen faisant result = (j-i)%5: Résultat 1et 2signifie que l'acteur A a gagné contre un acteur 1 ou 2 places respectivement devant lui; 3et 4signifie également qu'il a perdu contre un acteur derrière lui dans le tableau. 0signifie une cravate. (Notez que cela peut dépendre de la langue; dans Ruby (j-i)%5 == (5+j-i)%5aussi quand j>i.)

La partie la plus intéressante de mon code est l'utilisation de cette propriété pour trouver une fonction de tri des indices de deux acteurs. La valeur de retour sera -1, 0 ou 1 comme il se doit :

winner,loser = [i,j].sort { |x,y| ((y-x)%5+1)/2-1 }

Voici le tout:

def battle p1,p2
    who = %w(Scissors Lizard Paper Spock Rock)
    how = %w(cut decapitate poisons eats covers disproves smashes vaporizes crushes breaks)
    i,j = [p1,p2].map { |s| who.find_index s }

    winner,loser = [i,j].sort { |x,y| ((y-x)%5+1)/2-1 }

    method = (winner-loser)%5/2
    what = method == 0 && "ties" || how[winner*2 + method-1]

    return "#{who[winner]} #{what} #{who[loser]}"
end

2

Python


  def winner(p,q):
        if p==q:
           return(' '.join([p,'tie',q]))
        d = {'ca':'cut','ao':'covers','oi':'crushes','ip':'poisons','pc': 'smashes','ci':'decapitate','ia':'eats', 'ap':'disproves', 'po':'vaporizes','oc': 'breaks'}
        [a,b] = [p[1],q[1]]
        try:
           return(' '.join([p,d[a+b],q]))
        except KeyError:
           return(' '.join([q,d[b+a],p]))

Utilisation d'un dictionnaire délicat.


Joli. return(' '.join([p,'tie' + 's'*(p[1]!='c'),q]))obtiendra le verbe au temps correct.
dansalmo

2

C #

Hypothèses

Les adversaires sont disposés dans un tableau de n éléments où les joueurs battent les (n-1) / 2 joueurs devant eux et perdent face aux (n-1) / 2 joueurs derrière eux. (Avec des listes de longueurs égales, le joueur perd face aux ((n-1) / 2 + 1) joueurs derrière eux)

Les actions des joueurs sont organisées dans un tableau où les actions dans la plage de [(indexOfPlayer * (n-1) / 2)] à [(indexOfPlayer * (n-1) / 2)) + (n-2) / 2 - 1 ].

Information additionnelle

CircularBuffer<T>est un wrapper autour d'un tableau pour créer un tableau adressable "à l'infini". La IndexOffonction renvoie l'index d'un élément dans les limites réelles du tableau.

La classe

public class RockPaperScissors<T> where T : IComparable
{
    private CircularBuffer<T> players;
    private CircularBuffer<T> actions;

    private RockPaperScissors() { }

    public RockPaperScissors(T[] opponents, T[] actions)
    {
        this.players = new CircularBuffer<T>(opponents);
        this.actions = new CircularBuffer<T>(actions);
    }

    public string Battle(T a, T b)
    {
        int indexA = players.IndexOf(a);
        int indexB = players.IndexOf(b);

        if (indexA == -1 || indexB == -1)
        {
            return "A dark rift opens in the side of the arena.\n" +
                   "Out of it begins to crawl a creature of such unimaginable\n" +
                   "horror, that the spectators very minds are rendered\n" +
                   "but a mass of gibbering, grey jelly. The horrific creature\n" +
                   "wins the match by virtue of rendering all possible opponents\n" +
                   "completely incapable of conscious thought.";
        }

        int range = (players.Length - 1) / 2;

        if (indexA == indexB)
        {
            return "'Tis a tie!";
        }
        else
        {
            indexB = indexB < indexA ? indexB + players.Length : indexB;
            if (indexA + range < indexB)
            {
                // A Lost
                indexB = indexB >= players.Length ? indexB - players.Length : indexB;
                int actionIndex = indexB * range + (indexA > indexB ? indexA - indexB : (indexA + players.Length) - indexB) - 1;

                return players[indexB] + " " + actions[actionIndex] + " " + players[indexA];
            }
            else
            {
                // A Won
                int actionIndex = indexA * range + (indexB - indexA) - 1;

                return players[indexA] + " " + actions[actionIndex] + " " + players[indexB];
            }
        }
    }
}

Exemple

string[] players = new string[] { "Scissors", "Lizard", "Paper", "Spock", "Rock" };
string[] actions = new string[] { "decapitates", "cuts", "eats", "poisons", "disproves", "covers", "vaporizes", "smashes", "breaks", "crushes" };

RockPaperScissors<string> rps = new RockPaperScissors<string>(players, actions);

foreach (string player1 in players)
{
    foreach (string player2 in players)
    {
        Console.WriteLine(rps.Battle(player1, player2));
    }
}
Console.ReadKey(true);

1

Python, une ligne

winner=lambda a,b:(
    [a+" ties "+b]+
    [x for x in 
        "Scissors cut Paper,Paper covers Rock,Rock crushes Lizard,Lizard poisons Spock,Spock smashes Scissors,Scissors decapitate Lizard,Lizard eats Paper,Paper disproves Spock,Spock vaporizes Rock,Rock break Scissors"
        .split(',') 
     if a in x and b in x])[a!=b]

Très cool! Vous pouvez .split(', ')et ne devez pas brouiller les règles ensemble.
dansalmo

@dansalmo, merci, mais je ne vois aucun mal à JammingTheRulesTogether. Bien que ce ne soit pas un concours de golf, je pense que le plus court sera le mieux.
ugoren

1

Juste une petite chose que j'ai trouvée:

echo "winners('Paper', 'Rock')"|sed -r ":a;s/[^ ]*'([[:alpha:]]+)'./\1/;ta;h;s/([[:alpha:]]+) ([[:alpha:]]+)/\2 \1/;G"|awk '{while(getline line<"rules"){split(line,a," ");if(match(a[1],$1)&&match(a[3],$2))print line};close("rules")}' IGNORECASE=1

Ici, les règles est le fichier contenant toutes les règles qui ont été données.


0

Python

Inspiré du code APL de @ Tobia.

def winner(p1, p2):
  x,y = map(lambda s:'  scparolisp'.find(s.lower())/2, (p1[:2], p2[:2]))
  v = (' cut covers crushes poisons smashes'.split(' ')[x*(y in (x+1, x-4))] or
       ' decapitate disproves breaks eats vaporizes'.split(' ')[x*(y in (x+3, x-2))])
  return ' '.join((p1.capitalize(), v or 'tie'+'s'*(x!=1), p2)) if v or p1==p2 \
    else winner(p2, p1)

Résultats:

>>> winner('Spock', 'paper')
'Paper disproves Spock'
>>> winner('Spock', 'lizard')
'Lizard poisons Spock'
>>> winner('paper', 'lizard')
'Lizard eats paper'
>>> winner('paper', 'paper')
'Paper ties paper'
>>> winner('scissors',  'scissors')
'Scissors tie scissors'    

0

C ++

#include <stdio.h>
#include <string>
#include <map>
using namespace std ;
map<string,int> type = { {"Scissors",0},{"Paper",1},{"Rock",2},{"Lizard",3},{"Spock",4} };
map<pair<int,int>, string> joiner = {
  {{0,1}, " cuts "},{{0,3}, " decapitates "}, {{1,2}, " covers "},{{1,4}, " disproves "},
  {{2,3}, " crushes "},{{2,0}, " crushes "},  {{3,4}, " poisons "},{{3,1}, " eats "},
  {{4,0}, " smashes "},{{4,2}, " vaporizes "},
} ;
// return 0 if first loses, return 1 if 2nd wins
int winner( pair<int,int> p ) {
  return (p.first+1)%5!=p.second && (p.first+3)%5!=p.second ;
}
string winner( string sa, string sb ) {
  pair<int,int> pa = {type[sa],type[sb]};
  int w = winner( pa ) ;
  if( w )  swap(pa.first,pa.second), swap(sa,sb) ;
  return sa+(pa.first==pa.second?" Ties ":joiner[pa])+sb ;
}

Un peu de test

int main(int argc, const char * argv[])
{
  for( pair<const string&, int> a : type )
    for( pair<const string&, int> b : type )
      puts( winner( a.first, b.first ).c_str() ) ;
}

0

Javascript

function winner(c1,c2){
    var c = ["Scissors", "Paper", "Rock", "Lizard", "Spock"];
    var method={
        1:["cut", "covers", "crushes", "poisons", "smashes"],
        2:["decapitate", "disproves", "breaks", "eats", "vaporizes"]};
    //Initial hypothesis: first argument wins
    var win = [c.indexOf(c1),c.indexOf(c2)];
    //Check for equality
    var diff = win[0] - win[1];
    if(diff === 0){
        return c1 + ((win[0]===0)?" tie ":" ties ") + c2;
    }
    //If s is -1 we'll swap the order of win[] array
    var s = (diff>0)?1:-1;
    diff = Math.abs(diff);
    if(diff >2){
        diff = 5-diff;
        s= s * -1;
    }
    s=(diff==1)?s*-1:s;
    if(s === -1){
        win = [win[1],win[0]];
    }
    return c[win[0]] + " " + method[diff][win[0]] + " " + c[win[1]];
}

0

Javascript

Je vois que ce n'est pas un concours de golf, mais je jouais avec ce puzzle depuis un certain temps avant de trouver ce fil, alors voilà.

Voici une version js (standard) en 278 caractères:

function winner(a,b){var c={rock:0,paper:1,scissors:2,spock:3,lizard:4},d="crushe,crushe,cover,disprove,cut,decapitate,smashe,vaporize,poison,eat".split(","),i=c[a],j=c[b],I=i==(j+3)%5;return i^j?i==(j+1)%5||I?a+" "+d[i*2+I]+"s "+b:b+" "+d[j*2+(j==(i+3)%5)]+"s "+a:a+" ties "+b}

Ou un utilisant les fonctionnalités E6 (ne fonctionne probablement que dans Firefox) en 259 caractères:

winner=(a,b,c={rock:0,paper:1,scissors:2,spock:3,lizard:4},d="crushe,crushe,cover,disprove,cut,decapitate,smashe,vaporize,poison,eat".split(","),i=c[a],j=c[b],I=i==(j+3)%5)=>i^j?i==(j+1)%5||I?a+" "+d[i*2+I]+"s "+b:b+" "+d[j*2+(j==(i+3)%5)]+"s "+a:a+" ties "+b
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.