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!
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.
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With