Geohash my positions
Python 3, 250 bytes
lambda b,a:(lambda l:"".join("0123456789bcdefghjkmnpqrstuvwxyz"[int("".join(map(str,l[i*5:][:5])),2)]for i in range(8)))(sum(zip(f(a,180,-180),f(b,90,-90)),()))
f=lambda a,u,l,p=20:p and([1]+f(a,u,(u+l)/2,p-1)if u+l<a*2else[0]+f(a,(u+l)/2,l,p-1))or[]
Try it online!
I think using named functions would probably be better... anyway. I don't have time to golf this further yet, so just posting it here first.
Perl 5 (-ap -MList::Util+sum
), 136 bytes
@a=([-90,90],[-180,180]);map{$y=0;$a[--$|][$,=$F[$|]<($m=.5*sum@{$a[$|]})]=$m,$y+=$y+!$,for 0..4;$\.=(0..9,grep!/[ilo]/,b..z)[$y]}0..7}{
Try it online!
Verify all test cases
05AB1E, 64 63 61 42 41 bytes
90x‚R/>19o*î<Dd*b20jð0:SÅ=5ôJCžhA«„ŠÙaмsè
-19 bytes by porting @Neil's Charcoal answer, so make sure to upvote him as well!
-1 byte by taking the input in reversed order.
Try it online or verify all test cases.
Original 64 63 61 60 bytes answer:
εd©ˆ¾ƵΔN>÷‚19FÐÆÄ;UÅmyÄ‹®Qˆε¯θ®QNÊiXNi-ë+]¯Å=5ôJCžhA«„ŠÙaмsè
Try it online or verify all test cases.
Both take the input as [longitude, latitude]
and output as a list of characters.
Explanation:
90 # Push 90
x # Double it to 180 (without popping)
‚ # Pair them together: [90,180]
R # Reverse it: [180,90]
/ # Divide the (implicit) input-pair by these
> # Increase both by 1
19o # Push 2^19: 524288
* # Multiply both decimals by this 524288
î # Ceil both to an integer
< # Then decrease them by 1
# (ceil + decrement cannot be floor, if they already are integers)
Dd # Create a copy, and check if it's >=0 (1 if >=0; 0 if <0)
* # Multiply this to the pair (-1 becomes 0, else it stays the same)
b # Convert both integers to a binary string
20j # Pad them with leading spaces up to a length of 20
ð0: # Replace all spaces with 0s
S # Convert it to a flattened list of digits
Å= # Shuffle this list ([a,b,c,d,e,f] → [a,d,b,e,c,f])
5ô # Split this into parts of size 5
J # Join each inner list together to a string
C # Convert each binary string to a base-10 integer
žh # Push builtin "0123456789"
A« # Append the lowercase alphabet
„ŠÙa # Push dictionary string "oila"
м # Remove those characters from the string
s # Swap to get the list of integers at the top again
è # And (0-based) index them into the string
# (after which the list of characters is output implicitly
ε # Map both values in the pair to:
d # Pop and check if it's non-negative (1 if >=0; 0 if <0)
© # Store this in variable `®` (without popping)
ˆ # And pop and add it to the global_array
¾ # Push 0
ƵΔ # Push compressed 180
N # Push the 0-based map-index
> # Increase it by 1 to make it 1-based
÷ # Divide the 180 by this (longitude=180; latitude=90)
‚ # Pair it together with the 0
19F # Loop 19 times:
Ð # Triplicate the current pair
ÆÄ # Pop one, and get the absolute difference
; # Halve this
U # Pop and store this halved difference in variable `X`
Åm # Pop another copy, and take its average
‹ # Check that it's smaller than
yÄ # the absolute value of the current map value
# (1 if truthy; 0 if falsey)
®Q # Check if this is equal to `®`
# (this will invert the boolean for negative values)
ˆ # Pop and add this to the global_array
ε # Map over the third pair:
¯θ # Push the last value of the global_array
®Q # Check it this is equal to `®`
# (to invert for negative values again)
NÊi # If this is NOT equal to the 0-based inner map-index:
X # Push variable `X`
Ni # If the 0-based inner map-index is 1:
- # Subtract `X` from the current value we're mapping over
ë # Else:
+ # Add it instead
] # Close both if-statements, both maps, and the loop
¯ # Push the global_array
Å=5ôJCžhA«„ŠÙaмsè # Same as above
See this 05AB1E tip of mine (sections How to use the dictionary? and How to compress large integers?) to understand why „ŠÙa
is "oila"
and ƵΔ
is 180
.