in reply to calculating cribbage points

That's what arrays and loops are for!

my @c = split /,/, $hand; my $total = 0; # 2 cards for my $i1 (0..4) { for my $i2 ($i1+1..4) { $total += 2 if $c[$i1] + $c[$i2] == 15; } } # 3 cards for my $i1 (0..4) { for my $i2 ($i1+1..4) { for my $i3 ($i2+1..4) { $total += 2 if $c[$i1] + $c[$i2] + $c[$i3] == 15; } } } ...

But we can do better.

my @c = split /,/, $hand; my $total = 0; for my $i1 (0..4) { for my $i2 ($i1+1..4) { $total += 2 if $c[$i1] + $c[$i2] == 15; for my $i3 ($i2+1..4) { $total += 2 if $c[$i1] + $c[$i2] + $c[$i3] == 15; for my $i4 ($i3+1..4) { $total += 2 if $c[$i1] + $c[$i2] + $c[$i3] + $c[$i +4] == 15; for my $i5 ($i4+1..4) { $total += 2 if $c[$i1] + $c[$i2] + $c[$i3] + $ +c[$i4] + $c[$i5] == 15; } } } } }

Let's go further:

my @c = split /,/, $hand; my $total = 0; our $sum; for my $i1 (0..4) { local $sum = $i1; for my $i2 ($i1+1..4) { local $sum = $sum + $c[$i2]]; $total += 2 if $sum == 15; for my $i3 ($i2+1..4) { local $sum = $sum + $c[$i3]; $total += 2 if $sum == 15; for my $i4 ($i3+1..4) { local $sum = $sum + $c[$i4]; $total += 2 if $sum == 15; for my $i5 ($i4+1..4) { local $sum = $sum + $c[$i5]; $total += 2 if $sum == 15; } } } } }

Let's add optimizations:

my @c = split /,/, $hand; my $total = 0; our $sum; for my $i1 (0..4) { local $sum = $i1; for my $i2 ($i1+1..4) { local $sum = $sum + $c[$i2]]; $total += 2 if $sum == 15; next if $sum >= 15; for my $i3 ($i2+1..4) { local $sum = $sum + $c[$i3]; $total += 2 if $sum == 15; next if $sum >= 15; for my $i4 ($i3+1..4) { local $sum = $sum + $c[$i4]; $total += 2 if $sum == 15; next if $sum >= 15; for my $i5 ($i4+1..4) { local $sum = $sum + $c[$i5]; $total += 2 if $sum == 15; } } } } }

While I eliminated a lot of redundancy both visually and in the number of checks, I'm sure there's still a better *algorithm*.

Replies are listed 'Best First'.
Re^2: calculating cribbage points
by blokhead (Monsignor) on Mar 30, 2006 at 18:54 UTC
    If you want to abstract it a little step farther you can get rid of 5 levels of nested looping. All you're doing is looking at all subsets of cards. So using the power-set iterator from (tye)Re: Finding all Combinations, the code becomes much more high-level and reads more naturally: "For each subset of cards, check if their sum is 15" ... Whether it's overkill for cribbage, the OP must decide. I know cribbage is not usually generalized to >5 card hands ;)
    use List::Util 'sum'; sub combinations { ... } ## from [id://128293] my @c = split /,/, $hand; my $total = 0; my $iter = combinations(@c); while (my @subset = $iter->()) { $total += 2 if 15 == sum @subset; }
    You could also check for pairs inside that while loop, although runs would have to be calculated somewhere else.

    blokhead

Re^2: calculating cribbage points
by dracos (Sexton) on Mar 30, 2006 at 18:58 UTC
    Cool I knew there had to be a better way than brute force enthusiasm...