aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-03-30 17:54:24 +0200
committerJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-04-19 18:48:47 +0200
commit89e4d35a7a5a9396cd57c904d16ff01d63ce9648 (patch)
tree17d37d2fdaa87da610af9f824533163dc04cad9e
parent09b2eb8e9e0ba34dd5f3fa48882c6268855b8a78 (diff)
downloadperlweeklychallenge-club-89e4d35a7a5a9396cd57c904d16ff01d63ce9648.tar.gz
perlweeklychallenge-club-89e4d35a7a5a9396cd57c904d16ff01d63ce9648.tar.bz2
perlweeklychallenge-club-89e4d35a7a5a9396cd57c904d16ff01d63ce9648.zip
Challenge 044 task 1
-rwxr-xr-xchallenge-044/jo-37/perl/ch-1.pl60
1 files changed, 60 insertions, 0 deletions
diff --git a/challenge-044/jo-37/perl/ch-1.pl b/challenge-044/jo-37/perl/ch-1.pl
new file mode 100755
index 0000000000..0cceee6d39
--- /dev/null
+++ b/challenge-044/jo-37/perl/ch-1.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl -s
+
+use v5.16;
+use warnings;
+use Math::Prime::Util qw(forcomp todigits vecsum vecprod lastfor);
+use List::MoreUtils qw(zip6 zip);
+use experimental 'signatures';
+
+our ($digits, $sum, $help);
+$digits //= '123456789';
+$sum //= 100;
+
+die <<EOS if $help;
+usage: $0 [-digits=DIGITS] [-sum=SUM] [-help]
+
+-digits=DIGITS
+ digit string to be split into parts. Default: '123456789'
+
+-sum=SUM
+ sum to be produced from adding/substracting parts of DIGITS. Default: 100
+
+-help
+ this help text
+
+EOS
+
+### Input and Output
+
+say for combine_to($digits, $sum);
+
+
+### Implementation
+
+# Generalizing the task to arbitrary digit strings and sums.
+
+sub combine_to ($digits, $sum) {
+ my $len = length $digits;
+ my @out;
+ # Iterate over integer compositions.
+ forcomp {
+ # Split the digits into parts according to the current
+ # composition.
+ my @parts = $digits =~ /^@{[join('', map "(.{$_})", @_)]}$/;
+ # Loop over the signs for all but the first part (having a fixed
+ # sign of +1), represented by a number with the first bit of one
+ # in its binary representation.
+ for my $sb (2 ** (@_ - 1) .. 2 ** @_ - 1) {
+ # Convert number to signs.
+ my @signs = map $_ ? 1 : -1, todigits $sb, 2, @_;
+ # Multiply all parts with their sign and sum. Report a
+ # match.
+ if (vecsum(map vecprod(@$_), zip6 @parts, @signs) == $sum) {
+ # Convert 1/-1 to +/- removing the first.
+ my @ops = (map(chr(44 - $_), @signs[1..$#signs]), '');
+ push @out, "@{[zip @parts, @ops]}= $sum";
+ }
+ }
+ } $len, {amax => $len - 1};
+ @out;
+}