Skip to content

Commit

Permalink
Merge branch 'master' of github.com:chenshuo/recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
chenshuo committed Apr 4, 2013
2 parents fb864cb + 8420f2b commit 55da613
Show file tree
Hide file tree
Showing 7 changed files with 579 additions and 0 deletions.
22 changes: 22 additions & 0 deletions puzzle/poker/bench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/python

import time
import poker, poker2, generate

if __name__ == '__main__':

start = time.time()
max1 = max(generate.gen(5))
elapsed = time.time() - start
print ("%.4f" % (elapsed)), max1

start = time.time()
max2 = max(generate.gen(5), key=poker.score)
elapsed = time.time() - start
print ("%.4f" % (elapsed)), max2

start = time.time()
max3 = max(generate.gen(5), key=poker2.score2)
elapsed = time.time() - start
print ("%.4f" % (elapsed)), max3

20 changes: 20 additions & 0 deletions puzzle/poker/generate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/python

import itertools
import poker

def gen(num):
cards = []
ranks = '23456789TJQKA'
for rank in reversed(ranks):
for suit in 'SHDC':
cards.append(rank + suit)
return itertools.combinations(cards, num)

if __name__ == '__main__':
scores = []
for hand in gen(5):
scores.append((poker.score(hand), " ".join(hand)))
scores.sort(reverse=True)
for s in scores:
print s
198 changes: 198 additions & 0 deletions puzzle/poker/poker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include <algorithm>
#include <map>
#include <vector>

#include <assert.h>
#include <stdio.h>

// CAUTION: unreadable code

struct Card
{
int rank; // 2 .. 14 : 2 .. 9, T, J, Q, K, A
int suit; // 1 .. 4

Card() : rank(0), suit(0)
{
}
};

struct String
{
char str[16];
};

struct Hand
{
Card cards[5];

String toString() const
{
String result;
int idx = 0;
for (int i = 0; i < 5; ++i)
{
result.str[idx++] = "0123456789TJQKA"[cards[i].rank];
result.str[idx++] = " CDHS"[cards[i].suit];
result.str[idx++] = ' ';
}
assert(idx == 15);
result.str[14] = '\0';
return result;
}
};

struct Score
{
int score;
int ranks[5];
Hand hand;

bool operator<(const Score& rhs) const
{
return score < rhs.score
|| (score == rhs.score
&& std::lexicographical_compare(ranks, ranks+5, rhs.ranks, rhs.ranks+5));
}
};

struct Group
{
int count;
int rank;
bool operator<(const Group& rhs) const
{
return count > rhs.count
|| (count == rhs.count && rank > rhs.rank);
}
};

void fillGroups(const int ranks[], Group groups[], int* len)
{
int idx = -1;
int last_rank = 0;
for (int i = 0; i < 5; ++i)
{
if (ranks[i] == last_rank)
{
++groups[idx].count;
}
else
{
++idx;
++groups[idx].count;
groups[idx].rank = last_rank = ranks[i];
}
}
*len = idx+1;
std::sort(groups, groups+5);
}

Score getScore(const Hand& hand)
{
int ranks[5] = { 0, };
bool flush = true;
int suit = hand.cards[0].suit;
for (int i = 0; i < 5; ++i)
{
ranks[i] = hand.cards[i].rank;
flush = flush && suit == hand.cards[i].suit;
}
std::sort(ranks, ranks+5);

// 'A' is 1 for straight A, 2, 3, 4, 5
if (ranks[0] == 2
&& ranks[1] == 3
&& ranks[2] == 4
&& ranks[3] == 5
&& ranks[4] == 14)
{
ranks[0] = 1;
ranks[1] = 2;
ranks[2] = 3;
ranks[3] = 4;
ranks[4] = 5;
}

Group groups[5] = { { 0, }, };
int group_len = 0;
fillGroups(ranks, groups, &group_len);
assert(group_len <= 5);
bool straight = group_len == 5 && ranks[4] - ranks[0] == 4;
/*
for (int i = 0; i < group_len; ++i)
printf("%d %d, ", groups[i].count, groups[i].rank);
printf("\n");
*/

int score = 0;
if (group_len == 1)
score = 9;
else if (straight && flush)
score = 8;
else if (group_len == 2 && groups[0].count == 4)
score = 7;
else if (group_len == 2 && groups[0].count == 3)
score = 6;
else if (flush)
score = 5;
else if (straight)
score = 4;
else if (group_len == 3 && groups[0].count == 3)
score = 3;
else if (group_len == 3 && groups[0].count == 2)
score = 2;
else if (group_len == 4)
score = 1;
else
assert(group_len == 5);

Score result = { 0, };
result.score = score;
int idx = 0;
for (int i = 0; i < group_len; ++i)
for (int j = 0; j < groups[i].count; ++j)
result.ranks[idx++] = groups[i].rank;
assert(idx == 5);
result.hand = hand;

return result;
}

