scoring.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import math
  2. from typing import Tuple
  3. import haversine
  4. mean_earth_radius_km = (6378 + 6357) / 2
  5. # if you're more than 1/4 of the Earth's circumfrence away, you get 0
  6. max_dist_km = (math.pi * mean_earth_radius_km) / 2 # this is about 10,000 km
  7. # if you're within 1/16 of the Earth's circumfrence away, you get at least 1000 points
  8. quarter_of_max_km = max_dist_km / 4 # this is about 2,500 km
  9. # https://www.wolframalpha.com/input/?i=sqrt%28%28%28land+mass+of+earth%29+%2F+7%29%29+%2F+pi%29+in+kilometers
  10. # this is the average "radius" of a continent
  11. # within this radius, you get at least 2000 points
  12. avg_continental_rad_km = 1468.0
  13. # somewhat arbitrarily, if you're within 1000 km, you get at least 3000 points
  14. one_thousand = 1000.0
  15. # https://www.wolframalpha.com/input/?i=sqrt%28%28%28land+mass+of+earth%29+%2F+%28number+of+countries+on+earth%29%29+%2F+pi%29+in+kilometers
  16. # this is the average "radius" of a country
  17. # within this radius, you get at least 4000 points
  18. avg_country_rad_km = 479.7
  19. # if you're within 150m, you get a perfect score of 5000
  20. min_dist_km = 0.15
  21. def score_within(raw_dist: float, min_dist: float, max_dist: float) -> int:
  22. """
  23. Gives a score between 0 and 1000, with 1000 for the min_dist and 0 for the max_dist
  24. """
  25. # scale the distance down to [0.0, 1.0], then multiply it by 2 for easing
  26. pd2 = 2 * (raw_dist - min_dist) / (max_dist - min_dist)
  27. # perform a quadratic ease-in-out on pd2
  28. r = (pd2 ** 2) / 2 if pd2 < 1 else 1 - (((2 - pd2) ** 2) / 2)
  29. # use this to ease between 1000 and 0
  30. return int(1000 * (1 - r))
  31. def score(target: Tuple[float, float], guess: Tuple[float, float]) -> Tuple[int, float]:
  32. """
  33. Takes in two (latitude, longitude) pairs and produces an int score.
  34. Score is in the (inclusive) range [0, 5000]
  35. Higher scores are closer.
  36. Returns (score, distance in km)
  37. """
  38. dist_km = haversine.haversine(target, guess)
  39. if dist_km <= min_dist_km:
  40. point_score = 5000
  41. elif dist_km <= avg_country_rad_km:
  42. point_score = 4000 + score_within(dist_km, min_dist_km, avg_country_rad_km)
  43. elif dist_km <= one_thousand:
  44. point_score = 3000 + score_within(dist_km, avg_country_rad_km, one_thousand)
  45. elif dist_km <= avg_continental_rad_km:
  46. point_score = 2000 + score_within(dist_km, one_thousand, avg_continental_rad_km)
  47. elif dist_km <= quarter_of_max_km:
  48. point_score = 1000 + score_within(dist_km, avg_continental_rad_km, quarter_of_max_km)
  49. elif dist_km <= max_dist_km:
  50. point_score = score_within(dist_km, quarter_of_max_km, max_dist_km)
  51. else: # dist_km > max_dist_km
  52. point_score = 0
  53. return point_score, dist_km