Box the compass: Difference between revisions
m →{{header|Visual Basic .NET}}: Changed GetPoint to use "Mod 32" instead of subtraction of 32. |
J |
||
Line 81: | Line 81: | ||
32 North by west 354.37° |
32 North by west 354.37° |
||
1 North 354.38°</pre> |
1 North 354.38°</pre> |
||
=={{header|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,]' |
|||
by=:' by 'tween |
|||
points=:,2 ([;by;'-'tween;by~)&>/\ cardinal |
|||
deg2pnt=: points {~ 32 | 0.5 <.@+ %&11.25</lang> |
|||
As for the required example, sometimes it's simpler to do just a small bit of "extra" work: |
|||
<lang j> ((;@~."1@deg2pnt),.' ',.":)(_5.62 0 5.62 +/~11.25 * i.33) |
|||
North _5.62 0 5.62 |
|||
North by Northeast 5.63 11.25 16.87 |
|||
North-Northeast 16.88 22.5 28.12 |
|||
Northeast by North 28.13 33.75 39.37 |
|||
Northeast 39.38 45 50.62 |
|||
Northeast by East 50.63 56.25 61.87 |
|||
Northeast-East 61.88 67.5 73.12 |
|||
East by Northeast 73.13 78.75 84.37 |
|||
East 84.38 90 95.62 |
|||
East by Southeast 95.63 101.25 106.87 |
|||
East-Southeast 106.88 112.5 118.12 |
|||
Southeast by East 118.13 123.75 129.37 |
|||
Southeast 129.38 135 140.62 |
|||
Southeast by South 140.63 146.25 151.87 |
|||
Southeast-South 151.88 157.5 163.12 |
|||
South by Southeast 163.13 168.75 174.37 |
|||
South 174.38 180 185.62 |
|||
South by Southwest 185.63 191.25 196.87 |
|||
South-Southwest 196.88 202.5 208.12 |
|||
Southwest by South 208.13 213.75 219.37 |
|||
Southwest 219.38 225 230.62 |
|||
Southwest by West 230.63 236.25 241.87 |
|||
Southwest-West 241.88 247.5 253.12 |
|||
West by Southwest 253.13 258.75 264.37 |
|||
West 264.38 270 275.62 |
|||
West by Northwest 275.63 281.25 286.87 |
|||
West-Northwest 286.88 292.5 298.12 |
|||
Northwest by West 298.13 303.75 309.37 |
|||
Northwest 309.38 315 320.62 |
|||
Northwest by North 320.63 326.25 331.87 |
|||
Northwest-North 331.88 337.5 343.12 |
|||
North by Northwest 343.13 348.75 354.37 |
|||
North 354.38 360 365.62</lang> |
|||
Here, I compute the name for each of the numbers, and then find the unique set of names represented in each row (which is always only one name) and convert the whole thing to characters. |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
Revision as of 14:41, 28 March 2011
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.
- 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 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..33 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
Python
<lang python>majors = 'north east south west'.split() majors = majors + majors # 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°
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,]' by=:' by 'tween points=:,2 ([;by;'-'tween;by~)&>/\ cardinal deg2pnt=: points {~ 32 | 0.5 <.@+ %&11.25</lang>
As for the required example, sometimes it's simpler to do just a small bit of "extra" work:
<lang j> ((;@~."1@deg2pnt),.' ',.":)(_5.62 0 5.62 +/~11.25 * i.33) North _5.62 0 5.62 North by Northeast 5.63 11.25 16.87 North-Northeast 16.88 22.5 28.12 Northeast by North 28.13 33.75 39.37 Northeast 39.38 45 50.62 Northeast by East 50.63 56.25 61.87 Northeast-East 61.88 67.5 73.12 East by Northeast 73.13 78.75 84.37 East 84.38 90 95.62 East by Southeast 95.63 101.25 106.87 East-Southeast 106.88 112.5 118.12 Southeast by East 118.13 123.75 129.37 Southeast 129.38 135 140.62 Southeast by South 140.63 146.25 151.87 Southeast-South 151.88 157.5 163.12 South by Southeast 163.13 168.75 174.37 South 174.38 180 185.62 South by Southwest 185.63 191.25 196.87 South-Southwest 196.88 202.5 208.12 Southwest by South 208.13 213.75 219.37 Southwest 219.38 225 230.62 Southwest by West 230.63 236.25 241.87 Southwest-West 241.88 247.5 253.12 West by Southwest 253.13 258.75 264.37 West 264.38 270 275.62 West by Northwest 275.63 281.25 286.87 West-Northwest 286.88 292.5 298.12 Northwest by West 298.13 303.75 309.37 Northwest 309.38 315 320.62 Northwest by North 320.63 326.25 331.87 Northwest-North 331.88 337.5 343.12 North by Northwest 343.13 348.75 354.37 North 354.38 360 365.62</lang>
Here, I compute the name for each of the numbers, and then find the unique set of names represented in each row (which is always only one name) and convert the whole thing to characters.
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 visual basic .net>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°