11
\$\begingroup\$

Tomorrow is the Mid-Autumn festival, and in the spirit of that holiday, I will introduce a gambling game that we (people from Xiamen) play during the holiday!

Rules

The game is played with six 6-sided dice. Different combinations of numbers have different ranks, with a special emphasis on fours and ones. Your job is to write a program/function that will rank the hand, given a roll of 6 dice. Here are the ranks (I've modified/simplified the rules a bit):

ranks

I guess only Chinese people can do this challenge! Okay, fine, here are some English explanations.

  • 0: 4 fours and 2 ones.
  • 1: 6 fours.
  • 2: 6 ones.
  • 3: 6 of any kind except fours and ones.
  • 4: 5 fours.
  • 5: 5 of any kind except for fours.
  • 6: 4 fours.
  • 7: Straight. (1-6)
  • 8: 3 fours.
  • 9: 4 of any kind except 4.
  • 10: 2 fours.
  • 11: 1 four.
  • 12: Nothing.

Input

6 numbers, an array of 6 numbers, or a string of 6 numbers that represent the values of the 6 dice rolls from 1-6

Output

Your program/function may return/output anything to indicate the rank, as long as each rank is indicated by one output and vice versa. Ex. Using the numbers 0-12, 1-13, etc.

Examples(Using 0-12 as the outputs)

[1,1,1,1,1,1]->2
[1,4,4,4,1,4]->0
[3,6,5,1,4,2]->7
[1,2,3,5,6,6]->12
[3,6,3,3,3,3]->5
[4,5,5,5,5,5]->5

This is code-golf, so shortest byte count wins!

\$\endgroup\$
8
  • \$\begingroup\$ (I would've put this in the sandbox, but I wanted the timing to be right. I tried to be as thorough as possible, please let me know if there are any clarifications needed.) \$\endgroup\$
    – Quintec
    Sep 23, 2018 at 23:03
  • \$\begingroup\$ @Shaggy So the OP says that output 0-12 or 1-13 instead \$\endgroup\$ Sep 23, 2018 at 23:15
  • \$\begingroup\$ @Shaggy As I stated in the question, the output does not necessarily have to correspond with the label number. The skipped number and random gaps in the image are to simplify the rules a bit - there really aren't definite rules for this tradition, this is just my interpretation. \$\endgroup\$
    – Quintec
    Sep 23, 2018 at 23:18
  • \$\begingroup\$ Shouldn't it be [1,2,3,5,6,6]->13 ?? \$\endgroup\$
    – J.Doe
    Sep 24, 2018 at 13:02
  • \$\begingroup\$ @J.Doe The examples/test-cases use the indices as result instead of the values. Unlike the values, the 10 isn't skipped. \$\endgroup\$ Sep 24, 2018 at 14:06

9 Answers 9

10
\$\begingroup\$

JavaScript (ES6), 88 bytes

a=>a.map(o=n=>[x=o[n]=-~o[n],6,,,21,9,8^o[1]][a=x<a?a:x])[5]|[,1,4,5,o[1]&2|8,2,4][o[4]]

Try it online! or Test all possible rolls!

Outputs an integer according to the following mapping:

 Rank | Output       Rank | Output
------+--------     ------+--------
   0  |  31            7  |   7
   1  |  12            8  |   5
   2  |  14            9  |  21
   3  |   8           10  |   4
   4  |  11           11  |   1
   5  |   9           12  |   0
   6  |  29

How?

Method

The output is computed by performing a bitwise OR between:

  • a bitmask based on \$F\$: the number of 4's
  • a bitmask based on \$M\$: the maximum number of occurrences of the same dice

Exceptions:

  • When \$F=4\$: we use a special bitmask \$4b\$ when the two other dice are 1's, or a default bitmask \$4a\$ otherwise.
  • When \$M=6\$: we use a special bitmask \$6b\$ when we have a six-of-a-kind of 1's, or a default bitmask \$6a\$ otherwise.

Table

Valid combinations of \$F\$ and \$M\$ are highlighted in bold and blue in the following table.

$$\begin{array}{c|c|cccccccc} &F&0&1&2&3&4a&4b&5&6\\ \hline M&\text{OR}&0&1&4&5&8&10&2&4\\ \hline 1&6&\color{grey}{6}&\color{blue}{\textbf{7}}&\color{grey}{6}&\color{grey}{7}&\color{grey}{14}&\color{grey}{14}&\color{grey}{6}&\color{grey}{6}\\ 2&0&\color{blue}{\textbf{0}}&\color{blue}{\textbf{1}}&\color{blue}{\textbf{4}}&\color{grey}{5}&\color{grey}{8}&\color{grey}{10}&\color{grey}{2}&\color{grey}{4}\\ 3&0&\color{blue}{\textbf{0}}&\color{blue}{\textbf{1}}&\color{blue}{\textbf{4}}&\color{blue}{\textbf{5}}&\color{grey}{8}&\color{grey}{10}&\color{grey}{2}&\color{grey}{4}\\ 4&21&\color{blue}{\textbf{21}}&\color{blue}{\textbf{21}}&\color{blue}{\textbf{21}}&\color{grey}{21}&\color{blue}{\textbf{29}}&\color{blue}{\textbf{31}}&\color{grey}{23}&\color{grey}{21}\\ 5&9&\color{blue}{\textbf{9}}&\color{blue}{\textbf{9}}&\color{grey}{13}&\color{grey}{13}&\color{grey}{9}&\color{grey}{11}&\color{blue}{\textbf{11}}&\color{grey}{13}\\ 6a&8&\color{blue}{\textbf{8}}&\color{grey}{9}&\color{grey}{12}&\color{grey}{13}&\color{grey}{8}&\color{grey}{10}&\color{grey}{10}&\color{blue}{\textbf{12}}\\ 6b&14&\color{blue}{\textbf{14}}&\color{grey}{15}&\color{grey}{14}&\color{grey}{15}&\color{grey}{14}&\color{grey}{14}&\color{grey}{14}&\color{grey}{14}\\ \end{array}$$

All other combinations (in gray) can't possibly happen. For instance, if we have three 4's, we must have \$M\ge3\$. But because there are only 3 other remaining dice in such a roll, we also have \$M\le3\$. So, there's only one possible value of \$M\$ for \$F=3\$.

Example

If we have a straight, each dice appears exactly once. So we have \$M=1\$ and \$F=1\$. Using the bitmasks described in the above table, this leads to:

$$6 \text{ OR } 1 = 7$$

There is another \$7\$ in the table, but it's invalid. Therefore, a straight is uniquely identified by \$7\$.

Commented

a =>                   // a[] = input array, reused as an integer to keep track of the
  a.map(               //       maximum number of occurrences of the same dice (M)
    o =                // o = object used to count the number of occurrences of each dice
    n =>               // for each dice n in a[]:
    [                  //   this is the lookup array for M-bitmasks:
      x =              //     x = o[n] = number of occurrences of the current dice
        o[n] = -~o[n], //     increment o[n] (we can't have M = 0, so this slot is not used)
      6,               //     M = 1 -> bitmask = 6
      ,                //     M = 2 -> bitmask = 0
      ,                //     M = 3 -> bitmask = 0
      21,              //     M = 4 -> bitmask = 21
      9,               //     M = 5 -> bitmask = 9
      8 ^ o[1]         //     M = 6 -> bitmask = 14 for six 1's, or 8 otherwise
    ][a =              //   take the entry corresponding to M (stored in a)
        x < a ? a : x] //   update a to max(a, x)
  )[5]                 // end of map(); keep the last value
  |                    // do a bitwise OR with the second bitmask
  [                    // this is the lookup array for F-bitmasks:
    ,                  //   F = 0 -> bitmask = 0
    1,                 //   F = 1 -> bitmask = 1
    4,                 //   F = 2 -> bitmask = 4
    5,                 //   F = 3 -> bitmask = 5
    o[1] & 2 | 8,      //   F = 4 -> bitmask = 10 if we also have two 1's, 8 otherwise
    2,                 //   F = 5 -> bitmask = 2
    4                  //   F = 6 -> bitmask = 4
  ][o[4]]              // take the entry corresponding to F (the number of 4's)
\$\endgroup\$
5
\$\begingroup\$

R, 100 bytes

Encode the score as a bunch of indexed conditionals. Simpler than my first stringy-regex approach.

Edit- fixed bug and now rank all rolls.

function(d,s=sum(d<2))min(2[s>5],c(11,10,8,6-6*!s-2,4,1)[sum(d==4)],c(7,12,12,9,5,3)[max(table(d))])

Try it online!

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

Charcoal, 55 bytes

≡⌈Eθ№θι⁶I⁻²⌕14§θχ⁵I⁻⁵⁼⁵№θ4⁴⎇⁼№θ4⁴§60⁼№θ1²9¹7I⁻¹²⌊⊘X²№θ4

Try it online! Link is to verbose version of code. Does not skip 10. Explanation:

≡⌈Eθ№θι

Calculate the highest frequency of any digit.

⁶I⁻²⌕14§θχ

If there is a 6 of a kind, then subtract the position of the digit in the string 14 from 2. This results in 1 for 6 4s, 2 for 6 1s, and 3 for 6 of anything else.

⁵I⁻⁵⁼⁵№θ4

If there is a 5 of a kind, then the result is 5 unless there are 5 4s, in which case 1 is subtracted.

⁴⎇⁼№θ4⁴§60⁼№θ1²9

If there is a 4 of a kind, then if there are 4 4s then the result is 6 unless there are 2 1s in which case the result is 0, otherwise the result is 9.

¹7

If all the digits are different then the result is 7.

I⁻¹²⌊⊘X²№θ4

Otherwise the result is 12 - (4 >> (3 - # of 4s)).

\$\endgroup\$
2
  • \$\begingroup\$ It seems to be best practice to accept the shortest answer, so that's what I'll do :) Unfortunately not many people saw and upvoted your answer... \$\endgroup\$
    – Quintec
    Sep 29, 2018 at 19:02
  • \$\begingroup\$ @Quintec That's not a problem; people are supposed to upvote answers based on the ingenuity of the algorithm or other factor that makes them appreciate the answer. \$\endgroup\$
    – Neil
    Sep 29, 2018 at 21:25
2
\$\begingroup\$

JavaScript (Node.js), 169 bytes

a=>-~"114444|123456".search(w=a.sort().join``,[l,t]=/(.)\1{3,}/.exec(w)||[0],l=l.length)||(l>5?3-"14".search(t):l>3?4+(5.5-l)*(t-4?4:2):[,13,12,11,9][w.split`4`.length])

Try it online!

Returns 1..13

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

Python 2,  148  119 bytes

-27 bytes thanks to ovs's (1. use of .count allowing a map to be used; 2. removal of redundant 0 in slice; 3. use of an in rather than a max; 4. shortened (F==4)*O==2 to F==4>O==2 [since golfed to F>3>O>1])

C=map(input().count,range(1,7))
O,F=C[::3]
print[F>3>O>1,F>5,O>5,6in C,F>4,5in C,F>3,all(C),F>2,4in C,F>1,F,1].index(1)

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ @ovs oh heh .count >_< nice \$\endgroup\$ Sep 24, 2018 at 14:15
  • \$\begingroup\$ One last suggestion: As d is only needed one, this is shorter as a full program. \$\endgroup\$
    – ovs
    Sep 24, 2018 at 14:19
  • \$\begingroup\$ Python 3 version: 131 bytes \$\endgroup\$
    – Adirio
    Sep 24, 2018 at 14:31
  • \$\begingroup\$ @ovs - thanks for all your golfing. Saved another two to boot. \$\endgroup\$ Sep 24, 2018 at 17:17
  • \$\begingroup\$ Gotta love python conditional chaining! Also, the spec now doesn't skip the number 10 \$\endgroup\$
    – Quintec
    Sep 24, 2018 at 17:25
1
\$\begingroup\$

Pyth, 60 bytes

eS[@[ZhZ2 4*6hq2hJuXtHG1Qm0Q8hT)@J3*5hSJ*Tq6hJ*<3KeSJ@j937TK

Maps to reversed rank, 0-12. Try it online here, or verify all the test cases at once here.

The full mapping used is as follows:

12: 4 fours and 2 ones.
11: 6 fours.
10: 6 ones.
 9: 6 of any kind except fours and ones.
 8: 5 fours.
 7: 5 of any kind except for fours.
 6: 4 fours.
 5: Straight. (1-6)
 4: 3 fours.
 3: 4 of any kind except 4.
 2: 2 fours.
 1: 1 four.
 0: Nothing.

This works by mapping the dice values to frequencies, then calculating the value of several rules, and taking the maximum of the set.

Implicit: Q=eval(input()), Z=0, T=10

JuXtHG1Qm0Q   Input mapping
 u     Q      Reduce each element of the input, as H, ...
        m0Q   ...with initial value, G, as an array of 6 zeroes (map each roll to 0)
   tH           Decrement the dice roll
  X  G1         Add 1 to the frequency at that point
J             Store the result in J

@[ZhZ2 4*6hq2hJuXtHG1Qm0Q8hT)@J3   Rule 1 - Values for sets including 4
  Z                               *0
   hZ                             *1 (increment 0)
     2                            *2
       4                          *4
              JuXtHG1Qm0Q          Input mapping (as above)
             h                     First value of the above - i.e. number of 1's
           q2                      1 if the above is equal to 2, 0 otherwise
        *6h                       *Increment and multiply by 6
                                   Maps to 12 if there are 2 1's, 6 otherwise
                         8        *8
                          hT      *11 (increment 10)
 [                          )      Wrap the 7 starred results in an array
                             @J3   Get the 4th value of the input mapping - i.e. number of 4's
@                                  Get the value at that position in the array

*5hSJ   Rule 2 - Straight
  hSJ   Smallest frequency in input mapping (first, sort, J)
        For a straight, smallest value will be 1, 0 otherwise
*5      Multiply by 5

*Tq6hJ   Rule 3 - 6 1's
    hJ   Frequency of 1's (first value from input mapping)
  q6     1 if the above == 6, 0 otherwise
*T       Multiply by 10

*<3KeSJ@j937TK   Rule 4 - 4,5,6 of a kind, other than 4's
   KeSJ          Get the max frequency from input mapping, store in K
        j937T    [9,3,7]
       @     K   Get the element at K'th position in the above (modular indexing)
 <3K             1 if 3<K, 0 otherwise
*                Multiply the previous 2 results

eS[   Wrapping it all up!
  [   Wrap all the above rules in an array
eS    Take the max value of the above, implicit print
\$\endgroup\$
1
\$\begingroup\$

Retina, 137 126 bytes

4
A
O`.
^11A+
0
1+$
2
^A+
1
(.)\1{5}
3
^.A+
4
.?(.)\1{4}.?
5
^..A+
6
12356A
7
.+AAA$
8
.*(.)\1{3}.*
9
.+AA$
10
.+A$
11
.{6}
12

-11 bytes thanks to @Neil.

Output is 0-indexed (0..12).

Try it online or verify all test cases.

Explanation:

Replace every 4 with an 'A':

4
A

Sort all the input-digits (the A's will be at the back):

O`.

Every other two lines replaces the input with the expected output:

Regex         Replacement  Explanation

^11A+         0            starts with "11", followed by any amount of A's
1+$           2            ends with any amount of 1s
^A+           1            starts with any amount of A's
(.)\1{5}      3            six of the same characters
^.A+          4            starts with any character, followed by any amount of A's
.?(.)\1{4}.?  5            five of the same characters,
                           with optionally a leading or trailing character
^..A+         6            starts with any two characters, followed by any amount of A's
12356A        7            literal "12356A" match
.+AAA$        8            any amount of leading characters, ending with three A's
.*(.)\1{3}.*  9            four of the same characters,
                           with optionally any amount of leading/trailing chars
.+AA$         10           any amount of leading characters, ending with two A's
.+A$          11           any amount of leading characters, ending with a A
.{6}          12           any six characters
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Very clever, but I think you can go one step further and replace 4 with something outside of the range 1-6 to get it to sort to one end automatically (not sure whether it makes a difference which end you sort to). \$\endgroup\$
    – Neil
    Sep 24, 2018 at 16:06
  • \$\begingroup\$ @Neil Ah, that's clever as well! Thanks. \$\endgroup\$ Sep 24, 2018 at 16:57
1
\$\begingroup\$

05AB1E, 57 55 bytes

[email protected]¢©5-Di14¹нk2αë>Di5X-ë>i9X3*-¹1¢2Ê*ë®i7ë¹4¢o;ï12α

Port of @Neil's Charcoal answer, because my initial approach was already at 60 bytes and I wasn't done yet. My current answer can probably be golfed some more, though.

Input as a list of digits.

Try it online or verify all test cases.

Explanation:

4¢              # Count the amount of 4s in the (implicit) input-list
  4@            # Check if it's larger than or equal to 4
                # (results in 1 for truthy; 0 for falsey)
    U           # Pop and store that result in variable `X`
.M              # Push the most frequent number in the (implicit) input-list
  ¢             # Pop and push the count of that number in the (implicit) input-list
   ©            # Store it in the register (without popping)
5-Di            # If the maximum count - 5 is exactly 1 (so the maximum count is 6):
    14          #  Push 14
      ¹н        #  Push the first digit of the input-list
        k       #  Get its index in 14, resulting in -1, 0, or 1
         2α     #  Take the absolute difference with 2
                #  (This covers cases 1, 2, and 3)
ë>Di            # Else-if the maximum count - 5 + 1 is exactly 1 (so the maximum count is 5):
    5           #  Push 5
     X-         #  And subtract variable `X`
                #  (This covers cases 4 and 5)
ë>i             # Else-if the maximum count - 5 + 2 is exactly 1 (so the maximum count is 4):
   9            #  Push 9
    X3*         #  Multiply variable `X` by 3
       -        #  And subtract it from the 9
        ¹1¢     #  Count the amount of 1s in the input-list
           2Ê   #  Check if it's NOT equal to 2 (1 if truthy; 0 if falsey)
             *  #  Multiply it with the 9 or 6
                #  (This covers cases 0, 6, and 9)
ë®i             # Else-if the maximum count is 1:
   7            #  Push a 7
                #  (This covers case 7)
ë               # Else (maximum count is 2 or 3):
 ¹4¢            #  Count the amount of 4s in the input-list
    o           #  Take 2 to the power this count
     ;ï         #  Halve and floor it
       12α      #  And take the absolute difference with 12
                #  (This covers cases 8, 10, 11, and 12)
                # (Output the top of the stack implicitly as result)
\$\endgroup\$
0
\$\begingroup\$

Ruby, 100 bytes

->a{%w(^2.*4$ 6$ ^6 6 5$ 5 4$ ^1*$ 3$ 4 2$ 1$ .).index{|b|/#{b}/=~([1,*a,4].map{|c|a.count(c)}*'')}}

Try it online!

How it works:

Count occurrences of every number in the array, prepend number of 1s and append number of 4s.

After that, try to match with different regex patterns.

\$\endgroup\$

Your Answer

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

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