Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a programmatic way to elaborate the 'half-winds' in raku?

Tags:

raku

I have this working:

my %pnt = %( cardinal => <N E S W>, 
             ordinal  => <N NE E SE S SW W NW>,
             half-winds => <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>,
            );

and I thought it may be possible to create the half-winds array programatically.

However, my pathetic attempts seem to be more long-winded:

my @cards = <N E S W>; 
my @odds  = <NE SE SW NW>;
my @ords  = ( @cards Z @odds ).flat; 
my @mids  = ( ( @cards Z~ @odds ) Z ( @cards.rotate(1) Z~ @odds ) ).flat;
my @halfs = ( @ords Z @mids ).flat; 

say @cards; #[N E S W]
say @ords;  #[N NE E SE S SW W NW] 
say @mids;  #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]

Is there a better / more concise alternative?

viz. https://en.wikipedia.org/wiki/Points_of_the_compass -- bonus points for quarter winds!

like image 725
p6steve Avatar asked Jan 22 '21 21:01

p6steve


Video Answer


2 Answers

FWIW, in this case I would go for readability of the code, which I think your original code is the most readable you can get.

But if you want to get algorithmic, I would work off of the @halfs using an array slice using a sequence:

my @halfs = <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>;
my @mids  = @halfs[1,3...*];
my @ords  = @halfs[0,2...*];
my @cards = @halfs[0,4...*];

say @cards; #[N E S W]
say @ords;  #[N NE E SE S SW W NW] 
say @mids;  #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]

Leaving the quarter winds as an exercise for the reader, but basically that would be using the quarter winds as the base, and work off of that in a similar fashion.

like image 144
Elizabeth Mattijsen Avatar answered Jan 24 '23 18:01

Elizabeth Mattijsen


Assuming we have the principal winds to hand:

my @principals = <N NE E SE S SW W NW>;

Then we can follow the definition a la Wikipedia:

The name of each half-wind is constructed by combining the names of the principal winds to either side

This means we want to take principal winds in overlapping pairs, which rotor could do fairly neatly:

say @principals.rotor(2 => -1);

Which gives us:

((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW))

Which sadly has an off by one problem, because it misses (NW, N). OK, we can include N again, at the cost of a little beauty:

say @principals[*,0].flat.rotor(2 => -1)

Giving:

((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW) (NW N))

If we join them:

say @principals[*,0].flat.rotor(2 => -1).map(*.join)

We get:

(NNE NEE ESE SES SSW SWW WNW NWN)

Which isn't right yet, because the next thing the article says is:

with the cardinal wind coming first and the intercardinal wind second

The cardinal winds are the one character ones, which can be fixed with a sort:

say @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)

Which finally looks about right:

(NNE ENE ESE SSE SSW WSW WNW NNW)

Except that the half winds are these placed between the principal winds, which can be solved with zipping them and flattening the result:

say flat @principals Z @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)

Finally giving us:

(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)

If we want it shorter, the duplicate mention of @principals can go away with a given:

say flat $_ Z .[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join) given @principals

The .join can just become list stringification:

say flat $_ Z .[*,0].flat.rotor(2 => -1).map(~*.sort(*.chars)) given @principals:

And the inner flattening can be replaced with a use of the | slip operator:

say flat $_ Z (|$_,.[0]).rotor(2 => -1).map(~*.sort(*.chars)) given @principals;

Which is still longer than just listing them out in the first place, which is what I'd probably do, but it was fun trying to beat that anyway...

like image 44
Jonathan Worthington Avatar answered Jan 24 '23 18:01

Jonathan Worthington