Getting Oddly Even in a Clean Sweep

Wherein we clear the table by switching the balls around. But wait! Look at the time! Gotta go!

THE WEEKLY CHALLENGE – PERL & RAKU #120


episode one:
“Four-Card Full Monty”


Task 1

Swap Odd/Even bits

Submitted by: Mohammad S Anwar

You are given a positive integer $N less than or equal to 255.

Write a script to swap the odd positioned bit with even positioned bit and print the decimal equivalent of the new binary representation.

Example
Input: $N = 101
Output: 154

Binary representation of the given number is 01 10 01 01.
The new binary representation after the odd/even swap is 10 01 10 10.
The decimal equivalent of 10011010 is 154.

Input: $N = 18
Output: 33

Binary representation of the given number is 00 01 00 10.
The new binary representation after the odd/even swap is 00 10 00 01.
The decimal equivalent of 100001 is 33.

Method

Notice that the boundaries of the input are greater than 0, “a positive integer”, and less than or equal to 255, which is the largest number that can be represented with 8 binary bits. So the task is best understood to be to fit the input into a fixed 8-bit binary representation, with any leading zeros as required, and work on these 8 positions that we know to exist.

The first order of action is to convert the input into this set number of 0 and 1 digit characters, signifying bits, which we can do using sprintf or similar, using the “%08b” format specifier. This says we want “8 characters, 0-padded at the front to fill all 8 spaces, portrayed as the binary, ‘b’, representation of a number”. This is old-school formatting stuff that works.

Now the fun begins. How we proceed depends on what language we’re using.

PERL 5 SOLUTION

In Perl, we can parse our binary string using a regular expression.

We know the length of the string to be 8 characters exactly. By applying a global match against pairings of digits, 1s or 0s in any combination, we can divide our 8 characters into 4 groups of 2, returned as a list. In this list we use reverse in a scalar context to map each string to a reversed version of itself, swapping the characters. These mutated string bits are then rejoined with a “0b” prefix to indicate to oct that we wish to parse a string as though it were a binary number. This returns our altered bit string to the decimal number requested for output.

use warnings;
use strict;
use utf8;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';

my $num = shift // 18;

my $bin = sprintf "%08b", $num;
my $res = oct(join '', '0b', map { scalar reverse "$_" } $bin =~ /([01]{2})/g );

say<<"END";
input:  $num
output: $res

END

raku solution

In Raku, on the other hand, the control flow is, to pick a word, sublime. We have but-in functions that we can now chain to get the desired result.

  • fmt applies the sprintf-style conversion format
  • comb will divide a string along defined lines
  • map will apply flip to each of those segments
  • join reforms those segments back to the original 8-character string length
  • parse-base says to look at a string as a number written in a certain base
  • and then please tell us what you see

We even have extra time to install a little input validation to keep within our constraints.

unit sub MAIN ( Int $num where 0 < $num < 256 = 18 ) ;

$num.fmt("%08b")
    .comb(2)
    .map(*.flip)
    .join
    .parse-base(2)
    .say; 

episode two:
“Ever Hour We Come Together and Grow Apart”


task 2

Clock Angle

Submitted by: Mohammad S Anwar

You are given time $T in the format hh:mm.

Write a script to find the smaller angle formed by the hands of an analog clock at a given time.

HINT: A analog clock is divided up into 12 sectors. One sector represents 30 degree (360/12 = 30).

Example
Input: $T = '03:10'
Output: 35 degree

The distance between the 2 and the 3 on the clock is 30 degree.
For the 10 minutes i.e. 1/6 of an hour that have passed.
The hour hand has also moved 1/6 of the distance between the 3 and the 4, which adds 5 degree (1/6 of 30).
The total measure of the angle is 35 degree.

Input: $T = '04:00'
Output: 120 degree

Method

Rolex wristwatches, amongst horological enthusiasts, are known for their “sweep” second hand movement; that is to say the hand does not move incrementally, once a second, from one pip to the next, but rather is seen to move in a continuous flow around the dial. This action, it turns out, is remarkably difficult to achieve in a mechanical movement where the fundamental timekeeping period is based on an oscillating vibration, such as a pendulum. In fact it is ultimately illusionary, based in the end on a more rapidly alternating movement buffered by springs to appear more fluid, much like a collection of small discrete samples coming together to give the appearance of a smooth continuous line.

With the introduction of inexpensive, accurate electric motors in clocks much of the exotic panache of the sweep hand has gone away (although it still looks cool), and the Rolex has had to rely more on its rugged good looks and perhaps, maybe, the notion that its body is machined from a giant block of solid gold. But I digress. In a pendulum-driven clock movement the action is commonly designed to move with a two-second period: one across, and one back. This can be precisely tuned by adjusting the length of the pendulum arm, and forms the basis of all further internal timekeeping: each half-swing is one tick, 60 of these comprise a minute, with three thousand six hundred to an hour.

