Skip to content

Instantly share code, notes, and snippets.

@BennyHallett
Created August 30, 2014 04:48
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save BennyHallett/0199fd04ea797b437c15 to your computer and use it in GitHub Desktop.
Unfinished Terrain Generator
defmodule Terrain do
def generate do
size = 65 # or 129, 513, 1025 (2^x + 1)
initial_state(size)
|> diamond { 0, 0 }, { size-1, size-1 }
end
defp diamond(current, { x1, y1 }, { x2, y2 }) when x2 == x1 + 2 and y2 == y1 + 2 do
current
|> top( { x1, y1 }, { x2, y2 } )
|> bottom( { x1, y1 }, { x2, y2 } )
|> left( { x1, y1 }, { x2, y2 } )
|> right( { x1, y1 }, { x2, y2 } )
|> center( { x1, y1 }, { x2, y2 } )
end
defp diamond(current, { x1, y1 }, { x2, y2 }) do
current
|> top( { x1, y1 }, { x2, y2 } )
|> bottom( { x1, y1 }, { x2, y2 } )
|> left( { x1, y1 }, { x2, y2 } )
|> right( { x1, y1 }, { x2, y2 } )
|> center( { x1, y1 }, { x2, y2 } )
|> diamond( { x1, y1 }, { div(x1 + x2, 2), div(y1 + y2, 2) } )
|> diamond( { div(x1 + x2, 2), y1 }, { x2, div(y1 + y2, 2) } )
|> diamond( { x1, div(y1 + y2, 2) }, { div(x1 + x2, 2), y2 } )
|> diamond( { div(x1 + x2, 2), div(y1 + y2, 2) }, { x2, y2 } )
end
defp top(current, { x1, y1 }, { x2, y2 }) do
{ _, v1 } = Enum.find current, fn({ { x1, y1 }, value }) -> 0 end
{ _, v2 } = Enum.find current, fn({ { x2, y1 }, value }) -> 0 end
IO.puts "#{x1} #{y1} #{x2} #{y2}"
[ { { div(x1 + x2, 2), y1 }, (v1 + v2) / 2 } | current ]
end
defp bottom(current, { x1, y1 }, { x2, y2 }) do
{ _, v1 } = Enum.find current, fn({ { x1, y2 }, value }) -> 0 end
{ _, v2 } = Enum.find current, fn({ { x2, y2 }, value }) -> 0 end
[ { { div(x1 + x2, 2), y2 }, (v1 + v2) / 2 } | current ]
end
defp left(current, { x1, y1 }, { x2, y2 }) do
{ _, v1 } = Enum.find current, fn({ { x1, y1 }, value }) -> 0 end
{ _, v2 } = Enum.find current, fn({ { x1, y2 }, value }) -> 0 end
[ { { x1, div(y1 + y2, 2) }, (v1 + v2) / 2 } | current ]
end
defp right(current, { x1, y1 }, { x2, y2 }) do
{ _, v1 } = Enum.find current, fn({ { x2, y1 }, value }) -> 0 end
{ _, v2 } = Enum.find current, fn({ { x2, y2 }, value }) -> 0 end
[ { { x2, div(y1 + y2, 2) }, (v1 + v2) / 2 } | current ]
end
defp center(current, { x1, y1 }, { x2, y2 }) do
{ _, v1 } = Enum.find current, fn({ { x1, y1 }, value }) -> 0 end
{ _, v2 } = Enum.find current, fn({ { x2, y1 }, value }) -> 0 end
{ _, v3 } = Enum.find current, fn({ { x2, y2 }, value }) -> 0 end
{ _, v4 } = Enum.find current, fn({ { x1, y2 }, value }) -> 0 end
[ { { div(x1 + x2, 2), div(y1 + y2, 2) }, (v1 + v2 + v3 + v4) / 4 } | current ]
end
defp initial_state(size) do
[
{ {0, 0}, :random.uniform },
{ {0, size-1}, :random.uniform },
{ {size-1, 0}, :random.uniform },
{ {size-1, size-1}, :random.uniform }
]
end
def draw(heightmap) do
output = Enum.map(1..65*65, fn _ -> " " end)
output = update_output heightmap, output
File.open("terrain.txt", [:write], fn f ->
output |> draw_line(f)
end)
end
defp update_output([], output) do
output
end
defp update_output([ { {x, y}, value } | t ], output) do
IO.puts "Updating #{x},#{y}:#{point_to_pos(x, y)} to be #{point_to_char(value)}"
output = List.update_at(output, point_to_pos(x, y), fn _ -> point_to_char(value) end)
update_output t, output
end
defp draw_line([], _) do
end
defp draw_line(chars, file) do
{line, remaining} = Enum.split chars, 65
Enum.each line, &(IO.write file, &1)
IO.write file, "\n"
draw_line remaining, file
end
defp point_to_pos(x, y) do (y*57) + x end
defp point_to_char(a) when a > 0.6 do "^" end
defp point_to_char(a) when a < 0.3 do "~" end
defp point_to_char(a) do "." end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment