Skip to content

Instantly share code, notes, and snippets.

@zerowidth
Last active November 18, 2019 18:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zerowidth/89396097a0f7e023f37b0c48c18b4194 to your computer and use it in GitHub Desktop.
Save zerowidth/89396097a0f7e023f37b0c48c18b4194 to your computer and use it in GitHub Desktop.
Calculations for siting a Minecraft portal in the nether
require "set"
STDERR.sync
exclusion = 8 # one nether block distance, or 8 overworld
existing = [[-743, 63, -39], [-743, 63, -40]]
targets = [[-791, 152, -48], [-792, 152, -48], [-793, 152, -48]]
existing_nether = [[-87, 67, -4]]
search_from = existing_nether.first
# need to find minimal x, y, z in the nether that preferentially chooses the
# target portal instead of the existing overworld portal blocks
def euclidean(from, to)
Math.sqrt(from.zip(to).map { |a,b| (a - b)**2 }.sum)
end
def over(point)
x, y, z = *point
[8 * x, y, 8 * z]
end
def nether(point)
x, y, z = *point
[x / 8, y, z / 8]
end
def in_search_range?(target, point)
(target[0] - point[0]).abs <= 127 && (target[1] - point[1]).abs <= 127
end
# search nearby portal locations in the nether in order to:
# * minimize distance from the existing nether portal
# * while still exiting to the overworld in preference to the target instead of
# the existing portal blocks.
range = 48 # how far out to search, this doesn't need to ever be above 127
best = Set.new
(-range).upto(range).each do |ox|
x = search_from[0] + ox
(-range).upto(range).each do |oz|
z = search_from[2] + oz
121.downto(6).each do |y| # clamped to ignore bedrock above/below
# starting at a test point in the nether: is this a location that will
# prefer the target portal over my existing portal?
test = [x, y, z]
# where this test portal will exit into the overworld:
in_overworld = over(test)
next unless targets.any? { |t| in_search_range?(t, in_overworld) }
# how close is the preferred exit to the existing portals?
to_existing = existing.map { |orig| euclidean(in_overworld, orig) }
# and how close is it to the target portal?
to_target = targets.map { |target| euclidean(in_overworld, target) }
if to_target.all? { |tt| to_existing.all? { |te| tt < te } }
# reject it if it's not a round trip:
nearest_target = targets.sort_by { |t| euclidean(t, in_overworld) }.first
back = nether(nearest_target)
min_range = euclidean(back, test)
next if existing_nether.any? { |en| euclidean(back, en) <= min_range }
min_dist = to_target.flat_map { |tt| to_existing.flat_map { |to| (tt-to).abs } }.min
if min_dist >= exclusion
best << [test, min_dist]
end
end
end
end
STDERR.print "."
end
STDERR.puts
# find the nearest candidate nether portals, by closest vertical distance first
# and then overall distance:
best = best.to_a.sort_by do |point, dist|
existing_nether.map do |n|
[(point[1] - n[1]).abs, (point[2] + 4).abs, point[2], euclidean(n, point), dist]
# [euclidean(n, point), dist]
end.min
end
best.each do |point, min_dist|
in_overworld = over(point)
to_existing = existing.map { |o| euclidean(in_overworld, o)}
to_target = targets.map { |t| euclidean(in_overworld, t) }
puts "#{point.inspect} #{min_dist} -> #{in_overworld} : #{to_existing} to existing and #{to_target} to target"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment