# RogerBW's Blog

Perl Weekly Challenge 120: Swap Clock 07 July 2021

I’ve been doing the Perl Weekly Challenges. The latest involved more binary manipulation and analogue clocks. (Note that this is open until 11 July 2021.)

TASK #1 › Swap Odd/Even bits

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.

As with last week, one could do this by converting to a binary string, but we already have bitwise operators so we might as well use them. (If there were no limit on the input size it might be a bit more fiddly.)

``````  return ((\$n & 0x55)<<1) | ((\$n & 0xAA)>>1);
``````

which looks basically the same in the other four usual languages, except Raku where there are "+" signs at the start of the bitwise operators.

But because I like the mental gymnastics, I decided to do this one in PostScript as well. You can specify numbers in arbitrary bases, which makes life easier, and this is basically the same algorithm as above.

``````/seob {
``````

Make a copy of the input.

``````    dup
``````

Bitwise-and it with the lower mask, and shift up the result.

``````    16#55 and
1 bitshift
``````

Swap that on the stack with the other copy of the input.

``````    exch
``````

Upper mask and shift down the other copy.

``````    16#AA and
-1 bitshift
``````

And combine them.

``````    or
} def
``````

And then I wrote a basic test harness, because why wouldn't I? That runs the tests and spits out a table with input, output, and pass/fail status. It can also be conveniently invoked, at least where GhostScript is available, with `ps2txt`, which runs the PostScript code, converts the page image to plain text, and dumps it to standard output:

``````\$ ps2txt ch-1.ps
1.  101  154 Pass
2.  18   33  Pass
\$
``````

(I've written PostScript code before now to send stuff explicitly to `stdout`, but that's not what PostScript wants to do in more than a very basic way and it makes it appropriately fiddly.)

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.

Which seems again as though it has a fairly straightforward solution: determine the angle of each hand, then reduce the difference. Raku:

``````sub ca(\$n) {
my \$a=0;
``````

Extract hour and minute:

``````  if (\$n ~~ /(<[0..9]>+)\:(<[0..9]>+)/) {
``````

Convert each one to an angle (note that each minute puts half a degree on the hour hand, so we're in floating point territory):

``````    my (\$ha,\$ma)=map {\$_ % 360}, (\$0*30+\$1/2,\$1*6);
``````

Take the absolute difference:

``````    \$a=abs(\$ha-\$ma);
``````

Reduce until we get an angle lying in (-180..180):

``````    while (\$a > 180) {
\$a-=360;
}
``````

And take the absolute again.

``````    \$a=abs(\$a);
}
return \$a;
}
``````

And it's basically the same algorithm in PostScript, though it looks quite different and I don't have regexps:

``````/ca {
``````

Split the input string

``````    (:) search
``````

We now have, for the first test case, `(10) (:) (03) true`. Throw away the `true` (I don't care about error handling here).

``````    pop
``````

Get the hour angle (hour component only) and roll it to the bottom of the working stack. Throw away the `(:)`.

``````    cvi 30 mul
3 1 roll pop
``````

We now have `90 (10)`. Make that an integer, copy it, and get the minute angle.

``````    cvi dup
6 mul
``````

We now have `90 10 60`. Stow that minute angle at the bottom.

``````    3 1 roll
``````

We now have `60 90 10`. Generate the minute component of the hour angle and add it to the hour component we already have.

``````    2 div add
``````

We now have `60 95`, minute angle and hour angle. Take the difference and reduce.

``````    sub
abs
{
dup 180 gt
{ 360 sub }
{ exit }
ifelse
} loop
abs
} def
``````

It's very refreshing to write in a completely different paradigm from time to time. I still need to make notes on what's where in the stack as I go along, particularly when `roll` gets involved. (I'm not sure I have a feel for what's a "natively PostScript" coding style, but using the stack rather than defining local variables, and doing stuff in the order it shows up on the stack rather than shoving it into the order most convenient for me, seem to be a part of it.)

Full code on github.

1. Posted by RogerBW at 04:04pm on 12 July 2021

Part 1 seems most easily done by bitshifting, though there were some interesting approaches using arrays of two-character strings. (Perl can split a string into two-character chunks without needing Raku's `comb`, though it's a bit fiddly.) Some people haven't been reading the blogs to be aware of how `oct()` can also parse a binary string. (Granted, it's not the sort of thing you'd notice if you were guessing function names…)

A more straightforward approach to part 2: calculate the minutes since 00:00, multiply by 5.5 degrees per minute, then modulo 360. Here's a PostScript version to do that, just for fun:

``````/ca {
(:) search
pop
cvi 60 mul
exch pop
exch cvi
{
dup 180 gt
{ 360 sub }
{ exit }
ifelse
} loop
abs
} def
``````