10
\$\begingroup\$

Hearts is a 4-player game that uses the following scoring rules:

  1. Everyone starts with score 0.
  2. Each round every player gets a non-negative amount of points. The sum of the points is 26, and at least one player gets 13 or more points.1
  3. The points are then added to the players' score except if a player gets 26 points. If that happens, everyone else adds 26 to their score, and the player who got 26 points adds none.
  4. The game ends when someone gets a score of 100 or more. Until then, steps 2 and 3 are repeated.

Your task is to take 4 non-negative integers representing the scores of the players at the end of the game and decide if it's a valid game. That is, are those scores possible to achieve by following the rules until the game ends.

Samples

[26,26,26,26]  -> False (The game has not ended since no one has a score of 100 or more)
[1,1,2,100]    -> True  ([1,0,0,25]+[0,1,0,25]+[0,0,1,25]+[0,0,1,25])
[1,1,2,108]    -> False (Sum not divisible by 26)
[26,26,26,260] -> False (Game should have ended before a score of 260 is reached. In fact, 125 is the maximum score a player can have)
[104,104,104,0]-> True  ([26,26,26,0]+[26,26,26,0]+[26,26,26,0]+[26,26,26,0])
[0,0,0,104]    -> False (One can't just add 26 points to his score. That would add 26 to the 3 other players)
[13,13,104,104]-> True  ([0,0,13,13]+[0,0,13,13]+[0,0,13,13]+[0,0,13,13]+[0,0,13,13]+[0,0,13,13]+[13,0,13,0]+[0,13,0,13]+[0,0,13,13])
[10,10,120,120]-> False (The last turn must be [26,26,26,0] for two players to reach 120, but two players also have <26 score)
[0,0,5,125]    -> False (The last turn can't be [0,0,0,26], suggested by Neil
[117,117,117,117]-> False (Last turn get >26 point and is not a [0,26,26,26])
[104,104,104,104]-> False (Even if last round is [13,5,4,4], it was [91,99,100,100] which is impossible)
[101,101,101,113]-> True  ([7,7,6,6]+[26,26,26,0]+[26,26,0,26]+[26,0,26,26]+[0,26,26,26]+[13,13,0,0]+[0,0,13,13]+[3,3,4,16] thank AnttiP for the example)
[15,125,125,125] -> True  ([5,13,4,4]+[5,4,13,4]+[5,4,4,13]+[0,26,26,26]+[0,26,26,26]+[0,26,26,26]+[0,26,26,26] as Nitrodon suggest)

This is so the shortest code in each language wins.

Note

  • All true cases can be seen here. You can also see here for possibilities of score for a given amount of rounds and state(ended/not)

1 non-negative amount of points is the game part. 13 is the Queen of spades

\$\endgroup\$
2
  • \$\begingroup\$ Suggested test case: something that is possible, but requires a player to shoot the moon in the final round. The most extreme example would be [15, 125, 125, 125]. \$\endgroup\$
    – Nitrodon
    Feb 7 at 5:40
  • \$\begingroup\$ Suggested test case: [0, 0, 5, 125], which my previous answer revision mistakenly identified as possible. \$\endgroup\$
    – Neil
    Feb 7 at 23:13

4 Answers 4

2
\$\begingroup\$

Charcoal, 69 bytes

∧‹﹪Σθ²⁶‹³⁻Σθ⌈θ⎇‹⁹⁹⌊θ›³¹¹⁻Σθ⌈θ¬÷⎇‹²ΣEθ‹²⁵ι⁻⌈θ¹⁰⁰∨±‹¹²⁴⌈θ⊖ΣEθ⌈⟦⁰⁻ι⁹⁹⟧²⁶

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - if possible, nothing if not. Explanation: A final score is valid if it satisfies the following:

  • The sum of all the scores is a multiple of 26.
  • The three players excluding the highest score have scored at least 4 between them.
  • If all four players have scored at least 100, then the three players excluding the highest score have scored at most 310 between them.
  • Otherwise if at least three players have scored 26, then the highest score is between 100 and 125 inclusive.
  • Otherwise, the highest score is less than 125 but the sum of the amounts by which the relevant players have scored over 99 is between 1 and 26 inclusive.

In order to verify the assertions above I devised an alternative approach which unfortunately is still 7 bytes longer than the fixed version after it discovered a bug in my original approach.

F³⁸⁴¹⁶F⁴⊞υE⁴⁺﹪÷ιX¹⁴λ¹⁴×¹³⁼κλ›∧‹⁹⁹⌈θ‹³⁻Σθ⌈θ∨﹪Σθ²⁶⬤υ∨⁻²⁶Σι⊙⎇№ι²⁶⁻²⁶ιι÷⁻§θμλ¹⁰⁰

Try it online! Link is to verbose version of code. Explanation:

F³⁸⁴¹⁶F⁴⊞υE⁴⁺﹪÷ιX¹⁴λ¹⁴×¹³⁼κλ

Generate all valid captures for a single round (plus some invalid ones as well, but they'll be filtered out later). The idea is to generate all lists of four non-negative integers that sum to 13, then take each of those and add 13 in turn to each integer.

›∧‹⁹⁹⌈θ‹³⁻Σθ⌈θ∨﹪Σθ²⁶

Check at at least one score is at least 100, at least one other score is at least 4, and the sum of the scores is a multiple of 26.

⬤υ∨⁻²⁶Σι⊙⎇№ι²⁶⁻²⁶ιι÷⁻§θμλ¹⁰⁰

Check that there's at least one valid capture arrangement where subtracting the scores of that arrangement (adjusting for the case where one player captured all of the penalty cards) from the input results in a set of four scores between 0 and 99 inclusive.

\$\endgroup\$
4
  • \$\begingroup\$ I also didn't consider this case but I considered [117]*4 \$\endgroup\$
    – l4m2
    Feb 6 at 12:21
  • \$\begingroup\$ @l4m2 Hopefully my new set of constraints covers everything now? \$\endgroup\$
    – Neil
    Feb 6 at 15:48
  • \$\begingroup\$ Maybe you should try all cases, seems it doesn't take too long (\$\frac{126^4}{26}=9694130\$) \$\endgroup\$
    – l4m2
    Feb 7 at 12:02
  • \$\begingroup\$ @l4m2 I can only check a million cases before TIO times out, but I picked a hundred thousand and found one last edge case which I've now fixed. \$\endgroup\$
    – Neil
    Feb 7 at 23:12
1
\$\begingroup\$

Jelly, 40 bytes

®ṗ4’S⁼®ƊƇṀ>12ƊƇ
4⁻þ`×26©;¢ṗ⁴+\Ṁ>99ƊƇḢƊ€ċ

A monadic Link accepting a list of integers that yield 0 (falsey) if not a possible Hearts result or a positive integer (truthy) if it is.

Don't Try it online! ...it won't finish (Maybe I'll golf one that will too...).

How?

®ṗ4’S⁼®ƊƇṀ>12ƊƇ - Helper link: no arguments
®               - recall 26 from the register
 ṗ4             - All length 4 lists of [1..26]
   ’            - decrement (vectorises)
    S⁼®ƊƇ       - keep those with sum 26
         Ṁ>12ƊƇ - keep those with a maximum value over 12

4⁻þ`×26©;¢ṗ⁴+\Ṁ>99ƊƇḢƊ€ċ - Link: list of four integers, X
4⁻þ`                     - table of not-equal between [1,2,3,4] and itself
     26©                 - place 26 in the register
    ×                    - multiply the table values by 26
        ;¢               - concatenate all the other scores by calling the helper Link
          ṗ⁴             - All length 16 lists with those lists as elements
                             note: games take at most 15 rounds (and ⁴ is shorter than 15)
                     Ɗ€  - for each, last three links as a monad:
            +\           -   cumulative reduce by addition (non-vectorising, unlike Ä)
                   Ƈ     -   keep those for which:
              Ṁ>99Ɗ      -     maximum is greater than 99
                    Ḣ    -   head (first reached winning score list)
                       ċ - count occurrences of X
\$\endgroup\$
3
  • \$\begingroup\$ Nice. This was the only approach I could think of that guaranteed correctness, but I'm really curious if there are any clever shortcuts that avoid the full computation... \$\endgroup\$
    – Jonah
    Feb 6 at 22:55
  • \$\begingroup\$ Which part convert [26,0,0,0] into [0,26,26,26]? \$\endgroup\$
    – l4m2
    Feb 7 at 2:52
  • 1
    \$\begingroup\$ @l4m2 There is no conversion, instead the four are concatenated to the ways to use 0 to 25. They are made with 4⁻þ`×26 \$\endgroup\$ Feb 7 at 3:00
1
\$\begingroup\$

Python 3, 220 bytes

s={(0,)*4}
r=range(27)
f=lambda*a:[a]*(12<max(a)<sum(a)==26or sum(a)-min(a)*2==78)if len(a)>3 else sum([f(*a,i)for i in r],[])
for t in r:s={i*(max(i)>99)or tuple(map(sum,zip(i,j)))for j in f() for i in s}
s.__contains__

It should work in theory. But I had never tested it actually. No TIO links as it certainly timed out on TIO.

\$\endgroup\$
0
\$\begingroup\$

05AB1E, 48 bytes

An extremely slow brute-force approach..

30Åœ4ù<ć_₂*šʒà13@}€œ€`₂ã€η€`€øOʒàƵP‹}ʒ{¨OƵÓ‹}€Qà

No TIO since it's way too slow.

A port of @Neil's Charcoal answer would be 52 bytes:

{¨OUт@PiXƵÓ‹ë₂@O3@iàтƵOŸsåë₂LIZƵO‹*99-DdÏOå]IO₂ÖX4@P

Try it online or verify all test cases.

Explanation:

30Ŝ           # Get all lists of positive integers that sum to 30
    4ù         # Only keep all lists of length 4
      <        # Decrease each by 1
               # (we now have all non-negative integers that sum to 26)
       ć       # Extract head; pop and push remainder-list and first list
               # separated to the stack
               # (the first list is [0,0,0,26])
        _      # Check for each if it's 0: [1,1,1,0]
         ₂*    # Multiply that by 26: [26,26,26,0]
           š   # Prepend it back to the list
ʒ              # Filter these lists by:
 à13@          #  Check if the maximum is ≥13
}€             # After the filter: map over each remaining list:
  œ            #  Get all its permutations
   €`          # Flatten it one level down to a list of lists again
     ₂ã        # Take the cartesian product of 26
               # (at least 15 is required, and 26 is the smallest single byte
               # constant above this)
       €η      # Get the prefixes of each inner list of 26 lists
         €`    # Flatten it one level down to a list of list of lists
           €ø  # Zip/transpose each inner list of lists
             O # Sum each inner-most list
