59
\$\begingroup\$

When playing Rock-Paper-Scissors-Lizard-Spock, your robot reflexes let you see your opponent's throw before they make it. You just need to choose a throw that beats theirs, in as few bytes as possible of course.

There's always two winning throws, and either one will work.

RPSLS throws diagram

Input    -> Possible outputs
------------------------------
Rock     -> Spock or Paper
Spock    -> Paper or Lizard
Paper    -> Lizard or Scissors
Lizard   -> Scissors or Rock
Scissors -> Rock or Spock

Take a string as input, and output one of the strings that beats it. Strings must be exactly as given, with capitalization. List of characters may substitute for strings.

\$\endgroup\$
7
  • 14
    \$\begingroup\$ It's a pity that the two hands that start with S have no outputs in common... \$\endgroup\$
    – Jo King
    Commented Oct 31, 2019 at 0:38
  • \$\begingroup\$ How about leading or trailing whitespace? \$\endgroup\$
    – Bubbler
    Commented Oct 31, 2019 at 5:56
  • \$\begingroup\$ @Bubbler Nope, sorry. \$\endgroup\$
    – xnor
    Commented Oct 31, 2019 at 6:00
  • \$\begingroup\$ @JoKing Hardly! Necessity is the mother of invention, and your solution is pretty clever. \$\endgroup\$
    – jpaugh
    Commented Oct 31, 2019 at 15:54
  • 2
    \$\begingroup\$ @JoKing: The second letters of the possible inputs are distinct, though. Possibly useful. \$\endgroup\$
    – dan04
    Commented Nov 1, 2019 at 16:45

29 Answers 29

67
\$\begingroup\$

Perl 6, 36 30 bytes

{<Spock Lizard Rock>[.comb%4]}

Try it online!

Gets each output based on the length of the input modulo 4. I think this is probably the optimal strategy.

\$\endgroup\$
21
\$\begingroup\$

Perl 5 -p, 28 bytes

$_=/k/?Paper:/i/?Rock:Lizard

Try it online!

Tried @JoKing's length mod 4 method, but this turned out to be even shorter.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ At first glance this looked like sed for me. \$\endgroup\$ Commented Oct 31, 2019 at 19:39
  • 2
    \$\begingroup\$ @val, Perl was inspired by sed and awk \$\endgroup\$
    – ikegami
    Commented Nov 1, 2019 at 5:51
  • 1
    \$\begingroup\$ +1, pretty sure this is optimal unless you can combine output words somehow. \$\endgroup\$ Commented Nov 2, 2019 at 18:17
13
\$\begingroup\$

PHP, 39 bytes

Shorter md5 variants by Christoph and Benoit Esnard.

<?=[Lizard,Spock,Rock][md5(y.$argn)%3];

Try it online!

<?=[Spock,Rock,Lizard][md5($argn.m)%7];

Try it online!


PHP, 40 bytes

<?=[Rock,Spock,Lizard][md5($argn)[5]%3];

Try it online!

Takes sixth character of md5 of input, which gives unique number of 1 for "Rock" and "Scissors", unique number of 2 for "Spock" and "Paper" and unique number of 9 for "Lizard". A mod 3 on those numbers and we have 0 or 1 or 2 indexes.

| Input    | MD5                              | 6th char | %3 | Output |
|----------|----------------------------------|----------|----|--------|
| Rock     | 4cfbb125e9878528bab91d12421134d8 |        1 |  1 | Spock  |
| Spock    | 5769c28299713c949cd59d5469e40ace |        2 |  2 | Lizard |
| Paper    | d0a662a5235ecde30739fe50cf0de830 |        2 |  2 | Lizard |
| Lizard   | 2f7569e00c4d97aef5f2c2b3a4d2213f |        9 |  0 | Rock   |
| Scissors | 28204140cee6e34a9843b64e5a490b08 |        1 |  1 | Spock  |

PHP, 40 bytes

Alternative 40 bytes, port of Jo King's answer.

<?=[Spock,Lizard,Rock][strlen($argn)%4];

Try it online!


PHP, 41 bytes

This is based on 79037662's answer.

<?=[Lizard,Rock,Paper][ord($argn[-1])%3];

Try it online!


PHP (7.4), 42 bytes

Uses fifth and sixth characters of input to get one of 0, 1 or 2.

fn($s)=>[Rock,Lizard,Paper][!$s[5]+!$s[4]]

Try it online!


PHP, 43 bytes

Uses CRC32 of input and mod to get 0, 1 or 2.

