#!/usr/bin/perl
use strict;
use warnings;
use List::Util 'sum';
my %straight = (3 => \&straight_3, 4 => \&straight_4, 5 => \&straight_5);
my @deck = map { ($_) x 4 } 1 .. 9;
push @deck, (10) x 16;
my $iter = combo(5, @deck);
my %seen;
open(my $fh, '>', 'crib.dat') or die $!;
my $n;
while (my @hand = $iter->()) {
next if $seen{"@hand"}++;
my %card;
++$card{$_} for @hand;
my $score = 0;
# Determine if last card is 10
my $is_10 = $hand[-1] == 10 ? 1 : 0;
# if every card is < 10, calculate 2/3/4 of a kind
if (! $is_10) {
$score += $_ * ($_ - 1) for values %card;
}
# Can't possibly be a flush if 2/3/4 of a kind exceeds 1 pair
my $check_flush = $score > 2 ? 0 : 1;
# if every card is < 10, calculate straights
if (! $is_10) {
my @val = sort {$a <=> $b} keys %card;
my ($len, $beg, $end) = $straight{@val}->(@val) if @val > 2; # my and if together
if ($len) { $len *= $card{$_} for @val[$beg .. $end] }
$score += $len || 0;
}
# Calculate 15s
my $fifteen = 0;
for (2 .. 5) {
my $next = combo($_, @hand);
while (my $sum = sum($next->())) {
++$fifteen if $sum == 15;
}
}
$score += 2 * $fifteen;
$_ = $_ == 10 ? 'T' : $_ for @hand;
my $flags = ! $is_10 && ! $check_flush ? 0 : $is_10 && $check_flush ? 3 : $is_10 ? 1 : 2;
$score = sprintf("%.2d", $score);
print $fh join "", @hand, $flags, $score;
print $fh "\n" if not ++$n % 10;
}
sub straight_3 {
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
}
sub straight_4 {
return (4, 0, 3) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
return (3, 1, 3) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
}
sub straight_5 {
return (5, 0, 4) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
return (4, 0, 3) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (4, 1, 4) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
return (3, 1, 3) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (3, 2, 4) if $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
}
sub combo {
my $by = shift;
return sub { () } if ! $by || $by =~ /\D/ || @_ < $by;
my @list = @_;
my @position = (0 .. $by - 2, $by - 2);
my @stop = @list - $by .. $#list;
my $end_pos = $#position;
my $done = undef;
return sub {
return () if $done;
my $cur = $end_pos;
{
if ( ++$position[ $cur ] > $stop[ $cur ] ) {
$position[ --$cur ]++;
redo if $position[ $cur ] > $stop[ $cur ];
my $new_pos = $position[ $cur ];
@position[ $cur .. $end_pos ] = $new_pos .. $new_pos + $by;
}
}
$done = 1 if $position[0] == $stop[0];
return @list[ @position ];
}
}
####
package Cribbage::Hand;
use strict;
use warnings;
use constant SCORE => 0;
use constant HAS_10 => 1;
use constant CHK_FLSH => 2;
my %prescore;
{
while () {
chomp;
my $temp = 'A8' x (length($_) / 8);
for (unpack($temp, $_)) {
my $hand = join ' ', map $_ eq 'T' ? 10 : $_, unpack('AAAAA', $_);
my $flag = substr($_, 5, 1);
my ($has_10, $chk_flsh) = $flag == 0 ? (0, 0) : $flag == 1 ? (1, 0) : $flag == 2 ? (0, 1) : (1, 1);
my $score = sprintf("%d", substr($_, -2));
$prescore{$hand} = [$score, $has_10, $chk_flsh];
}
}
}
my %val = (
A => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7,
8 => 8, 9 => 9, T => 10, J => 10, Q => 10, K => 10,
);
my %ord = (
A => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7,
8 => 8, 9 => 9, T => 10, J => 11, Q => 12, K => 13,
);
my %rev = reverse %ord;
my %straight = (3 => \&straight_3, 4 => \&straight_4, 5 => \&straight_5);
sub straight_3 {
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
}
sub straight_4 {
return (4, 0, 3) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
return (3, 1, 3) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
}
sub straight_5 {
return (5, 0, 4) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
return (4, 0, 3) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (4, 1, 4) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
return (3, 0, 2) if $_[1] - $_[0] == 1 && $_[2] - $_[1] == 1;
return (3, 1, 3) if $_[2] - $_[1] == 1 && $_[3] - $_[2] == 1;
return (3, 2, 4) if $_[3] - $_[2] == 1 && $_[4] - $_[3] == 1;
}
sub score {
my $str = shift;
my %card;
++$card{$_} for unpack('AxAxAxAxAx', $str);
my @by_val = sort {$a <=> $b} map { ($val{$_}) x $card{$_} } keys %card;
my $info = $prescore{"@by_val"};
my $score = $info->[SCORE];
# If T/J/Q/K need to ...
if ($info->[HAS_10]) {
# Check for 2/3/4 of a kind
$score += $_ * ($_ - 1) for values %card;
# Check for straights
my @val = sort {$a <=> $b} @ord{keys %card};
my ($len, $beg, $end) = $straight{@val}->(@val) if @val > 2; # my and if together
if ($len) { $len *= $card{$rev{$_}} for @val[$beg .. $end] }
$score += $len || 0;
# Check for right jack
my %jack = map { $_ => 1 } substr($str, 0, 8) =~ /(?<=J)(.)/g;
++$score if $jack{ substr($str, -1, 1) };
}
# Check for flush
if ($info->[CHK_FLSH]) {
my %suit = map {$_ => undef} unpack('xAxAxAxA', $str);
if (keys %suit == 1) {
$score += 4;
$score += 1 if substr($str, 1, 1) eq substr($str, -1, 1);
}
}
return $score;
}
__DATA__
11112012111130121111401211115012111160121111701211118012111190121111T30011122008
111230151112400611125006111260061112700611128006111290061112T3021113300811134006
11135006111360061113700611138006111390081113T30611144008111450061114600611147006
11148008111490121114T30611155008111560061115700811158012111590121115T30211166010
1116701211168012111690081116T3001117701411178008111790061117T3001118800811189006
1118T300111990081119T300111TT300112220081122301611224004112250041122600411227004
11228004112290061122T30411233016112342101123520811236208112372081123821011239212
1123T3041124400411245202112462021124720411248206112492061124T3041125500411256204
1125720611258206112592061125T302112660081126720611268206112692041126T30011277008
11278204112792021127T30011288004112892021128T300112990041129T300112TT30011333008
1133400411335004113360041133700611338008113390061133T304113440041134520511346204
1134720611348204113492041134T30611355006113562061135720411358204113592061135T304
113660061136720411368206113692041136T3021137700811378204113792021137T30211388004
113892021138T302113990041139T302113TT3041144400811445006114460081144700611448004
114490081144T30811455008114562071145720211458204114592081145T3061146600411467204
11468206114692061146T3041147700811478204114792041147T30411488004114892041148T304
114990081149T306114TT30811555010115560041155700411558008115590121155T30411566004
1156720711568208115692081156T3021157700811578206115792061157T3021158800811589208
1158T304115990121159T306115TT304116660081166700811668012116690081166T30011677012
11678213116792061167T30211688012116892081168T304116990081169T302116TT30011777020
11778012117790081177T30411788008117892071178T302117990041179T300117TT30011888008
118890041188T300118990041189T300118TT300119990081199T300119TT30011TTT30012222012
122230151222400612225006122260061222700612228008122290081222T3061223301612234210
12235208122362081223721012238210122392121223T30612244004122452021224620412247204
12248206122492061224T30412255006122562041225720612258206122592041225T30412266008
1226720612268204122692041226T3021227700612278204122792021227T3021228800412289202
1228T302122990041229T302122TT304123330151233421012335208123362101233721012338210
123392141233T3041234421012345207123462061234720612348208123492081234T30412355207
123562051235720712358205123592071235T304123662091236720512368205123692071236T302
1237720712378205123792051237T30212388205123892051238T302123992091239T304123TT304
1244400812445204124462041244720412448206124492061244T304124552041245620512457202
12458204124592041245T304124662041246720212468204124692041246T3021247720412478204
124792021247T30212488206124892041248T304124992061249T304124TT3041255500812556202
1255720612558206125592061255T304125662041256720712568204125692041256T30212577208
12578206125792041257T30412588206125892041258T304125992061259T304125TT30412666012
1266720812668208126692081266T3021267720812678209126792041267T3021268820612689204
1268T302126992061269T302126TT3001277701212778208127792041277T3021278820612789205
1278T302127992021279T300127TT30012888006128892021288T300128992021289T300128TT300
129990061299T300129TT30012TTT300133330121333400613335008133360081333700613338012
133390121333T3001334400613345210133462021334720613348208133492041334T30213355004
133562061335720613358204133592061335T302133660081336720213368206133692061336T300
1337700613378206133792041337T30013388008133892061338T302133990081339T302133TT300
1344400813445208134462041344720813448206134492021344T304134552101345620813457207
13458205134592051345T304134662041346720213468204134692021346T3021347720813478206
134792021347T30413488206134892021348T304134992021349T302134TT3041355500813556206
1355720613558202135592061355T304135662081356720713568204135692061356T30413577208
13578204135792041357T30413588202135892021358T302135992061359T304135TT30413666012
1366720413668208136692081366T3021367720413678207136792021367T3001368820613689204
1368T302136992061369T302136TT3001377701213778208137792041377T3021378820613789205
1378T302137992021379T300137TT30013888006138892021388T300138992021389T300138TT300
139990061399T300139TT30013TTT300144440121444500614446012144470121444800614449006
1444T30614455008144562141445720414458202144592041445T306144660081446720614468206
144692061446T3061447701014478206144792041447T30614488004144892021448T30414499004
1449T304144TT30814555014145562141455720414558204145592081455T3081456621214567206
14568207145692091456T3061457720414578202145792021457T30414588202145892021458T304
145992061459T306145TT308146660061466720214668206146692061466T3021467720414678207
146792021467T30214688206146892041468T304146992061469T304146TT3041477701214778208
147792041477T30414788206147892051478T304147992021479T302147TT3041488800614889202
1488T302148992021489T302148TT304149990061499T302149TT30414TTT3061555502015556008
1555700815558008155590141555T308155660041556720815568204155692081556T30415577006
15578204155792061557T30415588004155892061558T304155990121559T308155TT30815666006
1566720815668206156692081566T3021567721015678208156792071567T3021568820615689206
1568T304156992101569T306156TT3041577701215778208157792061577T3041578820615789207
1578T304157992061579T304157TT30415888006158892041588T302158992061589T304158TT304
159990121599T306159TT30615TTT306166660121666700616668012166690121666T30016677006
16678214166792061667T30016688012166892101668T304166990121669T304166TT30016777012
16778216167792061677T30216788216167892101678T304167992061679T302167TT30016888012
168892081688T304168992081689T304168TT302169990121699T304169TT30216TTT30017777024
17778018177790121777T30617788014177892141778T306177990061779T302177TT30217888012
178892121788T304178992101789T302178TT302179990061799T300179TT30017TTT30018888012
188890061888T300188990041889T300188TT300189990061899T300189TT30018TTT30019999012
1999T300199TT30019TTT3001TTTT300222230122222401222225012222260122222701422228012
222290202222T300222330082223401522235006222360082223700622238012222390082223T306
2224400822245008222460062224701222248006222490142224T300222550082225601222257006
22258012222590082225T302222660082226701222268006222690102226T3002227700822278008
222790082227T30022288008222890082228T300222990122229T302222TT3002233300822334016
22335006223360042233700822338008223390062233T30822344018223452102234621222347210
22348212223492122234T30422355008223562042235720422358208223592022235T30622366006
2236720622368204223692042236T3042237700422378206223792022237T3042238800822389204
2238T306223990042239T304223TT308224440082244500822446004224470102244800422449012
2244T30022455004224562092245720422458206224592062245T302224660042246720822468202
224692082246T3002247700822478206224792082247T30222488004224892062248T30022499012
2249T304224TT30022555010225560082255700422558012225590042255T3042256600822567211
22568208225692062256T3042257700422578208225792022257T30222588012225892062258T306
225990042259T302225TT304226660082266701222668004226690082266T3002267701222678211
226792082267T30422688004226892042268T300226990082269T302226TT3002277700822778008
227790042277T30022788008227892072278T302227990042279T300227TT3002288800822889004
2288T300228990042289T300228TT300229990082299T300229TT30022TTT3002333301223334017
23335006233360082333701223338006233390122333T30623344016233452122334621223347210
23348212233492122334T30423355008233562022335720823358204233592042335T30623366008
2336720623368202233692062336T3042337700823378206233792062337T3062338800423389204
2338T304233990082339T306233TT308234440172344521223446212234472102344821223449212
2344T30223455212234562092345720623458208234592062345T304234662112346720723468207
234692092346T3042347720523478207234792052347T30223488209234892072348T30423499209
2349T304234TT30423555014235562042355720823558208235592042355T3082356620423567207
23568202235692022356T3042357720623578206235792022357T30623588206235892022358T306
235992022359T304235TT308236660122366720823668204236692082366T3042367720623678207
236792042367T30423688202236892022368T302236992062369T304236TT3042377700623778206
237792022377T30223788206237892052378T304237992022379T302237TT3042388800623889202
2388T302238992022389T302238TT304239990062399T302239TT30423TTT3062444401224445012
244460062444701224448006244490122444T3002445500824456214244572062445820624459208
2445T304244660042446720624468202244692082446T3002447700824478206244792082447T302
24488004244892062448T300244990122449T304244TT30024555008245562122455720224558206
245592042455T304245662122456720824568207245692092456T304245772022457820424579202
2457T30224588206245892042458T304245992062459T304245TT304246660062466720624668202
246692082466T3002467720624678207246792062467T30224688202246892042468T30024699210
2469T304246TT3002477700624778206247792042477T30024788206247892072478T30224799206
2479T302247TT30024888006248892042488T300248992062489T302248TT300249990122499T304
249TT30224TTT30025555020255560082555700825558014255590082555T3082556600425567210
25568206255692042556T3042557700425578208255792022557T30425588012255892062558T308
255990042559T304255TT308256660062566721225668204256692062566T3022567721225678210
256792072567T30425688206256892042568T304256992062569T304256TT3042577700625778208
257792022577T30225788210257892072578T306257992022579T302257TT3042588801225889206
2588T306258992042589T304258TT306259990062599T302259TT30425TTT3062666601226667012
26668006266690122666T3002667701226678214266792102667T30426688004266892062668T300
266990122669T304266TT3002677701226778216267792082677T30426788214267892102678T304
267992082679T304267TT30226888006268892042688T300268992062689T302268TT30026999012
2699T304269TT30226TTT3002777701227778012277790062777T30027788012277892122778T304
277990042779T300277TT30027888012278892122788T304278992102789T302278TT30227999006
2799T300279TT30027TTT30028888012288890062888T300288990042889T300288TT30028999006
2899T300289TT30028TTT300299990122999T300299TT30029TTT3002TTTT3003333401233335012
333360203333701233338012333390243333T3003334400833345021333460083334700633348012
333490123334T30033355008333560083335701233358006333590123335T3023336601833367008
33368008333690163336T3023337700833378008333790123337T30033388008333890123338T300
333990203339T306333TT3003344401233445020334460043344700633448012334490063344T300
33455020334562143345721433458214334592123345T30433466008334672023346820633469206
3346T3003347700433478208334792043347T30033488012334892083348T304334990083349T302
334TT30033555010335560043355701233558004335590063355T304335660083356720933568202
335692063356T3023357701233578208335792083357T30633588004335892043358T30233599008
3359T304335TT304336660203366700833668008336690143366T304336770043367820733679206
3367T30033688004336892063368T300336990123369T304336TT300337770083377800833779006
3377T30033788008337892093378T302337990083379T302337TT30033888008338890063388T300
338990083389T302338TT300339990143399T304339TT30233TTT300344440203444501734446008
3444701434448014344490083444T30234455016344562143445721234458212344592083445T302
344660063446720434468206344692043446T3003447700834478210344792043447T30234488012
344892063448T304344990043449T300344TT3003455501734556214345572123455821034559208
3455T304345662163456720934568208345692083456T3043457720934578209345792053457T304
34588209345892053458T304345992053459T302345TT30434666012346672043466820634669208
3466T3023467720234678207346792023467T30034688206346892043468T302346992063469T302
346TT3003477700634778208347792023477T30034788210347892073478T304347992023479T300
347TT30034888012348892063488T304348992043489T302348TT302349990063499T300349TT300
34TTT30035555020355560083555701435558008355590083555T308355660063556721235568202
355692043556T3043557701235578208355792063557T30835588004355892023558T30435599004
3559T304355TT308356660123566721235668204356692083566T304356772123567820835679207
3567T30435688202356892023568T302356992063569T304356TT304357770123577821035779206
3577T30635788208357892073578T306357992043579T304357TT30635888006358892023588T302
358992023589T302358TT304359990063599T302359TT30435TTT306366660243666701236668012
366690183666T3063667700636678212366792083667T30236688006366892083668T30236699014
3669T306366TT3023677700636778212367792043677T30036788212367892083678T30236799206
3679T302367TT30036888006368892043688T300368992063689T302368TT300369990123699T304
369TT30236TTT3003777701237778012377790063777T30037788012377892123778T30437799004
3779T300377TT30037888012378892123788T304378992103789T302378TT302379990063799T300
379TT30037TTT30038888012388890063888T300388990043889T300388TT300389990063899T300
389TT30038TTT300399990123999T300399TT30039TTT3003TTTT300444450124444601244447024
44448012444490124444T30044455008444560214445701244458006444590064445T30244466008
4446701244468006444690084446T3004447702044478014444790124447T3064448800844489006
4448T300444990084449T300444TT30044555010445560244455700644558004445590044455T304
445660244456721644568212445692144456T3064457700844578206445792044457T30444588004
445892024458T302445990044459T302445TT304446660084466700644668004446690084466T300
4467700844678209446792064467T30244688004446892044468T300446990084469T302446TT300
4477701444778012447790084477T30444788010447892094478T304447990064479T302447TT302
44888008448890044488T300448990044489T300448TT300449990084499T300449TT30044TTT300
45555020455560234555700845558008455590084555T30845566024455672144556821245569214
4556T3084557700445578204455792024557T30445588004455892024558T304455990044559T304
455TT308456660214566721445668212456692164566T3064567721245678209456792084567T304
45688207456892074568T304456992114569T306456TT3064577700645778206457792024577T302
45788206457892054578T304457992024579T302457TT30445888006458892024588T30245899202
4589T302458TT304459990064599T302459TT30445TTT30646666012466670064666800646669012
4666T3004667700446678210466792064667T30046688004466892064668T300466990124669T304
466TT3004677700646778212467792044677T30046788212467892084678T302467992064679T302
467TT30046888006468892044688T300468992064689T302468TT300469990124699T304469TT302
46TTT3004777701247778012477790064777T30047788012477892124778T304477990044779T300
477TT30047888012478892124788T304478992104789T302478TT302479990064799T300479TT300
47TTT30048888012488890064888T300488990044889T300488TT300489990064899T300489TT300
48TTT300499990124999T300499TT30049TTT3004TTTT30055556020555570205555802055559020
5555T316555660105556701755568008555690105556T3085557701055578010555790085557T308
55588010555890085558T308555990105559T308555TT31455666008556670165566800455669008
5566T3045567701655678212556792105567T30455688004556892045568T304556990085569T306
556TT3085577700855778008557790045577T30455788008557892075578T306557990045579T304
557TT30855888008558890045588T304558990045589T304558TT308559990085599T304559TT308
55TTT312566660125666701556668006566690125666T3025667701656678212566792125667T302
56688004566892065668T302566990125669T306566TT3045677701556778214567792105677T302
56788214567892095678T304567992095679T304567TT30456888006568892045688T30256899206
5689T304568TT304569990125699T306569TT30656TTT3065777701257778012577790065777T302
57788012577892125778T306577990045779T302577TT30457888012578892125788T30657899210
5789T304578TT306579990065799T302579TT30457TTT30658888012588890065888T30258899004
5889T302588TT304589990065899T302589TT30458TTT306599990125999T302599TT30459TTT306
5TTTT3086666701266668012666690206666T3006667700866678017666790126667T30066688008
666890126668T300666990206669T306666TT3006677700866778020667790086677T30066788020
667892166678T302667990126679T304667TT30066888008668890086688T300668990126689T304
668TT300669990206699T308669TT30466TTT3006777701267778021677790086777T30067788024
677892166778T304677990086779T302677TT30067888021678892166788T304678992166789T304
678TT302679990126799T304679TT30267TTT30068888012688890086888T300688990086889T302
688TT300689990126899T304689TT30268TTT300699990206999T306699TT30469TTT3026TTTT300
77778020777790127777T30077788020777890217778T306777990087779T300777TT30077888020
778890247788T308778990207789T304778TT304779990087799T300779TT30077TTT30078888020
788890217888T306788990207889T304788TT304789990177899T302789TT30278TTT30279999012
7999T300799TT30079TTT3007TTTT300888890128888T300888990088889T300888TT30088999008
8899T300889TT30088TTT300899990128999T300899TT30089TTT3008TTTT3009999T300999TT300
99TTT3009TTTT300TTTTT300
##
##
#!/usr/bin/perl
use strict;
use warnings;
require Cribbage::Hand;
my @deck = map {$_ . 'H', $_ . 'S', $_ . 'C', $_ . 'D'} 2..9, qw/T J Q K A/;
my $next = combo(5, @deck);
while (my $hand = join '', $next->()) {
my $score = Cribbage::Hand::score($hand);
print "$hand\t$score\n";
}
sub combo {
my $by = shift;
return sub { () } if ! $by || $by =~ /\D/ || @_ < $by;
my @list = @_;
my @position = (0 .. $by - 2, $by - 2);
my @stop = @list - $by .. $#list;
my $end_pos = $#position;
my $done = undef;
return sub {
return () if $done;
my $cur = $end_pos;
{
if ( ++$position[ $cur ] > $stop[ $cur ] ) {
$position[ --$cur ]++;
redo if $position[ $cur ] > $stop[ $cur ];
my $new_pos = $position[ $cur ];
@position[ $cur .. $end_pos ] = $new_pos .. $new_pos + $by;
}
}
$done = 1 if $position[0] == $stop[0];
return @list[ @position ];
}
}
##
##
sh-2.04$ time ./example.pl
real 3m43.859s
user 3m12.483s
sys 0m0.062s