Cheat at Rock-Paper-Scissors-Lizard-Spock

54

8

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.

xnor

Posted 2019-10-31T00:21:50.373

Reputation: 115 687

14It's a pity that the two hands that start with S have no outputs in common... – Jo King – 2019-10-31T00:38:44.067

How about leading or trailing whitespace? – Bubbler – 2019-10-31T05:56:23.847

@Bubbler Nope, sorry. – xnor – 2019-10-31T06:00:15.113

@JoKing Hardly! Necessity is the mother of invention, and your solution is pretty clever. – jpaugh – 2019-10-31T15:54:59.163

V for "Vulcan" would fix the overloaded S! – pkamb – 2019-10-31T18:20:25.160

2@JoKing: The second letters of the possible inputs are distinct, though. Possibly useful. – dan04 – 2019-11-01T16:45:36.943

@JoKing The two hands that end in <code>k</code> do, though. – Please stop being evil – 2019-11-02T18:15:08.207

Answers

64

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.

Jo King

Posted 2019-10-31T00:21:50.373

Reputation: 38 234

20

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.

Xcali

Posted 2019-10-31T00:21:50.373

Reputation: 7 671

1At first glance this looked like sed for me. – val says Reinstate Monica – 2019-10-31T19:39:36.150

2@val, Perl was inspired by sed and awk – ikegami – 2019-11-01T05:51:02.290

1+1, pretty sure this is optimal unless you can combine output words somehow. – Please stop being evil – 2019-11-02T18:17:54.973

13

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!

Night2

Posted 2019-10-31T00:21:50.373

Reputation: 5 484

139 by adding some pepper: <?=[Lizard,Spock,Rock][md5(y.$argn)%3];. – Christoph – 2019-10-31T09:14:53.530

1

39 bytes: <?=[Spock,Rock,Lizard][md5($argn.m)%7]; - Try it online!

– Benoit Esnard – 2019-10-31T09:14:58.107

2@BenoitEsnard ha beat you by 5 seconds! :) – Christoph – 2019-10-31T09:15:36.553

7

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

Bubbler

Posted 2019-10-31T00:21:50.373

Reputation: 16 616

4

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.

Unrelated String

Posted 2019-10-31T00:21:50.373

Reputation: 5 300

1Using split-at-spaces saves two bytes: “ŀ¡ḋ¤:1KỌ»Ḳị@L or Lị“ŀ¡ḋ¤:1KỌ»Ḳ¤ – Jonathan Allan – 2019-10-31T13:26:39.047

2

I was about to post an almost identical comment: https://tio.run/##y0rNyan8/9/n4e7uRw1zjjYcWvhwR/ehJVaG3g939xza/XDHpkNL/gNlgvKTs4FUQGJBahGQDk7OLC7OLyoGMn0yqxKLUkBiBWA1cw9tPbrncPujpjWR/wE

– Nick Kennedy – 2019-10-31T13:28:33.707

That's 29 bytes in UTF-8, not 14 – Valentin Lorentz – 2019-12-15T20:21:05.470

Am I missing something? It doesn't take input of the required form or produce output of the required form. – geocar – 2019-12-16T18:33:14.190

It's not in UTF-8, and it does input and output just fine if you take the footer out, and run it one case at a time. You can also use a footer that doesn't pair each input with the output, and just spits them out in order: Try it online! – Unrelated String – 2019-12-19T08:54:33.390

4

JavaScript, 40 bytes

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

Try it online!

darrylyeo

Posted 2019-10-31T00:21:50.373

Reputation: 6 214

3

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.

Draco18s no longer trusts SE

Posted 2019-10-31T00:21:50.373

Reputation: 3 053

3

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.

pizzapants184

Posted 2019-10-31T00:21:50.373

Reputation: 3 174

And it’s readable! – Connor McCormick – 2019-11-01T16:38:44.093

3

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!

ErikF

Posted 2019-10-31T00:21:50.373

Reputation: 2 149

You can replace the \0s with literal null bytes: Try it online!

– Unrelated String – 2019-10-31T05:08:02.643

3

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)

Lynn

Posted 2019-10-31T00:21:50.373

Reputation: 55 648

2Welcome back, Lynn! – xnor – 2019-10-31T23:47:58.990