It’s not hard to make a clock with a sweep minute hand, where the hand makes one revolution per hour in as many increments as the pendulum allows. But this is not always advantagous: in a clock without a second hand, such as one would find in a clock-tower, having the minute hand fall between marks leads to ambiguity in reading. One person may see 43 minutes past the hour, another 42. It is often more desirable to have an internal mechanism ratchet along counting pendulum swings on a gear, and then only once a revolution have a pin engage a mechanism and move the minute hand one place. In this way the clock hand stays at 42 until the moment arrives, when it moves all at once to 43, where it remains for another minute until it moves again.

On the other, other hand, no mechanical clock does this for the hour hand. We go about our day and normally deal with time in a finer granularity than the hour, and hence knowing that it’s somewhere between 1 and 2 is useful information in itself to know.

So ignoring the second hand, in just the hours and minutes of many common clocks we have two modes of moving the hand: continuous and discrete. With respect to an angle swept from midnight — or noon — the minute hand will have moved six degrees every minute, always. As without further information we have no idea how many seconds have elapsed since the last minute tick we cannot improve on this calculation even if we wanted to.

For the hours, back to one of our previous other hands, the hand moves a set amount for each hour, but also takes a submovement between the pips based on dividing the interval between any two hour points into 60 minutes. The final sweep amount for the hand at any given time will be the sum of these two partial motions.

As for the angle between the hands, this angle will grow as the two indicators diverge every hour, but then, after reaching the antipodal position, the frame of reference switches to the opposite side of the circular face and the angle then starts to decrease. For our purposes we never consider a 270° difference, but rather the 90° angle swept around the other side. We end up with a difference of 0°, rising to a maximum of 180°, and then smoothly declining back to 0°.

We’ll need to watch for that. We have a continuous output from a function that has two discrete modes, up and down. We’ll need a switch.

PERL 5 SOLUTION

time: 12:55
57.5 degrees

In Perl we’ll do a systematic breakdown of the logical steps, one action to a line for the most part. For the purposes of the demonstration we won’t worry too much about whether our input is a well-formed time, as that only draws our eye away from the underlying logic. We’ll instead focus on the meat of the matter.

We can parse out the hours and minutes from the input string using a regular expression. Then we first need to accommodate the oddity in clock notation that the first hour after midnight or noon is 12, followed by 1, and there is no 0 hour on a 12-hour clock. We do this by running the hours modulo 12. The notated 12 will be changed to 0 and the rest of the possible values will remain unchanged.

From there we can begin calculating in earnest. The minute angle, as we’ve said, is a simple function of the minutes times 6 degrees per minute. For the hours, the the other hand, we get 30 degrees per hour plus the movement between hours, which is 30 degrees divided by 60 minutes, or 0.5 degrees per minute. We need to add these together to compute the hour angle correctly. To get the difference we subtract one from the other — it doesn’t matter which — and take the absolute value.

For our discrete function we output the computed angel up to a value of 180, but over this we need to return the computed angle subtracted from 360. A simple conditional nicely does what we need.

use warnings;
use strict;
use utf8;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';


my $timestr = shift // qw ( 12:55 );

my ($h, $m) = $timestr =~ /(\d?\d):(\d\d)/;
$h %= 12;
my $mdeg = $m * 6;
my $hdeg = $h * 30 + $m * 0.5;
my $ang = abs( $hdeg - $mdeg );
$ang = 360 - $ang if $ang > 180;

say "time: $timestr";
say "$ang degrees";
Raku Solution

In Raku we’ll keep the same sequence of transformations, but tighten it up just a little bit, jumping straight from the captured regex groups to the angle computations.

unit sub MAIN (Str $time = "12:55" );
say $time;

unless $time ~~ /^ (\d?\d) \: (\d\d) $/ { 
    die "usage:\n    time input in the form hh:mm" 
}

my $h-ang = ( $0 % 12 ) * 30 + $1 * 0.5;
my $m-ang = $1 * 6;
my $ang   = ( $h-ang - $m-ang ).abs;
$ang = 360 - $ang if $ang > 180;
say $ang;


The Perl Weekly Challenge, that idyllic glade wherein we stumble upon the holes for these sweet descents, is now known as

The Weekly Challenge – Perl and Raku

It is the creation of the lovely Mohammad Sajid Anwar and a veritable swarm of contributors from all over the world, who gather, as might be expected, weekly online to solve puzzles. Everyone is encouraged to visit, learn and contribute at

https://perlweeklychallenge.org