Box the compass: Difference between revisions
(→{{header|Go}}: restructure for closer task conformance) |
(→{{header|Go}}: another try at task conformance. I still wasn't reading it right.) |
||
Line 653: | Line 653: | ||
import "fmt" |
import "fmt" |
||
// function required by task |
// function required by task |
||
⚫ | |||
// specifies that function must return compass point, but also specifies |
|||
⚫ | |||
// that the same function must be used in printing of an index number. |
|||
// The function then, returns both. |
|||
⚫ | |||
x := cpx(h) |
|||
⚫ | |||
} |
} |
||
// cpx returns integer index from 0 to 31 corresponding to compass point. |
// cpx returns integer index from 0 to 31 corresponding to compass point. |
||
// input heading h is in degrees. |
// input heading h is in degrees. Note this index is a zero-based index |
||
// suitable for indexing into the table of printable compass points, |
|||
// and is not the same as the index specified to be printed in the output. |
|||
func cpx(h float32) int { |
func cpx(h float32) int { |
||
x := int(h/11.25+.5) % 32 |
x := int(h/11.25+.5) % 32 |
||
Line 710: | Line 708: | ||
func main() { |
func main() { |
||
fmt.Println("Index Compass point Degree") |
fmt.Println("Index Compass point Degree") |
||
for |
for i, h := range []float32{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, |
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, |
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} { |
286.87, 286.88, 303.75, 320.62, 320.63, 337.5, 354.37, 354.38} { |
||
index := i%32 + 1 // printable index computed per pseudocode |
|||
x, cp := degrees2compasspoint(h) |
|||
fmt.Printf("%4d %-19s %7.2f°\n", |
fmt.Printf("%4d %-19s %7.2f°\n", index, degrees2compasspoint(h), h) |
||
x+1, // index, 1 based for consistency with wp table |
|||
cp, // compass point computed from heading |
|||
h) // heading given as input |
|||
} |
} |
||
}</lang> |
}</lang> |
||
<pre> |
|||
Index Compass point Degree |
|||
1 North 0.00° |
1 North 0.00° |
||
2 North by east 16.87° |
2 North by east 16.87° |
Revision as of 18:17, 18 July 2011
You are encouraged to solve this task according to the task description, using any language you may know.
Avast me hearties!
There be many a land lubber that knows naught of the pirate ways and gives direction by degree! They know not how to box the compass!
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 wikipedia article, but use only the following 33 headings as input:
[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]
. (They should give the same order of points but are spread throughout the ranges of acceptance).
Note
- The headings and indices can be calculated from this pseudocode:
for i in 0..32 inclusive: heading = i * 11.25 case i %3: if 1: heading += 5.62; break if 2: heading -= 5.62; break end index = ( i mod 32) + 1
ALGOL 68
<lang algol68>#!/usr/local/bin/a68g --script #
[]STRING
long by nesw = (" by ", "North", "East", "South", "West"), short by nesw = ("b", "N", "E", "S", "W");
MODE MINUTES = REAL; # minutes type # INT last minute=360*60; INT point width=last minute OVER 32;
PROC direction name = (REAL direction in minutes, []STRING locale directions)STRING: (
STRING by = locale directions[1]; []STRING nesw = locale directions[@-1];
PRIO MASK = 7; # same PRIOrity as * and / # OP MASK = (INT n, BITS lower)INT: ABS (BIN n AND NOT lower), DECAP = (STRING s)STRING: IF UPB s > 1 THEN REPR (ABS s[1]-ABS "A"+ABS "a")+s[2:] ELSE s FI;
PROC point name = (INT in point)STRING: (
INT point = in point MOD 32 # 32 points of a compass #; IF point MOD 8 = 0 THEN
- name the principle point: eg. N, E, S or W #
nesw[point OVER 8]
ELIF point MOD 4 = 0 THEN
- name the half: eg. NE, SE, SW or NW #
point name((point+8)MASK 2r1111)+DECAP point name(point MASK 2r1111 + 8)
ELIF point MOD 2 = 0 THEN
- name the quarter: eg. N-NE, E-NE, E-SE, S-SE, S-SW, W-SW, W-NW or N-NW #
point name((point+4)MASK 2r111)+"-"+point name(point MASK 2r111 + 4)
ELSE # Name the sixteenth point: #
- eg. NbE,NEbN,NEbE,EbN,EbS,SEbE,SEbS,SbE,SbW,SWbS,SWbW,WbS,WbN,NWbW,NWbN,NbW #
INT opp point = point OVER 8 + ABS NOT ODD (point OVER 2); point name((point+2)MASK 2r11)+ by +nesw(opp point MOD 4) FI ); point name(ROUND(direction in minutes/point width))
);
PROC traditional name = (MINUTES minutes)STRING: (
INT degrees = ROUND(minutes / 60); degrees=0 |"Tramontana" |: degrees=45 |"Greco or Bora" |: degrees=90 |"Levante" |: degrees=135|"Sirocco" |: degrees=180|"Ostro" |: degrees=225|"Libeccio" |: degrees=270|"Poniente or Zephyrus"|: degrees=315|"Mistral" |: degrees=360|"Tramontana" |""
);
- First generate the test set results #
test:(
printf($"Test:"l$); FOR i FROM 0 TO 32 DO REAL heading = i * 11.25 + CASE i MOD 3 IN +5.62, -5.62 OUT 0 ESAC; INT index = ( i MOD 32) + 1; printf(($zd" ", g23k, zzd.zzl$, index , direction name(heading*60, long by nesw), heading)) OD
);
table:(
OP OVER = (REAL r, INT base)INT: ENTIER ABS r OVER base, MOD = (REAL r, INT base)REAL: ( INT i = ENTIER r; i MOD base + r - i);
printf( $l"Table:"l " #|Compass point"22k"|Abbr|Traditional wind point| Lowest°′ | Middle°′ | Highest°′"l$ );
OP DEGMIN = (REAL minutes)STRUCT(INT d, REAL m): (minutes MOD last minute OVER 60, minutes MOD 60);
FOR point FROM 1 TO 32 DO REAL centre = (point-1) * point width; REAL from = centre - point width/2, to = centre + point width/2-1/120; printf(( $g(-2)"|"$, point, $g$, direction name(centre, long by nesw), $22k"|"g$, direction name(centre, short by nesw), $27k"|"g$, traditional name(centre), $50k$, $"|"g(-3)"°", dd.dd"′"$, DEGMIN from, DEGMIN centre, DEGMIN to, $l$ )) OD
)</lang> Output:
Test: 1 North 0.00 2 North by East 16.87 3 North-Northeast 16.88 4 Northeast by North 33.75 5 Northeast 50.62 6 Northeast by East 50.63 7 East-Northeast 67.50 8 East by North 84.37 9 East 84.38 10 East by South 101.25 11 East-Southeast 118.12 12 Southeast by East 118.13 13 Southeast 135.00 14 Southeast by South 151.87 15 South-Southeast 151.88 16 South by East 168.75 17 South 185.62 18 South by West 185.63 19 South-Southwest 202.50 20 Southwest by South 219.37 21 Southwest 219.38 22 Southwest by West 236.25 23 West-Southwest 253.12 24 West by South 253.13 25 West 270.00 26 West by North 286.87 27 West-Northwest 286.88 28 Northwest by West 303.75 29 Northwest 320.62 30 Northwest by North 320.63 31 North-Northwest 337.50 32 North by West 354.37 1 North 354.38 Table: #|Compass point |Abbr|Traditional wind point| Lowest°′ | Middle°′ | Highest°′ 1|North |N |Tramontana |354°22.50′| 0°00.00′| 5°37.49′ 2|North by East |NbE | | 5°37.50′| 11°15.00′| 16°52.49′ 3|North-Northeast |N-NE| | 16°52.50′| 22°30.00′| 28°07.49′ 4|Northeast by North|NEbN| | 28°07.50′| 33°45.00′| 39°22.49′ 5|Northeast |NE |Greco or Bora | 39°22.50′| 45°00.00′| 50°37.49′ 6|Northeast by East |NEbE| | 50°37.50′| 56°15.00′| 61°52.49′ 7|East-Northeast |E-NE| | 61°52.50′| 67°30.00′| 73°07.49′ 8|East by North |EbN | | 73°07.50′| 78°45.00′| 84°22.49′ 9|East |E |Levante | 84°22.50′| 90°00.00′| 95°37.49′ 10|East by South |EbS | | 95°37.50′|101°15.00′|106°52.49′ 11|East-Southeast |E-SE| |106°52.50′|112°30.00′|118°07.49′ 12|Southeast by East |SEbE| |118°07.50′|123°45.00′|129°22.49′ 13|Southeast |SE |Sirocco |129°22.50′|135°00.00′|140°37.49′ 14|Southeast by South|SEbS| |140°37.50′|146°15.00′|151°52.49′ 15|South-Southeast |S-SE| |151°52.50′|157°30.00′|163°07.49′ 16|South by East |SbE | |163°07.50′|168°45.00′|174°22.49′ 17|South |S |Ostro |174°22.50′|180°00.00′|185°37.49′ 18|South by West |SbW | |185°37.50′|191°15.00′|196°52.49′ 19|South-Southwest |S-SW| |196°52.50′|202°30.00′|208°07.49′ 20|Southwest by South|SWbS| |208°07.50′|213°45.00′|219°22.49′ 21|Southwest |SW |Libeccio |219°22.50′|225°00.00′|230°37.49′ 22|Southwest by West |SWbW| |230°37.50′|236°15.00′|241°52.49′ 23|West-Southwest |W-SW| |241°52.50′|247°30.00′|253°07.49′ 24|West by South |WbS | |253°07.50′|258°45.00′|264°22.49′ 25|West |W |Poniente or Zephyrus |264°22.50′|270°00.00′|275°37.49′ 26|West by North |WbN | |275°37.50′|281°15.00′|286°52.49′ 27|West-Northwest |W-NW| |286°52.50′|292°30.00′|298°07.49′ 28|Northwest by West |NWbW| |298°07.50′|303°45.00′|309°22.49′ 29|Northwest |NW |Mistral |309°22.50′|315°00.00′|320°37.49′ 30|Northwest by North|NWbN| |320°37.50′|326°15.00′|331°52.49′ 31|North-Northwest |N-NW| |331°52.50′|337°30.00′|343°07.49′ 32|North by West |NbW | |343°07.50′|348°45.00′|354°22.49′
C
<lang C>int main() {
int i, j; double degrees[] = { 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 }; char * names = "North " "North by east " "North-northeast " "Northeast by north " "Northeast " "Northeast by east " "East-northeast " "East by north " "East " "East by south " "East-southeast " "Southeast by east " "Southeast " "Southeast by south " "South-southeast " "South by east " "South " "South by west " "South-southwest " "Southwest by south " "Southwest " "Southwest by west " "West-southwest " "West by south " "West " "West by north " "West-northwest " "Northwest by west " "Northwest " "Northwest by north " "North-northwest " "North by west " "North ";
for (i = 0; i < 33; i++) { j = .5 + degrees[i] * 32 / 360;
printf("%2d %.22s %6.2f\n", i + 1, names + (j % 32) * 22, degrees[i]); }
return 0;
}</lang>Output:<lang>
1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38
10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 33 North 354.38 </lang>
C++
Using the Boost libraries
<lang cpp>#include <string>
- include <boost/array.hpp>
- include <boost/assign/list_of.hpp>
- include <boost/format.hpp>
- include <boost/foreach.hpp>
- include <iostream>
- include <math.h>
using std::string; using namespace boost::assign;
int get_Index(float angle) {
return static_cast<int>(floor(angle / 11.25 +0.5 )) % 32 + 1;
}
string get_Abbr_From_Index(int i) {
static boost::array<std::string, 32> points(list_of ("N")("NbE")("NNE")("NEbN")("NE")("NEbE")("ENE")("EbN") ("E")("EbS")("ESE")("SEbE")("SE")("SEbS")("SSE")("SbE") ("S")("SbW")("SSW")("SWbS")("SW")("SWbW")("WSW")("WbS") ("W")("WbN")("WNW")("NWbW")("NW")("NWbN")("NNW")("NbW")); return points[i-1];
}
string Build_Name_From_Abbreviation(string a) {
string retval; for (int i = 0; i < a.size(); ++i){ if ((1 == i) && (a[i] != 'b') && (a.size() == 3)) retval += "-"; switch (a[i]){ case 'N' : retval += "north"; break; case 'S' : retval += "south"; break; case 'E' : retval += "east"; break; case 'W' : retval += "west"; break; case 'b' : retval += " by "; break; } } retval[0] = toupper(retval[0]); return retval;
}
int main() {
boost::array<float,33> headings(list_of (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)); int i; boost::format f("%1$4d %2$-20s %3$_7.2f");
BOOST_FOREACH(float a, headings) { i = get_Index(a); std::cout << f % i % Build_Name_From_Abbreviation(get_Abbr_From_Index(i)) % a << std::endl; } return 0;
}</lang> Output:
1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 1 North 354.38
Clojure
<lang lisp>(ns boxing-the-compass
(:use [clojure.string :only [capitalize]]))
(def headings
(for [i (range 0 (inc 32))] (let [heading (* i 11.25)]
(case (mod i 3) 1 (+ heading 5.62) 2 (- heading 5.62) heading))))
(defn angle2compass
[angle] (let [dirs ["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"] unpack {\N "north" \E "east" \W "west" \S "south" \b " by " \- "-"} sep (/ 360 (count dirs)) dir (int (/ (mod (+ angle (/ sep 2)) 360) sep))]
(capitalize (apply str (map unpack (dirs dir))))))
(apply str (map-indexed #(format "%2s %-18s %7.2f\n"
(inc (mod %1 32)) (angle2compass %2) %2) headings)))</lang> Output:
1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 1 North 354.38
D
<lang d>import std.stdio, std.string, std.math, std.array;
struct boxTheCompass {
static string[32] points;
static this() { enum cardinal = ["north", "east", "south", "west"]; enum desc = ["1", "1 by 2", "1-C", "C by 1", "C", "C by 2", "2-C", "2 by 1"];
foreach (i; 0 .. 4) { auto s1 = cardinal[i]; auto s2 = cardinal[(i + 1) % 4]; auto sc = (s1 == "north" || s1 == "south") ? (s1 ~ s2) : (s2 ~ s1); foreach (j; 0 .. 8) points[i * 8 + j] = desc[j].replace("1", s1). replace("2", s2).replace("C",sc); } }
static string opCall(double degrees) { double testD = (degrees / 11.25) + 0.5; return capitalize(points[cast(int)floor(testD % 32)]); }
}
void main() {
foreach (i; 0 .. 33) { double heading = i * 11.25 + [0, 5.62, -5.62][i % 3]; writefln("%s\t%18s\t%s", i % 32 + 1, boxTheCompass(heading), heading); }
}</lang> Output:
1 North 0 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.5 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.5 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.5 32 North by west 354.37 1 North 354.38
Euphoria
<lang euphoria>constant names = {"North","North by east","North-northeast","Northeast by north",
"Northeast","Northeast by east","East-northeast","East by north","East", "East by south","East-southeast","Southeast by east","Southeast","Southeast by south", "South-southeast","South by east","South","South by west","South-southwest", "Southwest by south","Southwest","Southwest by west","West-southwest", "West by south","West","West by north","West-northwest","Northwest by west", "Northwest","Northwest by north","North-northwest","North by west"}
function deg2ind(atom degree)
return remainder(floor(degree*32/360+.5),32)+1
end function
sequence degrees degrees = {} for i = 0 to 32 do
degrees &= i*11.25 + 5.62*(remainder(i+1,3)-1)
end for
integer j for i = 1 to length(degrees) do
j = deg2ind(degrees[i]) printf(1, "%6.2f %2d %-22s\n", {degrees[i], j, names[j]})
end for</lang>
Output:
0.00 1 North 16.87 2 North by east 16.88 3 North-northeast 33.75 4 Northeast by north 50.62 5 Northeast 50.63 6 Northeast by east 67.50 7 East-northeast 84.37 8 East by north 84.38 9 East 101.25 10 East by south 118.12 11 East-southeast 118.13 12 Southeast by east 135.00 13 Southeast 151.87 14 Southeast by south 151.88 15 South-southeast 168.75 16 South by east 185.62 17 South 185.63 18 South by west 202.50 19 South-southwest 219.37 20 Southwest by south 219.38 21 Southwest 236.25 22 Southwest by west 253.12 23 West-southwest 253.13 24 West by south 270.00 25 West 286.87 26 West by north 286.88 27 West-northwest 303.75 28 Northwest by west 320.62 29 Northwest 320.63 30 Northwest by north 337.50 31 North-northwest 354.37 32 North by west 354.38 1 North
Fortran
<lang fortran>Program Compass
implicit none
integer :: i, ind real :: heading
do i = 0, 32 heading = i * 11.25 if (mod(i, 3) == 1) then heading = heading + 5.62 else if (mod(i, 3) == 2) then heading = heading - 5.62 end if ind = mod(i, 32) + 1 write(*, "(i2, a20, f8.2)") ind, compasspoint(heading), heading end do
contains
function compasspoint(h)
character(18) :: compasspoint character(18) :: points(32) = (/ "North ", "North by east ", "North-northeast ", & "Northeast by north", "Northeast ", "Northeast by east ", "East-northeast ", & "East by north ", "East ", "East by south ", "East-southeast ", & "Southeast by east ", "Southeast ", "Southeast by south", "South-southeast ", & "South by east ", "South ", "South by west ", "South-southwest ", & "Southwest by south", "Southwest ", "Southwest by west ", "West-southwest ", & "West by south ", "West ", "West by north ", "West-northwest ", & "Northwest by west ", "Northwest ", "Northwest by north", "North-northwest ", & "North by west " /) real, intent(in) :: h real :: x
x = h / 11.25 + 1.5 if (x >= 33.0) x = x - 32.0 compasspoint = points(int(x))
end function compasspoint end program Compass</lang> Output:
1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 1 North 354.38
Go
<lang go>package main
import "fmt"
// function required by task func degrees2compasspoint(h float32) string {
return compassPoint[cpx(h)]
}
// cpx returns integer index from 0 to 31 corresponding to compass point. // input heading h is in degrees. Note this index is a zero-based index // suitable for indexing into the table of printable compass points, // and is not the same as the index specified to be printed in the output. func cpx(h float32) int {
x := int(h/11.25+.5) % 32 if x < 0 { x += 32 } return x
}
// printable compass points var compassPoint = []string{
"North", "North by east", "North-northeast", "Northeast by north", "Northeast", "Northeast by east", "East-northeast", "East by north", "East", "East by south", "East-southeast", "Southeast by east", "Southeast", "Southeast by south", "South-southeast", "South by east", "South", "South by west", "South-southwest", "Southwest by south", "Southwest", "Southwest by west", "West-southwest", "West by south", "West", "West by north", "West-northwest", "Northwest by west", "Northwest", "Northwest by north", "North-northwest", "North by west",
}
func main() {
fmt.Println("Index Compass point Degree") for i, h := range []float32{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} { index := i%32 + 1 // printable index computed per pseudocode fmt.Printf("%4d %-19s %7.2f°\n", index, degrees2compasspoint(h), h) }
}</lang>
Index Compass point Degree 1 North 0.00° 2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.50° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.00° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.50° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.00° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.50° 32 North by west 354.37° 1 North 354.38°
Haskell
<lang haskell> import Data.Char import Data.Maybe import Text.Printf
dirs = ["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"]
-- Given an index between 0 and 31 return the corresponding compass point name. pointName = capitalize . concatMap (fromMaybe "?" . fromChar) . (dirs !!)
where fromChar c = lookup c [('N', "north"), ('S', "south"), ('E', "east"), ('W', "west"), ('b', " by "), ('-', "-")] capitalize (c:cs) = toUpper c : cs
-- Convert degrees to a compass point index between 0 and 31. pointIndex d = (round (d*1000) + 5625) `mod` 360000 `div` 11250
printPointName d = let deg = read d :: Double
idx = pointIndex deg in printf "%2d %-18s %6.2f°\n" (idx+1) (pointName idx) deg
main = do
input <- getContents mapM_ printPointName $ lines input
</lang> Output:
1 North 0.00° 2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.50° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.00° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.50° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.00° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.50° 32 North by west 354.37° 1 North 354.38°
Icon and Unicon
<lang Icon>link strings,numbers
procedure main()
every heading := 11.25 * (i := 0 to 32) do {
case i%3 of { 1: heading +:= 5.62 2: heading -:= 5.62 } write(right(i+1,3)," ",left(direction(heading),20)," ",fix(heading,,7,2)) }
end
procedure direction(d) # compass heading given +/- degrees static dirs initial {
every put(dirs := [], replacem(!["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","north","E","east","W","west","S","south","b"," by ")) } return dirs[round(((((d%360)+360)%360)/11.25)%32 + 1)]
end</lang>
strings for replacem numbers for round, fix
Output:
1 north 0.00 2 north by east 16.87 3 north-northeast 16.88 4 northeast by north 33.75 5 northeast 50.62 6 northeast by east 50.63 7 east-northeast 67.50 8 east by north 84.37 9 east 84.38 10 east by south 101.25 11 east-southeast 118.12 12 southeast by east 118.13 13 southeast 135.00 14 southeast by south 151.87 15 south-southeast 151.88 16 south by east 168.75 17 south 185.62 18 south by west 185.63 19 south-southwest 202.50 20 southwest by south 219.37 21 southwest 219.38 22 southwest by west 236.25 23 west-southwest 253.12 24 west by south 253.13 25 west 270.00 26 west by north 286.87 27 west-northwest 286.88 28 northwest by west 303.75 29 northwest 320.62 30 northwest by north 320.63 31 north-northwest 337.50 32 north by west 354.37
J
<lang j>require'strings' subs=: 'N,north,S,south,E,east,W,west,b, by ,' dirs=: subs (toupper@{., }.)@rplc~L:1 0&(<;._2) 0 :0 -. ' ',LF
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,
) indice=: 32 | 0.5 <.@+ %&11.25 deg2pnt=: dirs {~ indice</lang>
Example use:
<lang j> i.10 0 1 2 3 4 5 6 7 8 9
deg2pnt i.10
┌─────┬─────┬─────┬─────┬─────┬─────┬─────────────┬─────────────┬─────────────┬─────────────┐ │North│North│North│North│North│North│North by east│North by east│North by east│North by east│ └─────┴─────┴─────┴─────┴─────┴─────┴─────────────┴─────────────┴─────────────┴─────────────┘</lang>
Required example:
<lang j> (":@>:@indice,.' ',.>@deg2pnt,.' ',.":@,.)(*&11.25 + 5.62 * 0 1 _1 {~ 3&|) i.33 1 North 0 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.5 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.5 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.5 32 North by west 354.37 1 North 354.38</lang>
Java
<lang java>public class BoxingTheCompass{
private static String[] points = new String[32]; public static void main(String[] args){ buildPoints(); double heading = 0; for(int i = 0; i<= 32;i++){ heading = i * 11.25; switch(i % 3){ case 1: heading += 5.62; break; case 2: heading -= 5.62; break; default: } System.out.printf("%s\t%18s\t%s°\n",(i % 32) + 1, initialUpper(getPoint(heading)), heading); } } private static void buildPoints(){ String[] cardinal = {"north", "east", "south", "west"}; String[] pointDesc = {"1", "1 by 2", "1-C", "C by 1", "C", "C by 2", "2-C", "2 by 1"}; String str1, str2, strC; for(int i = 0;i <= 3;i++){ str1 = cardinal[i]; str2 = cardinal[(i + 1) % 4]; strC = (str1.equals("north") || str1.equals("south")) ? (str1 + str2): (str2 + str1); for(int j = 0;j <= 7;j++){ points[i * 8 + j] = pointDesc[j].replace("1", str1).replace("2", str2).replace("C", strC); } } } private static String initialUpper(String s){ return s.substring(0, 1).toUpperCase() + s.substring(1); } private static String getPoint(double degrees){ double testD = (degrees / 11.25) + 0.5; return points[(int)Math.floor(testD % 32)]; }
}</lang> Output:
1 North 0.0° 2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.5° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.0° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.5° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.0° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.5° 32 North by west 354.37° 1 North 354.38°
MUMPS
The TCL implementation was the starting point, but this isn't an exact translation. <lang MUMPS>BOXING(DEGREE)
;This takes in a degree heading, nominally from 0 to 360, and returns the compass point name. QUIT:((DEGREE<0)||(DEGREE>360)) "land lubber can't read a compass" NEW DIRS,UNP,UNPACK,SEP,DIR,DOS,D,DS,I,F SET DIRS="N^NbE^N-NE^NEbN^NE^NEbE^E-NE^EbN^E^EbS^E-SE^SEbE^SE^SEbS^S-SE^SbE^" SET DIRS=DIRS_"S^SbW^S-SW^SWbS^SW^SWbW^W-SW^WbS^W^WbN^W-NW^NWbW^NW^NWbN^N-NW^NbW" SET UNP="NESWb" SET UNPACK="north^east^south^west^ by " SET SEP=360/$LENGTH(DIRS,"^") SET DIR=(DEGREE/SEP)+1.5 SET DIR=$SELECT((DIR>33):DIR-32,1:DIR) SET DOS=$NUMBER(DIR-.5,0) SET D=$PIECE(DIRS,"^",DIR) SET DS="" FOR I=1:1:$LENGTH(D) DO . SET F=$FIND(UNP,$EXTRACT(D,I)) SET DS=DS_$SELECT((F>0):$PIECE(UNPACK,"^",F-1),1:$E(D,I)) KILL DIRS,UNP,UNPACK,SEP,DIR,D,I,F QUIT DOS_"^"_DS
BOXWRITE
NEW POINTS,UP,LO,DIR,P,X SET POINTS="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," SET POINTS=POINTS_"151.88,168.75,185.62,185.63,202.5,219.37,219.38,236.25,253.12,253.13,270.0,286.87," SET POINTS=POINTS_"286.88,303.75,320.62,320.63,337.5,354.37,354.38" SET UP="ABCDEFGHIJKLMNOPQRSTUVWXYZ" SET LO="abcdefghijklmnopqrstuvwxyz" FOR P=1:1:$LENGTH(POINTS,",") DO . SET X=$$BOXING($PIECE(POINTS,",",P)) . ;Capitalize the initial letter of the direction . SET DIR=$PIECE(X,"^",2) . SET DIR=$TRANSLATE($EXTRACT(DIR,1),LO,UP)_$EXTRACT(DIR,2,$LENGTH(DIR)) . WRITE $PIECE(X,"^"),?5,DIR,?40,$JUSTIFY($PIECE(POINTS,",",P),10,2),! KILL POINTS,UP,LO,DIR,P,X QUIT</lang>
Output:
Debugger executing 'BOXWRITE^COMPASS' 1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 1 North 354.38
Perl
Don't waste brain cells calculating names, not worth the effort. Code is probably shorter, faster, and easier to read this way. <lang Perl>use utf8;
my @names = ( "North", "North by east", "North-northeast", "Northeast by north", "Northeast", "Northeast by east", "East-northeast", "East by north", "East", "East by south", "East-southeast", "Southeast by east", "Southeast", "Southeast by south", "South-southeast", "South by east", "South", "South by west", "South-southwest", "Southwest by south", "Southwest", "Southwest by west", "West-southwest", "West by south", "West", "West by north", "West-northwest", "Northwest by west", "Northwest", "Northwest by north", "North-northwest", "North by west", ); my @angles = (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);
for (@angles) { my $i = int(($_ * 32 / 360) + .5) % 32; printf "%3d %18s %6.2f°\n", $i + 1, $names[$i], $_; }</lang>output<lang> 1 North 0.00°
2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.50° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.00° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.50° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.00° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.50° 32 North by west 354.37° 1 North 354.38°</lang>
Perl 6
<lang perl6>sub point (Int $index) {
my $ix = $index % 32; if $ix +& 1 { "&point(($ix + 1) +& 28) by &point(((2 - ($ix +& 2)) * 4) + $ix +& 24)" } elsif $ix +& 2 { "&point(($ix + 2) +& 24)-&point(($ix +| 4) +& 28)" } elsif $ix +& 4 { "&point(($ix + 8) +& 16)&point(($ix +| 8) +& 24)" } else { <north east south west>[$ix div 8]; }
}
sub test-angle ($ix) { $ix * 11.25 + (0, 5.62, -5.62)[ $ix % 3 ] } sub angle-to-point($𝜽) { floor $𝜽 / 360 * 32 + 0.5 }
for 0 .. 32 -> $ix {
my $𝜽 = test-angle($ix); printf " %2d %6.2f%s %s\n", $ix % 32 + 1, $𝜽, '°', ucfirst point angle-to-point $𝜽;
}</lang>
Output:
1 0.00° North 2 16.87° North by east 3 16.88° North-northeast 4 33.75° Northeast by north 5 50.62° Northeast 6 50.63° Northeast by east 7 67.50° East-northeast 8 84.37° East by north 9 84.38° East 10 101.25° East by south 11 118.12° East-southeast 12 118.13° Southeast by east 13 135.00° Southeast 14 151.87° Southeast by south 15 151.88° South-southeast 16 168.75° South by east 17 185.62° South 18 185.63° South by west 19 202.50° South-southwest 20 219.37° Southwest by south 21 219.38° Southwest 22 236.25° Southwest by west 23 253.12° West-southwest 24 253.13° West by south 25 270.00° West 26 286.87° West by north 27 286.88° West-northwest 28 303.75° Northwest by west 29 320.62° Northwest 30 320.63° Northwest by north 31 337.50° North-northwest 32 354.37° North by west 1 354.38° North
PicoLisp
<lang PicoLisp>(scl 3)
(setq *Compass # Build lookup table
(let H -16.875 (mapcar '((Str) (cons (inc 'H 11.25) # Heading in degrees (pack # Compass point (replace (chop Str) "N" "north" "E" "east" "S" "south" "W" "west" "b" " by " ) ) ) ) '("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" ) ) ) )
(de heading (Deg)
(rank (% Deg 360.00) *Compass) )
(for I (range 0 32)
(let H (* I 11.25) (case (% I 3) (1 (inc 'H 5.62)) (2 (dec 'H 5.62)) ) (tab (3 1 -18 8) (inc (% I 32)) NIL (cdr (heading H)) (round H 2) ) ) )</lang>
Output:
1 north 0.00 2 north by east 16.87 3 north-northeast 16.88 4 northeast by north 33.75 5 northeast 50.62 6 northeast by east 50.63 7 east-northeast 67.50 8 east by north 84.37 9 east 84.38 10 east by south 101.25 11 east-southeast 118.12 12 southeast by east 118.13 13 southeast 135.00 14 southeast by south 151.87 15 south-southeast 151.88 16 south by east 168.75 17 south 185.62 18 south by west 185.63 19 south-southwest 202.50 20 southwest by south 219.37 21 southwest 219.38 22 southwest by west 236.25 23 west-southwest 253.12 24 west by south 253.13 25 west 270.00 26 west by north 286.87 27 west-northwest 286.88 28 northwest by west 303.75 29 northwest 320.62 30 northwest by north 320.63 31 north-northwest 337.50 32 north by west 354.37 1 north 354.38
PureBasic
<lang PureBasic>DataSection
Data.s "N", "north", "E", "east", "W", "west", "S", "south", "b", " by " ;abbreviations, expansions Data.s "N NbE N-NE NEbN NE NEbE E-NE EbN E EbS E-SE SEbE SE SEbS S-SE SbE" ;dirs Data.s "S SbW S-SW SWbS SW SWbW W-SW WbS W WbN W-NW NWbW NW NWbN N-NW NbW"
EndDataSection
- initialize data
NewMap dirSubst.s() Define i, abbr.s, expansion.s For i = 1 To 5
Read.s abbr Read.s expansion dirSubst(abbr) = expansion
Next
Dim dirs.s(32) Define j, s.s For j = 0 To 1
Read.s s.s For i = 0 To 15 abbr.s = StringField(s, i + 1, " ") dirs(j * 16 + i) = abbr Next
Next
- expand abbreviated compass point and capitalize
Procedure.s abbr2compassPoint(abbr.s)
Shared dirSubst() Protected i, compassPoint.s, key.s For i = 1 To Len(abbr) key.s = Mid(abbr, i, 1) If FindMapElement(dirSubst(), key) compassPoint + dirSubst(key) Else compassPoint + key EndIf Next ProcedureReturn UCase(Left(compassPoint, 1)) + Mid(compassPoint, 2)
EndProcedure
Procedure.s angle2compass(angle.f)
Shared dirs() Static segment.f = 360.0 / 32 ;width of each compass segment Protected dir ;work out which segment contains the compass angle dir = Int((Mod(angle, 360) / segment) + 0.5) ;convert to a named direction ProcedureReturn abbr2compassPoint(dirs(dir))
EndProcedure
- box the compass
If OpenConsole()
Define i, heading.f, index For i = 0 To 32 heading = i * 11.25 If i % 3 = 1 heading + 5.62 EndIf If i % 3 = 2 heading - 5.62 EndIf index = i % 32 + 1 PrintN(RSet(Str(index), 2) + " " + LSet(angle2compass(heading), 18) + RSet(StrF(heading, 2), 7)) Next Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() CloseConsole()
EndIf</lang> Sample output:
1 North 0.00 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Northeast by east 50.63 7 East-northeast 67.50 8 East by north 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.00 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.50 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.00 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.50 32 North by west 354.37 1 354.38
Prolog
Part 1 : The following knowledge base takes a heading in degrees and returns the correct 32-point compass heading. It can also go in the other direction. <lang prolog> compassangle(1, 'North',n, 0.00). compassangle(2, 'North by east', nbe, 11.25). compassangle(3, 'North-northeast', nne,22.50). compassangle(4, 'Northeast by north', nebn,33.75). compassangle(5, 'Northeast', ne,45.00). compassangle(6, 'Norteast by east', nebe,56.25). compassangle(7, 'East-northeast', ene,67.50). compassangle(8, 'East by North', ebn,78.75). compassangle(9, 'East', e,90.00). compassangle(10, 'East by south', ebs, 101.25). compassangle(11, 'East-southeast', ese,112.50). compassangle(12, 'Southeast by east', sebe, 123.75). compassangle(13, 'Southeast', se, 135.00). compassangle(14, 'Southeast by south', sebs, 146.25). compassangle(15, 'South-southeast',sse, 157.50). compassangle(16, 'South by east', sbe, 168.75). compassangle(17, 'South', s, 180.00). compassangle(18, 'South by west', sbw, 191.25). compassangle(19, 'South-southwest', ssw, 202.50). compassangle(20, 'Southwest by south', swbs, 213.75). compassangle(21, 'Southwest', sw, 225.00). compassangle(22, 'Southwest by west', swbw, 236.25). compassangle(23, 'West-southwest', wsw, 247.50). compassangle(24, 'West by south', wbs, 258.75). compassangle(25, 'West', w, 270.00). compassangle(26, 'West by north', wbn, 281.25). compassangle(27, 'West-northwest', wnw, 292.50). compassangle(28, 'Northwest by west', nwbw, 303.75). compassangle(29, 'Northwest', nw, 315.00). compassangle(30, 'Northwest by north', nwbn, 326.25). compassangle(31, 'North-northwest', nnw, 337.50). compassangle(32, 'North by west', nbw, 348.75). compassangle(1, 'North', n, 360.00). compassangle(Index , Name, Heading, Angle) :- nonvar(Angle), resolveindex(Angle, Index),
compassangle(Index,Name, Heading, _).
resolveindex(Angle, Index) :- N is Angle / 11.25 + 0.5, I is floor(N),Index is (I mod 32) + 1. </lang> Part 2 : The following rules print a table of indexes. <lang prolog> printTableRow(Angle) :- compassangle(Index, Name, _, Angle),
write(Index), write(' '), write(Name), write(' '), write(Angle).
printTable([X|Xs]) :- printTableRow(X), nl, printTable(Xs),!. printTable([]). </lang> The following query prints the required table. <lang prolog> ?- printTable([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]).
1 North 0.0 2 North by east 16.87 3 North-northeast 16.88 4 Northeast by north 33.75 5 Northeast 50.62 6 Norteast by east 50.63 7 East-northeast 67.5 8 East by North 84.37 9 East 84.38 10 East by south 101.25 11 East-southeast 118.12 12 Southeast by east 118.13 13 Southeast 135.0 14 Southeast by south 151.87 15 South-southeast 151.88 16 South by east 168.75 17 South 185.62 18 South by west 185.63 19 South-southwest 202.5 20 Southwest by south 219.37 21 Southwest 219.38 22 Southwest by west 236.25 23 West-southwest 253.12 24 West by south 253.13 25 West 270.0 26 West by north 286.87 27 West-northwest 286.88 28 Northwest by west 303.75 29 Northwest 320.62 30 Northwest by north 320.63 31 North-northwest 337.5 32 North by west 354.37 1 North 354.38 true. </lang>
Python
<lang python>majors = 'north east south west'.split() majors *= 2 # no need for modulo later quarter1 = 'N,N by E,N-NE,NE by N,NE,NE by E,E-NE,E by N'.split(',') quarter2 = [p.replace('NE','EN') for p in quarter1]
def degrees2compasspoint(d):
d = (d % 360) + 360/64 majorindex, minor = divmod(d, 90.) majorindex = int(majorindex) minorindex = int( (minor*4) // 45 ) p1, p2 = majors[majorindex: majorindex+2] if p1 in {'north', 'south'}: q = quarter1 else: q = quarter2 return q[minorindex].replace('N', p1).replace('E', p2).capitalize()
if __name__ == '__main__':
for i in range(33): d = i * 11.25 m = i % 3 if m == 1: d += 5.62 elif m == 2: d -= 5.62 n = i % 32 + 1 print( '%2i %-18s %7.2f°' % (n, degrees2compasspoint(d), d) )</lang>
- Output
1 North 0.00° 2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.50° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.00° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.50° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.00° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.50° 32 North by west 354.37° 1 North 354.38°
Ruby
First I want a hash Headings = {1 => "north", 2 => "north by east", ...}. This program outputs the hash so that I can skip typing all 32 pairs.
<lang ruby>h = [] ["north", "east", "south", "west", "north"].each_cons(2) do |a, b|
c = if ["north", "south"].include? a then "#{a}#{b}" else "#{b}#{a}" end h << a h << "#{a} by #{b}" h << "#{a}-#{c}" h << "#{c} by #{a}" h << "#{c}" h << "#{c} by #{b}" h << "#{b}-#{c}" h << "#{b} by #{a}"
end
puts "Headings = {" h.each_with_index { |n, i| puts " #{i+1} => #{n.inspect}," } puts "}"</lang>
I paste the output from the first program into a second program, then add a method to find a compass heading from degrees, and some code to output the table.
<lang ruby>Headings = {
1 => "north", 2 => "north by east", 3 => "north-northeast", 4 => "northeast by north", 5 => "northeast", 6 => "northeast by east", 7 => "east-northeast", 8 => "east by north", 9 => "east", 10 => "east by south", 11 => "east-southeast", 12 => "southeast by east", 13 => "southeast", 14 => "southeast by south", 15 => "south-southeast", 16 => "south by east", 17 => "south", 18 => "south by west", 19 => "south-southwest", 20 => "southwest by south", 21 => "southwest", 22 => "southwest by west", 23 => "west-southwest", 24 => "west by south", 25 => "west", 26 => "west by north", 27 => "west-northwest", 28 => "northwest by west", 29 => "northwest", 30 => "northwest by north", 31 => "north-northwest", 32 => "north by west",
}
- Finds the 32-point compass heading nearest _degrees_, and
- returns an array of the index and name.
- p heading(60)
- # => [6, "northeast by east"]
def heading(degrees)
i = degrees.quo(360).*(32).round.%(32).+(1) [i, Headings[i]]
end
- an array of angles, in degrees
angles = (0..32).map { |i| i * 11.25 + [0, 5.62, -5.62][i % 3] }
angles.each do |degrees|
index, name = heading degrees printf "%2d %20s %6g\n", index, name.center(20), degrees
end</lang>
The second program outputs this table:
1 north 0 2 north by east 16.87 3 north-northeast 16.88 4 northeast by north 33.75 5 northeast 50.62 6 northeast by east 50.63 7 east-northeast 67.5 8 east by north 84.37 9 east 84.38 10 east by south 101.25 11 east-southeast 118.12 12 southeast by east 118.13 13 southeast 135 14 southeast by south 151.87 15 south-southeast 151.88 16 south by east 168.75 17 south 185.62 18 south by west 185.63 19 south-southwest 202.5 20 southwest by south 219.37 21 southwest 219.38 22 southwest by west 236.25 23 west-southwest 253.12 24 west by south 253.13 25 west 270 26 west by north 286.87 27 west-northwest 286.88 28 northwest by west 303.75 29 northwest 320.62 30 northwest by north 320.63 31 north-northwest 337.5 32 north by west 354.37 1 north 354.38
Tcl
<lang tcl>proc angle2compass {angle} {
set dirs {
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
} set unpack {N "north" E "east" W "west" S "south" b " by "}
# Compute the width of each compass segment set sep [expr {360.0 / [llength $dirs]}]
# Work out which segment contains the compass angle set dir [expr {round((fmod($angle + $sep/2, 360) - $sep/2) / $sep)}]
# Convert to a named direction, capitalized as in the wikipedia article return [string totitle [string map $unpack [lindex $dirs $dir]]]
}
- Box the compass, using the variable generation algorithm described
for {set i 0} {$i < 33} {incr i} {
set heading [expr {$i * 11.25}] if {$i % 3 == 1} {set heading [expr {$heading + 5.62}]} if {$i % 3 == 2} {set heading [expr {$heading - 5.62}]} set index [expr {$i % 32 + 1}]
# Pretty-print the results of converting an angle to a compass heading puts [format "%2i %-18s %7.2f°" $index [angle2compass $heading] $heading]
}</lang> Output:
1 North 0.00° 2 North by east 16.87° 3 North-northeast 16.88° 4 Northeast by north 33.75° 5 Northeast 50.62° 6 Northeast by east 50.63° 7 East-northeast 67.50° 8 East by north 84.37° 9 East 84.38° 10 East by south 101.25° 11 East-southeast 118.12° 12 Southeast by east 118.13° 13 Southeast 135.00° 14 Southeast by south 151.87° 15 South-southeast 151.88° 16 South by east 168.75° 17 South 185.62° 18 South by west 185.63° 19 South-southwest 202.50° 20 Southwest by south 219.37° 21 Southwest 219.38° 22 Southwest by west 236.25° 23 West-southwest 253.12° 24 West by south 253.13° 25 West 270.00° 26 West by north 286.87° 27 West-northwest 286.88° 28 Northwest by west 303.75° 29 Northwest 320.62° 30 Northwest by north 320.63° 31 North-northwest 337.50° 32 North by west 354.37° 1 North 354.38°
Visual Basic .NET
<lang vbnet>Module BoxingTheCompass
Dim _points(32) As String
Sub Main() BuildPoints()
Dim heading As Double = 0D
For i As Integer = 0 To 32 heading = i * 11.25 Select Case i Mod 3 Case 1 heading += 5.62 Case 2 heading -= 5.62 End Select
Console.WriteLine("{0,2}: {1,-18} {2,6:F2}°", (i Mod 32) + 1, InitialUpper(GetPoint(heading)), heading) Next End Sub
Private Sub BuildPoints() Dim cardinal As String() = New String() {"north", "east", "south", "west"} Dim pointDesc As String() = New String() {"1", "1 by 2", "1-C", "C by 1", "C", "C by 2", "2-C", "2 by 1"}
Dim str1, str2, strC As String
For i As Integer = 0 To 3 str1 = cardinal(i) str2 = cardinal((i + 1) Mod 4) strC = IIf(str1 = "north" Or str1 = "south", str1 & str2, str2 & str1) For j As Integer = 0 To 7 _points(i * 8 + j) = pointDesc(j).Replace("1", str1).Replace("2", str2).Replace("C", strC) Next Next End Sub
Private Function InitialUpper(ByVal s As String) As String Return s.Substring(0, 1).ToUpper() & s.Substring(1) End Function
Private Function GetPoint(ByVal Degrees As Double) As String Dim testD As Double = (Degrees / 11.25) + 0.5 Return _points(CInt(Math.Floor(testD Mod 32))) End Function
End Module </lang> Output:
1: North 0.00° 2: North by east 16.87° 3: North-northeast 16.88° 4: Northeast by north 33.75° 5: Northeast 50.62° 6: Northeast by east 50.63° 7: East-northeast 67.50° 8: East by north 84.37° 9: East 84.38° 10: East by south 101.25° 11: East-southeast 118.12° 12: Southeast by east 118.13° 13: Southeast 135.00° 14: Southeast by south 151.87° 15: South-southeast 151.88° 16: South by east 168.75° 17: South 185.62° 18: South by west 185.63° 19: South-southwest 202.50° 20: Southwest by south 219.37° 21: Southwest 219.38° 22: Southwest by west 236.25° 23: West-southwest 253.12° 24: West by south 253.13° 25: West 270.00° 26: West by north 286.87° 27: West-northwest 286.88° 28: Northwest by west 303.75° 29: Northwest 320.62° 30: Northwest by north 320.63° 31: North-northwest 337.50° 32: North by west 354.37° 1: North 354.38°