19
\$\begingroup\$

Write code to determine who wins a four-card trick in a game of Spades. Fewest bytes wins.

The input is a string that lists the four cards played in sequence like TH QC JH 2H (Ten of Hearts, Queen of Clubs, Jack of Hearts, Two of Hearts). A card is given by two characters: a suit from CDHS and a value from 23456789TJQKA. You are guaranteed that the input is valid and the cards are distinct.

You should output a number 1, 2, 3, or 4 for the winner of the trick. In the example TH QC JH 2H, the jack of hearts wins the trick, so you should output 3.

Your input and output must be exactly as described, except trailing newlines are optional.

Here are the Spades rules for winning a trick. The winning card is the highest card of the four, with some caveats. Spades is the trump suit, so any spade outranks any non-spade. The suit of the first card played is the lead suit, and only cards of that suit or spades are eligible to win the trick. Cards of the same suit are compared by their values, which are given in increasing order as 23456789TJQKA.

Test cases:

TH QC JH 2H
3
KC 5S QS 9C
3
QD 2D TD 5D
1
9S 5D AD QS
4
3D 4C 3H JH
1
9S 4S TS JS
4
5H 9H 2C AD
2
5S 4C 3H QD
1
2H 2S KH AH
2
\$\endgroup\$
0

10 Answers 10

10
\$\begingroup\$

Pyth, 28 27 25 bytes

J"KTAZ"hxcz)eo_XN+@z1JJcz

Try it online: Demonstration or Test Suite (first 4 chars are the test suite construct)

Thanks to @isaacg for a trick, which saved 2 chars.

The main idea is to modify chars of each hand such a in way, that the winning hand has the maximal value.

The values of the hands 23456789TJQKA is already nearly sorted. I just have to replace T with A, K with T and A with Z, resulting with 23456789AJQSZ.

The order of suits CDHSare for the most not really important. S, the most powerful suit, which is already the maximal value. Important is to give the suit of the first hand the second most powerful value. So I translate this suit into K.

All hands also have to be read reverse, since the suit is more powerful than the value.

                           implicit: z = input string
J"KTAZ"                    J = "KTAZ"
             o         cz  orders the hands N of split(z) by:
              _              the reversed of 
               XN+@z1JJ      N, where the values z[1]+J are replaced by J
            e              last element (winning hand)
        xcz)               index of the winning hand in split(z)
       h                   + 1
\$\endgroup\$
6
  • \$\begingroup\$ I give up, well played :P \$\endgroup\$
    – orlp
    Apr 20, 2015 at 11:14
  • \$\begingroup\$ I don't think the .e stuff is worth it - using o is 1 character shorter as I figure it. \$\endgroup\$
    – isaacg
    Apr 20, 2015 at 11:17
  • \$\begingroup\$ @isaacg Your right. Funny thing is, I had the 27 solution before the .e 28 solution. But the 27 solution ended with a ) and therefore also had 28 bytes. :oops: \$\endgroup\$
    – Jakube
    Apr 20, 2015 at 11:22
  • 1
    \$\begingroup\$ I thought of a way to save another 2 characters: Translate from +@z1"KTA" to "KTAZ", but instead of using the strings directly use J"KTAZ" at the beginning and +@z1J to J. \$\endgroup\$
    – isaacg
    Apr 20, 2015 at 12:35
  • \$\begingroup\$ @isaacg Very clever. Thanks. Btw. I thinking quite a while about making the 3rd argument of X optional (Only if a and b are strings). But I'm not really sure, if Xab) should evaluate to Xab_b (inverted b, would be nice for stuff like Xa"</\>") or Xab+tbhb (b shifted). What your preference? \$\endgroup\$
    – Jakube
    Apr 20, 2015 at 12:53
6
\$\begingroup\$

CJam, 34 33 bytes

lS/_{)2$0='S+\#\"TQKA"_$er+}$W>#)

Algorithm

The logic is simple. I have a custom sort going on, in which I first give priority to the second character representing the suit. In this, Spades gets the highest priority and then the first thrown suite. Rest all are -1. Then I sort on the first character with swapping of T with A and Q with K to have lexical sorting.

Code explanation

First off, lets see what is the lexical order of the face values of the cards:

"23456789TJQKA"$

23456789AJKQT

So, all numbers are at correct position. J is also at correct position. We need to swap K and Q and J and A to get lexical order.

lS/_{)2$0='S+\#\"TQKA"_$er+}$W>#)
lS/                                 "Read an input line and split on spaces";
   _{                      }$       "Copy the array and sort it using this custom logic";
     )                              "Take off the last character of each hand.";
      2$0=                          "Get the suit of the first hand";
          'S+                       "Add Spades suit to it";
             \#                     "Get the index of the current hand suit.
                                     1 for Spades, 0 for first hand suit, -1 otherwise";
               \                    "Put face value of this hand on top of stack";
                "TQKA"              "Put string TQKA on stack";
                      _$            "Copy and sort. This essentially reverses the string
                                     TQKA to form AKQT. This is 1 byte shorter than _W%";
                        er+         "Swap T with A and K with Q and add to the
                                     suit index calculated previously";
                                    "After the above tuple, sorting will automatically
                                     convert the tuple to string and sort lexically";
                             W>     "Get the array containing only the last element";
                               #)   "Get the index of this hand in original set and
                                     increment to convert it to 1 based";

Try it online here

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 112

