Who wins a Spades trick

19

1

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

xnor

Posted 2015-04-20T08:27:29.113

Reputation: 115 687

Answers

10

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

Jakube

Posted 2015-04-20T08:27:29.113

Reputation: 21 462

I give up, well played :P – orlp – 2015-04-20T11:14:34.803

I don't think the .e stuff is worth it - using o is 1 character shorter as I figure it. – isaacg – 2015-04-20T11:17:41.170

@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: – Jakube – 2015-04-20T11:22:56.610

1I 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. – isaacg – 2015-04-20T12:35:22.000

@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? – Jakube – 2015-04-20T12:53:35.133

Hm. Well, since I was thinking of adding a rotate function to Pyth, probably .r, I'll use that for the latter behavior and the reversal for X with the third argument omitted. Both will have a 2 character overhead. – isaacg – 2015-04-20T12:55:28.743

6

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

Optimizer

Posted 2015-04-20T08:27:29.113

Reputation: 25 836

3

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>

edc65

Posted 2015-04-20T08:27:29.113

Reputation: 31 086

3

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.

nutki

Posted 2015-04-20T08:27:29.113

Reputation: 3 634

2

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}

histocrat

Posted 2015-04-20T08:27:29.113

Reputation: 20 600

2

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.

randomra

Posted 2015-04-20T08:27:29.113

Reputation: 19 909

2

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)

CSCODE

Posted 2015-04-20T08:27:29.113

Reputation: 21

1

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.

orlp

Posted 2015-04-20T08:27:29.113

Reputation: 37 067

Did you try avoiding the sort and just find the highest value? In JavaScript that turned out to be shorter – edc65 – 2015-04-20T10:09:31.153

@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. – orlp – 2015-04-20T11:00:04.927

Downvoter, care to explain? – orlp – 2015-04-21T13:58:08.833

1

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.

isaacg

Posted 2015-04-20T08:27:29.113

Reputation: 39 268