#!/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 ```