ʒ              # Filter these lists of sums:
 àƵP‹          #  Check if the maximum is smaller than 126
}ʒ             # Filter again:
  {            #  Sort the four values
   ¨           #  Remove the last/highest
    O          #  Sum the lowest three
     ƵÓ‹       #  Check if it's smaller than 311
 }€Q           # After the filter: check for each remaining list if it's equal to
               # the (implicit) input-list
    à          # Max: check if any is truthy
               # (which is output implicitly as result)
{                     # Sort the (implicit) input-list
 ¨                    # Remove the last/highest value
  O                   # Sum the remaining three
   U                  # Pop and store it in variable `X`
т@Pi                  # If all four values in the (implicit) input-list are ≥100:
    XƵÓ‹              #  Check if `X` is smaller than 311
   ë₂@O3@i            # Else-if at least three values are ≥26:
          àтƵOŸså     #  Check if the maximum is in the range [100,125]
         ë            # Else:
            IZƵO‹     #  Check if the maximum of the input is <125
                 *    #  Make everything 0 if this is falsey
             99-      #  Decrease each value in the input-list by 99
                DdÏ   #  Only keep the non-negative values
                   O  #  Sum those together
          ₂L        å #  Check if this sum is in a [1,26]-ranged list
]                     # Close all if-else statements
IO₂Ö                  # Check that the sum of the input-list is divisible by 26
X4@                   # Check that `X` is ≥4
P                     # Check if all four checks on the stack are truthy
                      # (after which this is output implicitly as result)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why ƵÓ is 311 and ƵO is 125.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I had to revise my answer because it claimed that [0, 0, 5, 125] was possible. \$\endgroup\$
    – Neil
    Feb 7 at 23:13
  • \$\begingroup\$ @Neil Should be fixed again, thanks for the heads up. \$\endgroup\$ Feb 8 at 8:50
  • \$\begingroup\$ I've also posted the code I used to check my original answer. In Charcoal it's longer than my original approach, even after the bugfix, but it might be shorter in 05AB1E, since it takes an awful lot of bytes to subtract all possible round scores from the input to see whether there's a result where all the values are between 0 and 99. \$\endgroup\$
    – Neil
    Feb 8 at 9:50

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.