123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- import math
- from typing import Tuple
- import haversine
- mean_earth_radius_km = (6378 + 6357) / 2
- # if you're more than 1/4 of the Earth's circumfrence away, you get 0
- max_dist_km = (math.pi * mean_earth_radius_km) / 2 # this is about 10,000 km
- # if you're within 1/16 of the Earth's circumfrence away, you get at least 1000 points
- quarter_of_max_km = max_dist_km / 4 # this is about 2,500 km
- # this is the total of the land area of all continents on Earth except Antarctica
- relevant_land_area = sum([
- 3.036e7, # https://www.wolframalpha.com/input?i=geographic+area+of+africa+in+km2
- 4.981e7, # https://www.wolframalpha.com/input?i=geographic+area+of+asia+in+km2
- 2.450e7, # https://www.wolframalpha.com/input?i=geographic+area+of+north+america+in+km2
- 1.782e7, # https://www.wolframalpha.com/input?i=geographic+area+of+south+america+in+km2
- 5.973e6, # https://www.wolframalpha.com/input?i=geographic+area+of+europe+in+km2
- 8.563e6, # https://www.wolframalpha.com/input?i=geographic+area+of+oceania+in+km2
- ])
- # this is the "radius" of an "average" continent
- # within this radius, you get at least 2000 points
- avg_continental_rad_km = math.sqrt(relevant_land_area / (6 * math.pi))
- # this works out to be approx 2700 km
- # somewhat arbitrarily, if you're within 1000 km, you get at least 3000 points
- one_thousand = 1000.0
- # this is the "radius" of the "average" country
- # within this radius, you get at least 4000 points
- # TODO increment or decrement number of countries as wars develop
- avg_country_rad_km = math.sqrt(relevant_land_area / (206 * math.pi))
- # this works out to be approx 460 km
- # if you're within 150m, you get a perfect score of 5000
- min_dist_km = 0.15
- def score_within(raw_dist: float, min_dist: float, max_dist: float) -> int:
- """
- Gives a score between 0 and 1000, with 1000 for the min_dist and 0 for the max_dist
- """
- # scale the distance down to [0.0, 1.0], then multiply it by 2 for easing
- pd2 = 2 * (raw_dist - min_dist) / (max_dist - min_dist)
- # perform a quadratic ease-in-out on pd2
- r = (pd2 ** 2) / 2 if pd2 < 1 else 1 - (((2 - pd2) ** 2) / 2)
- # use this to ease between 1000 and 0
- return int(1000 * (1 - r))
- def ramp(dist_km: float) -> float:
- if dist_km <= min_dist_km:
- return 5000
- elif dist_km <= avg_country_rad_km:
- return 4000 + score_within(dist_km, min_dist_km, avg_country_rad_km)
- elif dist_km <= one_thousand:
- return 3000 + score_within(dist_km, avg_country_rad_km, one_thousand)
- elif dist_km <= avg_continental_rad_km:
- return 2000 + score_within(dist_km, one_thousand, avg_continental_rad_km)
- elif dist_km <= quarter_of_max_km:
- return 1000 + score_within(dist_km, avg_continental_rad_km, quarter_of_max_km)
- elif dist_km <= max_dist_km:
- return score_within(dist_km, quarter_of_max_km, max_dist_km)
- else: # dist_km > max_dist_km
- return 0
- def score(target: Tuple[float, float], guess: Tuple[float, float]) -> Tuple[int, float]:
- """
- Takes in two (latitude, longitude) pairs and produces an int score.
- Score is in the (inclusive) range [0, 5000]
- Higher scores are closer.
- Returns (score, distance in km)
- """
- dist_km = haversine.haversine(target, guess)
- return ramp(dist_km), dist_km
- def score_pow(target: Tuple[float, float], guess: Tuple[float, float]) -> Tuple[int, float]:
- """
- Takes in two (latitude, longitude) pairs and produces an int score.
- Score is in the (inclusive) range [0, 5000]
- Higher scores are closer.
- Uses the same ramp as standard score, but raises the distance to a power first
- Returns (score, distance in km)
- """
- dist_km = haversine.haversine(target, guess)
- return ramp(dist_km ** 1.2), dist_km
- def score_country_race(target: str, guess: str, time_remaining: int, time_total: int):
- if target != guess:
- return 0
- time_used = time_total - time_remaining
- if time_used <= 5:
- return 5000
-
- # TODO make this into an interesting curve but for now linear is fine
- return int(5000 * (time_remaining / time_total))
- def score_hard(target: Tuple[float, float], guess: Tuple[float, float]) -> Tuple[int, float]:
- """
- Takes in two (latitude, longitude) pairs and produces an int score.
- Score is in the (inclusive) range [0, 5000]
- Higher scores are closer.
- Scoring is much more punishing than standard
- Returns (score, distance in km)
- """
- dist_km = haversine.haversine(target, guess)
- return max(0, 5000 - int(dist_km * 10)), dist_km
- def score_nightmare(target: Tuple[float, float], guess: Tuple[float, float]) -> Tuple[int, float]:
- """
- Takes in two (latitude, longitude) pairs and produces an int score.
- Score is in the range (-inf, 5000]
- Higher scores are closer.
- Scoring is much, MUCH more punishing than standard
- Returns (score, distance in km)
- """
- dist_km = haversine.haversine(target, guess)
- return 5000 - int(dist_km * 1000), dist_km
|