70
\$\begingroup\$

Given two string inputs of "Rock", "Paper", or "Scissors", determine the outcome of the RPS round. Output 1 if the first player wins, -1 if the second player wins, or 0 for a tie.

Rock Rock -> 0
Rock Paper -> -1
Rock Scissors -> 1
Paper Rock -> 1
Paper Paper -> 0
Paper Scissors -> -1
Scissors Rock -> -1
Scissors Paper -> 1
Scissors Scissors -> 0

You must use the exact strings "Rock", "Paper", and "Scissors" as inputs. You may choose whether the first players' choice is (consistently) given first or second. You may alternatively take them as a single input with a single-character or empty separator. The input is guaranteed one of the 9 possible pairings of the three choices in your input format.

The output should be a number 1, 0, or -1, or its string representation. Floats are fine. So are +1, +0, and -0.

Related: Coding an RPS game


Leaderboard:

var QUESTION_ID=106496,OVERRIDE_USER=20260;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/106496/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
  • \$\begingroup\$ Does a single input with empty separator mean for example "rockpaper"? \$\endgroup\$ – Emigna Jan 11 '17 at 21:25
  • 1
    \$\begingroup\$ @Emigna Yes, but capitalized as RockPaper. \$\endgroup\$ – xnor Jan 11 '17 at 21:26
  • 15
    \$\begingroup\$ That was WAY more fun than I had anticipated, my lord there are some cool ways to do this. \$\endgroup\$ – Magic Octopus Urn Jan 11 '17 at 21:30
  • \$\begingroup\$ Can the input be an array of the two strings? \$\endgroup\$ – Luis Mendo Jan 11 '17 at 22:33
  • \$\begingroup\$ @LuisMendo Yes. \$\endgroup\$ – xnor Jan 11 '17 at 22:34

50 Answers 50

73
\$\begingroup\$

Groovy, 67 56 50 Bytes

{a,b->Math.sin(1.3*((int)b[0]-(int)a[0])).round()}

Try it online!

Turns out that the rock, paper, scissors game has a pretty cool property.
Given strings a and b, take the first letter of each, this results in two of the following: R,P,S

The exhaustive list of possible values are (When 2 choices are combined):

XX=ASCII=Y=Wanted output
RR=82-82=0=0
PP=80-80=0=0
SS=83-83=0=0
RS=82-83=-1=1
RP=82-80=2=-1
PS=80-83=-3=-1
PR=80-82=-2=1
SR=83-82=1=-1
SP=83-80=3=1

Reorganizing the list to:

-3->-1
-2->1
-1->1
0->0
1->-1
2->-1
3->1

Gives us a sequence that looks inversely sinusoidal, and you can actually represent this formula as approximately (and by approximately I mean just barely enough to work, you could get an equation that is dead on but costs more bytes):

-sin((4*a[0]-b[0])/PI).roundNearest() = sin(1.3*(b[0]-a[0])).roundNearest()

The simplification of 4/pi to 1.3 was suggested first by @flawr and then tested by @titus for a total savings of 6 bytes.

Equation Explanation

Using groovy's double rounding properties, this results in the correct output for rock-paper-scissors.


05AB1E, 10 bytes (non-compete)

