9
\$\begingroup\$

Objective

Given a nonempty multiset of Rock, Paper, and Scissors, output the winning figure according to the special rule.

Background

For a multiplayer RPS, if all three figures come out, usually it's considered a draw. But by that rule, the probability to draw would dramatically increase when there are many and many players.

Let's resolve that by a special rule.

Input

Though defined as a multiset, the input type and format doesn't matter. Valid formats of the input include:

  • A multiset

  • A sequential container with or without guarantee of order

  • An size-3 array of integers representing the count of each of RPS

Also, Rock, Paper, and Scissors may be encoded by an arbitrary type.

The Special Rule and Output

Let's say \$r\$ Rocks, \$p\$ Papers, and \$s\$ Scissors-es(?) are given.

  • If one of them is zero, output the winning figure of the other two.

  • If none of them is zero, allot them a score by multiplicating the number of themselves and the number of the figure they win to. That is, Rock gets score \$r×s\$, Paper gets score \$p×r\$, and Scissors get score \$s×p\$.

    • If the scores don't tie, output the figure with the maximum score.

    • If the scores tie by two figures, output the winning figure amongst the two figures.

    • Otherwise, output a fourth value indicating draw.

  • Otherwise, output either the only figure or the fourth value.

The output type and format doesn't matter.

Rule about code golf

Invalid inputs (Empty container, contains a fourth value, etc) fall into don't care situation.

Example

Given the following input:

[Rock, Rock, Rock, Paper, Paper, Scissors, Scissors]

Rock gets score 3×2=6, Paper gets score 2×3=6, and Scissors get score 2×2=4. Since Paper wins to Rock, the output is Paper.

\$\endgroup\$
7
  • \$\begingroup\$ I'm not sure what you mean by "The output format must match the input's format." Say, can the output be one of the numbers 0,1,2,3 for rock, paper, scissors, tie? \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 5:30
  • 3
    \$\begingroup\$ Is the "If one of them is zero, ..." rule necessary? That side would always get a score of 0 anyway. \$\endgroup\$ Commented Apr 2, 2020 at 5:30
  • 2
    \$\begingroup\$ I'd really suggest allowing input to just be the counts of the three symbols. Getting those counts from a list of items seems like an extraneous step that all solutions will do. (Edit: On second thought, I'm less sure about this. Maybe some solutions would get the product of counts directly by counting pairs via two loops.) \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 5:32
  • 1
    \$\begingroup\$ @Monicareinstate, I'm just making the rule intuitively understandable. Nice inspection for a code golf tho. \$\endgroup\$ Commented Apr 2, 2020 at 5:37
  • \$\begingroup\$ What's a multiset? \$\endgroup\$
    – S.S. Anne
    Commented Apr 5, 2020 at 1:19

3 Answers 3

5
\$\begingroup\$

Python, 41 bytes

lambda r,s,p:[s>p<=r>0,p>r<=s>0,r>s<=p>0]

Try it online!

Takes counts as (r,s,p). Outputs a three-element list with True at the position of the winner, or all False's if there's a tie or only a single figure appearing.

Rock:     [True, False, False]
Scissors: [False, True, False]
Paper:    [False, False, True]
Tie:      [False, False, False]

We use an alternate characterization without multiplication (except when only one figure is present). Below is the condition for Rock winning, with Scissors and Paper having similar conditions.

Rock wins if: Paper has the fewest, strictly fewer than Scissors but possibly the same as Rock.

We can write this in Python as s>p<=r using inequality chaining.

Unfortunately, this doesn't correctly handle the special case when r=p=0, saying that Rock wins even though only Scissors is present. To fix this, we strengthen the condition for Rock to win to include r>0 via s>p<=r>0, which makes the only-Scissors case give all False for every condition, matching a tie.


44 bytes

lambda r,s,p:r*s==s*p==p*r or[s>p<=r,p>r<=s]

Try it online!

Takes counts as (r,s,p). Outputs as:

Rock:     [True, False]
Scissors: [False, True]
Paper:    [False, False]
Tie:      True    

The "Tie" case also includes where there's only a single figure present.

\$\endgroup\$
4
  • \$\begingroup\$ By my reading of the question, for an input of [Scissors, Scissors] you are allowed to output either Scissors wins or Tie, which would save 6 bytes. \$\endgroup\$
    – Neil
    Commented Apr 2, 2020 at 10:21
  • \$\begingroup\$ @Neil Do you mean by getting rid of the >0's? The issue with that is for inputs [0, 2, 0] for two Scissors, the code would actually gives that Rock wins. The difficulty is that in a similarly ordered input like [1, 2, 1], we should in fact say that Rock wins due to it winning tiebreak between Rock and Scissors. So the two-zeros case is special. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 10:25
  • \$\begingroup\$ Oh sorry I misunderstood the problem. \$\endgroup\$
    – Neil
    Commented Apr 2, 2020 at 10:32
  • \$\begingroup\$ @Noodle9 Yup, good catch, thanks. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 12:33
3
\$\begingroup\$

05AB1E, 14 13 bytes

Ćü*ZÊ2βD3*7%M

Input as a list of integers in the order \$[r,s,p]\$.
Output as one of the following four:

Rock wins:      3
Scissors wins:  5
Paper wins:     6
Tie:            0

-1 byte thanks to @xnor.

