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