113 lines
3.4 KiB
Python
113 lines
3.4 KiB
Python
import json
|
|
import random
|
|
import functools
|
|
import datetime
|
|
import multiprocessing
|
|
from math import sqrt, acos, cos, sin, radians, degrees
|
|
from PIL import Image
|
|
|
|
img_north_border = radians(54.8364)
|
|
img_west_border = radians(14.1229)
|
|
img_south_border = radians(49.0024)
|
|
img_east_border = radians(24.1455)
|
|
img_path = "poland.bmp"
|
|
|
|
img = Image.open(img_path)
|
|
print(img.size)
|
|
|
|
p_horiz_scale = img.width / (img_east_border - img_west_border)
|
|
p_verti_scale = img.height / (img_north_border - img_south_border)
|
|
|
|
with open("pos.json") as df:
|
|
data = json.loads(df.read())
|
|
frog_shop_positions = [(radians(x['lat']), radians(x['lon'])) for x in data]
|
|
|
|
# @functools.cache
|
|
# def dist(lat, lon):
|
|
# return min([sqrt((lat-i[0])**2 + (lon-i[1])**2) for i in frog_shop_positions])
|
|
|
|
|
|
def gcd(a: tuple[float, float], b: tuple[float, float]) -> float:
|
|
return acos(sin(a[0])*sin(b[0]) + cos(a[0])*cos(b[0])*cos(abs(a[1]-b[1])))
|
|
|
|
def dist(lat, lon):
|
|
return min([gcd((lat, lon), i) for i in frog_shop_positions])
|
|
|
|
def in_poland(lat, lon, im):
|
|
if lat < img_south_border or lat >= img_north_border or lon < img_west_border or lon >= img_east_border:
|
|
return False
|
|
offlat = lat - img_south_border
|
|
offlon = lon - img_west_border
|
|
ppos = (offlon * p_horiz_scale, offlat * p_verti_scale)
|
|
ppos = (ppos[0], img.height - ppos[1] - 1)
|
|
# try:
|
|
return im.getpixel(ppos) == (0, 0, 0)
|
|
# except Exception as e:
|
|
# print("FUCK")
|
|
# print(e)
|
|
# print(lat, lon)
|
|
# exit(1)
|
|
|
|
def start_point(im):
|
|
lat, lon = 0, 0
|
|
while not in_poland(lat, lon, im):
|
|
lat = random.uniform(img_south_border, img_north_border)
|
|
lon = random.uniform(img_west_border, img_east_border)
|
|
return (lat, lon)
|
|
|
|
epsilon = 0.00005
|
|
|
|
def get_next_point(curr, im):
|
|
point_candidates = [
|
|
(curr[0] + epsilon, curr[1]),
|
|
(curr[0] - epsilon, curr[1]),
|
|
(curr[0], curr[1] + epsilon),
|
|
(curr[0], curr[1] - epsilon),
|
|
]
|
|
points = [x for x in point_candidates if in_poland(x[0], x[1], im)]
|
|
best_dist = dist(curr[0], curr[1])
|
|
best = curr
|
|
for point in points:
|
|
d = dist(point[0], point[1])
|
|
if d > best_dist:
|
|
best = point
|
|
return best
|
|
|
|
def find_local_best(start, im):
|
|
iters = 0
|
|
curr = None
|
|
next = start
|
|
start_time = datetime.datetime.now()
|
|
while curr != next:
|
|
curr = next
|
|
print(curr)
|
|
iters += 1
|
|
next = get_next_point(curr, im)
|
|
print(f"Local minimum at {next}, {dist(next[0], next[1])} ({datetime.datetime.now() - start_time})")
|
|
return next
|
|
|
|
def search(id):
|
|
best_point = None
|
|
best_dist = 0
|
|
img = Image.open(img_path)
|
|
for i in range(2000):
|
|
print(f"Runner {id} at attempt {i}")
|
|
start = start_point(img)
|
|
local = find_local_best(start, img)
|
|
if dist(local[0], local[1]) > best_dist:
|
|
best_point = local
|
|
best_dist = dist(local[0], local[1])
|
|
print(f"Better than previous, new best for {id} is {best_point} with {best_dist}")
|
|
return (best_point, best_dist)
|
|
|
|
# with multiprocessing.Pool(16) as p:
|
|
# found = p.map(search, range(40))
|
|
# best_overall = max(found, key=lambda x: x[1])
|
|
# print(f"Found best point at {degrees(best_overall[0][0]), degrees(best_overall[0][1])} with distance {degrees(best_overall[1])}")
|
|
|
|
#print(degrees(dist(radians(49.92), radians(14.19))))
|
|
|
|
fuck = find_local_best(
|
|
(radians(52), radians(19)), img
|
|
)
|
|
print(degrees(fuck[0]), degrees(fuck[1])) |