# Score a hand of Hearts

Hearts is a trick-taking card game for 4 players. Each trick is taken by the player who played the highest card of the leading suit. At the end of each hand, the players incur a penalty score depending on the penalty cards they have taken; the task is to determine the scores under Microsoft Hearts rules.

## Input

Input is 4 lists (or delimited string, array, etc.) showing the penalty cards taken by each of the 4 players. The penalty cards are

2♥, 3♥, 4♥, 5♥, 6♥, 7♥, 8♥, 9♥, 10♥, J♥, Q♥, K♥, A♥, Q♠


which we shall represent as

2,  3,  4,   5,  6,  7,  8,  9,  10,  11, 12,  13,  1,  0


respectively.

## Output

Output is the 4 penalty points incurred by the 4 players (list, string, array etc.). Scoring is as follows:

• Each heart (♥, represented by integers 1 to 13 inclusive) incurs 1 point
• The queen of spades (Q♠, represented by 0) incurs 13 points
• Exception: if a player has taken all of the penalty cards (called shooting the moon), then he incurs 0 points, while all other players incur 26 points.

## Test cases

[2, 8, 7, 1], [3, 4], [], [9, 5, 6, 0, 10, 11, 12, 13]     -->  4,  2,  0, 20
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [], [], [1]   --> 25,  0,  0,  1
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0], [], [], [] -->  0, 26, 26, 26


Shortest code in bytes wins.

## R, 85 77 74 bytes

function(x,z=sapply(x,function(x)sum(x>0)+any(x<1)*13))abs(z-any(z>25)*26)


Unnamed function that takes an R-list as input. Works by counting the number of elements >0 and adds 13 if any element within each vector is <1 (i.e. queen of spades) and store as z.

If any element in z is >25, return 26-z, else return z.

Try it on R-fiddle

• Would 26-z work?
– user58632
Nov 14 '16 at 9:07
• @lastresort Yes of course. /facepalm Nov 14 '16 at 9:08

# C++14, 158 bytes

As unnamed Lambda:

[](auto c){typename decltype(c)::value_type r;int b=0;for(auto d:c){int q=0;for(auto i:d)q+=i?1:13;r.push_back(q);b+=q==26;}if(b)for(int&x:r)x=26-x;return r;}


Requires a vector<vector<int>> and returns vector<int>

Ungolfed:

[](auto c){
typename decltype(c)::value_type r;   //result vector
int b=0;                              //flag if one has all cards
for(auto d:c){                        //over all decks
int q=0;                             //count points
for(auto i:d) q+=i?1:13;             //+13 for queen, +1 else
b+=q==26;                            //possibly activate flag
}
if(b) for(int&x:r) x=26-x;            //if flag is set, mirror the results
return r;
}


Few testcases for you:

 auto r = std::vector<std::vector<int>>{{2,8,7,1},{3,4},{},{9,5,6,0,10,11,12,13}};
auto s = std::vector<std::vector<int>>{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},{},{},{}};
auto t = std::vector<std::vector<int>>{{},{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},{},{1}};


## Python 2, 7572 71 bytes

i=[len(a)+12*(0in a)for a in input()]
print[[x,26-x][26in i]for x in i]


Takes input as [2, 8, 7, 1], [3, 4], [], [9, 5, 6, 0, 10, 11, 12, 13]

• Could you save 3 characters by using 12*[0in a] instead of [0,12][0in a]? Nov 14 '16 at 14:06
• @Costantino I think you mean 12*(0in a). Nov 14 '16 at 14:25
• print[[x,26-x][26in i]for x in i] is one byte shorter. Nov 14 '16 at 16:37

## CJam, 22 20 bytes

Thanks to jimmy23013 for saving 2 bytes.

{{XD?}f%1fb_26&1bf^}


An unnamed block (function), which takes a list of 4 lists as input and returns the list of scores.

Try it online!

### Explanation

{      e# For each card...
XD?  e#   Choose 1 if it's positive and 13 if it's zero.
}f%
1fb    e# Sum each hand.
_26&   e# Get the set intersection of the scores with 26. This gives [26]
e# if someone shot the moon, and [] otherwise.
1b     e# Treat as base-1 digits, which gives 26 if someone shot the moon
e# and zero otherwise.
f^     e# XOR each result with this number. This swaps zeros and 26s when
e# someone shot the moon and does nothing otherwise.

• _26&1b. -2 bytes. Nov 14 '16 at 13:24
• @jimmy23013 Ahhhh, 1b... I was trying to find a short way to turn [26] into 26 and [] into 0 but somehow that didn't occur to me. Thank you :) Nov 14 '16 at 13:25

# PHP, 113 bytes

function h($a){foreach($a as&$b)$b=count($b)+12*in_array(0,$b);if(max($a)>25)foreach($a as&$n)$n=26-$n;return$a;}


function takes an array of arrays, returns an array of values.

Marvel the other array mapping in PHP: loops with referenced items. Waaay shorter than array_map.

f x|all(<26)x=x|0<1=map(26-)x
f.map(sum.map((13^).(0^)))