<?=[Rock,Lizard,Paper][crc32($argn)%866%3];

Try it online!


PHP, 43 bytes

Uses second to the last character of input ("Rock" and "Spock" = "c", "Paper" = "e", "Lizard" and "Scissors" = "r").

<?=[c=>Paper,e=>Lizard,r=>Rock][$argn[-2]];

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 39 by adding some pepper: <?=[Lizard,Spock,Rock][md5(y.$argn)%3];. \$\endgroup\$
    – Christoph
    Commented Oct 31, 2019 at 9:14
  • 1
    \$\begingroup\$ 39 bytes: <?=[Spock,Rock,Lizard][md5($argn.m)%7]; - Try it online! \$\endgroup\$ Commented Oct 31, 2019 at 9:14
  • 2
    \$\begingroup\$ @BenoitEsnard ha beat you by 5 seconds! :) \$\endgroup\$
    – Christoph
    Commented Oct 31, 2019 at 9:15
7
\$\begingroup\$

APL (Dyalog Unicode), 28 bytes

'Spock' 'Lizard' 'Rock'⊃⍨4|≢

Try it online!

Uses the simple strategy based on input length modulo 4 (idea from Jo King's answer). ⎕IO←0.


APL (Dyalog Unicode), 34 bytes

'Lizard' 'Rock' 'Paper'⊃⍨'Xbj'⍸2∘⊃

Try it online!

Uses the shortest choice for all cases. ⎕IO←1.

How it works

'Lizard' 'Rock' 'Paper'⊃⍨'Xbj'⍸2∘⊃
2∘⊃     Take the second character
'Xbj'⍸  Classify it by intervals:
        'X'≤c<'b': 1
        'b'≤c<'j': 2
        'j'≤c    : 3
...⊃⍨   Give the nth string
\$\endgroup\$
4
\$\begingroup\$

Jelly, 16 14 bytes

Lị“ŀ¡ḋ¤:1KỌ»Ḳ¤

Try it online!

-2 bytes thanks to Jonathan Allan and Nick Kennedy both independently coming up with splitting on spaces instead of using a list literal.

A translation of Jo King's Perl 6 solution, using Jelly's compressed strings and modular indexing.

 ị                The element of
  “ŀ¡ḋ¤:1KỌ»      "Lizard Rock  Spock"
            Ḳ¤    split on spaces
 ị                at (1-based) index
L                 length of the input
  “ŀ¡ḋ¤:1KỌ»Ḳ¤    mod 4.
\$\endgroup\$
5
4
\$\begingroup\$

JavaScript, 40 bytes

s=>['Spock','Lizard','Rock'][s.length%4]

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Runic Enchantments, 42 bytes

il͍4%:0)9*?~"Spock"@1)9*?"Lizard"@"Rock"@

Try it online!

