aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-11-28 02:43:01 +0000
committerGitHub <noreply@github.com>2022-11-28 02:43:01 +0000
commit4a0736675714e2285c79506fa53e85505d028ecb (patch)
treefea6901812e8a38e1875ed5da3da8b2461b621d2
parentbfd764e1bd9c861cd92064e74a327e9b80732e12 (diff)
parent395ae0a74243c7e4a7aca93fb7bbf83675ce5dbc (diff)
downloadperlweeklychallenge-club-4a0736675714e2285c79506fa53e85505d028ecb.tar.gz
perlweeklychallenge-club-4a0736675714e2285c79506fa53e85505d028ecb.tar.bz2
perlweeklychallenge-club-4a0736675714e2285c79506fa53e85505d028ecb.zip
Merge pull request #7167 from Util/branch-for-challenge-192
Add TWC 192 blog post and solutions by Bruce Gray (Raku, Perl, and Rust)
-rw-r--r--challenge-192/bruce-gray/blog.txt1
-rw-r--r--challenge-192/bruce-gray/perl/ch-1.pl17
-rw-r--r--challenge-192/bruce-gray/perl/ch-2.pl65
-rw-r--r--challenge-192/bruce-gray/raku/ch-1.raku27
-rw-r--r--challenge-192/bruce-gray/raku/ch-2.raku54
-rw-r--r--challenge-192/bruce-gray/rust/ch-1.rs35
-rw-r--r--challenge-192/bruce-gray/rust/ch-2.rs73
7 files changed, 272 insertions, 0 deletions
diff --git a/challenge-192/bruce-gray/blog.txt b/challenge-192/bruce-gray/blog.txt
new file mode 100644
index 0000000000..2bac4e7dde
--- /dev/null
+++ b/challenge-192/bruce-gray/blog.txt
@@ -0,0 +1 @@
+http://blogs.perl.org/users/bruce_gray/2022/11/twc-192-frosting-a-cake-without-flipping-the-spatula.html
diff --git a/challenge-192/bruce-gray/perl/ch-1.pl b/challenge-192/bruce-gray/perl/ch-1.pl
new file mode 100644
index 0000000000..2197d0a95f
--- /dev/null
+++ b/challenge-192/bruce-gray/perl/ch-1.pl
@@ -0,0 +1,17 @@
+use v5.36;
+sub task1 ($n) {
+ return oct '0b' . sprintf('%b', $n) =~ tr/01/10/r;
+}
+
+
+my @tests = (
+ [ 5, 2 ],
+ [ 4, 3 ],
+ [ 6, 1 ],
+);
+use Test::More;
+plan tests => 0+@tests;
+for (@tests) {
+ my ( $in, $expected ) = @{$_};
+ is task1($in), $expected, "task1($in) == $expected";
+}
diff --git a/challenge-192/bruce-gray/perl/ch-2.pl b/challenge-192/bruce-gray/perl/ch-2.pl
new file mode 100644
index 0000000000..497d1c6930
--- /dev/null
+++ b/challenge-192/bruce-gray/perl/ch-2.pl
@@ -0,0 +1,65 @@
+use v5.36;
+use List::Util qw<sum0 reductions>;
+sub functional ( @a ) {
+ my $s = sum0 @a;
+
+ return -1 if $s % @a;
+ my $target = $s / @a;
+
+ return sum0 map { abs $_ }
+ reductions { $a + $b }
+ map { $_ - $target }
+ @a;
+}
+sub task2 ( @a ) {
+ return -1 if sum0(@a) % scalar(@a);
+ my $target = sum0(@a) / scalar(@a);
+
+ my ($count, $mound) = 0, 0;
+ for my $n (@a) {
+ $mound += $n - $target;
+ $count += abs $mound;
+ }
+
+ die "Cannot happen: $mound" unless $mound == 0;
+
+ return $count;
+}
+
+my @tests = (
+ # Examples from task:
+ [ [1, 0, 5], 4 ],
+ [ [0, 2, 0], -1 ],
+ [ [0, 3, 0], 2 ],
+
+ # Invented:
+ [ [4,0,0,0], 6],
+ [ [3,1,0,0], 5],
+ [ [3,0,1,0], 4],
+ [ [3,0,0,1], 3],
+ [ [2,2,0,0], 4],
+ [ [2,0,2,0], 2],
+ [ [2,0,0,2], 2],
+ [ [2,1,1,0], 3],
+ [ [2,1,0,1], 2],
+ [ [2,0,1,1], 1],
+ [ [1,1,1,1], 0],
+ [ [1,2,1,0], 2],
+ [ [1,2,0,1], 1],
+ [ [1,1,2,0], 1],
+ [ [1,1,0,2], 1],
+
+ [ [2+(8*1000), 2, 2, 2, 2, 2, 2, 2], 1000*sum0(1..7) ],
+ [ [2, 2, 2, 2, 2, 2, 2, 2+(8*1000)], 1000*sum0(1..7) ],
+ [ [2, 2, 2, 2, 2, 2, 2+(8*1000), 2], 1000*sum0(1..6, 1) ],
+
+ [ [6,3,3,3,3,0,3,3,3,3,0,1,3,3,3,6,5], 15+15+10], # For the blog post
+);
+
+use Test::More;
+plan tests => 2*@tests;
+for (@tests) {
+ my ( $in_aref, $expected ) = @{$_};
+ is task2(@{$in_aref}), $expected;
+ is functional(@{$in_aref}), $expected;
+}
diff --git a/challenge-192/bruce-gray/raku/ch-1.raku b/challenge-192/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..4af0b6a0ab
--- /dev/null
+++ b/challenge-192/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,27 @@
+# Faster, by about 10x
+sub all_ones ( UInt $n --> UInt ) { ( 1 +< ($n.log2.floor + 1) ) - 1 }
+sub fast1 ( UInt $n --> UInt ) { $n +^ all_ones($n) }
+
+# Clearer:
+sub task1 ( UInt $n --> UInt ) {
+ return $n.base(2)
+ .trans( <0 1> => <1 0> )
+ .parse-base(2);
+}
+
+
+my @tests =
+ ( 5, 2 ),
+ ( 4, 3 ),
+ ( 6, 1 ),
+;
+use Test;
+plan +@tests + 1;
+for @tests -> ( $in, $expected ) {
+ is task1($in), $expected, "task1($in) == $expected";
+}
+{
+ my Range $r = 1 .. (2 ** 14);
+ my Bool $ok = not defined first { .&task1 != .&fast1 }, $r.list;
+ ok $ok, "Two different approaches over {$r.raku}";
+}
diff --git a/challenge-192/bruce-gray/raku/ch-2.raku b/challenge-192/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..afadbcea43
--- /dev/null
+++ b/challenge-192/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,54 @@
+# Because I still have 60-characters-worth of residual evil left over from Halloween:
+sub golfed(@a){(@a.sum!%%+@a)??-1!!([\+](@a X-(@a.sum div+@a)))».abs.sum}
+
+sub task2 ( @a --> Int ) {
+ return -1 if @a.sum !%% +@a;
+
+ my $target = @a.sum div @a.elems;
+
+ my ($count, $mound) = 0, 0;
+ for @a -> $a {
+ $mound += $a - $target;
+ $count += $mound.abs;
+ }
+
+ die "Cannot happen: $mound" unless $mound == 0;
+
+ return $count;
+}
+
+my @tests =
+ # Examples from task:
+ ( (1, 0, 5), 4 ),
+ ( (0, 2, 0), -1 ),
+ ( (0, 3, 0), 2 ),
+
+ # Invented:
+ ( (4,0,0,0), 6),
+ ( (3,1,0,0), 5),
+ ( (3,0,1,0), 4),
+ ( (3,0,0,1), 3),
+ ( (2,2,0,0), 4),
+ ( (2,0,2,0), 2),
+ ( (2,0,0,2), 2),
+ ( (2,1,1,0), 3),
+ ( (2,1,0,1), 2),
+ ( (2,0,1,1), 1),
+ ( (1,1,1,1), 0),
+ ( (1,2,1,0), 2),
+ ( (1,2,0,1), 1),
+ ( (1,1,2,0), 1),
+ ( (1,1,0,2), 1),
+
+ ( (2+(8*1000), 2, 2, 2, 2, 2, 2, 2), 1000*(1..7).sum ),
+ ( (2, 2, 2, 2, 2, 2, 2, 2+(8*1000)), 1000*(1..7).sum ),
+ ( (2, 2, 2, 2, 2, 2, 2+(8*1000), 2), 1000*(|(1..6),1).sum ),
+ ( (6,3,3,3,3,0,3,3,3,3,0,1,3,3,3,6,5), 15+15+10), # For the blog post
+;
+
+use Test;
+plan 2*@tests;
+for @tests -> ( $in, $expected ) {
+ is task2($in), $expected;
+ is golfed($in), $expected;
+}
diff --git a/challenge-192/bruce-gray/rust/ch-1.rs b/challenge-192/bruce-gray/rust/ch-1.rs
new file mode 100644
index 0000000000..9a5a39be34
--- /dev/null
+++ b/challenge-192/bruce-gray/rust/ch-1.rs
@@ -0,0 +1,35 @@
+fn flip_bits(n: u32) -> u32 {
+ let all_ones = (n + 1).next_power_of_two() - 1;
+
+ return n ^ all_ones;
+}
+
+// Run with either of:
+// rustc --test rust/ch-1.rs && ./ch-1
+// rustc rust/ch-1.rs && ./ch-1 99999
+
+fn main() {
+ let n: u32 = std::env::args().nth(1).expect("missing command-line argument")
+ .parse().expect("failed to parse");
+
+ println!("flip_bits({}) == {}", n, flip_bits(n));
+}
+
+#[test]fn task_example_01() { assert_eq!(flip_bits( 5), 2) }
+#[test]fn task_example_02() { assert_eq!(flip_bits( 4), 3) }
+#[test]fn task_example_03() { assert_eq!(flip_bits( 6), 1) }
+#[test]fn test_range_1_64() {
+
+ let got: Vec<u32> = (1..(64+1)).map(flip_bits).collect();
+
+ assert_eq!(got, vec![
+ 0,
+ 1, 0,
+ 3, 2, 1, 0,
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 63
+ ])
+}
diff --git a/challenge-192/bruce-gray/rust/ch-2.rs b/challenge-192/bruce-gray/rust/ch-2.rs
new file mode 100644
index 0000000000..729c90d211
--- /dev/null
+++ b/challenge-192/bruce-gray/rust/ch-2.rs
@@ -0,0 +1,73 @@
+// Run with either of:
+// rustc --test rust/ch-2.rs && ./ch-2
+// rustc rust/ch-2.rs && ./ch-2 3 6 3
+
+fn task2 ( a : Vec<i32> ) -> i32 {
+ let sum : i32 = a.iter().sum();
+ let len : i32 = a.len() as i32;
+
+ if sum % len != 0 {
+ return -1;
+ }
+
+ let target = sum / len;
+
+ // Raku code: ( [\+] ( @a X- target ) )».abs.sum
+ return a.iter()
+ .scan(0, |state, &x| { *state += x - target; Some(*state) })
+ .map(|x| { x.abs() })
+ .sum();
+}
+
+fn main () {
+ let input : Vec<i32> = std::env::args()
+ .skip(1)
+ .map(|x| { x.parse::<i32>().unwrap() })
+ .collect();
+
+ assert!( !input.is_empty(), "Error: Need integer arguments on the command-line" );
+
+ println!("task2({:?}) = {:?}", input.clone(), task2(input));
+}
+
+#[test]fn task_example_01() { assert_eq!(task2( vec![1, 0, 5] ), 4) }
+#[test]fn task_example_02() { assert_eq!(task2( vec![0, 2, 0] ), -1) }
+#[test]fn task_example_03() { assert_eq!(task2( vec![0, 3, 0] ), 2) }
+
+#[test]fn test_misc_01() { assert_eq!(task2( vec![4,0,0,0] ), 6) }
+#[test]fn test_misc_02() { assert_eq!(task2( vec![3,1,0,0] ), 5) }
+#[test]fn test_misc_03() { assert_eq!(task2( vec![3,0,1,0] ), 4) }
+#[test]fn test_misc_04() { assert_eq!(task2( vec![3,0,0,1] ), 3) }
+#[test]fn test_misc_05() { assert_eq!(task2( vec![2,2,0,0] ), 4) }
+#[test]fn test_misc_06() { assert_eq!(task2( vec![2,0,2,0] ), 2) }
+#[test]fn test_misc_07() { assert_eq!(task2( vec![2,0,0,2] ), 2) }
+#[test]fn test_misc_08() { assert_eq!(task2( vec![2,1,1,0] ), 3) }
+#[test]fn test_misc_09() { assert_eq!(task2( vec![2,1,0,1] ), 2) }
+#[test]fn test_misc_10() { assert_eq!(task2( vec![2,0,1,1] ), 1) }
+#[test]fn test_misc_11() { assert_eq!(task2( vec![1,1,1,1] ), 0) }
+#[test]fn test_misc_12() { assert_eq!(task2( vec![1,2,1,0] ), 2) }
+#[test]fn test_misc_13() { assert_eq!(task2( vec![1,2,0,1] ), 1) }
+#[test]fn test_misc_14() { assert_eq!(task2( vec![1,1,2,0] ), 1) }
+#[test]fn test_misc_15() { assert_eq!(task2( vec![1,1,0,2] ), 1) }
+
+#[test]fn test_large_01() {
+ let got = task2( vec![2 + (8*1000), 2, 2, 2, 2, 2, 2, 2] );
+ let expected = 1000 * (1..(7+1)).sum::<i32>();
+ assert_eq!(got, expected);
+}
+#[test]fn test_large_02() {
+ let got = task2( vec![2, 2, 2, 2, 2, 2, 2, 2 + (8*1000)] );
+ let expected = 1000 * (1..(7+1)).sum::<i32>();
+ assert_eq!(got, expected);
+}
+#[test]fn test_large_03() {
+ let got = task2( vec![2, 2, 2, 2, 2, 2, 2 + (8*1000), 2] );
+ let expected = 1000 * (1+(1..(6+1)).sum::<i32>());
+ assert_eq!(got, expected);
+}
+
+#[test]fn for_blog_post_01() {
+ let got = task2( vec![6,3,3,3,3,0,3,3,3,3,0,1,3,3,3,6,5] );
+ let expected = 15+15+10;
+ assert_eq!(got, expected);
+}