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


Notes;
 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
 The column of indices can be thought of as an enumeration of the thirty two cardinal points (see talk page)..


#!/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
)