fucking hell
This commit is contained in:
commit
5b949b892c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"python.REPL.enableREPLSmartSend": false
|
||||||
|
}
|
209
Cargo.lock
generated
Normal file
209
Cargo.lock
generated
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "Froggy"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bmp",
|
||||||
|
"rand",
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bmp"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69985ff4f58085ac696454692d0b646a66ad1f9cc9be294c91dc51bb5df511ae"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.158"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "Froggy"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
bmp = "0.5.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rayon = "1.10.0"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
113
find.py
Normal file
113
find.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
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]))
|
96
flake.lock
Normal file
96
flake.lock
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1724015816,
|
||||||
|
"narHash": "sha256-hVESnM7Eiz93+4DeiE0a1TwMeaeph1ytRJ5QtqxYRWg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "9aa35efbea27d320d0cdc5f922f0890812affb60",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1718428119,
|
||||||
|
"narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1724120436,
|
||||||
|
"narHash": "sha256-/MvfxTjco5UDBF6SEvwyeXrXwZG7nz7/mDVreQNKsWg=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "48e61fe824f5823e4f3f15dd9a75c19c63649269",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
27
flake.nix
Normal file
27
flake.nix
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils, rust-overlay }:
|
||||||
|
utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
overlays = [ (import rust-overlay) ];
|
||||||
|
pkgs = import nixpkgs { inherit system overlays; };
|
||||||
|
in {
|
||||||
|
devShell = with pkgs; mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
python312 python312Packages.decorator python312Packages.pillow
|
||||||
|
perf-tools
|
||||||
|
linuxPackages_latest.perf
|
||||||
|
(rust-bin.stable.latest.default.override {
|
||||||
|
extensions = [ "rust-src" ];
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
BIN
poland.bmp
Normal file
BIN
poland.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 MiB |
6
poland.bpw
Normal file
6
poland.bpw
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
0.00084698025551684
|
||||||
|
0
|
||||||
|
0
|
||||||
|
-0.00084698025551684
|
||||||
|
14.12177084785133729
|
||||||
|
54.83555301974448071
|
BIN
poland2.bmp
Normal file
BIN
poland2.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 MiB |
6
polang.pgw
Normal file
6
polang.pgw
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
0.00577623762376237
|
||||||
|
0
|
||||||
|
0
|
||||||
|
-0.00577623762376237
|
||||||
|
14.12620198019802054
|
||||||
|
54.83062376237623425
|
BIN
polang.png
Normal file
BIN
polang.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
8
preprocess.py
Normal file
8
preprocess.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
with open("raw.json", "r") as f:
|
||||||
|
string = f.read()
|
||||||
|
rawls = json.loads(string)
|
||||||
|
latlons = [{'lat': x['lat'], 'lon': x['lon']} for x in rawls if x['lon'] != None]
|
||||||
|
with open("pos.json", "w") as w:
|
||||||
|
w.write(json.dumps(latlons))
|
5
refrogger.js
Normal file
5
refrogger.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const frogs = require('./pos.json');
|
||||||
|
|
||||||
|
for (let { lat, lon } of frogs) {
|
||||||
|
process.stdout.write(`${lat} ${lon}\n`);
|
||||||
|
}
|
1
sample.json
Normal file
1
sample.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"lat": 52.444686, "lon": 16.881193}, {"lat": 52.411081, "lon": 16.926432}, {"lat": 52.410221, "lon": 17.078734}, {"lat": 52.385385, "lon": 16.914945}, {"lat": 50.326686, "lon": 19.186558}, {"lat": 53.234833, "lon": 20.175232}, {"lat": 52.094746, "lon": 17.020672}, {"lat": 51.878283, "lon": 17.016359}, {"lat": 50.334049, "lon": 18.886466}, {"lat": 52.408623, "lon": 16.941987}, {"lat": 52.392868, "lon": 16.889022}, {"lat": 50.364616, "lon": 19.036451}, {"lat": 50.3688, "lon": 18.849958}, {"lat": 52.894126, "lon": 16.171218}, {"lat": 51.42558, "lon": 17.932531}]
|
200
src/main.rs
Normal file
200
src/main.rs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use bmp::Image;
|
||||||
|
use std::{fs::File, io::{self, BufRead, Cursor}};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||||
|
struct Radians(f64);
|
||||||
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||||
|
struct Degrees(f64);
|
||||||
|
|
||||||
|
impl From<Degrees> for Radians {
|
||||||
|
fn from(value: Degrees) -> Self {
|
||||||
|
Radians(value.0 * std::f64::consts::PI / 180f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<f64> for Radians {
|
||||||
|
fn into(self) -> f64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Radians> for Degrees {
|
||||||
|
fn from(value: Radians) -> Self {
|
||||||
|
Degrees(value.0 * (180f64 / std::f64::consts::PI))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<f64> for Degrees {
|
||||||
|
fn into(self) -> f64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
struct Location {
|
||||||
|
lat: Radians,
|
||||||
|
lon: Radians,
|
||||||
|
}
|
||||||
|
impl From<(Degrees, Degrees)> for Location {
|
||||||
|
fn from(value: (Degrees, Degrees)) -> Self {
|
||||||
|
Location {
|
||||||
|
lat: value.0.into(),
|
||||||
|
lon: value.1.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const IMG_NORTH_BORDER: Radians = Radians(0.9570757299); // Degrees(54.8364);
|
||||||
|
const IMG_WEST_BORDER: Radians = Radians(0.2464911049); // Degrees(14.1229);
|
||||||
|
const IMG_SOUTH_BORDER: Radians = Radians(0.8552532214); // Degrees(49.0024);
|
||||||
|
const IMG_EAST_BORDER: Radians = Radians(0.4214184745); // Degrees(24.1455);
|
||||||
|
const EPSILON: f64 = 0.00001f64;
|
||||||
|
|
||||||
|
struct ImageMeta {
|
||||||
|
image: Image,
|
||||||
|
horizontal_scale: f64,
|
||||||
|
vertical_scale: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn gcd(a: &Location, b: &Location) -> f64 {
|
||||||
|
return f64::acos(
|
||||||
|
f64::sin(a.lat.into())*f64::sin(b.lat.into()) +
|
||||||
|
f64::cos(a.lat.into())*f64::cos(b.lat.into())*f64::cos(
|
||||||
|
f64::abs(a.lon.0 - b.lon.0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dist(location: &Location, shops: &Vec<Location>) -> f64 {
|
||||||
|
shops.into_iter().map(|a| {
|
||||||
|
gcd(a, &location)
|
||||||
|
}).min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Greater)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_poland(
|
||||||
|
location: &Location,
|
||||||
|
im: &ImageMeta,
|
||||||
|
) -> bool {
|
||||||
|
if location.lat < IMG_SOUTH_BORDER ||
|
||||||
|
location.lat >= IMG_NORTH_BORDER ||
|
||||||
|
location.lon < IMG_WEST_BORDER ||
|
||||||
|
location.lon >= IMG_EAST_BORDER {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let offlat = location.lat.0 - IMG_SOUTH_BORDER.0;
|
||||||
|
let offlon = location.lon.0 - IMG_WEST_BORDER.0;
|
||||||
|
let ppos: (f64, f64) = (offlon * im.horizontal_scale, offlat * im.vertical_scale);
|
||||||
|
let ppos = (ppos.0 as u32, im.image.get_height() - (ppos.1 as u32) - 1);
|
||||||
|
|
||||||
|
return im.image.get_pixel(ppos.0, ppos.1) == bmp::consts::BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_point(
|
||||||
|
im: &ImageMeta
|
||||||
|
) -> Location {
|
||||||
|
loop {
|
||||||
|
let loc = Location {
|
||||||
|
lat: Radians(rand::thread_rng().gen_range(IMG_SOUTH_BORDER.0 .. IMG_NORTH_BORDER.0)),
|
||||||
|
lon: Radians(rand::thread_rng().gen_range(IMG_WEST_BORDER.0 .. IMG_EAST_BORDER.0) )
|
||||||
|
};
|
||||||
|
if in_poland(&loc, im) {
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_next_point(curr: Location, im: &ImageMeta, shops: &Vec<Location>) -> (f64, Location) {
|
||||||
|
[
|
||||||
|
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0)},
|
||||||
|
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0)},
|
||||||
|
Location {lat: Radians(curr.lat.0), lon: Radians(curr.lon.0 + EPSILON)},
|
||||||
|
Location {lat: Radians(curr.lat.0), lon: Radians(curr.lon.0 - EPSILON)},
|
||||||
|
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0 + EPSILON)},
|
||||||
|
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0 - EPSILON)},
|
||||||
|
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0 - EPSILON)},
|
||||||
|
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0 + EPSILON)},
|
||||||
|
curr
|
||||||
|
].into_iter().filter(|loc| {
|
||||||
|
in_poland(loc, im)
|
||||||
|
}).map(|loc| {
|
||||||
|
(dist(&loc, shops), loc)
|
||||||
|
}).max_by(|x, y| {
|
||||||
|
x.0.partial_cmp(&y.0).unwrap()
|
||||||
|
}).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_local_best(start: Location, im: &ImageMeta, shops: &Vec<Location>) -> (f64, Location) {
|
||||||
|
let mut curr = start;
|
||||||
|
loop {
|
||||||
|
let next = get_next_point(curr.clone(), im, shops);
|
||||||
|
if curr == next.1 {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr = next.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(im: &ImageMeta, shops: &Vec<Location>) -> (Location, f64) {
|
||||||
|
let mut best_dist = 0f64;
|
||||||
|
let mut best_point = Location {lat: Radians(0f64), lon: Radians(0f64)};
|
||||||
|
for iter in 0..3000 {
|
||||||
|
let start = start_point(im);
|
||||||
|
let local = find_local_best(start, im, shops);
|
||||||
|
if local.0 > best_dist {
|
||||||
|
best_dist = local.0;
|
||||||
|
best_point = local.1.clone();
|
||||||
|
println!("At iter {}, new best", iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (best_point, best_dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let file = File::open("./pos.txt")?;
|
||||||
|
let mut frog_shops: Vec<Location> = Vec::with_capacity(10778);
|
||||||
|
for line in io::BufReader::new(file).lines() {
|
||||||
|
let line = line?;
|
||||||
|
let numbers: Vec<f64> = line.split(" ").map(str::parse::<f64>).map(Result::unwrap).collect();
|
||||||
|
frog_shops.push(Location {
|
||||||
|
lat: Degrees(numbers[0]).into(),
|
||||||
|
lon: Degrees(numbers[1]).into()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let poland = include_bytes!("../poland.bmp");
|
||||||
|
let mut cursor = Cursor::new(poland);
|
||||||
|
let img = bmp::from_reader(&mut cursor)?;
|
||||||
|
// println!("{:?}", img);
|
||||||
|
|
||||||
|
// println!("{:?}", dist((
|
||||||
|
// radians!(52f64), radians!(19f64)
|
||||||
|
// ), &frog_shops));
|
||||||
|
|
||||||
|
// println!("{:?}", in_poland((radians!(52f64), radians!(19f64)), &img, p_horiz_scale, p_verti_scale));
|
||||||
|
// println!("{:?}", degrees_but_tuple!(start_point(&img, p_horiz_scale, p_verti_scale)));
|
||||||
|
// println!("{:?}", degrees_but_tuple!(find_local_best(
|
||||||
|
// (radians!(52f64), radians!(19f64)), &img, p_horiz_scale, p_verti_scale, &frog_shops
|
||||||
|
// )));
|
||||||
|
let imagemeta = ImageMeta {
|
||||||
|
horizontal_scale: (img.get_width() as f64) / (IMG_EAST_BORDER.0 - IMG_WEST_BORDER.0),
|
||||||
|
vertical_scale: (img.get_height() as f64) / (IMG_NORTH_BORDER.0 - IMG_SOUTH_BORDER.0),
|
||||||
|
image: img
|
||||||
|
};
|
||||||
|
// let result = (0..100)
|
||||||
|
// .into_iter()
|
||||||
|
// .into_par_iter()
|
||||||
|
// .map(|_| search(&imagemeta, &frog_shops))
|
||||||
|
// .max_by(|a, b| {
|
||||||
|
// a.1.partial_cmp(&b.1).unwrap()
|
||||||
|
// }).unwrap();
|
||||||
|
let result = search(&imagemeta, &frog_shops);
|
||||||
|
|
||||||
|
let best_point: (Degrees, Degrees) = (result.0.lat.into(), result.0.lon.into());
|
||||||
|
println!("Found best point at ({}, {}); Distance is {}", best_point.0.0, best_point.1.0, result.1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user