aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubos Kolouch <lubos@kolouch.net>2025-09-16 12:25:09 +0200
committerLubos Kolouch <lubos@kolouch.net>2025-09-16 12:50:05 +0200
commita445a4de5501bcd731883b25ad138bace3417a8b (patch)
treedffeb343fcc80a52f5d53f4b5e92609259aeec21
parent65fdce07ae9b197000d4c64b9f1699cef16befe8 (diff)
downloadperlweeklychallenge-club-a445a4de5501bcd731883b25ad138bace3417a8b.tar.gz
perlweeklychallenge-club-a445a4de5501bcd731883b25ad138bace3417a8b.tar.bz2
perlweeklychallenge-club-a445a4de5501bcd731883b25ad138bace3417a8b.zip
Add challenge 336 solutions for Lubos
-rw-r--r--challenge-336/lubos-kolouch/README76
-rw-r--r--challenge-336/lubos-kolouch/perl/ch-1.pl80
-rw-r--r--challenge-336/lubos-kolouch/perl/ch-2.pl83
-rw-r--r--challenge-336/lubos-kolouch/python/ch-1.py45
-rw-r--r--challenge-336/lubos-kolouch/python/ch-2.py48
5 files changed, 332 insertions, 0 deletions
diff --git a/challenge-336/lubos-kolouch/README b/challenge-336/lubos-kolouch/README
index 921b2d9f4a..a8bfeee6c2 100644
--- a/challenge-336/lubos-kolouch/README
+++ b/challenge-336/lubos-kolouch/README
@@ -1 +1,77 @@
Solutions by Lubos Kolouch.
+
+# The Weekly Challenge - 336
+
+## Task 1: Equal Group
+
+### Description
+
+Given an array of integers, determine whether it can be partitioned into one or
+more groups of equal size (at least two elements per group) such that every
+member within a group has the same value.
+
+### Solution
+
+#### Perl (ch-1.pl)
+
+Counts occurrences of each value, ensures every frequency is at least two, and
+computes the greatest common divisor across the frequencies. A GCD of two or
+more confirms that the array can be divided into uniform groups. Embedded
+`Test::More` cases cover the official examples.
+
+#### Python (ch-1.py)
+
+Uses `collections.Counter` and `math.gcd` to mirror the Perl logic. Type hints
+and `unittest` tests verify the five examples supplied in the challenge.
+
+### Examples
+
+- Example 1: `[1, 1, 2, 2, 2, 2]` → `True`
+- Example 2: `[1, 1, 1, 2, 2, 2, 3, 3]` → `False`
+- Example 3: `[5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7]` → `True`
+- Example 4: `[1, 2, 3, 4]` → `False`
+- Example 5: `[8, 8, 9, 9, 10, 10, 11, 11]` → `True`
+
+## Task 2: Final Score
+
+### Description
+
+Given a sequence of scoring operations consisting of integers, `C`, `D`, and
+`+`, compute the final total. `C` removes the previous score, `D` doubles it,
+and `+` adds the last two scores.
+
+### Solution
+
+#### Perl (ch-2.pl)
+
+Maintains a stack of recorded scores, applying each operation as specified, and
+returns the sum of the stack. `Test::More` subtests cover the challenge cases.
+
+#### Python (ch-2.py)
+
+Implements the same stack-based logic using type annotations and `unittest`
+coverage for the provided examples.
+
+### Examples
+
+- Example 1: `["5", "2", "C", "D", "+"]` → `30`
+- Example 2: `["5", "-2", "4", "C", "D", "9", "+", "+"]` → `27`
+- Example 3: `["7", "D", "D", "C", "+", "3"]` → `45`
+- Example 4: `["-5", "-10", "+", "D", "C", "+"]` → `-55`
+- Example 5: `["3", "6", "+", "D", "C", "8", "+", "D", "-2", "C", "+"]` → `128`
+
+## Running the Code
+
+### Perl
+
+```bash
+perl ch-1.pl
+perl ch-2.pl
+```
+
+### Python
+
+```bash
+python3 ch-1.py
+python3 ch-2.py
+```
diff --git a/challenge-336/lubos-kolouch/perl/ch-1.pl b/challenge-336/lubos-kolouch/perl/ch-1.pl
new file mode 100644
index 0000000000..3a4a7d6f10
--- /dev/null
+++ b/challenge-336/lubos-kolouch/perl/ch-1.pl
@@ -0,0 +1,80 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+=head1 NAME
+
+ch-1.pl - The Weekly Challenge 336 Task 1: Equal Group
+
+=head1 DESCRIPTION
+
+Determine whether an array of integers can be partitioned into one or more
+groups so that:
+
+=over 4
+
+=item * all groups have the same size (at least two members), and
+
+=item * all values inside each group are identical.
+
+=back
+
+The implementation counts occurrences of each value and verifies that the
+greatest common divisor of the counts is at least two.
+
+=head1 AUTHOR
+
+Lubos Kolouch
+
+=cut
+
+use List::Util qw(all reduce);
+use Test::More tests => 5;
+
+use constant IntArray => 'ARRAY';
+
+sub _gcd {
+ my ( $a, $b ) = @_;
+ ( $a, $b ) = ( abs $a, abs $b );
+ return $a if $b == 0;
+ return _gcd( $b, $a % $b );
+}
+
+sub equal_group {
+ my (@ints) = @_;
+ return 0 if @ints < 2;
+
+ my %freq;
+ $freq{$_}++ for @ints;
+ my @counts = values %freq;
+
+ return 0 if !all { $_ >= 2 } @counts;
+
+ my $gcd = reduce { _gcd( $a, $b ) } @counts;
+ return $gcd >= 2 ? 1 : 0;
+}
+
+subtest 'Example 1' => sub {
+ my @ints = ( 1, 1, 2, 2, 2, 2 );
+ ok( equal_group(@ints), 'Groups (1,1), (2,2), (2,2)' );
+};
+
+subtest 'Example 2' => sub {
+ my @ints = ( 1, 1, 1, 2, 2, 2, 3, 3 );
+ ok( !equal_group(@ints), 'Cannot group equally' );
+};
+
+subtest 'Example 3' => sub {
+ my @ints = ( 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7 );
+ ok( equal_group(@ints), 'Groups of size 6' );
+};
+
+subtest 'Example 4' => sub {
+ my @ints = ( 1, 2, 3, 4 );
+ ok( !equal_group(@ints), 'Distinct values cannot group' );
+};
+
+subtest 'Example 5' => sub {
+ my @ints = ( 8, 8, 9, 9, 10, 10, 11, 11 );
+ ok( equal_group(@ints), 'Pairs of equal values' );
+};
diff --git a/challenge-336/lubos-kolouch/perl/ch-2.pl b/challenge-336/lubos-kolouch/perl/ch-2.pl
new file mode 100644
index 0000000000..8aceb3b007
--- /dev/null
+++ b/challenge-336/lubos-kolouch/perl/ch-2.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+=head1 NAME
+
+ch-2.pl - The Weekly Challenge 336 Task 2: Final Score
+
+=head1 DESCRIPTION
+
+Compute the total score for a sequence of operations. Each entry is one of:
+
+=over 4
+
+=item * an integer representing a new score,
+
+=item * C<'C'> to invalidate and remove the previous score,
+
+=item * C<'D'> to record double the previous score, or
+
+=item * C<'+'> to add the sum of the previous two scores.
+
+=back
+
+The solution tracks scores on a stack and sums the remaining values.
+
+=head1 AUTHOR
+
+Lubos Kolouch
+
+=cut
+
+use List::Util qw(sum0);
+use Test::More tests => 5;
+
+use constant ScoreList => 'ARRAY';
+
+sub final_score {
+ my (@entries) = @_;
+ my @record;
+
+ for my $entry (@entries) {
+ if ( $entry eq 'C' ) {
+ pop @record;
+ }
+ elsif ( $entry eq 'D' ) {
+ push @record, 2 * $record[-1];
+ }
+ elsif ( $entry eq '+' ) {
+ push @record, $record[-1] + $record[-2];
+ }
+ else {
+ push @record, 0 + $entry;
+ }
+ }
+
+ return sum0(@record);
+}
+
+subtest 'Example 1' => sub {
+ my @scores = qw(5 2 C D +);
+ is( final_score(@scores), 30, 'Total score 30' );
+};
+
+subtest 'Example 2' => sub {
+ my @scores = qw(5 -2 4 C D 9 + +);
+ is( final_score(@scores), 27, 'Total score 27' );
+};
+
+subtest 'Example 3' => sub {
+ my @scores = qw(7 D D C + 3);
+ is( final_score(@scores), 45, 'Total score 45' );
+};
+
+subtest 'Example 4' => sub {
+ my @scores = qw(-5 -10 + D C +);
+ is( final_score(@scores), -55, 'Total score -55' );
+};
+
+subtest 'Example 5' => sub {
+ my @scores = qw(3 6 + D C 8 + D -2 C +);
+ is( final_score(@scores), 128, 'Total score 128' );
+};
diff --git a/challenge-336/lubos-kolouch/python/ch-1.py b/challenge-336/lubos-kolouch/python/ch-1.py
new file mode 100644
index 0000000000..2643543a6d
--- /dev/null
+++ b/challenge-336/lubos-kolouch/python/ch-1.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+"""The Weekly Challenge 336 Task 1: Equal Group."""
+from collections import Counter
+from math import gcd
+import unittest
+
+IntList = list[int]
+
+
+def equal_group(ints: IntList) -> bool:
+ """Return True if values can be partitioned into equal homogeneous groups."""
+ if len(ints) < 2:
+ return False
+
+ counts = Counter(ints)
+ if any(count < 2 for count in counts.values()):
+ return False
+
+ group_size = 0
+ for count in counts.values():
+ group_size = gcd(group_size, count)
+ return group_size >= 2
+
+
+class TestEqualGroup(unittest.TestCase):
+ """Unit tests using the provided examples."""
+
+ def test_example1(self) -> None:
+ self.assertTrue(equal_group([1, 1, 2, 2, 2, 2]))
+
+ def test_example2(self) -> None:
+ self.assertFalse(equal_group([1, 1, 1, 2, 2, 2, 3, 3]))
+
+ def test_example3(self) -> None:
+ self.assertTrue(equal_group([5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7]))
+
+ def test_example4(self) -> None:
+ self.assertFalse(equal_group([1, 2, 3, 4]))
+
+ def test_example5(self) -> None:
+ self.assertTrue(equal_group([8, 8, 9, 9, 10, 10, 11, 11]))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/challenge-336/lubos-kolouch/python/ch-2.py b/challenge-336/lubos-kolouch/python/ch-2.py
new file mode 100644
index 0000000000..a7dc021f95
--- /dev/null
+++ b/challenge-336/lubos-kolouch/python/ch-2.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+"""The Weekly Challenge 336 Task 2: Final Score."""
+import unittest
+
+ScoreList = list[str]
+
+
+def final_score(scores: ScoreList) -> int:
+ """Calculate the total score from a list of operations."""
+ record: list[int] = []
+ for entry in scores:
+ if entry == "C":
+ record.pop()
+ elif entry == "D":
+ record.append(2 * record[-1])
+ elif entry == "+":
+ record.append(record[-1] + record[-2])
+ else:
+ record.append(int(entry))
+ return sum(record)
+
+
+class TestFinalScore(unittest.TestCase):
+ """Unit tests derived from the specification examples."""
+
+ def test_example1(self) -> None:
+ self.assertEqual(final_score(["5", "2", "C", "D", "+"]), 30)
+
+ def test_example2(self) -> None:
+ self.assertEqual(
+ final_score(["5", "-2", "4", "C", "D", "9", "+", "+"]), 27)
+
+ def test_example3(self) -> None:
+ self.assertEqual(final_score(["7", "D", "D", "C", "+", "3"]), 45)
+
+ def test_example4(self) -> None:
+ self.assertEqual(final_score(["-5", "-10", "+", "D", "C", "+"]), -55)
+
+ def test_example5(self) -> None:
+ self.assertEqual(
+ final_score(
+ ["3", "6", "+", "D", "C", "8", "+", "D", "-2", "C", "+"]),
+ 128,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()