aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2021-07-09 15:38:41 +0100
committerGitHub <noreply@github.com>2021-07-09 15:38:41 +0100
commitfa33a3f4a0df5999865744e2aaa031d4c231fc8b (patch)
treeb818b7b15c26f48ab2c16282c81587a4cec0ad05
parent59563d9c16649ef35dbd61cbf75f87e5507c6b20 (diff)
parent1502ed76b95ffcd630967448dc3e01aaf21a982c (diff)
downloadperlweeklychallenge-club-fa33a3f4a0df5999865744e2aaa031d4c231fc8b.tar.gz
perlweeklychallenge-club-fa33a3f4a0df5999865744e2aaa031d4c231fc8b.tar.bz2
perlweeklychallenge-club-fa33a3f4a0df5999865744e2aaa031d4c231fc8b.zip
Merge pull request #4466 from jo-37/contrib
Solutions to challenge 120
-rwxr-xr-xchallenge-120/jo-37/perl/ch-1.pl67
-rwxr-xr-xchallenge-120/jo-37/perl/ch-2.pl82
2 files changed, 149 insertions, 0 deletions
diff --git a/challenge-120/jo-37/perl/ch-1.pl b/challenge-120/jo-37/perl/ch-1.pl
new file mode 100755
index 0000000000..ca6f560789
--- /dev/null
+++ b/challenge-120/jo-37/perl/ch-1.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -s
+
+use v5.16;
+use Test2::V0;
+use experimental 'signatures';
+
+our ($tests, $examples);
+
+run_tests() if $tests || $examples; # does not return
+
+die <<EOS unless @ARGV;
+usage: $0 [-examples] [-tests] [N...]
+
+-examples
+ run the examples from the challenge
+
+-tests
+ run some tests
+
+N...
+ number(s)
+
+EOS
+
+
+### Input and Output
+
+say swap_bits($_) for @ARGV;
+
+
+### Implementation
+
+sub swap_bits ($n) {
+ no warnings 'portable';
+ # Set $odd to a mask with all odd bits set in the maximum internal
+ # representation.
+ # Oops! There was a restriction to N < 256 again. Realized it only
+ # after the full-size solution had been finished.
+ state $odd = hex 5 x ((unpack '%b*', pack 'j', -1) / 4);
+
+ # Right-shift even bits and left-shift odd bits.
+ ($n & ($odd << 1)) >> 1 | ($n & $odd) << 1;
+}
+
+
+### Examples and tests
+
+sub run_tests {
+ SKIP: {
+ skip "examples" unless $examples;
+
+ is swap_bits(101), 154, 'example 1';
+ is swap_bits(18), 33, 'example 2';
+ }
+
+ SKIP: {
+ skip "tests" unless $tests;
+
+ is swap_bits(0), 0, 'no bit set';
+ is swap_bits(~0), ~0, 'all bits set';
+ is swap_bits(0x55555555), 0xaaaaaaaa, 'odd to even';
+ is swap_bits(0xaaaaaaaa), 0x55555555, 'even to odd';
+ }
+
+ done_testing;
+ exit;
+}
diff --git a/challenge-120/jo-37/perl/ch-2.pl b/challenge-120/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..2ee102cb6d
--- /dev/null
+++ b/challenge-120/jo-37/perl/ch-2.pl
@@ -0,0 +1,82 @@
+#!/usr/bin/perl -s
+
+use v5.16;
+use Test2::V0;
+use experimental 'signatures';
+
+our ($tests, $examples);
+
+run_tests() if $tests || $examples; # does not return
+
+die <<EOS unless @ARGV;
+usage: $0 [-examples] [-tests] [time...]
+
+-examples
+ run the examples from the challenge
+
+-tests
+ run some tests
+
+time...
+ calculate the smaller angle between hour and minute hands for the
+ given time(s).
+
+EOS
+
+
+### Input and Output
+
+say clock_angle($_) // "invalid time: $_" for @ARGV;
+
+
+### Implementation
+
+# To find the smaller angle between the hands we need a "double
+# triangular" function in the range (-2m, 2m) with this shape:
+#
+# m /\ /\
+# / \ / \
+# / \ / \
+# 0 / \/ \
+# -2m -m 0 m 2m
+#
+# which is provided by: f(x) = m - abs(m - abs(x))
+#
+# The minute and hour hands move 6° and 0.5° per minute respectively,
+# resulting in a difference of 5.5° per minute.
+
+sub clock_angle ($time) {
+ # The accepted time format is [H]H:MM. Distinguishing between
+ # invalid time strings and a zero degree angle.
+ $time =~ /^([01]?\d|2[0-3]):([0-5]\d)$/ || undef and
+ 180 - abs 180 - abs $1 % 12 * 30 - 5.5 * $2;
+}
+
+
+### Examples and tests
+
+sub run_tests {
+ SKIP: {
+ skip "examples" unless $examples;
+
+ is clock_angle('03:10'), 35, 'example 1';
+ is clock_angle('04:00'), 120, 'example 2';
+ }
+
+ SKIP: {
+ skip "tests" unless $tests;
+
+ is clock_angle(12345), U(), 'not a valid time';
+ is clock_angle('25:00'), U(), 'not a valid hour';
+ is clock_angle('23:60'), U(), 'not a valid minute';
+ is clock_angle('0:00'), 0, 'omit leading zero';
+ is clock_angle('12:00'), 0, 'zero degrees';
+ is clock_angle('5:00'), 150, 'min to hour';
+ is clock_angle('7:00'), 150, 'hour to min';
+ # The smallest angles besides noon and midnight:
+ is clock_angle($_), 0.5, $_ for (qw(2:11 9:49 14:11 21:49));
+ }
+
+ done_testing;
+ exit;
+}