Usage:

> f.map(sum.map((13^).(0^))) $[[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [], [], [1]] [25,0,0,1]  • I think you can write f as f n=13^0^n. – xnor Nov 14 '16 at 10:01 • @xnor I think you're right. Saves 3 bytes. – Angs Nov 14 '16 at 10:25 • I think defining f x|all(<26)x=x|0<1=map(26-)x and using it in place of the lambda function saves some bytes. Nov 14 '16 at 12:54 • @Zgarb right you are, I'd say that's another 3 bytes. – Angs Nov 14 '16 at 13:12 # 05AB1E, 2622 21 bytes Trailing whitespace must be removed from input so that it is interpreted as an array. The ending was inspired of the other answers when using (26-x) when a player gathered all penalty cards. vy0å12*yg+})D26©åi(®+ v For each array y Push array on the stack 0å Generate a boolean array indicating whether the queen of spades is at the same index in the original array 12* Multiply by 12 the value of the queen of spades yg+ Add the length of the array; the queen of spades gets her last point from this part } End for ) Push an array of all evaluated scores D26©å 1 if there is a 26, 0 otherwise i If there is a 26 (®+ Mirror the array: for each element yield 26-element Implicit end if Implicitly print the score array  Try it online! It still looks pretty golfable, with duplicated constants and conditional statements. # Former version, 26 bytes (One byte for each point in maximal penalty value) I decided to keep it as its length fits best this challenge in my opinion :) . vyD0å12*sg+})D26©QDOi_®*ë\  Try it online! # Python 3, 101 bytes def s(a):r=[sum([(1,13)[c==0]for c in h])for h in a];s=(r,[(26,0)[s==26]for s in r]);return s[26in r]  Full code: def score(hands): result = [sum([(1, 13)[card == 0] for card in hand]) for hand in hands] results = (result, [(26, 0)[score == 26] for score in result]) return results[26 in result]  • 12*(c<1)+1 is 2 bytes shorter than (1,13)[c==0]. 26*(s>25) is 3 bytes shorter than (26,0)[s==26]. – user45941 Nov 14 '16 at 18:39 ## JavaScript (ES6), 828077727069 67 bytes Saved 2 bytes thanks to @Neil f = s=>s.map(c=>c.map(t=>r+=t?1:13,r=0)|(b|=r>25,r),b=0).map(c=>b*26^c) console.log(f.toString().length) console.log(f([[2, 8, 7, 1], [3, 4], [], [9, 5, 6, 0, 10, 11, 12, 13]])); console.log(f([[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [], [], [1] ])); console.log(f([[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [], [1], [] ])); console.log(f([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0], [], [], []])); console.log(f([[],[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0], [], []])); ### Breakdown s=>s.map( // for each hand c=>c.map( // for each card t=>r+=t?1:13, // add value of card r=0)|( b=b|r>25,r // set flag if any hand scores 26 points ), b=0) .map(c=>b? // for every card if a hand scored 26 c?0:26 // set every 0 hand to 26 and the 26 hand to 0 :c) // otherwise do nothing  • c=>b*26^c saves 2 bytes. – Neil Nov 15 '16 at 13:13 ## Pip, 28 bytes 27 bytes of code, +1 for -p flag. Y{$+1+12*!*a}M Va26Ny?26-yy


Takes input on the command-line as a string representing a nested list, like "[[2 8 7 1] [3 4] [] [9 5 6 0 10 11 12 13]]" (quotes not needed on TIO). Try it online!

# Ruby, 59 bytes

->a{a.map{|h|a.max.size>13?h.min||26:h.size+12*h.count(0)}}


Or, alternatively,

->a{a.map{|h|a.count([])>2?h.min||26:h.size+12*h.count(0)}}


If only one hand has any cards, we want the empty hands to get a value of 26, and the hand with cards to get a value of 0. I do this by calling min on the hands - this returns nil for an empty array, and then I || it into 26. In other cases, I count the number of cards in a hand and then add 12 to the Queen of Spades.

# Scala, 93 bytes

a=>{val% =a.map(_.map{case 0=>13;case _=>1}sum)
if(%toSet 26)%map{case 0=>26;case _=>0}else%}


Usage:

val f:(Seq[Seq[Int]]=>Seq[Int])=...
f(Seq(Seq(2, 8, 7, 1), Seq(3, 4), Seq(), Seq(9, 5, 6, 0, 10, 11, 12, 13)))


Explanation:

a=>{           //define an anonymou function with a parameter a
val% =         //define % as...
a.map(         //map each element of a...
_.map{         //to each of the card
case 0=>13     //replaced with its value
case _=>1
}
sum            //and the sum of the values
)
if(            //if
%toSet 26      //one player has all cards
)
%map{          //return % with...
case 0=>26     //each 0 replaced with 26
case _=>0      //and everything else (aka the 26) replaced 0
}
else           //else
%              //return %
}


I could use %toSet 26 instead of % contains 26 because Set's apply method is contains and not get-at-index like Seq's