Box the compass: Difference between revisions
(J: subliminal bug fix) |
m (→{{header|J}}) |
||
Line 69: | Line 69: | ||
1 North 354.38 360 365.62</lang> |
1 North 354.38 360 365.62</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 |
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|Python}}== |
=={{header|Python}}== |
Revision as of 15:18, 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
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 fixup=: (rplc |.@;{.@;:@tolower) ^:(' '&e.)L:0 points=:fixup ,2 ([;by;'-'tween;by~)&>/\ cardinal indice=: 32 | 0.5 <.@+ %&11.25 deg2pnt=: points {~ indice</lang>
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,.' ',.":) _5.62 0 5.62 +/~11.25 * i.33
1 North _5.62 0 5.62 2 North by east 5.63 11.25 16.87 3 North-northeast 16.88 22.5 28.12 4 Northeast by north 28.13 33.75 39.37 5 Northeast 39.38 45 50.62 6 Northeast by east 50.63 56.25 61.87 7 Northeast-east 61.88 67.5 73.12 8 East by north 73.13 78.75 84.37 9 East 84.38 90 95.62
10 East by south 95.63 101.25 106.87 11 East-southeast 106.88 112.5 118.12 12 Southeast by east 118.13 123.75 129.37 13 Southeast 129.38 135 140.62 14 Southeast by south 140.63 146.25 151.87 15 Southeast-south 151.88 157.5 163.12 16 South by east 163.13 168.75 174.37 17 South 174.38 180 185.62 18 South by west 185.63 191.25 196.87 19 South-southwest 196.88 202.5 208.12 20 Southwest by south 208.13 213.75 219.37 21 Southwest 219.38 225 230.62 22 Southwest by west 230.63 236.25 241.87 23 Southwest-west 241.88 247.5 253.12 24 West by south 253.13 258.75 264.37 25 West 264.38 270 275.62 26 West by north 275.63 281.25 286.87 27 West-northwest 286.88 292.5 298.12 28 Northwest by west 298.13 303.75 309.37 29 Northwest 309.38 315 320.62 30 Northwest by north 320.63 326.25 331.87 31 Northwest-north 331.88 337.5 343.12 32 North by west 343.13 348.75 354.37
1 North 354.38 360 365.62</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.
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°
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°