Hand formHand(int choose[])
{
Hand hand;
int c = 0;
for (int i = 0; i < 52; ++i)
{
if (choose[i])
{
hand.cards[c].rank = i / 4 + 2;
hand.cards[c].suit = i % 4 + 1;
++c;
if (c == 5)
break;
}
}
assert(c == 5);
return hand;
}

int main()
{
int choose[52] = { 1, 1, 1, 1, 1, 0, };
int count = 0;
std::vector<Score> scores;
do {
Hand hand(formHand(choose));
//puts(hand.toString().str);
Score score = getScore(hand);
scores.push_back(score);
++count;
} while (std::prev_permutation(choose, choose + 52));
std::sort(scores.begin(), scores.end());
for (auto it = scores.rbegin(); it != scores.rend(); ++it)
printf("((%d, [%d, %d, %d, %d, %d]), '%s')\n", it->score,
it->ranks[0], it->ranks[1], it->ranks[2], it->ranks[3], it->ranks[4],
it->hand.toString().str);
}
57 changes: 57 additions & 0 deletions puzzle/poker/poker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/python

import sys

def get_ranks(hand):
ranks = ['--23456789TJQKA'.index(r) for r, s in hand]
ranks.sort(reverse = True)
if ranks == [14, 5, 4, 3, 2]:
ranks = [5, 4, 3, 2, 1]
return ranks

def straight(ranks):
return len(set(ranks)) == 5 and (max(ranks) - min(ranks) == 4)

def flush(hand):
suits = [s for r, s in hand]
return len(set(suits)) == 1

def kind(n, ranks):
for r in ranks:
if ranks.count(r) == n:
return r
return None

def two_pair(ranks):
pair = kind(2, ranks)
lowpair = kind(2, list(reversed(ranks)))
if pair and lowpair != pair:
return (pair, lowpair)
else:
return None

def score(hand):
assert len(hand) == 5
ranks = get_ranks(hand)
if straight(ranks) and flush(hand):
return (8, max(ranks))
elif kind(4, ranks):
return (7, kind(4, ranks), kind(1, ranks))
elif kind(3, ranks) and kind(2, ranks):
return (6, kind(3, ranks), kind(2, ranks))
elif flush(hand):
return (5, ranks)
elif straight(ranks):
return (4, max(ranks))
elif kind(3, ranks):
return (3, kind(3, ranks), ranks)
elif two_pair(ranks):
return (2, two_pair(ranks), ranks)
elif kind(2, ranks):
return (1, kind(2, ranks), ranks)
else:
return (0, ranks)

if __name__ == '__main__':
hand = sys.argv[1:]
print score(hand)
46 changes: 46 additions & 0 deletions puzzle/poker/poker2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/python

import sys

def get_ranks(hand):
ranks = ['--23456789TJQKA'.index(r) for r, s in hand]
ranks.sort(reverse = True)
if ranks == [14, 5, 4, 3, 2]:
ranks = [5, 4, 3, 2, 1]
return ranks

def expand(counts, ranks):
cards = []
for i in range(len(counts)):
cards.extend((ranks[i], ) * counts[i])
return cards

def score2(hand):
assert len(hand) == 5
cards = get_ranks(hand)
assert len(cards) == len(hand)
groups = [(cards.count(x), x) for x in set(cards)]
groups.sort(reverse = True)
counts, ranks = zip(*groups)
cards = expand(counts, ranks)
assert sum(counts) == len(hand)
assert len(set(ranks)) == len(ranks)
straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
suits = [s for r, s in hand]
flush = len(set(suits)) == 1

if (5, ) == counts: score = 9
elif straight and flush: score = 8
elif (4, 1) == counts: score = 7
elif (3, 2) == counts: score = 6
elif flush: score = 5
elif straight: score = 4
elif (3, 1, 1) == counts: score = 3
elif (2, 2, 1) == counts: score = 2
elif (2, 1, 1, 1) == counts: score = 1
else: score = 0
return score, cards

if __name__ == '__main__':
hand = sys.argv[1:]
print score2(hand)
Loading

0 comments on commit 55da613

Please sign in to comment.