Scan the list and return the position of the highest value found.

Run snippet to test (in Firefox)

F=t=>t.split(' ').map((c,i)=>(n='23456789TJQKA'.search(c[0])+(c[1]>'H'?40:c[1]==t[1]&&20))>m&&(m=n,r=i+1),m=0)|r

C.innerHTML=['TH QC JH 2H','KC 5S QS 9C','QD 2D TD 5D','9S 5D AD QS','3D 4C 3H JH','9S 4S TS JS','5H 9H 2C AD','5S 4C 3H QD'].map(h=>h+' -> '+F(h)).join('\n')
<pre id=C></pre>

\$\endgroup\$
3
\$\begingroup\$

Perl, 73 bytes

#!perl -pl
/\B./;s/$&/P/g;y/TKA/IRT/;$_=reverse;@a=sort split;/$a[-1]/;$_=4-"@-"/3

Try me.

Converts the card names so the game value order follows the alphabetical order, then picks the highest by sorting and looks for it in the original string for position.

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

Ruby, 59+2=61

With command-line flags na, run

p (1..4).max_by{|i|$F[i-1].tr($_[1]+'SJQKA','a-z').reverse}
\$\endgroup\$
2
\$\begingroup\$

J, 47 bytes

1+[:(i.>./)_3+/\16!@-]i.~'SXAKQJT9876543'1}~1&{

Usage:

   (1+[:(i.>./)_3+/\16!@-]i.~'SXAKQJT9876543'1}~1&{) 'TH QC 9S 8S'
3

Method:

  • For every input char we assign a value based in its position in the 'S[second char of input]AKQJT9876543' string. Non-found chars get the value last position + 1 implicitly. Further characters have much less value (value=(16-position)!).
  • Compute the sum for the 3 input-char triplet and one duplet (e.g. TH_ QC_ 9S_and 8S).
  • Choose the 1-based index of the maximal value.

(J unfortunately can't compare chars or strings directly. It can only check for their equality which ruled out some other approaches for this challenge.)

Try it online here.

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

C#, 237

using System;namespace S{class P{static void Main(string[] a){var V="23456789TJQKA";int x=0;int y=0;var z=a[0][1];for(int i=0;i<4;i++){int q=V.IndexOf(a[i][0])+2;var w=a[i][1];q*=w==z?1:w=='S'?9:0;if(q>y){x=i;y=q;}}Console.Write(x+1);}}}

How it works: Iterate each hand to calculate the "value" of the card.. store the highest valued index. A cards value is determined as the rank of the card multiplied by 0 if it is not a spade or the opening suit, 1 if it is the opening suit and 9 if it is a spade but not the opening suit. (9 choosen b/c 2*9=18> A=14 & 9 is a single char)

\$\endgroup\$
1
\$\begingroup\$

Pyth, 36 33 bytes

KczdhxKeo,x,ehK\SeNXhN"TKA""AYZ"K

Fairly straightforward approach, uses sorting with a custom key function, then finds the index of the highest value.

\$\endgroup\$
3
  • \$\begingroup\$ Did you try avoiding the sort and just find the highest value? In JavaScript that turned out to be shorter \$\endgroup\$
    – edc65
    Apr 20, 2015 at 10:09
  • \$\begingroup\$ @edc65 In Pyth there is no operation to find the highest value, just to sort. But with one character (e) you can get the last element, so finding the highest value is just sorting followed by getting the last element. \$\endgroup\$
    – orlp
    Apr 20, 2015 at 11:00
  • \$\begingroup\$ Downvoter, care to explain? \$\endgroup\$
    – orlp
    Apr 21, 2015 at 13:58
1
\$\begingroup\$

Pyth, 31 bytes

hxczdeo}\SNo}@z1Zox"TJQKA"hNScz

Try it here.

How it works:

The proper way to read this procedure is back to front. The procedure sorts the desired card to the end of the list, then pulls it out and finds its index in the original list.

  • cz: This generates the list of card strings. c, chop, is normally a binary function (arity 2), but when called on only one input, serves as the .split() string method.

  • S: This applies the normal sorting behavior, which sorts lower numbered cards before higher ones.

  • ox"TJQKA"hN: This orders the cards by the index (x) in the string "TJQKA" of the first letter of the card (hN). For cards with numbers, the first letter is not found, giving the result -1. Since Pyth's sorting function is stable, the numbered cards' order is not affected.

  • o}@z1Z: Next we order by whether the suit of the first card played (@z1) is in the card in question. Since True sorts behind False, this sends cards of the lead suit to the back.

  • o}\SN: This is the same as the sort before, but it sorts on whether the letter S is in the card, sending spades to the back.

  • hxczde: This extracts the last card sorted this way (e), finds its index in the list of cards (xczd) and increments by 1 (h), giving the desired player location.

\$\endgroup\$
1
\$\begingroup\$

Python, 172 bytes

l=input().split(" ")
s="23456789TJQKA"
h=l[0]
for c in l:
  if c[1] not in [h[1],"S"]:
    continue
  if s.index(h[0])>s.index(c[0]):
    continue
  h=c
print(l.index(h)+1)

There wasn't a Python answer here, so I fixed that :)

Simply compares the cards, discarding them if they are of a different suit to the current highest (and not a spade), then if they are of a lower value. At the end, simply get the highest card, and add 1 to its index.

\$\endgroup\$

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.