Try it online or verify some more test cases.

Explanation:

Ć              # Enclose the (implicit) input-list, appending its own head
               #  i.e. input=[3,2,2] → STACK: [[3,2,2,3]
 ü             # For each overlapping pair: [a,b,c,d] → [[a,b],[b,c],[c,d]]
  *            #  Multiply them together
               #   STACK: [[6,4,6]]
   Z           # Get the maximum (without popping)
               #   STACK: [[6,4,6],6]
    Ê          # Check which of the values in the list are NOT equals to this maximum
               #  STACK: [[0,1,0]]
     2β        # Convert this list of 0s and 1s from a binary list to integer
               #  STACK: [2]
       D       # Duplicate it
               #  STACK: [2,2]
        3*     # Multiply it by 3
               #  STACK: [2,6]
          7%   # Take modulo-7:
               #  STACK: [2,6]
            M  # Push the largest value on the stack
               #  STACK: [2,6,6]
               # (after which the top of the stack is output implicitly as result)

After the Ćü*ZÊ we can have the following values:

                One of:
Rock wins:      [[0,1,1], [0,0,1]]
Scissors wins:  [[1,0,1], [1,0,0]]
Paper wins:     [[1,1,0], [0,1,0]]
Ties:           [[0,0,0]]

Converting those from binary-lists to integers:

                One of:
Rock wins:      [3, 1]
Scissors wins:  [5, 4]
Paper wins:     [6, 2]
Ties:           [0]

The 3*7% (thanks to @xnor!) will map the lower values to the higher values in the pair, and will also unsure the lower values won't increase.

This works because the pairs [1,3], [2,6], [4,5] are constructed from bits where the second number has two bits set: that of the first number, and the bit position to its right, wrapping around in 3 bits. This comes from the binary-list of the RPS game. We can do the set-next-bit with *3 and enforce 3-bit wrapping with %7.

                One of:
Rock wins:      [3→2, 1→3]
Scissors wins:  [5→1, 4→5]
Paper wins:     [6→4, 2→6]
Ties:           [0]

After which we can use M to only keep the largest value on the stack for our result:

                One of:
Rock wins:      [3, 3]
Scissors wins:  [5, 5]
Paper wins:     [6, 6]
Ties:           [0]
\$\endgroup\$
10
  • \$\begingroup\$ It might be useful that in each of the pairs in the mapping, the second number is the first one times 5 modulo 7. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 13:41
  • \$\begingroup\$ @xnor Hmm, but how to effectively combine it so it won't map the other value. I could use D5*7%‚ß (Duplicate; use your *5%7; pair these two integers together; and pop and push the smallest integer), but unfortunately it's also 14 bytes: verify all test cases. PS: If we could somehow map the [1,4,2] to [3,5,6] and ensure that same fomula won't make [3,5,6] themselves larger, I could do it with D...M instead of D...‚ß to save a byte. \$\endgroup\$ Commented Apr 2, 2020 at 13:53
  • 1
    \$\begingroup\$ It looks like the reverse map of *3%7 would meet your criterion. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 13:58
  • 1
    \$\begingroup\$ I've used a script for some brute-forcing before, and I'm rewriting it into a form that's less hacked-together that I intend to share. In this case though, I didn't use anything like that here, or even coded anything, but thought up the formula logically. The pairs(1,3), (2,6), (4,5) are constructed from bits where the second number has two bits set: that of the first number, and the bit position to its right, wrapping around in 3 bits. This comes from the RPS game. We can do the set-next-bit with *3 and enforce 3-bit wrapping with %7. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 14:16
  • 1
    \$\begingroup\$ Thinking through some bit logic, ~(n*2%7)&n converts [3,5,6] to [1,4,2] while leaving the latter unchaged. \$\endgroup\$
    – xnor
    Commented Apr 2, 2020 at 14:26
2
\$\begingroup\$

C (gcc), 61 \$\cdots\$ 53 52 bytes

Saved 3 bytes thanks to Kevin Cruijssen!!!
Saved 3 bytes thanks to Arnauld!!!
Saved a byte thanks to ceilingcat!!!

Uses xnor's formula converted to \$3\$ for Rock, \$2\$ for Scissors, \$1\$ for Paper, and \$0\$ for a tie or only a single figure appearing.

f(r,s,p){r=s>p&p<=r&&r?3:p>r&r<=s&&s?2:r>s&s<=p&&p;}

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ The first && in each part can be & for -3 (i.e. (s>p&&p<=r&&r) to (s>p&p<=r&&r)). \$\endgroup\$ Commented Apr 2, 2020 at 12:17
  • \$\begingroup\$ @KevinCruijssen Interesting - thanks! :-) \$\endgroup\$
    – Noodle9
    Commented Apr 2, 2020 at 12:25
  • \$\begingroup\$ &&p?1:0 ~> &!!p? \$\endgroup\$
    – Arnauld
    Commented Apr 2, 2020 at 19:27
  • \$\begingroup\$ @Arnauld Very sweet - thanks! :-) \$\endgroup\$
    – Noodle9
    Commented Apr 2, 2020 at 19:40
  • \$\begingroup\$ @ceilingcat Very good, now realise the ?1:0 was totally redundant - thanks! :-) \$\endgroup\$
    – Noodle9
    Commented Apr 2, 2020 at 21:28

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.