1

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.

– xnor – 2019-11-02T03:09:59.783

2

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.

ElPedro

Posted 2019-10-31T00:21:50.373

Reputation: 5 301

2

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.

Neil

Posted 2019-10-31T00:21:50.373

Reputation: 95 035

Nice. I still need to learn the new features in Retina 1. The .{6,} is clever though and saves bytes for mine too. – Business Cat – 2019-10-31T13:57:42.270

@BusinessCat I'm glad it helped you, as I've switched to an even better Retina 1 method now! – Neil – 2019-10-31T20:44:45.717

2

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

79037662

Posted 2019-10-31T00:21:50.373

Reputation: 1 739

Why not .size instead of .length? – IMP1 – 2019-10-31T14:53:09.627

Also, have a look at this. You can use %w(Lizard Rock Paper) instead of ["Lizard","Rock","Paper"]

– IMP1 – 2019-10-31T14:55:07.280

@IMP1 Thanks for the tips, still new to Ruby. – 79037662 – 2019-10-31T14:55:47.487

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. – IMP1 – 2019-10-31T14:57:06.543

1

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…

Delta

Posted 2019-10-31T00:21:50.373

Reputation: 543

1

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

James

Posted 2019-10-31T00:21:50.373

Reputation: 54 537

1

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

AZTECCO

Posted 2019-10-31T00:21:50.373

Reputation: 2 441

1

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!

Ahndwoo

Posted 2019-10-31T00:21:50.373

Reputation: 111

257 bytes by deleting some spaces – Stephen – 2019-11-01T13:59:43.490

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 – Ahndwoo – 2019-11-01T14:01:46.157

1

@Ahndwoo Check out my tip on omitting spaces. tldr: you usually need a space only when letters are followed by letters or digits.

– xnor – 2019-11-01T22:50:02.687

1

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

randomdude999

Posted 2019-10-31T00:21:50.373

Reputation: 789

1

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

Wernisch

Posted 2019-10-31T00:21:50.373

Reputation: 2 534

1

R, 52 bytes

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

Fino

Posted 2019-10-31T00:21:50.373

Reputation: 111

1

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.

Jorel Fermin

Posted 2019-10-31T00:21:50.373

Reputation: 11

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 – Jo King – 2019-12-15T03:47:29.327

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. – Shieru Asakoto – 2019-12-15T03:52:21.163

Fair enough. The lambda function definition is not much longer. I updated the .net fiddle to reflect that usage. – Jorel Fermin – 2019-12-17T16:01:13.523

1

Python 2, 50 bytes

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

Try it online!

Colin Beveridge

Posted 2019-10-31T00:21:50.373

Reputation: 11

0

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.

user85052

Posted 2019-10-31T00:21:50.373

Reputation:

0

05AB1E, 16 bytes

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

Try it online!

Grimmy

Posted 2019-10-31T00:21:50.373

Reputation: 12 521

Produces wrong answer for "Spock" (returns 5 "Papers" instead of the one) – geocar – 2019-12-16T18:37:18.713

@geocar No it doesn’t.

– Grimmy – 2019-12-16T20:08:48.633

0

Retina 0.8.2, 36 33 31 bytes

-3 thanks to Neil

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

Try it online!

Business Cat

Posted 2019-10-31T00:21:50.373

Reputation: 8 927

Can the first line be .[ci].*? – Neil – 2019-10-31T13:35:10.207

@Neil Yeah, probably. – Business Cat – 2019-10-31T13:36:38.327

1Or not. That makes Rock give SpRock. I guess it would need to be ^.[ci].* – Business Cat – 2019-10-31T13:38:31.757

0

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.

Neil

Posted 2019-10-31T00:21:50.373

Reputation: 95 035

0

K, 26 bytes

`Paper`Rock`Lizard@&/"ki"?

geocar

Posted 2019-10-31T00:21:50.373

Reputation: 214

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Ọ»

– Kevin Cruijssen – 2019-12-16T10:32:15.867

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. – geocar – 2019-12-16T18:32:02.440

0

///, 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.

Comrade SparklePony

Posted 2019-10-31T00:21:50.373

Reputation: 5 784

0

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.

Hello Goodbye

Posted 2019-10-31T00:21:50.373

Reputation: 442