Footer runs all five input possibilities (the y sequences make them print in the correct order, no I'm not sure why the last one needed so many) and presets the stack with an input value (the input command then reads no input) and a newline. Remove the footer to use input instead.

\$\endgroup\$
3
\$\begingroup\$

Python 3, 44 bytes

lambda s:["Spock","Lizard","Rock"][len(s)%4]

Try it online!

Uses the input-length-modulo-4 strategy in Jo King's answer.

\$\endgroup\$
1
  • \$\begingroup\$ And it’s readable! \$\endgroup\$ Commented Nov 1, 2019 at 16:38
3
\$\begingroup\$

C (gcc), 51 49 bytes

Thanks to Unrelated String for the suggestion.

The second byte of the string has sufficient uniqueness that I can take its two least-significant bits and use them to then index into a string (with the longest-length result at the end if I rotate the result, fortunately!) The separator between the strings should be a literal NUL character, but I put a space in between them below so that you can see the gaps.

f(char*s){s="Spock Paper Scissors"+(s[1]-3)%4*6;}

Try it online!

\$\endgroup\$
1
3
\$\begingroup\$

Python 2, 73 69 bytes

lambda i:l[l.index(i)-1]
l="Rock Lizard Spock Scissors Paper".split()

Try it online!

Since there are already plenty of ports of @JoKing's excellent answer, here is a different way of doing it.

\$\endgroup\$
3
\$\begingroup\$

Haskell, 43 bytes

(k!!).length
k="Spock":"Lizard":"Rock":"":k

Try it online!

The mod-4 approach. Longer approaches:

f t|t<"Q"="Scissors"|t<"Sd"="Spock"|1<2="Paper"   (47)
f.last;f 'k'="Paper";f 'r'="Lizard";f _="Rock"    (46)
(["Spock","Lizard","Rock"]!!).(`mod`4).length     (45)
(words"Spock Lizard Rock"!!).(`mod`4).length      (44)
(cycle["Spock","Lizard","Rock",""]!!).length      (44)
(cycle(words"Spock Lizard Rock .")!!).length      (44)
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome back, Lynn! \$\endgroup\$
    – xnor
    Commented Oct 31, 2019 at 23:47
  • 1
    \$\begingroup\$ I tried golfing some tweaks to your code, but it looks like your alternatives have pretty much covered everything. I did get two kind-of weird 45's: 1, 2. \$\endgroup\$
    – xnor
    Commented Nov 2, 2019 at 3:09
3
\$\begingroup\$

Shakespeare Programming Language, 1359 bytes

(Whitespace added for readability)

R.Ajax,.Puck,.Act I:.Scene I:.[Enter Ajax and Puck]Ajax:
Open mind.Open mind.You is the remainder of the quotient betweenyou a big big cat.
Be you nicer a cat?If solet usScene V.
Be you nicer I?If solet usScene X.
You is twice twice twice twice the sum ofa big big cat a cat.Speak thy.You is the sum ofthe sum ofyou a big big big big cat a cat.Speak thy.You is the sum ofthe sum ofyou a big big big big cat a pig.Speak thy.You is the sum ofthe square oftwice the sum ofa big big cat a cat a cat.Speak thy.You is the sum ofyou the sum ofa cat twice twice the sum ofa big cat a cat.Let usScene L.
Scene V:.Ajax:
You is the sum ofa big cat the square ofthe sum ofa big big big cat a cat.Speak thy.You is twice twice twice twice the sum ofa big big big cat a pig.Speak thy.You is the sum ofyou a pig.Speak thy.You is the sum ofyou twice twice the sum ofa big pig a pig.Speak thy.You is the sum ofyou a big big big cat.Let usScene L.
Scene X:.Ajax:
You is the sum ofa big cat the square ofthe sum ofa big big big cat a cat.Speak thy.You is the sum ofyou a big big big big cat.Speak thy.You is the sum ofyou twice the sum ofa big cat a cat.Speak thy.You is the sum ofyou twice the sum ofa big big cat a cat.Remember you.Speak thy.Speak thy.You is the sum ofyou a big big pig.Speak thy.You is the sum ofyou the sum ofa big cat a cat.Speak thy.Recall.
Scene L:.Ajax:Speak thy.

Try it online!

Explanation:

I get the second character of the input mod 4:

  • This is 0 when the input is Spock, at which point Puck is neither nicer than a cat nor nicer than Ajax. Then, Scene I prints Paper.
  • This is 1 when the input is Paper or Lizard, at which point Puck is not nicer than a cat, but he is nicer than Ajax. Then, Scene X prints Scissors.
  • This is 3 when the input is Rock or Scissors, at which point Puck is nicer than a cat. Then, Scene L prints Spock.

Possible improvements:

  • Better math when printing to get between the letters, including switching characters and using Recall more
  • Better modulus because some of the things are longer than others, and I could reuse the ock
  • Possibly better ways to write the existing numbers. I actually am using a brute forcer that I wrote to do this, but it doesn’t yet account for getting between the letters (using ‘you’). GitHub link coming soon.

This was really fun and I love this language and I have no regrets.

\$\endgroup\$
2
\$\begingroup\$

Retina, 30 27 bytes

'R(`R
Sp
'i(K`Rock
K`Lizard

Try it online! Link includes all possible test cases. @BusinessCat's answer works perfectly well in Retina 0.8.2 but for Retina 1 we can do a little better by using a conditional stage. Explanation:

'R(`

If the input contains R...

R
Sp

... then replace the R with Sp, thus turning Rock into Spock...

'i(

... otherwise if the input contains i...

K`Rock

... then overwrite it with the string Rock, which beats Lizard and Scissors...

K`Lizard

... otherwise overwrite the input with Lizard, which beats Spock and Paper.

\$\endgroup\$
2
  • \$\begingroup\$ Nice. I still need to learn the new features in Retina 1. The .{6,} is clever though and saves bytes for mine too. \$\endgroup\$ Commented Oct 31, 2019 at 13:57
  • \$\begingroup\$ @BusinessCat I'm glad it helped you, as I've switched to an even better Retina 1 method now! \$\endgroup\$
    – Neil
    Commented Oct 31, 2019 at 20:44
2
\$\begingroup\$

Ruby, 42 36 bytes

->c{%w(Spock Lizard Rock)[c.size%4]}

Try it online!


Ruby, 43 39 bytes

->c{%w(Lizard Rock Paper)[c[-1].ord%3]}

Try it online!

The second one is an alternative I found to Jo's method, using the ASCII value of the last character, but alas is 3 bytes longer in Ruby.

It is conceivable that my method is better in some language where finding the ASCII value of the last character is shorter than finding the string's length, but I don't know of any.

EDIT: Saved several bytes thanks to @IMP1

\$\endgroup\$
4
  • \$\begingroup\$ Why not .size instead of .length? \$\endgroup\$
    – IMP1
    Commented Oct 31, 2019 at 14:53
  • \$\begingroup\$ Also, have a look at this. You can use %w(Lizard Rock Paper) instead of ["Lizard","Rock","Paper"] \$\endgroup\$
    – IMP1
    Commented Oct 31, 2019 at 14:55
  • \$\begingroup\$ @IMP1 Thanks for the tips, still new to Ruby. \$\endgroup\$
    – 79037662
    Commented Oct 31, 2019 at 14:55
  • \$\begingroup\$ No worries. Ruby often has multiple methods that do the same thing (like .size and .length), so it's worth looking to see if there's one that's a few characters shorter. \$\endgroup\$
    – IMP1
    Commented Oct 31, 2019 at 14:57
1
\$\begingroup\$

V (vim), 28 bytes

2ORock
Lizard
SpockLÝkYHVGp

Try it online!

Hexdump:

00000000: 324f 526f 636b 0d4c 697a 6172 640d 5370  2ORock.Lizard.Sp
00000010: 6f63 6b1b 4cdd 6b59 4856 4770            ock.L.kYHVGp
\$\endgroup\$
1
\$\begingroup\$

F# (.NET Core), 53 49 46 bytes

 ["Spock";"Lizard";"Rock"].[String.length n%4]

Try it online!

I am using the input-length-modulo-4 strategy from Jo King's answer, so please check his answer.
And I know it's not in competition but I wanted to try something new…

\$\endgroup\$
1
\$\begingroup\$

Japt, 24 bytes

`Spock Lizd Rock`¸gUÊu4

Try it

"Spock Lizard Rock" //=>compressed
.q(S) // split on " "
.g(U.l().u(4)) // return element at index ( length of input % 4 )

Thanks to @Shaggy for the help

\$\endgroup\$
1
\$\begingroup\$

Python 3, 69 64 61 57 bytes

lambda s:[["Scissors","Paper"]['k'in s],"Rock"]['i'in s] 

Not as short as the mod 4 solution, but not a bad alternative.

Try it online!

\$\endgroup\$
3
  • 2
    \$\begingroup\$ 57 bytes by deleting some spaces \$\endgroup\$
    – Stephen
    Commented Nov 1, 2019 at 13:59
  • \$\begingroup\$ Haha, thanks! First code golf, my nasty programmer habits of formatting code are still strong! I also didn't realize you could remove spaces between a string and 'in'. TIL \$\endgroup\$
    – Ahndwoo
    Commented Nov 1, 2019 at 14:01
  • 1
    \$\begingroup\$ @Ahndwoo Check out my tip on omitting spaces. tldr: you usually need a space only when letters are followed by letters or digits. \$\endgroup\$
    – xnor
    Commented Nov 1, 2019 at 22:50
1
\$\begingroup\$

Pyth, 24 bytes

@c."Lzž›^ºéëEL”‡"\`lz

Try it online!

Port of Jo King's mod-4 answer. Without the compressed string, it's 2 bytes longer: @c"Spock`Lizard`Rock`"\`lz

\$\endgroup\$
1
\$\begingroup\$

Excel, 49 bytes

Mod4 approach:

=CHOOSE(MOD(LEN(A1),4)+1,"Spock","Lizard","Rock")

Switching on last character: 57 bytes

=CHOOSE(MOD(CODE(RIGHT(A1)),3)+1,"Lizard","Rock","Paper")
\$\endgroup\$
1
\$\begingroup\$

R, 52 bytes

function(x)c("Spock","Lizard","Rock")[nchar(x)%%4+1]
\$\endgroup\$
1
\$\begingroup\$

///, 81 70 bytes

/~/\/\/.//.Sp/.~R/.~ock/Paper~Paper/Lizard~Lizard/Rock~Scissors/Rock/.

Because there is no other way to take input in ///, it goes after the . at the end of the code. For an input of Spock:

/~/\/\/.//.Sp/.~R/.~ock/Paper~Paper/Lizard~Lizard/Rock~Scissors/Rock/.Spock

Try it online!

Test suite

Explanation:

/// works by replacing strings with other strings, within the code.

The first chunk of code, /~/\/\/./, works as a macro replacing ~ with //.. After this, the code expands to:

/.Sp/.//.R/.//.ock/Paper//.Paper/Lizard//.Lizard/Rock//.Scissors/Rock/

/.Sp/./ and /.R/./ change spock and rock to ock, allowing me to just replace ock with Paper.

The rest of the cases are just explicitly handled.

The period before the input is to make sure that none of the code itself is changed, just the input.

\$\endgroup\$
1
\$\begingroup\$

Python 2, 50 bytes

lambda s:["Lizard","Rock","Paper"][cmp(s[-2],"e")]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

K, 26 bytes

`Paper`Rock`Lizard@&/"ki"?
\$\endgroup\$
2
  • \$\begingroup\$ The footer of the Jelly answer is simply a loop over the possible test cases, not a dictionary as additional argument. Jelly, and some other golfing languages like 05AB1E, have builtin dictionary files with ~10,000 words they know and can access with compressed strings. Here is that same Jelly program without a footer, and a given argument, so you can see the footer isn't part of the program and unrelated to the dictionary string “ŀ¡ḋ¤:1KỌ» \$\endgroup\$ Commented Dec 16, 2019 at 10:32
  • \$\begingroup\$ I've removed my comment, but that "program" doesn't work since it doesn't take the input as a string or as an argument. \$\endgroup\$
    – geocar
    Commented Dec 16, 2019 at 18:32
1
\$\begingroup\$

C# dotnet core, 47 bytes

h=>(new[]{"Spock","Lizard","Rock"})[h.Length%4]

Try it online

Uses the input-length-modulo-4 strategy in Jo King's answer.

\$\endgroup\$
3
  • \$\begingroup\$ You seem to be missing the function declaration part of your answer, i.e. the public static string RPSLS(string h){return ... } part. Taking input as a predefined variable is not an allowed input format, plus you're not actually outputting anything \$\endgroup\$
    – Jo King
    Commented Dec 15, 2019 at 3:47
  • \$\begingroup\$ This is a snippet where h is implicit. However, here we need a complete program or function. Unfortunately, though, dotnet core is too old to have =>, so a boilerplate will be quite long for this. \$\endgroup\$ Commented Dec 15, 2019 at 3:52
  • \$\begingroup\$ Fair enough. The lambda function definition is not much longer. I updated the .net fiddle to reflect that usage. \$\endgroup\$ Commented Dec 17, 2019 at 16:01
0
\$\begingroup\$

Wren, 47 bytes

Fn.new{|s|["Spock","Lizard","Rock"][s.count%4]}

Try it online!

Uses the input-length-modulo-4 strategy in Jo King's answer.

\$\endgroup\$
0
\$\begingroup\$

05AB1E, 16 bytes

”‰«†ÕâŸard”#I3öè

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Produces wrong answer for "Spock" (returns 5 "Papers" instead of the one) \$\endgroup\$
    – geocar
    Commented Dec 16, 2019 at 18:37
  • \$\begingroup\$ @geocar No it doesn’t. \$\endgroup\$
    – Grimmy
    Commented Dec 16, 2019 at 20:08
0
\$\begingroup\$

Retina 0.8.2, 36 33 31 bytes

-3 thanks to Neil

R
s
.{6,}
Rock
.{5}
Lizard
s
Sp

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ Can the first line be .[ci].*? \$\endgroup\$
    – Neil
    Commented Oct 31, 2019 at 13:35
  • \$\begingroup\$ @Neil Yeah, probably. \$\endgroup\$ Commented Oct 31, 2019 at 13:36
  • 1
    \$\begingroup\$ Or not. That makes Rock give SpRock. I guess it would need to be ^.[ci].* \$\endgroup\$ Commented Oct 31, 2019 at 13:38
0
\$\begingroup\$

Batch, 87 bytes

@set/ps=
@for %%a in (Rock.d Rock.s Paper.k Lizard.r)do @if %%~xa==.%s:~-1% echo %%~na

Takes input on STDIN. Works by switching on the last character of the input, which saves a case.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.