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

57 Answers 57

77
\$\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\$
12
  • 4
    \$\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
    Commented Jan 11, 2017 at 21:43
  • 3
    \$\begingroup\$ PS: I also suggest making a link to try it online so people like me can play around with your submission=) \$\endgroup\$
    – flawr
    Commented Jan 11, 2017 at 21:45
  • 4
    \$\begingroup\$ You can save 1 byte with sin(b-a) instead of -sin(a-b). Great find! \$\endgroup\$
    – Titus
    Commented Jan 12, 2017 at 8:27
  • 3
    \$\begingroup\$ Save another 7 bytes by multiplying by 1.3 instead of 4/Math.PI; that´s sufficiently exact. \$\endgroup\$
    – Titus
    Commented Jan 12, 2017 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
    Commented Jan 12, 2017 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\$
2
  • \$\begingroup\$ Just don't do anything like calculating -f(i) to calculate the other player's score - unexpected output will result! \$\endgroup\$
    – nneonneo
    Commented Jan 12, 2017 at 1:56
  • 5
    \$\begingroup\$ @nneonneo -(f(i)) should work fine. Macros are fun! \$\endgroup\$
    – nwp
    Commented Jan 12, 2017 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\$
0
17
\$\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\$
0
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\$
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
  • 1
    \$\begingroup\$ "It turns out..." You have an eye for these things \$\endgroup\$
    – user61980
    Commented Jan 11, 2017 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\$
7
  • \$\begingroup\$ You can use an anonymous lambda and save 2 characters. \$\endgroup\$
    – G B
    Commented Jan 11, 2017 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
    Commented Jan 11, 2017 at 22:03
  • \$\begingroup\$ That's not cheating. Anonymous functions are allowed by default. \$\endgroup\$
    – Dennis
    Commented Jan 15, 2017 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
    Commented Jan 15, 2017 at 19:44
  • \$\begingroup\$ Sure you can. tio.run/nexus/… \$\endgroup\$
    – Dennis
    Commented Jan 15, 2017 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\$
2
  • \$\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\$ Commented Jan 11, 2017 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\$ Commented Jan 12, 2017 at 7:14
9
\$\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\$
4
  • \$\begingroup\$ You beat my fun one :( Ç¥13T/*.½ò WHY IT WORKS? NOBODY KNOWS. \$\endgroup\$ Commented Feb 8, 2018 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
    Commented Feb 8, 2018 at 18:32
  • \$\begingroup\$ ['R','P'] :P It's a port of this. \$\endgroup\$ Commented Feb 9, 2018 at 16:18
  • \$\begingroup\$ @MagicOctopusUrn: Oh yeah, I forgot about that one. My favorite answer to this challenge :) \$\endgroup\$
    – Emigna
    Commented Feb 9, 2018 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\$

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\$
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\$
5
  • \$\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
    Commented Jan 15, 2017 at 10:17
  • \$\begingroup\$ @hashcode55 - I have added an explanation to my answer. \$\endgroup\$
    – ElPedro
    Commented Jan 15, 2017 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
    Commented Jan 15, 2017 at 13:22
  • \$\begingroup\$ Thanks @FlipTack. Kinda guessed that was what it is doing but thanks for the proper explanation. \$\endgroup\$
    – ElPedro
    Commented Jan 15, 2017 at 13:26
  • \$\begingroup\$ @ElPedro Thanks a lot! That indeed helped me. \$\endgroup\$
    – hashcode55
    Commented Jan 15, 2017 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\$
3
  • 1
    \$\begingroup\$ @WashingtonGuedes I can do even better than that! \$\endgroup\$
    – Neil
    Commented Jan 11, 2017 at 22:07
  • \$\begingroup\$ You could curry to save 1 byte \$\endgroup\$
    – bren
    Commented Aug 30, 2017 at 0:22
  • \$\begingroup\$ i tried running it and always return 0 \$\endgroup\$
    – Vitim.us
    Commented Jan 19, 2018 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\$

Python 3, 54 bytes

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

Try it online!

\$\endgroup\$
0
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\$
3
  • \$\begingroup\$ Why the second letter out of curiosity? I had the same approach (kinda) but used the first letter. \$\endgroup\$ Commented Jan 12, 2017 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\$ Commented Jan 12, 2017 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\$ Commented Jan 12, 2017 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\$
0
4
\$\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\$
2
  • \$\begingroup\$ Could you write this as a curried function a=>b=> to save a byte? \$\endgroup\$
    – FlipTack
    Commented Jan 27, 2017 at 21:39
  • \$\begingroup\$ Yes. Thank you @FlipTack \$\endgroup\$
    – Grax32
    Commented Jan 30, 2017 at 0:53
4
\$\begingroup\$

Perl 5 -p, 24 bytes

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

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.

Try it online!

\$\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\$
1
  • \$\begingroup\$ Save one byte by using currying i.e. a=>b=>... \$\endgroup\$ Commented Jan 13, 2017 at 15:36
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\$
1
  • \$\begingroup\$ Dammit, I was about to start reading up on Jelly. Oh well, here it is in pyth. +1. \$\endgroup\$ Commented Jan 12, 2017 at 0:17
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\$
3
  • 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\$ Commented Jan 11, 2017 at 22:47
  • \$\begingroup\$ @ETHproductions Thanks! I don't know how I forget about © \$\endgroup\$
    – Oliver
    Commented Jan 12, 2017 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\$ Commented Jan 12, 2017 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
  • 1
    \$\begingroup\$ For the sine version for can save 3 bytes by replacing round(x) with 2*x^0 \$\endgroup\$
    – user59178
    Commented Jan 12, 2017 at 9:27
2
\$\begingroup\$

Python 2, 32 bytes

lambda*l:cmp(*l)*(1|-('R'in`l`))

Try it online

A fairly short "natural" solution, though not as short as Dennis's brute-forced solution.

The cmp(*l) compares the inputs lexicographically, giving -1, 0, or +1 for smaller, equal, and greater. This gives the right negated answer on each pair of "Paper", "Rock", "Scissors" except on Paper vs Scissors in either order. To fix that, we multiply by -1 on any input without an 'R' in the string rep. This also flips Scissors vs Scissors and Paper vs Paper, but those gave 0 anyway.

Thanks to xsot for saving a byte with the (1|-(_)) construct to turn a Bool into ±1. This is shorter than the alternatives.

lambda*l:cmp(*l)*cmp(.5,'R'in`l`)
lambda*l:cmp(*l)*(-1)**('R'in`l`)
lambda*l:cmp(*l)*(1-2*('R'in`l`))
\$\endgroup\$
3
  • 1
    \$\begingroup\$ There's a shorter alternative: (1|-('R'in`l`)) \$\endgroup\$
    – xsot
    Commented Jan 16, 2017 at 1:59
  • \$\begingroup\$ @xsot Thanks! That's a nice trick for a common situation, you could add a tip for it. \$\endgroup\$
    – xnor
    Commented Jan 18, 2017 at 0:17
  • \$\begingroup\$ Perhaps you could mention it in this tip. Also, for what it's worth, I first encountered this trick here. \$\endgroup\$
    – xsot
    Commented Jan 18, 2017 at 2:55

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.