Ç¥13T/*.½ò

Try it online!

Same answer ported to 05AB1E using the new commands added 10/26/2017.

\$\endgroup\$
  • 3
    \$\begingroup\$ Couldn't you make it shorter by using that -sin(x) = sin(-x),that means just reversing the order of a and b and dropping the leading -? Other than that, hardcoding an approximation of 4/Pi like 1.273 could be sufficient, or 1.3 or 9/7 or 5/4. \$\endgroup\$ – flawr Jan 11 '17 at 21:43
  • 2
    \$\begingroup\$ PS: I also suggest making a link to try it online so people like me can play around with your submission=) \$\endgroup\$ – flawr Jan 11 '17 at 21:45
  • 3
    \$\begingroup\$ You can save 1 byte with sin(b-a) instead of -sin(a-b). Great find! \$\endgroup\$ – Titus Jan 12 '17 at 8:27
  • 2
    \$\begingroup\$ Save another 7 bytes by multiplying by 1.3 instead of 4/Math.PI; that´s sufficiently exact. \$\endgroup\$ – Titus Jan 12 '17 at 8:58
  • 1
    \$\begingroup\$ @carusocomputing XX=ASCII=Y=Wanted output RR=82-82=0=0 PP=83-83=0=0 SS=80-80=0=0 \$\endgroup\$ – CraigR8806 Jan 12 '17 at 15:09
44
\$\begingroup\$

C, 50 35 bytes

#define f(i)*(short*)(i+7)%51%4%3-1

Call f with a string containing both players, without separator, and it will return whether the first one wins.

Explanation:

By looking at the nine possible strings, it turns out that the letter pairs on columns 7 and 8 are unique:

       vv
RockPaper
PaperScissors
ScissorsRock
RockRock         // Sneakily taking advantage of the terminating zero
PaperPaper
ScissorsScissors
RockScissors
PaperRock
ScissorsPaper
       ^^

The offset and savage cast to short* retrieve these letter pairs, and interpret them as numbers:

29285
29545
21107
107
25968
21363
29555
27491
20595

Then it was a matter of brute-force to find the 51 and 4 remainders, which applied successively reduce these numbers to:

3 0 0 1 1 1 2 2 2

Which is just perfect to tack yet another remainder at the end, and offsetting the result.

See it live on Coliru

\$\endgroup\$
  • \$\begingroup\$ Just don't do anything like calculating -f(i) to calculate the other player's score - unexpected output will result! \$\endgroup\$ – nneonneo Jan 12 '17 at 1:56
  • 4
    \$\begingroup\$ @nneonneo -(f(i)) should work fine. Macros are fun! \$\endgroup\$ – nwp Jan 12 '17 at 18:29
18
\$\begingroup\$

MATLAB/Octave, 63 54 52 bytes

It is very convenient that the ASCII-codes of the first letters of Rock,Paper,Scissors are R=82,P=80,S=83. If we subtract 79 we get conveniently 3,1,4, which we will use now as matrix indices: Here a 4x4-matrix is hardcoded, where the i,j-th entry corresponds to the outcome if you plug in the values from just before:

     1   2   3   4
  +---------------
1 |  0   0   1  -1
2 |  0   0   0   0
3 | -1   0   0   1
4 |  1   0  -1   0
A(5,5)=0;A(4:7:18)=1;A=A-A';@(x,y)A(x(1)-79,y(1)-79)

Try it online!

\$\endgroup\$
16
\$\begingroup\$

Pure Bash, 31

Borrowing @Dennis's formula:

a=$1$1$2
echo $[(${#a}^67)%3-1]

Try it online.


Previous answer:

Pure Bash, 43 35

echo $[(7+(${#2}^3)-(${#1}^3))%3-1]
  • Get the string length of each arg (4, 5, 8 respectively for Rock, Paper, Scissors)
  • XOR each with 3 to give 7, 6, 11 (which when taken mod 3 give 1, 0, 2)

  • Then subtract and fiddle with mod 3 to get the desired result.

Try it online.

\$\endgroup\$
15
\$\begingroup\$

Python, 40 30 bytes

lambda x,y:(len(2*x+y)^67)%3-1

Try it online!

Background

I've started with the function template

lambda x,y:(len(a*x+b*y)^c)%d-e

and ran a brute-force search for suitable parameters using the following program, then picked one with a minimal-length implementation.

RPS = 'Rock Paper Scissors'.split()
g = lambda x,y:2-(94>>len(6*x+y)%7)%4
r = range(1,10)
R = range(100)

def f(a, b, c, d, e):
    h = lambda x,y:(len(a*x+b*y)^c)%d-e
    return all(g(x, y) == h(x, y) for x in RPS for y in RPS)

[
    print('%2d ' * 5 % (a, b, c, d, e))
    for e in r
    for d in r
    for c in R
    for b in r
    for a in r
    if f(a, b, c, d, e)
]

Try it online!

\$\endgroup\$
14
\$\begingroup\$

Mathematica, 32 bytes

Mod[{1,-1}.(Length/@#-3)!,3,-1]&

Unnamed function taking an ordered pair of lists of characters, such as {{"R","o","c","k"},{"P","a","p","e","r"}}, and returning -1|0|1.

I wanted the code to avoid not only the three input words, but also the way-too-long function name ToCharacterCode; so I worked with the length 4,5,8 of the input words instead, and looked for a short function of those lengths that gave distinct answers modulo 3. (Integer division by 2 is mathematically promising, but those functions have too-long names in Mathematica.)

It turns out that taking the factorial of (the length – 3) gives the answers 1,2,120, which are 1,-1,0 modulo 3. Then we just compute, modulo 3, the difference of the two values (via the dot product {1,-1}.{x,y} = x-y, which is a good way when the two values are in a list).

\$\endgroup\$
  • 1
    \$\begingroup\$ "It turns out..." You have an eye for these things \$\endgroup\$ – ngenisis Jan 11 '17 at 22:08
12
\$\begingroup\$

Ruby, 36 35 30 bytes

a=->a,b{(a+b)[12]?a<=>b:b<=>a}

Try it on ideone.com

Test output:

a=->a,b{(a+b)[12]?a<=>b:b<=>a}

puts a.call("Rock", "Rock")
puts a.call("Rock", "Paper")
puts a.call("Rock", "Scissors")
puts a.call("Paper", "Rock")
puts a.call("Paper", "Paper")
puts a.call("Paper", "Scissors")
puts a.call("Scissors", "Rock")
puts a.call("Scissors", "Paper")
puts a.call("Scissors", "Scissors")

0
-1
1
1
0
-1
-1
1
0

Takes advantage of the fact that 7 of the 9 correct results are generated just by doing a lexicographic comparison using the spaceship operator <=>. The (a+b)[12] just reverses the inputs to the comparison if the inputs are Paper and Scissors (and also Scissors Scissors - but that's 0 either way round).

With thanks to Horváth Dávid for saving me a character, and thanks to G B for saving me another 5.

\$\endgroup\$
  • \$\begingroup\$ You can use an anonymous lambda and save 2 characters. \$\endgroup\$ – G B Jan 11 '17 at 21:57
  • \$\begingroup\$ @GB If I don't give the function a name how am I supposed to call it? That smacks of cheating to me. But thanks for the other tip - I had looked at that but rejected it because ScissorsScissors is 16, but I see that doesn't actually matter. :-) \$\endgroup\$ – Gareth Jan 11 '17 at 22:03
  • \$\begingroup\$ That's not cheating. Anonymous functions are allowed by default. \$\endgroup\$ – Dennis Jan 15 '17 at 19:41
  • \$\begingroup\$ @Dennis You can't call it without assigning it. It feels like cheating to me, and unfair on languages without anonymous functions that have to define a name. \$\endgroup\$ – Gareth Jan 15 '17 at 19:44
  • \$\begingroup\$ Sure you can. tio.run/nexus/… \$\endgroup\$ – Dennis Jan 15 '17 at 19:50
10
\$\begingroup\$

Python, 39 36 34 33 bytes

lambda x,y:2-(94>>len(6*x+y)%7)%4

Try it online!

How it works

Let's take a look at a few values of the length of six copies of x and one copy of y modulo 7.

                                l(x,y) =:
x        y        len(x) len(y) len(6*x+y)%7
--------------------------------------------
Rock     Rock          4      4            0
Rock     Paper         4      5            1
Rock     Scissors      4      8            4
Paper    Rock          5      4            6
Paper    Paper         5      5            0
Paper    Scissors      5      8            3
Scissors Rock          8      4            3
Scissors Paper         8      5            4
Scissors Scissors      8      8            0

We can encode the outcomes ({-1, 0, 1}) by mapping them into the set {0, 1, 2, 3}. For example, the mapping t ↦ 2 - t achieves this and is its own inverse.

Let's denote the outcome of x and y by o(x, y). Then:

x        y        l(x,y) o(x,y) 2-o(x,y) (2-o(x,y))<<l(x,y)
-----------------------------------------------------------
Rock     Rock          0      0        2                10₂
Rock     Paper         1     -1        3               110₂
Rock     Scissors      4      1        1            010000₂
Paper    Rock          6      1        1          01000000₂
Paper    Paper         0      0        2                10₂
Paper    Scissors      3     -1        3             11000₂
Scissors Rock          3     -1        3             11000₂
Scissors Paper         4      1        1            010000₂
Scissors Scissors      0      0        2                10₂

Luckily, the bits in the last columns all agree with each other, so we can OR them to form a single integer n and retrieve o(x, y) as 2 - ((n ≫ o(x,y)) % 4). The value of n is 94.

\$\endgroup\$
9
\$\begingroup\$

Retina, 35 31 bytes

G`k P|r S|s R
*\)`.+
-
D`\w+
 .

Try it online!

Explanation

This works in two steps. First, we print the minus signs for the relevant inputs. Then we print a 0 for ties and a 1 otherwise.

G`k P|r S|s R
*\)`.+
-

This is two stages. The ) in the second stage groups them together, the * makes them a dry run (which means the input string will be restored after they were processed, but the result will be printed) and \ suppresses printing of a trailing linefeed. The two stages together will print a - if applicable.

The first stage is a Grep stage which only keeps the line if it contains either k P, r S, or s R. These correspond to the cases where we need to output -1. If it's not one of those cases, the input will be replaced with an empty string.

The second stage replaces .+ (the entire string, but only if it contains at least one character) with -. So this prints a - for those three cases and nothing otherwise.

D`\w+
 .

This is two more stages. The first stage is a Deduplication. It matches words and removes duplicates. So if and only if the input is a tie, this drops the second word.

The second stage counts the number of matches of ., which is a space followed by any character. If the input was a tie, and the second word was removed, this results in 0. Otherwise, the second word is still in place, and there's one match, so it prints 1 instead.

\$\endgroup\$
  • \$\begingroup\$ Here's a different approach based off the input string lengths. Its longer than yours, but I wonder if it could be golfed down any more? \$\endgroup\$ – Digital Trauma Jan 11 '17 at 22:38
  • \$\begingroup\$ @DigitalTrauma that's a really neat idea, but I'm not seeing anything to shorten it. I think you should post it anyway (and if you move the first line into the header then TIO won't include it in the byte count). \$\endgroup\$ – Martin Ender Jan 12 '17 at 7:14
8
\$\begingroup\$

05AB1E, 18 17 15 10 9 bytes

6 bytes saved with Digital Trauma's input length trick

€g3^Æ>3%<

Takes input as [SecondPlayersChoice,FirstPlayersChoice]

Try it online! or Validate all test-cases

Alternative 9 byte solution: íø¬ÇÆ>3%<

Explanation

€g          # length of each in input
  3^        # xor 3
    Æ       # reduce by subtraction
     >      # increment
      3%    # modulus 3
        <   # decrement

Previous 15 byte solution

A-D{„PSÊiR}Ç`.S

Try it online! or Validate all test-cases

Explanation

 A-               # remove the lowercase alphabet from the input (leaves a 2 char string)
   D{             # sort a copy of the leftover
     „PSÊ         # check if the copy isn't "PS" (our special case)
         iR}      # if true, reverse the string to get the correct sign
            Ç`    # convert the two letters to their character codes
              .S  # compare their values
\$\endgroup\$
  • \$\begingroup\$ You beat my fun one :( Ç¥13T/*.½ò WHY IT WORKS? NOBODY KNOWS. \$\endgroup\$ – Magic Octopus Urn Feb 8 '18 at 16:45
  • \$\begingroup\$ @MagicOctopusUrn: Uuuh, that sure is a weird one. What would the input format be for it to return an int as output? \$\endgroup\$ – Emigna Feb 8 '18 at 18:32
  • \$\begingroup\$ ['R','P'] :P It's a port of this. \$\endgroup\$ – Magic Octopus Urn Feb 9 '18 at 16:18
  • \$\begingroup\$ @MagicOctopusUrn: Oh yeah, I forgot about that one. My favorite answer to this challenge :) \$\endgroup\$ – Emigna Feb 9 '18 at 19:33
6
\$\begingroup\$

Jelly, 8 bytes

L€Iµ-*×Ṡ

Try it online! (test suite, casts to integer for clarity)

How it works

L€Iµ-*×Ṡ  Main link. Argument: A (string array)

L€        Take the length of each string.
  I       Increments; compute the forward difference of the length.
   µ      Begin a new chain with the difference d as argument.
    -*    Compute (-1)**d.
      ×Ṡ  Multiply the result with the sign of d.
\$\endgroup\$
6
\$\begingroup\$

Python 2, 46 40 bytes

lambda x,y:+(x!=y,-1)[x[0]+y[0]in'RPSR']

Try it online!

With many thanks to @Dennis for letting me borrow his Try it online test code and for saving me 6 bytes.

Edit

@hashcode55 - Pretty much as you describe. (x!=y,-1) is a two element sequence and [x[0]+y[0]in'RPSR'] is computing which element to take. If the first letter of x + the first letter of y is in the character list then it will evaluate to True or 1 so (x!=y,-1)[1] will be returned. If it is not then (x!=y,-1)[0]. This is where it gets a bit tricky. The first element is in itself effectively another if. If x!=y then the first element will be True otherwise it will be False so if x[0]+y[0]in'RPSR' is false then either True or False will be returned depending on whether x==y. The + is a bit sneaky and thanks again to @Dennis for this one. The x!=y will return a literal True or False. We need a 1 or a 0. I still don't quite know how but the + does this conversion. I can only assume that by using a mathematical operator on True/False it is forcing it to be seen as the integer equivalent. Obviously the + in front of the -1 will still return -1.

Hope this helps!

\$\endgroup\$
  • \$\begingroup\$ Hi! Can you please tell me how this syntax is working? Logically guessing, (x!=y,-1) this is working like if, if the list generates a true then -1 else x!=y. Whats the use of that + sign? A source documenting this kind of syntax would be really helpful! \$\endgroup\$ – hashcode55 Jan 15 '17 at 10:17
  • \$\begingroup\$ @hashcode55 - I have added an explanation to my answer. \$\endgroup\$ – ElPedro Jan 15 '17 at 11:32
  • \$\begingroup\$ To answer your uncertainty about the + - in this case, that's a unary plus, like +10, and is essentially a short way to convert to an integer. \$\endgroup\$ – FlipTack Jan 15 '17 at 13:22
  • \$\begingroup\$ Thanks @FlipTack. Kinda guessed that was what it is doing but thanks for the proper explanation. \$\endgroup\$ – ElPedro Jan 15 '17 at 13:26
  • \$\begingroup\$ @ElPedro Thanks a lot! That indeed helped me. \$\endgroup\$ – hashcode55 Jan 15 '17 at 19:10
5
\$\begingroup\$

JavaScript (ES6), 46 38 bytes

(a,b)=>(4+!b[4]+!b[5]-!a[4]-!a[5])%3-1

Makes use of the fact that Rock-Paper-Scissors is cyclic. JavaScript has neither spaceship nor balanced ternary operators, otherwise the answer would be (a,b)=>((b<=>'Rock')-(a<=>'Rock'))%%3.

Edit: Saved 8 bytes thanks to @WashingtonGuedes.

\$\endgroup\$
  • 1
    \$\begingroup\$ @WashingtonGuedes I can do even better than that! \$\endgroup\$ – Neil Jan 11 '17 at 22:07
  • \$\begingroup\$ You could curry to save 1 byte \$\endgroup\$ – MayorMonty Aug 30 '17 at 0:22
  • \$\begingroup\$ i tried running it and always return 0 \$\endgroup\$ – Vitim.us Jan 19 '18 at 23:03
5
\$\begingroup\$

MATL, 14 13 bytes

TTt_0vic1Z)d)

Try it online! Or verify all test cases.

Explanation

If the ASCII code of the initial letter of the first string is subtracted from that of the second string we get the value in the D column below. Taking modulo 5 gives the value M. The final value in parentheses is the desired result, R.

                        D        M     R
                       ---      ---   ---
Rock Rock          ->   0   ->   0   ( 0) 
Rock Paper         ->  −2   ->   3   (−1)
Rock Scissors      ->   1   ->   1   ( 1)
Paper Rock         ->   2   ->   2   ( 1)
Paper Paper        ->   0   ->   0   ( 0)
Paper Scissors     ->   3   ->   3   (−1)
Scissors Rock      ->  −1   ->   4   (−1)
Scissors Paper     ->  −3   ->   2   ( 1)
Scissors Scissors  ->   0   ->   0   ( 0)

Thus if we compute D and then M, to obtain R we only need to map 0 to 0; 1 and 2 to 1; 3 and 4 to −1. This can be done by indexing into an array of five entries equal to 0, 1 or −1. Since indexing in MATL is 1-based and modular, the array should be [1, 1, −1, −1, 0] (the first entry has index 1, the last has index 5 or equivalently 0). Finally, the modulo 5 operation can luckily be avoided, because it is implicitly carried out by the modular indexing.

TT     % Push [1 1]
t_     % Duplicate, negate: pushes [−1 −1]
0      % Push 0
v      % Concatenate vertically into the 5×1 array [1; 1; −1; −1; 0]
i      % Input cell array of strings
c      % Convert to 2D char array, right-padding with zeros if necessary
1Z)    % Take the first column. Gives a 2×1 array of the initial letters
d      % Difference
)      % Index into array. Implicit display
\$\endgroup\$
5
\$\begingroup\$

CJam, 12 bytes

0XXWW]rcrc-=

The two inputs are space-separated. Their order is reversed with respect to that in the challenge text.

Try it online! Or verify all test cases.

Explanation

Translation of my MATL answer. This exploits the fact that in CJam c (convert to char) applied on a string takes its first character. Also, the array for the mapping is different because indexing in CJam is 0-based.

0XXWW    e# Push 0, 1, 1, -1, -1
]        e# Pack into an array
rc       e# Read whitespace-separated token as a string, and take its first char
rc       e# Again
-        e# Subtract code points of characters
=        e# Index into array. Implicitly display
\$\endgroup\$
5
\$\begingroup\$

CJam, 15 14 12 bytes

rW=rW=-J+3%(

Take the ascii code of the last character of each string, then returns:

(a1 - a2 + 19) % 3 - 1

Test it here!

\$\endgroup\$
5
\$\begingroup\$

Python 3, 54 bytes

lambda o,t:(o!=t)*[-1,1]['RPS'['PS'.find(t[0])]!=o[0]]

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Java 7, 82 bytes

int c(String...a){int x=(a[0].charAt(1)-a[1].charAt(1))%5/2;return x%2==x?x:x/-2;}

Ungolfed:

int c(String... a){
   int x = (a[0].charAt(1) - a[1].charAt(1)) % 5 / 2;
   return x%2 == x
           ? x
           : x / -2;
}

Explanation:

  • The second letters are o, a and c, with the ASCII decimals 111, 97 and 99.
  • If we subtract these from each other for the test cases we have the following results:
    • 0 (Rock, Rock)
    • 14 (Rock, Paper)
    • 12 (Paper, Scissors)
    • -14 (Paper, Rock)
    • 0 (Paper, Paper)
    • -2 (Paper, Scissors)
    • -2 (Scissors, Rock)
    • 2 (Scissors, Paper)
    • 0 (Scissors, Scissors)
  • If we take modulo 5 for each, we get 4, 2, -4, -2, -2, 2.
  • Divided by 2 x is now the following for the test cases:
    • x=0 (Rock, Rock)
    • x=2 (Rock, Paper)
    • x=1 (Paper, Scissors)
    • x=-2 (Paper, Rock)
    • x=0 (Paper, Paper)
    • x=-1 (Paper, Scissors)
    • x=-1 (Scissors, Rock)
    • x=1 (Scissors, Paper)
    • x=0 (Scissors, Scissors)
  • Only the 2 and -2are incorrect, and should have been -1 and 1instead. So if x%2 != x (everything above 1 or below -1) we divide by -2 to fix these two 'edge-cases'.

Test code:

Try it here.

class M{
  static int c(String...a){int x=(a[0].charAt(1)-a[1].charAt(1))%5/2;return x%2==x?x:x/-2;}

  public static void main(String[] a){
    String R = "Rock",
           P = "Paper",
           S = "Scissors";
    System.out.println(c(R, R)); // 0
    System.out.println(c(R, P)); // -1
    System.out.println(c(R, S)); // 1
    System.out.println(c(P, R)); // 1
    System.out.println(c(P, P)); // 0
    System.out.println(c(P, S)); // -1
    System.out.println(c(S, R)); // -1
    System.out.println(c(S, P)); // 1
    System.out.println(c(S, S)); // 0
  }
}

Output:

0
-1
1
1
0
-1
-1
1
0
\$\endgroup\$
  • \$\begingroup\$ Why the second letter out of curiosity? I had the same approach (kinda) but used the first letter. \$\endgroup\$ – Magic Octopus Urn Jan 12 '17 at 14:38
  • \$\begingroup\$ @carusocomputing Well, I noticed most of the other people were using either the first letter or length, and wanted to try something else. I first used the third letters (c, p, i) with the ASCII values 99, 112 and 105, as they seemed most useful, and noticed it would become 4, 2, 0 if I did modulo 5. Only then I figured I had to subtract both, so the 4, 2 and 0 weren't of much use. After some fuddling around/trial-and-error I tried the second letter and was getting more useful results with the same modulo 5 still present. Then I quickly came to the solution I presented above. :) \$\endgroup\$ – Kevin Cruijssen Jan 12 '17 at 14:48
  • \$\begingroup\$ @carusocomputing Wanted to try an unique approach, and considering I'm pretty bad at these kind of solutions, it isn't as short as some other solutions, but still unique (which was my initial goal). :) \$\endgroup\$ – Kevin Cruijssen Jan 12 '17 at 14:49
4
\$\begingroup\$

dc, 18

1?Z9+2/rZ1+2/-3%-p

Try it online.

Note that the two args are passed (space-separated) on one line to STDIN. The args are contained in square brackets [ ] as this is how dc likes its strings.

dc has very limited string handling, but it turns out one of the things you can do is use the Z command to get a string length, which luckily is distinct for "Rock", "Paper" and "Scissors", and can be fairly simply arithmetically manipulated to give the desired result.

\$\endgroup\$
4
\$\begingroup\$

PHP, 34 bytes

<?=md5("BMn$argv[1]$argv[2]")%3-1;
\$\endgroup\$
3
\$\begingroup\$

Pyth, 16

t%+7h.+mx3ldQ3

Probably could be shorter.

        x3ld      # lambda to get string length then XOR with 3
       m    Q     # map over the input (array of 2 strings)
     .+           # difference of the two results
    h             # flatten one-element array
  +7              # add 7
 %           3    # mod 3
t                 # subtract 1 and implicit print

Online.

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

C#, 85 84 bytes

Saved 1 byte, thanks to TheLethalCoder

a=>b=>a==b?0:(a[0]=='R'&b[0]=='S')|(a[0]=='P'&b[0]=='R')|(a[0]=='S'&b[0]=='P')?1:-1;

It accepts two strings as an input, and outputs an integer. There is a tie, if the two strings are equal, otherwise it checks for the first charachter of the strings, in order to determine, which player wins.

\$\endgroup\$
  • \$\begingroup\$ Save one byte by using currying i.e. a=>b=>... \$\endgroup\$ – TheLethalCoder Jan 13 '17 at 15:36
3
\$\begingroup\$

JavaScript, 37, 32, 31 bytes

a=>b=>a==b?0:!(a+b)[12]^a>b||-1

If a equals b, output zero.

Otherwise, xor the result of checking if length not greater than 12 (comparison of Scissors and Paper) with the comparison of a greater than b.
If this returns 1, return it.

If it returns 0, use the OR operator to replace with -1.

\$\endgroup\$
  • \$\begingroup\$ Could you write this as a curried function a=>b=> to save a byte? \$\endgroup\$ – FlipTack Jan 27 '17 at 21:39
  • \$\begingroup\$ Yes. Thank you @FlipTack \$\endgroup\$ – Grax Jan 30 '17 at 0:53
2
\$\begingroup\$

Batch, 116 bytes

@if %1==%2 echo 0&exit/b
@for %%a in (RockScissors PaperRock ScissorsPaper)do @if %%a==%1%2 echo 1&exit/b
@echo -1
\$\endgroup\$
2
\$\begingroup\$

Perl, 33 bytes

32 bytes of code + -p flag.

$_=/(.+) \1/?0:-/k P|r S|s R/||1

To run it:

perl -pe '$_=/(.+) \1/?0:-/k P|r S|s R/||1' <<< "Rock Paper"

Saved 3 bytes by using the regex of Martin Ender's Retina answer. (my previous regex was /R.*P|P.*S|S.*R/)

Explanation:

First, /(.+) \1/ checks if the input contains twice the same word, if so, the result is 0. Otherwise, /k P|r S|s R/ deals with the case where the answer is -1. If this last regex is false, then -/k P|r S|s R/is false, so we return 1.

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

Jelly, 9 bytes

L€^3Iæ%1.

This uses the algorithm from @DigitalTrauma's Bash answer.

Try it online!

How it works

L€^3Iæ%1.  Main link. Argument: A (string array)

L€         Take the length of each string.
  ^3       XOR the lengths bitwise with 3.
    I      Increments; compute the forward difference of both results.
     æ%1.  Balanced modulo 1.5; map the results into the interval (-1.5, 1.5].
\$\endgroup\$
2
\$\begingroup\$

Japt, 19 bytes

-Ms(4*(Uc -Vc)/MP¹r

Try it here!

Inspired by carusocomputing's solution

Old 53-byte Solution

W=Ug c X=Vg c W¥X?0:W¥82©X¥83?1:W¥80©X¥82?1:W¥83©X¥80?1:J

Try it online!

Thanks again, ETHproductions!

\$\endgroup\$
  • 1
    \$\begingroup\$ You could start by using © instead of &&, changing the Ug0 c to Ug c (same with V) and replacing -1 with J. It's still quite a bit longer than the JS answer though, perhaps you can take some ideas from that \$\endgroup\$ – ETHproductions Jan 11 '17 at 22:47
  • \$\begingroup\$ @ETHproductions Thanks! I don't know how I forget about © \$\endgroup\$ – Oliver Jan 12 '17 at 1:03
  • 1
    \$\begingroup\$ Actually you can just do W=Uc. I don't know why I keep forgetting that c works on any string :P \$\endgroup\$ – ETHproductions Jan 12 '17 at 1:38
2
\$\begingroup\$

PHP, 55 53 bytes

<?=(3-(ord($argv[2])%6%4-ord($argv[1])%6%4+3)%3*2)%3;
  • takes the ascii values of the first letters (from command line arguments): 82,80,83
  • %6: 4,2,5
  • %4: 0,2,1
  • difference (b-a):
    • PS:1-2,SR:2-0,RP:2-0 -> -1 or 2; +3,%3 -> 2
    • SP:2-1,RS:0-2,PR:0-2 -> -2 or 1; +3,%3 -> 1
    • RR,PP,SS:0; +3,%3: 0
  • (3-2*x): -1,1,3
  • %3: -1,1,0

sine version, 49 46 bytes

<?=2*sin(1.3*(ord($argv[2])-ord($argv[1])))|0;

a golfed port of carusocomputing´s answer:

3 bytes saved by @user59178

\$\endgroup\$
  • 1
    \$\begingroup\$ For the sine version for can save 3 bytes by replacing round(x) with 2*x^0 \$\endgroup\$ – user59178 Jan 12 '17 at 9:27
2
\$\begingroup\$

Perl, 25 bytes

$_=/kS|rR|sP/-/kP|rS|sR/

Code 24 bytes +1 byte for -p option.

The input should be on stdin without separators, e.g.:

echo PaperRock | perl -pe'$_=/kS|rR|sP/-/kP|rS|sR/'

The first regexp searches for first player win, the second for his loss. The difference is printed.

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

Scala, 148 bytes

object R extends App{val t=Seq('R','P','S')
val(a,b)=(args(0)(0),args(1)(0))
print(if(a==b)0 else if(t.indexOf(a)%3==(t.indexOf(b)-1)%3)-1 else 1)}

Thankfully, since semicolons are required to separate multiple commands on the same line, Scala benefits from having formattable golf code!

In this golfing attempt I learned that you can replace

"somestring".charAt(index) 

with

"somestring"(index) 

because Scala lets you treat strings as arrays for the purpose of getting characters.

\$\endgroup\$
  • \$\begingroup\$ This can be golfed immensely. For starters, you're allowed to do a function instead of a complete program in most challenges here, so instead of the whole object extends app thing and pulling from args, try something like: def g(a:Seq,b:Seq)=... \$\endgroup\$ – Ethan Jan 13 '17 at 19:54
  • \$\begingroup\$ Additionally, you need not print the value. Returning it is sufficient, which is great when golfing Scala, since the return is free. And you can improve it even further by using the trick posted in the Groovy answer, which works almost identically in Scala. \$\endgroup\$ – Ethan Jan 13 '17 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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