2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -3,12 +3,13 @@ Avast me hearties!
There be many a [http://www.talklikeapirate.com/howto.html land lubber] that knows [http://oxforddictionaries.com/view/entry/m_en_gb0550020#m_en_gb0550020 naught] of the pirate ways and gives direction by degree!
They know not how to [[wp:Boxing the compass|box the compass]]!
'''Task description'''
;Task description:
# Create a function that takes a heading in degrees and returns the correct 32-point compass heading.
# Use the function to print and display a table of Index, Compass point, and Degree; rather like the corresponding columns from, the first table of the [[wp:Boxing the compass|wikipedia article]], but use only the following 33 headings as input:
:<code>[0.0, 16.87, 16.88, 33.75, 50.62, 50.63, 67.5, 84.37, 84.38, 101.25, 118.12, 118.13, 135.0, 151.87, 151.88, 168.75, 185.62, 185.63, 202.5, 219.37, 219.38, 236.25, 253.12, 253.13, 270.0, 286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37, 354.38]</code>. (They should give the same order of points but are spread throughout the ranges of acceptance).
;Notes;
* The headings and indices can be calculated from this pseudocode:
<pre>for i in 0..32 inclusive:
@ -19,3 +20,4 @@ They know not how to [[wp:Boxing the compass|box the compass]]!
end
index = ( i mod 32) + 1</pre>
* The column of indices can be thought of as an enumeration of the thirty two cardinal points (see [[Talk:Box the compass#Direction, index, and angle|talk page]])..
<br><br>

View file

@ -0,0 +1,375 @@
use framework "Foundation"
use scripting additions
property plstLangs : [{|name|:"English"} & ¬
{expansions:{N:"north", S:"south", E:"east", W:"west", b:" by "}} & ¬
{|N|:"N", |NNNE|:"NbE", |NNE|:"N-NE", |NNENE|:"NEbN", |NE|:"NE", |NENEE|:"NEbE"} & ¬
{|NEE|:"E-NE", |NEEE|:"EbN", |E|:"E", |EEES|:"EbS", |EES|:"E-SE", |EESES|:"SEbE"} & ¬
{|ES|:"SE", |ESESS|:"SEbS", |ESS|:"S-SE", |ESSS|:"SbE", |S|:"S", |SSSW|:"SbW"} & ¬
{|SSW|:"S-SW", |SSWSW|:"SWbS", |SW|:"SW", |SWSWW|:"SWbW", |SWW|:"W-SW"} & ¬
{|SWWW|:"WbS", |W|:"W", |WWWN|:"WbN", |WWN|:"W-NW", |WWNWN|:"NWbW"} & ¬
{|WN|:"NW", |WNWNN|:"NWbN", |WNN|:"N-NW", |WNNN|:"NbW"}, ¬
¬
{|name|:"Chinese", |N|:"北", |NNNE|:"北微东", |NNE|:"东北偏北"} & ¬
{|NNENE|:"东北微北", |NE|:"东北", |NENEE|:"东北微东", |NEE|:"东北偏东"} & ¬
{|NEEE|:"东微北", |E|:"东", |EEES|:"东微南", |EES|:"东南偏东", |EESES|:"东南微东"} & ¬
{|ES|:"东南", |ESESS|:"东南微南", |ESS|:"东南偏南", |ESSS|:"南微东", |S|:"南"} & ¬
{|SSSW|:"南微西", |SSW|:"西南偏南", |SSWSW|:"西南微南", |SW|:"西南"} & ¬
{|SWSWW|:"西南微西", |SWW|:"西南偏西", |SWWW|:"西微南", |W|:"西"} & ¬
{|WWWN|:"西微北", |WWN|:"西北偏西", |WWNWN|:"西北微西", |WN|:"西北"} & ¬
{|WNWNN|:"西北微北", |WNN|:"西北偏北", |WNNN|:"北微西"}]
-- Scale invariant keys for points of the compass
-- (allows us to look up a translation for one scale of compass (32 here)
-- for use in another size of compass (8 or 16 points)
-- (Also semi-serviceable as more or less legible keys without translation)
-- compassKeys :: Int -> [String]
on compassKeys(intDepth)
-- Simplest compass divides into two hemispheres
-- with one peak of ambiguity to the left,
-- and one to the right (encoded by the commas in this list):
set urCompass to ["N", "S", "N"]
-- Necessity drives recursive subdivision of broader directions, shrinking
-- boxes down to a workable level of precision:
script subdivision
on lambda(lstCompass, N)
if N 1 then
lstCompass
else
script subKeys
on lambda(a, x, i, xs)
-- Borders between N and S engender E and W.
-- further subdivisions (boxes) concatenate their two parent keys.
if i > 1 then
cond(N = intDepth, ¬
a & {cond(x = "N", "W", "E")} & x, ¬
a & {item (i - 1) of xs & x} & x)
else
a & x
end if
end lambda
end script
lambda(foldl(subKeys, {}, lstCompass), N - 1)
end if
end lambda
end script
tell subdivision to items 1 thru -2 of lambda(urCompass, intDepth)
end compassKeys
-- pointIndex :: Int -> Num -> String
on pointIndex(power, degrees)
set nBoxes to 2 ^ power
set i to round (degrees + (360 / (nBoxes * 2))) mod 360 * nBoxes / 360 rounding up
cond(i > 0, i, 1)
end pointIndex
-- pointNames :: Int -> Int -> [String]
on pointNames(precision, iBox)
set k to item iBox of compassKeys(precision)
script translation
on lambda(recLang)
set maybeTrans to keyValue(recLang, k)
set strBrief to cond(maybeTrans is missing value, k, maybeTrans)
set recExpand to keyValue(recLang, "expansions")
if recExpand is not missing value then
script expand
on lambda(c)
set t to keyValue(recExpand, c)
cond(t is not missing value, t, c)
end lambda
end script
set strName to (intercalate(cond(precision > 5, " ", ""), ¬
map(expand, characters of strBrief)))
toUpper(text item 1 of strName) & text items 2 thru -1 of strName
else
strBrief
end if
end lambda
end script
map(translation, plstLangs)
end pointNames
-- maxLen :: [String] -> Int
on maxLen(xs)
-- compareByLength = (String, String) -> (-1 | 0 | 1)
script compareByLength
on lambda(a, b)
set {intA, intB} to {length of a, length of b}
cond(intA < intB, -1, cond(intA > intB, 1, 0))
end lambda
end script
length of maximumBy(compareByLength, xs)
end maxLen
-- alignRight :: Int -> String -> String
on alignRight(nWidth, x)
justifyRight(nWidth, space, x)
end alignRight
-- alignLeft :: Int -> String -> String
on alignLeft(nWidth, x)
justifyLeft(nWidth, space, x)
end alignLeft
-- show :: asString => a -> Text
on show(x)
x as string
end show
-- compassTable :: Int -> [Num] -> Maybe String
on compassTable(precision, xs)
if precision < 1 then
missing value
else
set intPad to 2
set rightAligned to curry(alignRight)
set leftAligned to curry(alignLeft)
set join to curry(my intercalate)
-- INDEX COLUMN
set lstIndex to map(lambda(precision) of curry(pointIndex), xs)
set lstStrIndex to map(show, lstIndex)
set nIndexWidth to maxLen(lstStrIndex)
set colIndex to map(lambda(nIndexWidth + intPad) of rightAligned, lstStrIndex)
-- ANGLES COLUMN
script degreeFormat
on lambda(x)
set {c, m} to splitOn(".", x as string)
c & "." & (text 1 thru 2 of (m & "0")) & "°"
end lambda
end script
set lstAngles to map(degreeFormat, xs)
set nAngleWidth to maxLen(lstAngles) + intPad
set colAngles to map(lambda(nAngleWidth) of rightAligned, lstAngles)
-- NAMES COLUMNS
script precisionNames
on lambda(iBox)
pointNames(precision, iBox)
end lambda
end script
set lstTrans to transpose(map(precisionNames, lstIndex))
set lstTransWidths to map(maxLen, lstTrans)
script spacedNames
on lambda(lstLang, i)
map(lambda((item i of lstTransWidths) + 2) of leftAligned, lstLang)
end lambda
end script
set colsTrans to map(spacedNames, lstTrans)
-- TABLE
intercalate(linefeed, ¬
map(lambda("") of join, ¬
transpose({colIndex} & {colAngles} & ¬
{replicate(length of lstIndex, " ")} & colsTrans)))
end if
end compassTable
-- TEST
on run
set xs to [0.0, 16.87, 16.88, 33.75, 50.62, 50.63, 67.5, 84.37, ¬
84.38, 101.25, 118.12, 118.13, 135.0, 151.87, 151.88, 168.75, ¬
185.62, 185.63, 202.5, 219.37, 219.38, 236.25, 253.12, 253.13, ¬
270.0, 286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37, ¬
354.38]
-- If we supply other precisions, like 4 or 6, (2^n -> 16 or 64 boxes)
-- the bearings will be divided amongst smaller or larger numbers of boxes,
-- either using name translations retrieved by the generic hash
-- or using the keys of the hash itself (combined with any expansions)
-- to substitute for missing names for very finely divided boxes.
compassTable(5, xs) -- // 2^5 -> 32 boxes
end run
-- GENERIC FUNCTIONS
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to lambda(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to lambda(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
-- curry :: (Script|Handler) -> Script
on curry(f)
script
on lambda(a)
script
on lambda(b)
lambda(a, b) of mReturn(f)
end lambda
end script
end lambda
end script
end curry
-- transpose :: [[a]] -> [[a]]
on transpose(xss)
script column
on lambda(_, iCol)
script row
on lambda(xs)
item iCol of xs
end lambda
end script
map(row, xss)
end lambda
end script
map(column, item 1 of xss)
end transpose
-- maximumBy :: (a -> a -> Ordering) -> [a] -> a
on maximumBy(f, xs)
set cmp to mReturn(f)
script max
on lambda(a, b)
if a is missing value or cmp's lambda(a, b) < 0 then
b
else
a
end if
end lambda
end script
foldl(max, missing value, xs)
end maximumBy
-- splitOn :: Text -> Text -> [Text]
on splitOn(strDelim, strMain)
set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
set xs to text items of strMain
set my text item delimiters to dlm
return xs
end splitOn
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
-- keyValue :: Record -> String -> Maybe String
on keyValue(rec, strKey)
set ca to current application
set v to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
if v is not missing value then
item 1 of ((ca's NSArray's arrayWithObject:v) as list)
else
missing value
end if
end keyValue
-- toLower :: String -> String
on toLower(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
lowercaseStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toLower
-- toUpper :: String -> String
on toUpper(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
uppercaseStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toUpper
-- toTitle :: String -> String
on toTitle(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
capitalizedStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toTitle
-- justifyLeft :: Int -> Char -> Text -> Text
on justifyLeft(N, cFiller, strText)
if N > length of strText then
text 1 thru N of (strText & replicate(N, cFiller))
else
strText
end if
end justifyLeft
-- justifyRight :: Int -> Char -> Text -> Text
on justifyRight(N, cFiller, strText)
if N > length of strText then
text -N thru -1 of ((replicate(N, cFiller) as text) & strText)
else
strText
end if
end justifyRight
-- replicate :: Int -> a -> [a]
on replicate(N, a)
set out to {}
if N < 1 then return out
set dbl to {a}
repeat while (N > 1)
if (N mod 2) > 0 then set out to out & dbl
set N to (N div 2)
set dbl to (dbl & dbl)
end repeat
return out & dbl
end replicate
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property lambda : f
end script
end if
end mReturn
-- cond :: Bool -> a -> a -> a
on cond(bool, f, g)
if bool then
f
else
g
end if
end cond

View file

@ -0,0 +1,67 @@
identification division.
program-id. box-compass.
data division.
working-storage section.
01 point pic 99.
01 degrees usage float-short.
01 degrees-rounded pic 999v99.
01 show-degrees pic zz9.99.
01 box pic z9.
01 fudge pic 9.
01 compass pic x(4).
01 compass-point pic x(18).
01 shortform pic x.
01 short-names.
05 short-name pic x(4) occurs 33 times.
01 overlay.
05 value "N " & "NbE " & "N-NE" & "NEbN" & "NE " &
"NEbE" & "E-NE" & "EbN " & "E " & "EbS " &
"E-SE" & "SEbE" & "SE " & "SEbS" & "S-SE" &
"SbE " & "S " & "SbW " & "S-SW" & "SWbS" &
"SW " & "SWbW" & "W-SW" & "WbS " & "W " &
"WbN " & "W-NW" & "NWbW" & "NW " & "NWbN" &
"N-NW" & "NbW " & "N ".
procedure division.
display "Index Compass point Degree"
move overlay to short-names.
perform varying point from 0 by 1 until point > 32
compute box = function mod(point 32) + 1
compute degrees = point * 11.25
compute fudge = function mod(point 3)
evaluate fudge
when equal 1
add 5.62 to degrees
when equal 2
subtract 5.62 from degrees
end-evaluate
compute degrees-rounded rounded = degrees
move degrees-rounded to show-degrees
inspect show-degrees replacing trailing '00' by '0 '
inspect show-degrees replacing trailing '50' by '5 '
move short-name(point + 1) to compass
move spaces to compass-point
display space box space space space with no advancing
perform varying tally from 1 by 1 until tally > 4
move compass(tally:1) to shortform
move function concatenate(function trim(compass-point),
function substitute(shortform,
"N", "North",
"E", "East",
"S", "South",
"W", "West",
"b", " byZ",
"-", "-"))
to compass-point
end-perform
move function substitute(compass-point, "Z", " ")
to compass-point
move function lower-case(compass-point) to compass-point
move function upper-case(compass-point(1:1))
to compass-point(1:1)
display compass-point space show-degrees
end-perform
goback.

View file

@ -0,0 +1,239 @@
(() => {
'use strict';
// GENERIC FUNCTIONS
// toTitle :: String -> String
let toTitle = s => s.length ? (s[0].toUpperCase() + s.slice(1)) : '';
// COMPASS DATA AND FUNCTIONS
// Scale invariant keys for points of the compass
// (allows us to look up a translation for one scale of compass (32 here)
// for use in another size of compass (8 or 16 points)
// (Also semi-serviceable as more or less legible keys without translation)
// compassKeys :: Int -> [String]
let compassKeys = depth => {
let urCompass = ['N', 'S', 'N'],
subdivision = (compass, n) => n <= 1 ? (
compass
) : subdivision( // Borders between N and S engender E and W.
// other new boxes concatenate their parent keys.
compass.reduce((a, x, i, xs) => {
if (i > 0) {
return (n === depth) ? (
a.concat([x === 'N' ? 'W' : 'E'], x)
) : a.concat([xs[i - 1] + x, x]);
} else return a.concat(x);
}, []),
n - 1
);
return subdivision(urCompass, depth)
.slice(0, -1);
};
// https://zh.wikipedia.org/wiki/%E7%BD%97%E7%9B%98%E6%96%B9%E4%BD%8D
let lstLangs = [{
'name': 'English',
expansions: {
N: 'north',
S: 'south',
E: 'east',
W: 'west',
b: ' by ',
'-': '-'
},
'N': 'N',
'NNNE': 'NbE',
'NNE': 'N-NE',
'NNENE': 'NEbN',
'NE': 'NE',
'NENEE': 'NEbE',
'NEE': 'E-NE',
'NEEE': 'EbN',
'E': 'E',
'EEES': 'EbS',
'EES': 'E-SE',
'EESES': 'SEbE',
'ES': 'SE',
'ESESS': 'SEbS',
'ESS': 'S-SE',
'ESSS': 'SbE',
'S': 'S',
'SSSW': 'SbW',
'SSW': 'S-SW',
'SSWSW': 'SWbS',
'SW': 'SW',
'SWSWW': 'SWbW',
'SWW': 'W-SW',
'SWWW': 'WbS',
'W': 'W',
'WWWN': 'WbN',
'WWN': 'W-NW',
'WWNWN': 'NWbW',
'WN': 'NW',
'WNWNN': 'NWbN',
'WNN': 'N-NW',
'WNNN': 'NbW'
}, {
'name': 'Chinese',
'N': '北',
'NNNE': '北微东',
'NNE': '东北偏北',
'NNENE': '东北微北',
'NE': '东北',
'NENEE': '东北微东',
'NEE': '东北偏东',
'NEEE': '东微北',
'E': '东',
'EEES': '东微南',
'EES': '东南偏东',
'EESES': '东南微东',
'ES': '东南',
'ESESS': '东南微南',
'ESS': '东南偏南',
'ESSS': '南微东',
'S': '南',
'SSSW': '南微西',
'SSW': '西南偏南',
'SSWSW': '西南微南',
'SW': '西南',
'SWSWW': '西南微西',
'SWW': '西南偏西',
'SWWW': '西微南',
'W': '西',
'WWWN': '西微北',
'WWN': '西北偏西',
'WWNWN': '西北微西',
'WN': '西北',
'WNWNN': '西北微北',
'WNN': '西北偏北',
'WNNN': '北微西'
}];
// pointIndex :: Int -> Num -> Int
let pointIndex = (power, degrees) => {
let nBoxes = (power ? Math.pow(2, power) : 32);
return Math.ceil(
(degrees + (360 / (nBoxes * 2))) % 360 * nBoxes / 360
) || 1;
};
// pointNames :: Int -> Int -> [String]
let pointNames = (precision, iBox) => {
let k = compassKeys(precision)[iBox - 1];
return lstLangs.map(dctLang => {
let s = dctLang[k] || k, // fallback to key if no translation
dctEx = dctLang.expansions;
return dctEx ? toTitle(s.split('')
.map(c => dctEx[c])
.join(precision > 5 ? ' ' : ''))
.replace(/ /g, ' ') : s;
});
};
// maximumBy :: (a -> a -> Ordering) -> [a] -> a
let maximumBy = (f, xs) =>
xs.reduce((a, x) => a === undefined ? x : (
f(x, a) > 0 ? x : a
), undefined);
// justifyLeft :: Int -> Char -> Text -> Text
let justifyLeft = (n, cFiller, strText) =>
n > strText.length ? (
(strText + replicate(n, cFiller)
.join(''))
.substr(0, n)
) : strText;
// justifyRight :: Int -> Char -> Text -> Text
let justifyRight = (n, cFiller, strText) =>
n > strText.length ? (
(replicate(n, cFiller)
.join('') + strText)
.slice(-n)
) : strText;
// replicate :: Int -> a -> [a]
let replicate = (n, a) => {
let v = [a],
o = [];
if (n < 1) return o;
while (n > 1) {
if (n & 1) o = o.concat(v);
n >>= 1;
v = v.concat(v);
}
return o.concat(v);
};
// transpose :: [[a]] -> [[a]]
let transpose = xs =>
xs[0].map((_, iCol) => xs.map((row) => row[iCol]));
// length :: [a] -> Int
// length :: Text -> Int
let length = xs => xs.length;
// compareByLength = (a, a) -> (-1 | 0 | 1)
let compareByLength = (a, b) => {
let [na, nb] = [a, b].map(length);
return na < nb ? -1 : na > nb ? 1 : 0;
};
// maxLen :: [String] -> Int
let maxLen = xs => maximumBy(compareByLength, xs)
.length;
// compassTable :: Int -> [Num] -> Maybe String
let compassTable = (precision, xs) => {
if (precision < 1) return undefined;
else {
let intPad = 2;
let lstIndex = xs.map(x => pointIndex(precision, x)),
lstStrIndex = lstIndex.map(x => x.toString()),
nIndexWidth = maxLen(lstStrIndex),
colIndex = lstStrIndex.map(
x => justifyRight(nIndexWidth, ' ', x)
);
let lstAngles = xs.map(x => x.toFixed(2) + '°'),
nAngleWidth = maxLen(lstAngles) + intPad,
colAngles = lstAngles.map(x => justifyRight(nAngleWidth, ' ', x));
let lstTrans = transpose(
lstIndex.map(i => pointNames(precision, i))
),
lstTransWidths = lstTrans.map(x => maxLen(x) + 2),
colsTrans = lstTrans
.map((lstLang, i) => lstLang
.map(x => justifyLeft(lstTransWidths[i], ' ', x))
);
return transpose([colIndex]
.concat([colAngles], [replicate(lstIndex.length, " ")])
.concat(colsTrans))
.map(x => x.join(''))
.join('\n');
}
}
// TEST
let xs = [0.0, 16.87, 16.88, 33.75, 50.62, 50.63, 67.5, 84.37,
84.38, 101.25, 118.12, 118.13, 135.0, 151.87, 151.88, 168.75,
185.62, 185.63, 202.5, 219.37, 219.38, 236.25, 253.12, 253.13,
270.0, 286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37,
354.38
];
// If we supply other precisions, like 4 or 6, (2^n -> 16 or 64 boxes)
// the bearings will be divided amongst smaller or larger numbers of boxes,
// either using name translations retrieved by the generic hash
// or using the hash itself (combined with any expansions)
// to substitute for missing names for very finely divided boxes.
return compassTable(5, xs); // 2^5 -> 32 boxes
})();

View file

@ -0,0 +1,16 @@
function Convert-DegreeToDirection ( [double]$Degree )
{
$Directions = @( 'n','n by e','n-ne','ne by n','ne','ne by e','e-ne','e by n',
'e','e by s','e-se','se by e','se','se by s','s-se','s by e',
's','s by w','s-sw','sw by s','sw','sw by w','w-sw','w by s',
'w','w by n','w-nw','nw by w','nw','nw by n','n-nw','n by w',
'n'
).Replace( 's', 'south' ).Replace( 'e', 'east' ).Replace( 'n', 'north' ).Replace( 'w', 'west' )
$Directions[[math]::floor(( $Degree % 360 ) / 11.25 + 0.5 )]
}
$x = 0.0, 16.87, 16.88, 33.75, 50.62, 50.63, 67.5, 84.37, 84.38, 101.25, 118.12, 118.13, 135.0, 151.87, 151.88, 168.75, 185.62, 185.63, 202.5, 219.37, 219.38, 236.25, 253.12, 253.13, 270.0, 286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37, 354.38
$x | % { Convert-DegreeToDirection -Degree $_ }

View file

@ -0,0 +1,23 @@
function Convert-DegreeToDirection ( [double]$Degree, [int]$Points )
{
$Directions = @( 'n','n by e','n-ne','ne by n','ne','ne by e','e-ne','e by n',
'e','e by s','e-se','se by e','se','se by s','s-se','s by e',
's','s by w','s-sw','sw by s','sw','sw by w','w-sw','w by s',
'w','w by n','w-nw','nw by w','nw','nw by n','n-nw','n by w',
'n'
).Replace( 's', 'south' ).Replace( 'e', 'east' ).Replace( 'n', 'north' ).Replace( 'w', 'west' )
$Directions[[math]::floor((( $Degree % 360 ) * $Points / 360 + 0.5 )) * 32 / $Points ]
}
$x = 0.0, 16.87, 16.88, 33.75, 50.62, 50.63, 67.5, 84.37, 84.38, 101.25, 118.12, 118.13, 135.0, 151.87, 151.88, 168.75, 185.62, 185.63, 202.5, 219.37, 219.38, 236.25, 253.12, 253.13, 270.0, 286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37, 354.38
$Values = @()
ForEach ( $Degree in $X ) { $Values += [pscustomobject]@{ Degree = $Degree
32 = ( Convert-DegreeToDirection -Degree $Degree -Points 32 )
16 = ( Convert-DegreeToDirection -Degree $Degree -Points 16 )
8 = ( Convert-DegreeToDirection -Degree $Degree -Points 8 )
4 = ( Convert-DegreeToDirection -Degree $Degree -Points 4 ) } }
$Values | Format-Table

View file

@ -1,29 +1,29 @@
/*REXX program "boxes the compass" (from º headings ───► a 32 point set).*/
parse arg # /*allow a º heading to be specified.*/
if #='' then #= 0 16.87 16.88 33.75 50.62 50.63 67.5 84.37 84.38 101.25 118.12,
118.13 135 151.87 151.88 168.75 185.62 185.63 202.5 219.37,
219.38 236.25 253.12 253.13 270 286.87 286.88 303.75 320.62,
320.63 337.5 354.37 354.38 /* [↑] use default in degrees.*/
/*REXX program "boxes the compass" [from degree (º) headings ───► a 32 point set]. */
parse arg $ /*allow a º heading to be specified. */
if $='' then $= 0 16.87 16.88 33.75 50.62 50.63 67.5 84.37 84.38 101.25 118.12 118.13 ,
135 151.87 151.88 168.75 185.62 185.63 202.5 219.37 219.38 236.25 ,
253.12 253.13 270 286.87 286.88 303.75 320.62 320.63 337.5 354.37 354.38
/* [↑] use default, they're in degrees*/
@pts= 'n nbe n-ne nebn ne nebe e-ne ebn e ebs e-se sebe se sebs s-se sbe',
"s sbw s-sw swbs sw swbw w-sw wbs w wbn w-nw nwbw nw nwbn n-nw nbw"
points= 'n nbe n-ne nebn ne nebe e-ne ebn e ebs e-se sebe se sebs s-se sbe',
's sbw s-sw swbs sw swbw w-sw wbs w wbn w-nw nwbw nw nwbn n-nw nbw'
#=words(@pts) + 1 /*#: used for integer ÷ remainder (//)*/
dirs= 'north south east west' /*define cardinal compass directions. */
/* [↓] choose a glyph for degree (°).*/
if 4=='f4'x then degSym= "a1"x /*is this system an EBCDIC system? */
else degSym= "a7"x /*'f8'x is the degree symbol: ° vs º */
/*──────────────────────────── f8 vs a7*/
say right(degSym'heading', 30) center("compass heading", 20)
say right( '', 30) copies( "", 20)
dirs= 'north south east west' /*define cardinal compass directions.*/
/* [↓] choose a degree (°) glyph. */
if 4=='f4'x then degSym='a1'x /*is this system an EBCDIC system? */
else degSym='f8'x /*although 'a7'x looks better: ° vs º*/
/*─────────────────────────── f8 a7*/
say right(degSym'heading',30) center('compass heading',20)
say right( '',30) copies('' ,20)
do j=1 for words(#); x=word(#,j) /*get one of the degree headings*/
say right(format(x,,2)degSym,30-1) ' ' boxHeading(x)
do j=1 for words($); x=word($, j) /*obtain one of the degree headings. */
say right(format(x, , 2)degSym, 30-1) ' ' boxHeading(x)
end /*j*/
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
boxHeading: _=arg(1)//360; if _<0 then _=360-_ /*normalize the heading.*/
_=word(points,trunc(max(1,(_/11.25+1.5)//33)))
do k=1 for words(dirs); d=word(dirs,k)
_=changestr(left(d,1), _, d)
end /*k*/
return changestr('b', _, " by ") /*expand "b" ──► "by"*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
boxHeading: y=arg(1)//360; if y<0 then y=360 - y /*normalize heading within unit circle.*/
z=word(@pts, trunc(max(1, (y/11.25+1.5) // #))) /*convert degrees─►heading*/
do k=1 for words(dirs); d=word(dirs, k)
z=changestr( left(d,1), z, d)
end /*k*/ /* [↑] old, haystack, new*/
return changestr('b', z, " by ") /*expand "b" ──► " by " */

View file

@ -0,0 +1,26 @@
10 DATA "North","North by east","North-northeast"
20 DATA "Northeast by north","Northeast","Northeast by east","East-northeast"
30 DATA "East by north","East","East by south","East-southeast"
40 DATA "Southeast by east","Southeast","Southeast by south","South-southeast"
50 DATA "South by east","South","South by west","South-southwest"
60 DATA "Southwest by south","Southwest","Southwest by west","West-southwest"
70 DATA "West by south","West","West by north","West-northwest"
80 DATA "Northwest by west","Northwest","Northwest by north","North-northwest"
90 DATA "North by west"
100 DIM p$(32,18)
110 FOR i=1 TO 32
120 READ p$(i)
130 NEXT i
140 FOR i=0 TO 32
150 LET h=i*11.25
160 LET r=FN m(i,3)
170 IF r=1 THEN LET h=h+5.62: GO TO 190
180 IF r=2 THEN LET h=h-5.62
190 LET ind=FN m(i,32)+1
200 PRINT ind;TAB 4;
210 LET x=h/11.25+1.5
220 IF x>=33 THEN LET x=x-32
230 PRINT p$(INT x);TAB 25;h
240 NEXT i
250 STOP
260 DEF FN m(i,n)=((i/n)-INT (i/n))*n : REM modulus function