Create new instant answer for combinations and permutations
parent
71dedeac11
commit
3798fb6dab
|
@ -0,0 +1,90 @@
|
|||
package DDG::Goodie::Combination;
|
||||
# ABSTRACT: Compute combinations and permutations
|
||||
# Start at https://duck.co/duckduckhack/goodie_overview if you are new
|
||||
# to instant answer development
|
||||
|
||||
use DDG::Goodie;
|
||||
with 'DDG::GoodieRole::NumberStyler';
|
||||
|
||||
zci answer_type => "combination";
|
||||
zci is_cached => 1;
|
||||
|
||||
name "Combination";
|
||||
description "Computes combinations and permutations.";
|
||||
primary_example_queries "10 choose 3", "25 permute 16";
|
||||
secondary_example_queries "16 permutation 3";
|
||||
category "calculations";
|
||||
topics "math";
|
||||
code_url "https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Combination.pm";
|
||||
attribution github => ["richardscollin", "Collin Richards"];
|
||||
|
||||
triggers any => "any", "choose", "permute", "permutation";
|
||||
|
||||
my $number_re = number_style_regex();
|
||||
|
||||
# Handle statement
|
||||
handle query => sub {
|
||||
my $query = $_;
|
||||
return unless /^($number_re) (choose|permute|permutation) ($number_re)$/i;
|
||||
|
||||
my $style = number_style_for($1,$3);
|
||||
return unless $style; #Cannot determine number format
|
||||
my $operation = lc $2;
|
||||
|
||||
if ($operation eq 'permutation') {
|
||||
$operation = 'permute';#standardizes output for tests
|
||||
}
|
||||
|
||||
my $p1 = $style->for_computation($1);
|
||||
my $p2 = $style->for_computation($3);
|
||||
|
||||
#Ensure both are non-negative integers
|
||||
return unless $p1 =~ /^\d+$/ && $p2 =~ /^\d+$/;
|
||||
|
||||
#Do not try to calculate undefined combinations
|
||||
return unless $p1 >= $p2;
|
||||
|
||||
my $result;
|
||||
my %struct_ans;
|
||||
|
||||
if ('choose' eq $operation) {
|
||||
$result = $style->for_display(choose($p1, $p2));
|
||||
} else { #must be permute
|
||||
$result = $style->for_display(permute($p1, $p2));
|
||||
}
|
||||
|
||||
return $result,
|
||||
structured_answer => {
|
||||
input => [$style->for_display($p1) . " $operation " . $style->for_display($p2)],
|
||||
operation => $operation,
|
||||
result => $style->with_html($result),
|
||||
};
|
||||
};
|
||||
|
||||
#Computes the cumulative product of the numbers from $_[0] to $_[1] inclusive
|
||||
#Do not call when first parameter is greater then second.
|
||||
sub cumprod {
|
||||
my $acc = 1;
|
||||
for (my $i = $_[0]; $i <= $_[1]; $i++) {
|
||||
$acc *= $i;
|
||||
}
|
||||
return $acc;
|
||||
}
|
||||
|
||||
sub choose {
|
||||
my ($n, $k) = @_;
|
||||
|
||||
#optimiztion combination is semetric
|
||||
my $diff = $n - $k;
|
||||
if ($k > $diff) {
|
||||
$k = $diff;
|
||||
}
|
||||
return cumprod($n - $k + 1, $n) / cumprod(1, $k);
|
||||
}
|
||||
|
||||
sub permute {
|
||||
my ($n, $k) = @_;
|
||||
return cumprod($n - $k + 1, $n);
|
||||
}
|
||||
|
||||
1;
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
use DDG::Test::Goodie;
|
||||
|
||||
zci answer_type => "combination";
|
||||
zci is_cached => 1;
|
||||
|
||||
ddg_goodie_test(
|
||||
[qw( DDG::Goodie::Combination )],
|
||||
# At a minimum, be sure to include tests for all:
|
||||
# - primary_example_queries
|
||||
# - secondary_example_queries
|
||||
'10 choose 3' => test_zci('120',
|
||||
structured_answer => {
|
||||
input => ['10 choose 3'],
|
||||
operation => 'choose',
|
||||
result => '120',
|
||||
}
|
||||
),
|
||||
'25 permute 16' => test_zci('4.27447366714368 * 10^19',
|
||||
structured_answer => {
|
||||
input => ["25 permute 16"],
|
||||
operation => "permute",
|
||||
result => "4.27447366714368 * 10<sup>19</sup>"
|
||||
}
|
||||
),
|
||||
'16 permutation 3' => test_zci('3,360',
|
||||
structured_answer => {
|
||||
input => ["16 permute 3"],
|
||||
operation => "permute",
|
||||
result => "3,360"
|
||||
}
|
||||
),
|
||||
'15 permutation 0' => test_zci('1',
|
||||
structured_answer => {
|
||||
input => ["15 permute 0"],
|
||||
operation => "permute",
|
||||
result => "1"
|
||||
}
|
||||
),
|
||||
'1,000 choose 2' => test_zci('499,500',
|
||||
structured_answer => {
|
||||
input => ["1,000 choose 2"],
|
||||
operation => "choose",
|
||||
result => "499,500"
|
||||
}
|
||||
),
|
||||
'0 choose 100' => undef,
|
||||
'10 choose 100' => undef,
|
||||
'10.5 choose 1' => undef,
|
||||
'1.000,5 choose 2' => undef,
|
||||
);
|
||||
|
||||
done_testing;
|
Loading…
Reference in New Issue