frog/find.py
2024-08-21 00:10:50 +02:00

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]))