Piedra, papel, tijeras, lagarto, Spock [cerrado]

16

Cree una función que tomará dos cadenas como entrada y devolverá una única salida para el resultado. La respuesta más popular gana.

Las reglas de Rock-paper-scissors-lizard-Spock son:

  • Tijeras cortadas de papel
  • Papel cubre roca
  • Lagarto aplasta roca
  • Veneno de lagarto Spock
  • Spock rompe las tijeras
  • Tijeras decapitan lagarto
  • Lagarto come papel
  • El papel refuta a Spock
  • Spock vaporiza roca
  • Piedra rompe tijeras

La salida para cada caso de entrada posible es:

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'

Desafío adicional sugerido por @Sean Cheshire: permitir listas personalizadas, como las de este sitio. Con la lista n-item, el ítem pierde ante el (n-1) / 2 anterior y gana sobre el (n-1) / 2 siguiente

dansalmo
fuente
77
Crear una tabla de búsqueda de 25 elementos no es un desafío, y ser popular no es un desafío de código .
Peter Taylor
66
Y cuando digo que ser popular no es un desafío de código : comienza la explicación de esa etiqueta. Un desafío de código es una competencia por formas creativas de resolver un rompecabezas de programación para un criterio objetivo que no sea el tamaño del código. "La respuesta más popular gana" no es un criterio objetivo: no se puede dar el texto de dos respuestas a alguien y preguntar cuál es la más popular.
Peter Taylor
1
@PeterTaylor, dansalmo tiene razón, siempre y cuando esa tabla de búsqueda esté en un bucle: este es un famoso teorema de Conway: en.wikipedia.org/wiki/FRACTRAN
stand el
1
@dansalmo El desafío al que se vinculó se creó antes de la existencia de la etiqueta de concurso de popularidad .
primo
1
Una sugerencia para agregar al desafío: permita listas personalizadas, como las de este sitio, que tengan hasta 101 elementos. Con la lista de n-ítems, el ítem pierde ante el (n-1) / 2 anterior y gana sobre el (n-1) / 2 siguiente
SeanC

Respuestas:

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

Salida exactamente como se requiere en todos los casos, incluidos los empates. No hay tabla de búsqueda, excepto las palabras reales.

Puedes probarlo en http://ngn.github.io/apl/web/

'Spock' vs 'Paper'
Paper  disproves  Spock

APL solo lo sabe!

Tobia
fuente
+1, nunca noté APL hasta ahora. Hipnotizante Tu estructura también es genial. Me gusta la última línea lo mejor.
dansalmo
@dansalmo Gracias :) Me gusta mucho. Y ahora, gracias a github.com/ngn/apl , tenemos un intérprete de código abierto y listo para la web (durante décadas solo hubo intérpretes comerciales)
Tobia
@dansalmo por cierto, APL es un complemento perfecto para el tipo de codificación funcional que parece estar haciendo en Python (que también me gusta)
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
Hasturkun
fuente
1
Esto es ... diabólico.
Wayne Conrad el
4

Aquí hay una solución general basada en una cadena de reglas de cualquier tamaño. Realiza la mayúscula correcta para el nombre propio "Spock" y también permite reglas para especificar 'empate' en lugar de 'empates' para objetos plurales.

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

Resultados:

>>> 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'    
dansalmo
fuente
Al definir rules, puede usar una cadena multilínea en lugar de una concatenación literal. Esto le permite eliminar los paréntesis redundantes.
Bakuriu
3

Pitón

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)
Ugoren
fuente
Las tijeras son plurales, por lo que el papel "cortar s " y "decaitate s " lagarto "está mal (el último también pierde una P). Y" Spock smashs "debería ser" smashes ";)
daniero
@daniero, gracias. Noté el problema de las tijeras, pero arreglarlo complica las cosas. Arreglando "aplasta" ahora.
ugoren
@Daniel "Tijeras" es plural. "Tijeras" también es singular. Ver en.wiktionary.org/wiki/scissors
DavidC
Tan sutil Quiéralo.
kaoD
2

Pitón

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]])
dansalmo
fuente
1
Por cierto, "más flojo" es lo contrario de "más estricto". "Perdedor" es lo contrario de "ganador". Y te ahorrará algunos caracteres en tu código.
Joe
2

Ruby, enfoque aritmético

Los actores se pueden organizar en una matriz de tal manera que cada actor a[i]gane contra los actores a[i+1]y a[i+2], módulo 5, por ejemplo:

%w(Scissors Lizard Paper Spock Rock)

Luego, para un actor Acon índice i, podemos ver cómo hace coincidir el actor Bcontra el índice jhaciendo result = (j-i)%5: Resultado 1y 2significa que el actor A ganó contra un actor 1 o 2 lugares frente a él, respectivamente; 3y de 4manera similar significa que perdió contra un actor detrás de él en la serie. 0significa un empate. (Tenga en cuenta que esto puede depender del idioma; en Ruby (j-i)%5 == (5+j-i)%5también cuando j>i).

La parte más interesante de mi código es el uso de esta propiedad para encontrar una función de clasificación de los índices de dos actores. El valor de retorno será -1, 0 o 1 como debería :

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

Aquí está todo:

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
daniero
fuente
2

Pitón


  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 diccionario complicado.

ryanstone
fuente
Buena esa. return(' '.join([p,'tie' + 's'*(p[1]!='c'),q]))obtendrá el tiempo verbal correcto.
dansalmo
2

C#

Supuestos

Los oponentes están dispuestos en una matriz de n elementos donde los jugadores vencen a los jugadores (n-1) / 2 por delante de ellos y pierden ante los jugadores (n-1) / 2 detrás de ellos. (Con listas de longitud par, el jugador pierde ante los jugadores ((n-1) / 2 + 1) detrás de ellos)

Las acciones del jugador se organizan en una matriz donde las acciones dentro del rango de [(indexOfPlayer * (n-1) / 2)] a [(indexOfPlayer * (n-1) / 2)) + (n-2) / 2 - 1 ]

Información adicional

CircularBuffer<T>es un contenedor alrededor de una matriz para crear una matriz direccionable "infinitamente". La IndexOffunción devuelve el índice de un elemento dentro de los límites reales de la matriz.

La clase

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

Ejemplo

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);
XNargaCazadora
fuente
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]
Ugoren
fuente
¡Muy genial! Puede .split(', ')y no tiene que atascarse, las reglas, juntas.
dansalmo
@dansalmo, gracias, pero no veo ningún daño en JammingTheRulesTogether. Aunque no es un concurso de golf, creo que cuanto más corto mejor.
ugoren
1

Solo una pequeña cosa que se me ocurrió:

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

Aquí, reglas es el archivo que contiene todas las reglas que se dieron.

justinpc
fuente
0

Pitón

Inspirado en el código 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)

Resultados:

>>> 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'    
dansalmo
fuente
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 poco de prueba

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() ) ;
}
bobobobo
fuente
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]];
}
topkara
fuente
0

Javascript

Veo que esto no es un concurso de golf, pero había estado jugando con este rompecabezas por un tiempo antes de encontrar este hilo, así que aquí va.

Aquí hay una versión js (estándar) en 278 caracteres:

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 que usa características E6 (probablemente solo funciona en Firefox) en 259 caracteres:

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
Christian Sonne
fuente