054 Poker hands.pl 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 28 August 2016
  4. # License: GPLv3
  5. # Website: https://github.com/trizen
  6. # Lazy, ugly and very rough implementation.
  7. # https://projecteuler.net/problem=54
  8. #~ In the card game poker, a hand consists of five cards and are ranked, from lowest to highest, in the following way:
  9. #~ High Card: Highest value card.
  10. #~ One Pair: Two cards of the same value.
  11. #~ Two Pairs: Two different pairs.
  12. #~ Three of a Kind: Three cards of the same value.
  13. #~ Straight: All cards are consecutive values.
  14. #~ Flush: All cards of the same suit.
  15. #~ Full House: Three of a kind and a pair.
  16. #~ Four of a Kind: Four cards of the same value.
  17. #~ Straight Flush: All cards are consecutive values of same suit.
  18. #~ Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
  19. #~ The cards are valued in the order:
  20. #~ 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
  21. use 5.014;
  22. use warnings;
  23. use List::Util qw(uniq max all);
  24. my %convert = (
  25. 'T' => '10',
  26. 'J' => '11',
  27. 'Q' => '12',
  28. 'K' => '13',
  29. 'A' => '14',
  30. );
  31. my @keys = keys %convert;
  32. sub numify {
  33. my ($card) = @_;
  34. [$card->[0] =~ s/^([@keys])/$convert{$1}/r, $card->[1]];
  35. }
  36. #<<<
  37. sub split_hand {
  38. my ($hand) = @_;
  39. [sort {
  40. ($a->[0] <=> $b->[0])
  41. || ($a->[1] cmp $b->[1])
  42. } map { numify($_) }
  43. map { [split(//, $_, 2)] } split(' ', $hand)];
  44. }
  45. #>>>
  46. sub royal_flush {
  47. my ($hand) = @_;
  48. $hand->[0][0] == 10
  49. and $hand->[1][0] == 11
  50. and $hand->[2][0] == 12
  51. and $hand->[3][0] == 13
  52. and $hand->[4][0] == 14;
  53. }
  54. sub straight {
  55. my ($hand) = @_;
  56. all { $hand->[$_][0] - $hand->[$_ - 1][0] == 1 } 1 .. $#{$hand};
  57. }
  58. sub straight_flush {
  59. my ($hand) = @_;
  60. my @suits = map { $_->[1] } @{$hand};
  61. uniq(@suits) == 1 or return;
  62. straight($hand);
  63. }
  64. sub n_pairs {
  65. my ($n, %h) = @_;
  66. (grep { $_ == 2 } values %h) == $n;
  67. }
  68. sub decide_winner {
  69. my ($h1, $h2) = @_;
  70. $h1 = split_hand($h1);
  71. $h2 = split_hand($h2);
  72. royal_flush($h1) && return 1;
  73. royal_flush($h2) && return 2;
  74. my (%t1, %t2);
  75. my (%u1, %u2);
  76. for (@$h1) {
  77. ++$u1{$_->[1]};
  78. ++$t1{$_->[0]};
  79. }
  80. for (@$h2) {
  81. ++$u2{$_->[1]};
  82. ++$t2{$_->[0]};
  83. }
  84. my %r1 = reverse(%t1);
  85. my %r2 = reverse(%t2);
  86. my %s1 = reverse(%u1);
  87. my %s2 = reverse(%u2);
  88. if (straight_flush($h1)) {
  89. if (straight_flush($h2)) {
  90. return ($h1->[-1] > $h2->[-1] ? 1 : 2);
  91. }
  92. return 1;
  93. }
  94. elsif (straight_flush($h2)) {
  95. return 2;
  96. }
  97. FOUR_OF_A_KIND:
  98. if (exists $r1{4}) {
  99. if (exists $r2{4}) {
  100. if ($r1{4} == $r2{4}) {
  101. $r1{1} == $r2{1} && goto FULL_HOUSE;
  102. return ($r1{1} > $r2{1} ? 1 : 2);
  103. }
  104. return ($r1{4} > $r2{4} ? 1 : 2);
  105. }
  106. return 1;
  107. }
  108. elsif (exists $r2{4}) {
  109. return 2;
  110. }
  111. FULL_HOUSE:
  112. if (exists($r1{3}) and exists($r1{2})) {
  113. if (exists($r2{3}) and exists($r2{2})) {
  114. if ($r1{3} == $r2{3}) {
  115. $r1{2} == $r2{2} && goto FLUSH;
  116. return ($r1{2} > $r2{2} ? 1 : 2);
  117. }
  118. return ($r1{3} > $r2{3} ? 1 : 2);
  119. }
  120. return 1;
  121. }
  122. elsif (exists($r2{3}) and exists($r2{2})) {
  123. return 2;
  124. }
  125. FLUSH:
  126. if (exists $s1{5}) {
  127. if (exists $s2{5}) {
  128. goto STRAIGHT;
  129. }
  130. return 1;
  131. }
  132. elsif (exists $s2{5}) {
  133. return 2;
  134. }
  135. STRAIGHT:
  136. if (straight($h1)) {
  137. if (straight($h2)) {
  138. return ($h1->[-1] > $h2->[-1] ? 1 : 2);
  139. }
  140. return 1;
  141. }
  142. elsif (straight($h2)) {
  143. return 2;
  144. }
  145. THREE_OF_A_KIND:
  146. if (exists $r1{3}) {
  147. if (exists $r2{3}) {
  148. $r1{3} == $r2{3} && goto TWO_PAIRS;
  149. return ($r1{3} > $r2{3} ? 1 : 2);
  150. }
  151. return 1;
  152. }
  153. elsif (exists $r2{3}) {
  154. return 2;
  155. }
  156. TWO_PAIRS:
  157. if (n_pairs(2, %t1)) {
  158. if (n_pairs(2, %t2)) {
  159. my @p1 = sort { $b <=> $a } grep { $t1{$_} == 2 } keys %t1;
  160. my @p2 = sort { $b <=> $a } grep { $t2{$_} == 2 } keys %t2;
  161. foreach my $i (0 .. $#p1) {
  162. if ($p1[$i] > $p2[$i]) {
  163. return 1;
  164. }
  165. elsif ($p2[$i] > $p1[$i]) {
  166. return 2;
  167. }
  168. }
  169. foreach my $i (reverse(1 .. 14)) {
  170. if (exists $t1{$i}) {
  171. if (not exists $t2{$i}) {
  172. return 1;
  173. }
  174. }
  175. elsif (exists $t2{$i}) {
  176. return 2;
  177. }
  178. }
  179. }
  180. return 1;
  181. }
  182. elsif (n_pairs(2, %t2)) {
  183. return 2;
  184. }
  185. ONE_PAIR:
  186. if (n_pairs(1, %t1)) {
  187. if (n_pairs(1, %t2)) {
  188. my $cmp = $r1{2} <=> $r2{2};
  189. if ($cmp > 0) {
  190. return 1;
  191. }
  192. elsif ($cmp < 0) {
  193. return 2;
  194. }
  195. else {
  196. delete $t1{$r1{2}};
  197. delete $t2{$r2{2}};
  198. goto HIGHEST_CARD;
  199. }
  200. }
  201. return 1;
  202. }
  203. elsif (n_pairs(1, %t2)) {
  204. return 2;
  205. }
  206. HIGHEST_CARD:
  207. (max(keys %t1) > max(keys %t2) ? 1 : 2);
  208. }
  209. my $count = 0;
  210. while (<>) {
  211. my (@game) = split(' ');
  212. my ($hand1, $hand2) = (join(' ', @game[0 .. 4]), join(' ', @game[5 .. 9]));
  213. my $winner = decide_winner($hand1, $hand2);
  214. ++$count if ($winner == 1);
  215. }
  216. say $count;