Box the compass: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added C++)
m (C++ improved formatting)
Line 33: Line 33:
#include <iostream>;
#include <iostream>;
#include <math.h>
#include <math.h>

using std::string;
using std::string;
using namespace boost::assign;
using namespace boost::assign;
Line 71: Line 70:
case 'N' : retval += "north"; break;
case 'N' : retval += "north"; break;
case 'S' : retval += "south"; break;
case 'S' : retval += "south"; break;
case 'E' : retval += "east"; break;
case 'E' : retval += "east"; break;
case 'W' : retval += "west"; break;
case 'W' : retval += "west"; break;
case 'b' : retval += " by "; break;
case 'b' : retval += " by "; break;
}
}
}
}
Line 88: Line 87:
320.62, 320.63, 337.5, 354.37, 354.38;
320.62, 320.63, 337.5, 354.37, 354.38;
int i;
int i;
format f("%1$4d %2$-25s %3%");
format f("%1$4d %2$-20s %3$_7.2f");


BOOST_FOREACH(float a, headings)
BOOST_FOREACH(float a, headings)
Line 100: Line 99:
Output:
Output:
<pre>
<pre>
1 North 0
1 North 0.00
2 North by east 16.87
2 North by east 16.87
3 North-northeast 16.88
3 North-northeast 16.88
4 Northeast by north 33.75
4 Northeast by north 33.75
5 Northeast 50.62
5 Northeast 50.62
6 Northeast by east 50.63
6 Northeast by east 50.63
7 East-northeast 67.5
7 East-northeast 67.50
8 East by north 84.37
8 East by north 84.37
9 East 84.38
9 East 84.38
10 East by south 101.25
10 East by south 101.25
11 East-southeast 118.12
11 East-southeast 118.12
12 Southeast by east 118.13
12 Southeast by east 118.13
13 Southeast 135
13 Southeast 135.00
14 Southeast by south 151.87
14 Southeast by south 151.87
15 South-southeast 151.88
15 South-southeast 151.88
16 South by east 168.75
16 South by east 168.75
17 South 185.62
17 South 185.62
18 South by west 185.63
18 South by west 185.63
19 South-southwest 202.5
19 South-southwest 202.50
20 Southwest by south 219.37
20 Southwest by south 219.37
21 Southwest 219.38
21 Southwest 219.38
22 Southwest by west 236.25
22 Southwest by west 236.25
23 West-southwest 253.12
23 West-southwest 253.12
24 West by south 253.13
24 West by south 253.13
25 West 270
25 West 270.00
26 West by north 286.87
26 West by north 286.87
27 West-northwest 286.88
27 West-northwest 286.88
28 Northwest by west 303.75
28 Northwest by west 303.75
29 Northwest 320.62
29 Northwest 320.62
30 Northwest by north 320.63
30 Northwest by north 320.63
31 North-northwest 337.5
31 North-northwest 337.50
32 North by west 354.37
32 North by west 354.37
1 North 354.38
1 North 354.38
</pre>
</pre>

=={{header|Clojure}}==
=={{header|Clojure}}==
{{trans|Tcl}}
{{trans|Tcl}}

Revision as of 11:57, 23 April 2011

Task
Box the compass
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

  1. Create a function that takes a heading in degrees and returns the correct 32-point compass heading.
  2. 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

C++

Using the Boost libraries

Library: Boost

<lang C++>#include <map>;

  1. include <string>;
  2. include <vector>
  3. include <boost/assign/list_inserter.hpp>
  4. include <boost/assign/std/vector.hpp>
  5. include <boost/format.hpp>
  6. include <boost/foreach.hpp>
  7. include <iostream>;
  8. include <math.h>

using std::string; using namespace boost::assign; using boost::format;

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 bool first_time(true);
   static std::map<int, string> points;
   if (first_time){
       first_time = false;
       insert (points)
           ( 1,  "N") ( 2,  "NbE") ( 3, "NNE") ( 4, "NEbN")
           ( 5, "NE") ( 6, "NEbE") ( 7, "ENE") ( 8,  "EbN")
           ( 9,  "E") (10,  "EbS") (11, "ESE") (12, "SEbE")
           (13, "SE") (14, "SEbS") (15, "SSE") (16,  "SbE")
           (17,  "S") (18,  "SbW") (19, "SSW") (20, "SWbS")
           (21, "SW") (22, "SWbW") (23, "WSW") (24,  "WbS")
           (25,  "W") (26,  "WbN") (27, "WNW") (28, "NWbW")
           (29, "NW") (30, "NWbN") (31, "NNW") (32,  "NbW");
   }
   return points[i];

}

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() {

   std::vector<float> headings;
   headings += 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;
   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

Translation of: Tcl

<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))))))

(print

(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

Translation of: Java

<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

J

<lang j>require'strings' cardinal=: ;:'N Ne E Se S Sw W Nw N' rplc;:'N North E East e east S South W West w west' tween=:1 :'[,m,tolower@]' by=:' by 'tween hy=:'-'tween&>/@(/: #@>)@; fixup=: (rplc |.@;{.@;:@tolower) ^:(' '&e.)L:0 points=: , fixup 2 ([;by;hy;by~)&>/\ cardinal indice=: 32 | 0.5 <.@+ %&11.25 deg2pnt=: points {~ 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

Translation of: Visual Basic .NET

<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

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",

}

  1. Finds the 32-point compass heading nearest _degrees_, and
  2. returns an array of the index and name.
  3. p heading(60)
  4. # => [6, "northeast by east"]

def heading(degrees)

 i = degrees.quo(360).*(32).round.%(32).+(1)
 [i, Headings[i]]

end

  1. 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]]]

}

  1. 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°