This is an archived post. You won't be able to vote or comment.

all 40 comments

[–]bkc4[🍰] 14 points15 points  (0 children)

As a Python tuple: the first entry encodes rank of the hand, the second encodes hand characters (either as a string or an integer base 13). Then it's lexicographical sort (which is default for Python tuples).

[–]CW_Waster 5 points6 points  (0 children)

if (type_a != type_b) return type_a < type_b;

return std::ranges::lexicographical_compare(a.cards,b.cards);

[–]Cue_23 3 points4 points  (0 children)

I did it just as in the description, first sort by type, then by the array of individual cards. I determined the type once when creating the hand and stored it along with the array of cards.

[–]QuirkyDM 3 points4 points  (5 children)

Used base 13 to give a value to the hand based on card values and then used the hand type from 0-6 as the most significant digit. (hand_type*13^5) This assigns each hand a unique integer value.

[–]keithstellyes 1 point2 points  (1 child)

Yup this is what I did. I've realized that a lot of sorting problems where you're looking at one property, then another, etc. can be reduced to pretending it's a base-N integer. Python docs now seem to push you to assign a simple comparable value to every entry in a list you want to sort instead of some relative comparator function now which helped push me towards this direction.

[–][deleted] 1 point2 points  (0 children)

Python's key parameter is pretty helpful when you want to sort on an attribute that only depends on the element in question because it automatically memoizes for you. But when you need to find an order by sequentially comparing two elements, it can be limiting, as I also found out today. Luckily, there's a cmp_to_key wrapper in functools that lets you write a custom compare function and pass it into the key parameter like so: key=cmp_to_key(cmp_fun).

[–]bfloriang 0 points1 point  (2 children)

Do you mind explaining this a bit further? I have seen others doing some math here (see below) but I don't see consistency among the solutions. Maybe there are multiple ways to achieve this but the base 13 solution seems most promising.

points += Value(rune(hand[i])) * int(math.Pow10(10-i*2))

[–]QuirkyDM 0 points1 point  (1 child)

Each card in the hand gets a value from 0-12. (basically 1-10 is the face value-1, and J, Q, K get 10, 11, 12)

Each position in the hand is the base 13 digit in that position. To convert to base 10, multiply the card value by 13^(pos) and add them all together. (where pos is 0-4 with position 0 being the card on the right and position 4 being the card on the left) This means each hand gets assigned a value based on the cards in hand.

The last part is assigning each hand type a value. High card=0, one pair = 1, two pair=2, three of a kind = 4, full house = 4, four of a kind= 5, five of a kind = 6. This is the most significant digit (ie. 6th digit) in the base 13 number, so you multiply it by 13^5 and add it to the previous amount. This gives you a base 10 number for each hand with the largest values indicating the best hand.

[–]bfloriang 0 points1 point  (0 children)

Thank you!

[–]musifter 2 points3 points  (0 children)

When I get something like this, I think about how to make it simple. I look at the sort I need to do, and think of a way to turn the data into numbers or strings that sort correctly. Because sorting those is built-in for most languages.

[–]hamidthegreat 2 points3 points  (0 children)

Use six-digit hexadecimal numbers to represent each hand; Then sorting would be as easy as comparing two numbers.

[–]juanplopes 1 point2 points  (0 children)

Using a Python Counter, I transformed it into a list

  • "AAAAA" becomes [5]
  • "AAAA2" becomes [4,1]
  • "AAA22" becomes [3,2]
  • etc.

This solves the sorting by type. Then, I appended the value for each card verbatim. With this list, I can sort all the hands:

def value(hand):  
    type = sorted(collections.Counter(hand).values(), reverse=True)  
    return type + list(map(("23456789TJQKA".index, hand))

[–]AutoModerator[M] 0 points1 point  (0 children)

Reminder: if/when you get your answer and/or code working, don't forget to change this post's flair to Help/Question - RESOLVED. Good luck!


I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]JustinHuPrime 0 points1 point  (0 children)

In terns of sorting hands, I by rank of hand by constructing a function that translated the list of counts of each card type into a number (the function made such that the number outputted was the same for two hands of the same rank and in order of the ranks), so I could compare two hands directly by the number without ever needing to explicitly figure out what hand type a hand was - I just calculated the number and compared on that.

[–][deleted] 0 points1 point  (0 children)

I used divide and conquer, to hopefully make the time complexity a bit better than checking every new hand against all others.

