Box the compass: Difference between revisions

From Rosetta Code
Content added Content deleted
(Only these headings.)
(J: update to track task description)
Line 42: Line 42:
└─────┴─────┴─────┴─────┴─────┴─────┴─────────────┴─────────────┴─────────────┴─────────────┘</lang>
└─────┴─────┴─────┴─────┴─────┴─────┴─────────────┴─────────────┴─────────────┴─────────────┘</lang>


Required example:
As for the required example, sometimes it's simpler to do just a small bit of "extra" work:


<lang j> ((1 ":@:+ ~."1@index),.' ',.;@~."1@deg2pnt,.' ',.'7.2'8!:2]) _5.62 0 5.62 +/~11.25 * i.33
<lang j> (":@>:@indice,.' ',.>@deg2pnt,.' ',.":@,.)(*&11.25 + 5.62 * 0 1 _1 {~ 3&|) i.33
1 North -5.62 0.00 5.62
1 North 0
2 North by east 5.63 11.25 16.87
2 North by east 16.87
3 North-northeast 16.88 22.50 28.12
3 North-northeast 16.88
4 Northeast by north 28.13 33.75 39.37
4 Northeast by north 33.75
5 Northeast 39.38 45.00 50.62
5 Northeast 50.62
6 Northeast by east 50.63 56.25 61.87
6 Northeast by east 50.63
7 East-northeast 61.88 67.50 73.12
7 East-northeast 67.5
8 East by north 73.13 78.75 84.37
8 East by north 84.37
9 East 84.38 90.00 95.62
9 East 84.38
10 East by south 95.63 101.25 106.87
10 East by south 101.25
11 East-southeast 106.88 112.50 118.12
11 East-southeast 118.12
12 Southeast by east 118.13 123.75 129.37
12 Southeast by east 118.13
13 Southeast 129.38 135.00 140.62
13 Southeast 135
14 Southeast by south 140.63 146.25 151.87
14 Southeast by south 151.87
15 South-southeast 151.88 157.50 163.12
15 South-southeast 151.88
16 South by east 163.13 168.75 174.37
16 South by east 168.75
17 South 174.38 180.00 185.62
17 South 185.62
18 South by west 185.63 191.25 196.87
18 South by west 185.63
19 South-southwest 196.88 202.50 208.12
19 South-southwest 202.5
20 Southwest by south 208.13 213.75 219.37
20 Southwest by south 219.37
21 Southwest 219.38 225.00 230.62
21 Southwest 219.38
22 Southwest by west 230.63 236.25 241.87
22 Southwest by west 236.25
23 West-southwest 241.88 247.50 253.12
23 West-southwest 253.12
24 West by south 253.13 258.75 264.37
24 West by south 253.13
25 West 264.38 270.00 275.62
25 West 270
26 West by north 275.63 281.25 286.87
26 West by north 286.87
27 West-northwest 286.88 292.50 298.12
27 West-northwest 286.88
28 Northwest by west 298.13 303.75 309.37
28 Northwest by west 303.75
29 Northwest 309.38 315.00 320.62
29 Northwest 320.62
30 Northwest by north 320.63 326.25 331.87
30 Northwest by north 320.63
31 North-northwest 331.88 337.50 343.12
31 North-northwest 337.5
32 North by west 343.13 348.75 354.37
32 North by west 354.37
1 North 354.38 360.00 365.62</lang>
1 North 354.38</lang>

Here, I compute the name (and index) for each of the numbers, and then find the unique list of names (and indices) represented in each row -- which is always only one name (and only one index) -- and convert the whole thing to characters.


=={{header|Java}}==
=={{header|Java}}==

Revision as of 18:23, 29 March 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

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

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

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°

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
   return [string totitle [string map $unpack [lindex $dirs $dir]]]

}

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}]
   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°