Rock, Paper, Scissors, Lizard, Spock [chiuso]


16

Creare una funzione che prenderà due stringhe come input e restituirà un singolo output per il risultato. Vince la risposta più popolare.

Le regole di Rock-paper-scissors-lizard-Spock sono:

  • Le forbici tagliano la carta
  • La carta copre il rock
  • La roccia schiaccia la lucertola
  • La lucertola avvelena Spock
  • Spock rompe le forbici
  • Le forbici decapitano la lucertola
  • La lucertola mangia la carta
  • La carta smentisce Spock
  • Spock vaporizza la roccia
  • Il rock rompe le forbici

L'output per ogni possibile caso di input è:

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'

Sfida extra suggerita da @Sean Cheshire: consentire elenchi personalizzati, come quelli di questo sito. Con l'elenco n-item, l'oggetto perde in (n-1) / 2 precedente e vince sul (n-1) / 2 seguente


7
La creazione di una tabella di ricerca di 25 elementi non è una sfida ed essere popolare non è una sfida del codice .
Peter Taylor,

6
E quando dico che essere popolari non è una sfida al codice : inizia la spiegazione di quel tag Una sfida al codice è una competizione per modi creativi per risolvere un puzzle di programmazione per un criterio oggettivo diverso dalla dimensione del codice. "La risposta più popolare vince" non è un criterio oggettivo: non si può dare il testo di due risposte a qualcuno e chiedere loro quale sia il più popolare.
Peter Taylor,

1
@PeterTaylor, dansalmo ha ragione, purché la tabella di ricerca sia in loop: questo è un famoso teorema di Conway: en.wikipedia.org/wiki/FRACTRAN
stand

1
@dansalmo La sfida a cui ti colleghi è stata creata prima dell'esistenza del tag contest di popolarità .
primo

1
Un suggerimento da aggiungere alla sfida - Consenti elenchi personalizzati, come quelli di questo sito che possono contenere fino a 101 elementi. Con la lista n-item, l'oggetto perde il (n-1) / 2 precedente e vince il (n-1) / 2 che
segue

Risposte:


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'
    ⍵∇⍺
}

Stampa esattamente come richiesto in tutti i casi, compresi i pareggi. Nessuna tabella di ricerca, ad eccezione delle parole effettive.

Puoi provarlo su http://ngn.github.io/apl/web/

'Spock' vs 'Paper'
Paper  disproves  Spock

APL lo sa!


+1, non ho mai notato APL fino ad ora. Ipnotizzante. Anche la tua struttura è fantastica. Mi piace l'ultima riga, la migliore.
dansalmo,

@dansalmo Grazie :) Mi piace molto. E ora grazie a github.com/ngn/apl abbiamo un interprete open source e web-ready (per decenni c'erano solo interpreti commerciali)
Tobia,

@dansalmo a proposito, APL si adatta perfettamente al tipo di codifica funzionale che sembra stia facendo in Python (cosa che mi piace fare anche io)
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
Questo è ... diabolico.
Wayne Conrad,

4

Ecco una soluzione generale basata su una stringa di regole di qualsiasi dimensione. Esegue le maiuscole corrette per il nome proprio "Spock" e consente anche le regole per specificare 'tie' anziché 'tie' per oggetti plurali.

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

risultati:

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

Quando si definisce rulesè possibile utilizzare una stringa multilinea anziché concatenazione letterale. Ciò consente di rimuovere le parentesi ridondanti.
Bakuriu,

3

Pitone

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)

Le forbici sono plurali, quindi la carta "taglia s " e "decapita la " lucertola "è sbagliata (l'ultima manca anche una P)." Spock smashs "dovrebbe essere" smash ";)
daniero

@daniero, grazie. Ho notato il problema delle forbici, ma risolverlo complica le cose. Risolve "smash" ora.
ugoren,

@Daniel "Scissors" è plurale. "Scissors" è anche singolare. Vedi en.wiktionary.org/wiki/scissors
DavidC

Così sottile. Lo adoro.
Kaao,

2

Pitone

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
A proposito, "più sciolto" è l'opposto di "più stretto". "Perdente" è l'opposto di "vincitore". E ti farà risparmiare alcuni caratteri nel tuo codice.
Joe,

2

Rubino, approccio aritmetico

Gli attori possono essere disposti in una matrice in modo tale che ogni attore a[i]vince contro gli attori a[i+1]e a[i+2], modulo 5, ad esempio:

%w(Scissors Lizard Paper Spock Rock)

Quindi, per un attore Acon indice ipossiamo vedere come abbina nuovamente l'attore Bcon l'indice jfacendo result = (j-i)%5: Risultato 1e 2significa che l'attore A ha vinto contro un attore 1 o 2 posti davanti a lui rispettivamente; 3e 4allo stesso modo significa che ha perso contro un attore dietro di lui nella schiera. 0significa un pareggio. (Nota che questo può dipendere dalla lingua; in Ruby (j-i)%5 == (5+j-i)%5anche quando j>i.)

La parte più interessante del mio codice è l'uso di questa proprietà per trovare una funzione di ordinamento degli indici di due attori. Il valore restituito sarà -1, 0 o 1 come dovrebbe :

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

Ecco il tutto:

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

Pitone


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

Usando un dizionario complicato.


Ben fatto. return(' '.join([p,'tie' + 's'*(p[1]!='c'),q]))otterrà il tempo verbale corretto.
dansalmo,

2

C #

ipotesi

Gli avversari sono disposti in un array di oggetti n in cui i giocatori battono i (n-1) / 2 giocatori davanti a loro e perdono contro i (n-1) / 2 giocatori dietro di loro. (Con elenchi di lunghezza pari, il giocatore perde i giocatori ((n-1) / 2 + 1) dietro di loro)

Le azioni del giocatore sono organizzate in un array in cui le azioni nell'intervallo da [(indexOfPlayer * (n-1) / 2)] a [(indexOfPlayer * (n-1) / 2)) + (n-2) / 2 - 1 ].

Informazioni addizionali

CircularBuffer<T>è un wrapper attorno a un array per creare un array indirizzabile "all'infinito". La IndexOffunzione restituisce l'indice di un elemento entro i limiti effettivi dell'array.

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

Esempio

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, one-liner

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]

Molto bello! È possibile .split(', ')e non dover incepparsi, le regole, insieme.
dansalmo,

@dansalmo, grazie, ma non vedo nulla di male in JammingTheRulesTogether. Anche se non è una gara di golf, penso che più corto è, meglio è.
ugoren,

1

Solo una piccola cosa che mi è venuta in mente:

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

Qui, rules è il file che contiene tutte le regole che sono state fornite.


0

Pitone

Ispirato al codice APL di @ 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)

risultati:

>>> 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 po 'di prova

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

Vedo che non si tratta di una gara di golf, ma mi sono armeggiato con questo puzzle per un po 'prima di trovare questa discussione, quindi ecco qui.

Ecco una versione js (standard) con 278 caratteri:

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}

O uno che utilizza le funzionalità E6 (probabilmente funziona solo con Firefox) con 259 caratteri:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.