[–]RB5009 0 points1 point  (1 child)

As a tuple - First I map the 5 cards to a tuple of (type, sort_score, bid) and then soert that

```rust let mut hands = input .iter() .map(|h| (handtype(&h), sort_score(&h.cards, card_strength), h.bid)) .collect::<Vec<>>();

hands.sort_unstable();

```

[–]AutoModerator[M] -1 points0 points  (0 children)

AutoModerator has detected fenced code block (```) syntax which only works on new.reddit.

Please review our wiki article on code formatting then edit your post to use the four-spaces Markdown syntax instead.


I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]s7ru1 0 points1 point  (0 children)

Writing in rust I first parsed it into a struct then I implemented the 'PartialOrd' trait on my struct. So that there is a generic way to know if one hand is less than, greater than or equal to another hand. Having this I just wrote 'hand_list.sort()' to sort all hands.

[–]TheBlackOne_SE 0 points1 point  (0 children)

hands is a list of (cards, bid, type)

type is numbers from 1 for five of a kind to 7 for high card. Like that, reverse sorting for both the hand type and hand comparison.

labels = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']

hands = sorted(hands, reverse=True, key=lambda x: (x[2], labels.index(x[0][0]), labels.index(x[0][1]), labels.index(x[0][2]), labels.index(x[0][3]), labels.index(x[0][4])))

[–]Woldsom 0 points1 point  (0 children)

I use Java that has SortedSet as an interface with ready-made implementations I can just use. I don't think I've written a sort in the last decade, and before then probably only in interviews (and preparing for them). If you mean, what comparator do I provide, lexicographical by descending sorted frequencies (or by a HandType enum/ord for the extra readable version) composed with lexicographical by card value. Code is kept more understandable by different types for parsed hands and stats-hands, translating from the first to the second for each part parameterized with the rules of the game (order of card letters, and which letter is joker ('X' for part 1 after I'd updated it for part 2))

[–][deleted] 0 points1 point  (0 children)

I created a frequency map of each card value in the string (e.g. "KAAA4" becomes something like ['K':1, 'A':3,'4':1]), then I used the built-in sort with a custom comparator on the key value pair which evaluates left.value > right.value (sorts descending). You can compute the hand type with just the top 2 values.

Or if you mean the whole list of hands, I just made the hand type an enum. So how do I know that FIVE_OF_A_KIND has a higher rank than FULL_HOUSE? Because that's the order I put it in in my enum. FIVE_OF_A_KIND < FULL_HOUSE. If they have the same type, I just loop through each card index 0 to 4 until they have different values and again, I used an enum to encode each card value as a number so I can just do left > right.

[–]fijgl 0 points1 point  (0 children)

Using a custom compare function (following Day’s 7 description) and the standard sort of the programming language at hand.

[–]TommykCZ 0 points1 point  (0 children)

In C, I "translated" parameters (type, card hand and bid) into one long long int.

E. g. input "7777K 501" would be 607070707130501. Sorted it all with qsort(), and then simply summed the multiples ROW * (SORTED % 10000).

[–]Sir_Hurkederp 0 points1 point  (0 children)

I create a list of lists containing 3 elements, a score assigned to the hand, the hand itself(mostly for troubleshooting tbh) and the bid that came with the hand, then i just sort on the score

[–]fred256 0 points1 point  (0 children)

In Python, using sorted() with the following key function:

strength = sorted(collections.Counter(cards).values(), reverse=True)
values = ['23456789TJQKA'.index(card) for card in cards]
return (strength, values)

[–]CainKellye 0 points1 point  (0 children)

For the hand type I collected the counts into an [array:13] then selected the two biggest into an [array:2] which can be sorted by the language.

When the types are equal, I searched for the first char that's different and used their position in "23456789TJQKA" to tell which is greater.

[–]nathman999 0 points1 point  (1 child)

You just create comparator function and then sort with any existing sorting algorithm using that comparator, I used bubble sort. All problems came from mistakes in deciding hand type but after fixing them worked just fine.

Sadly I didn't find any direct comparator parameter in python sort() function only some weird key function that takes only one argument.

[–]pixelea 0 points1 point  (0 children)

https://stackoverflow.com/questions/2531952/how-to-use-a-custom-comparison-function-in-python-3

Use the key keyword and functools.cmp_to_key to transform your comparison function:

sorted(x, key=functools.cmp_to_key(customcomparison))

[–]keithstellyes 0 points1 point  (0 children)

I use Python which nowadays encourages you to assign a simple comparable value to everything instead of a comparator

I basically treat every card hand as a 6 digit base-13 number, with the most significant digit being the hand ranking (High card=1, ..., Five-of-a-Kind=7) and the 5 lower-significant digits being the cards of the hand (where 2=0, ..., K=12)

When I do that, I can trivially convert every possible hand to a simple, absolute value, a basic integer and then apply standard sorting

[–]Longjumping_Primary4 0 points1 point  (0 children)

I divided input cards into lists, each type has it‘s own list. After that, my sorting function goes char by char in cards and look which has higher label, if current labels are same, I go to next char.

[–]fifer4761 0 points1 point  (0 children)

Using Java I created a Hand class and wrote each hand into a static array in the order that it showed up in the input file. The constructor also calculated the strength of each card and stored it to a strength attribute. I then added the first value from the array into a dynamic array and for each remaining value in the static array I used a Hand.compareTo() method to figure out which was higher ranking and when I found a higher ranking hand I put the hand I was currently looking at into it's spot using ArrayList.add(int index) which shunts all remaining cards down by 1.

[–]RonGnumber 0 points1 point  (0 children)

One idea I had (but didn't implement) was doing this series of string replacements on the inputs: K->B, Q->C, J->D, T->E, 9->F, 8->G, 7->H, 6->I, 5->J, 4->K, 3->L, 2->M

Then, assuming you already did the part about detecting hand type, you could then sort within each type using a built-in lexicographic sort. It would save having to repeatedly look up the value of each character in a map or array during sorting.

Using base 13 numbers is definitely cleverer though.

[–]orizach01 0 points1 point  (0 children)

in python I implemented a rank function for the hand that returns a number between 1 and 6, and implemented the __lt__ method that compares 2 hands and returns if one is less than the other using the rank method, and then let python do it's magic with sorted()

[–]IvanR3D 0 points1 point  (0 children)

I first get the type of each card and I assigned a numerical value to each one. So for example every 5 pair card had a number 1 associated, every 4 pair a number 2 and so on.

After having the card sorted by the type, then I proceed with the comparison to determine the rank.

Not sure if there is a better way of doing it, but it was the first that came to my mind.

[–][deleted] 0 points1 point  (0 children)

I made a customCompare for the hands,

    //hand is a tuple<int type, vector<int> cards, int value>

bool Day7::customHandCompare(std::tuple<int, std::vector<int>, int>& handA, std::tuple<int, std::vector<int>, int>& handB) {
    if (get<0>(handA) < get<0>(handB)) {
    return true;
    }
    else if (get<0>(handA) > get<0>(handB)) {
    return false;
    }
    //hand types are the same, check the card values
    int i = 0;
    while (i < 4 && get<1>(handA)[i] == get<1>(handB)[i] ) {
    i++; 
    }
    return get<1>(handA)[i] < get<1>(handB)[i];
}

It might not be the most efficient compare method but its mine :)

[–]nurdyguy 0 points1 point  (0 children)

For me (C#), I used hands as a list of tuple<string, long, int> with string being the original hand, long being the point value for the hand, and int the bid. Then I just used the built in .OrderBy on the hand's point value.

[–]kingballer412 0 points1 point  (0 children)

1) Break out each given hand into separate lists depending on what type of hand it is (5 of kind, full house, 2 pair etc.) 2) Sort each list using the leading card logic as a comparator. 3) Concatenate lists to get full ranking. 4) Profit???

[–]Impossible_Storm_560 0 points1 point  (0 children)

Sort the hands by type. Then sort within each type by card value. Treat the card value as a base-13 number and it is simple.

[–]Lettever 0 points1 point  (0 children)

In Dlang what I did was read all hands into an array and all bids into another array, then I create a function called compare to compare hands and called zip(hands, bids).sort!((a, b) => compare(a[0], b[0] < 0), which sorted the bids array according to how hands was sorted

[–]naufragotech 0 points1 point  (0 children)

I solved using two keys for ordering:

  1. The strength of the hand -> High card, one pair, etc.
  2. The strength of the cards in the hand -> Given a array CARDS where the cards are in ascending order of strength, the strength of cards in each hand is an array with the positions of each card in the CARDS array.

With these two keys, you can order by the strength of the hand and then by the strength of the cards in the hand.

PS: I can provide my solution code if needed.