Skip to content

Instantly share code, notes, and snippets.

@unak
Created March 22, 2015 17:46
Show Gist options
  • Save unak/fa8c3c92e3b1e4df769c to your computer and use it in GitHub Desktop.
Save unak/fa8c3c92e3b1e4df769c to your computer and use it in GitHub Desktop.
中点変位法によるランダム地形生成器
#!ruby
require 'zlib'
PNG = 'sample.png'
WIDTH = 192
HEIGHT = 192
# 中点変位法による基礎データ生成
d = [WIDTH, HEIGHT].max
m = 1
m *= 2 while m < d
d = m
map = [[]]
map[0][0] = rand(256)
map[0][d] = rand(256)
map[d] = []
map[d][0] = rand(256)
map[d][d] = rand(256)
offx = 0
offy = 0
while d > 0
0.step(m - 1, d) do |offy|
0.step(m - 1, d) do |offx|
map[offy + d / 2] = [] unless map[offy + d / 2]
map[offy + d / 2][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d][offx] + map[offy + d][offx + d]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i
if offy <= 0
map[offy][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i
else
map[offy][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d / 2][offx + d / 2] + map[offy - d / 2][offx + d / 2]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i
end
if offx <= 0
map[offy + d / 2][offx] = ((map[offy][offx] + map[offy + d][offx] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i
else
map[offy + d / 2][offx] = ((map[offy][offx] + map[offy + d][offx] + map[offy + d / 2][offx + d / 2] + map[offy + d / 2][offx - d / 2]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i
end
map[offy + d / 2][offx + d] = ((map[offy][offx + d] + map[offy + d][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i
map[offy + d][offx + d / 2] = ((map[offy + d][offx] + map[offy + d][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i
end
end
d /= 2
end
# いらん範囲は捨てる
map = map[0, HEIGHT].map{|e| e[0, WIDTH]}
# 各ピクセルの最大値・最小値を取って、0~255に正規化する
max, min = 0, 255
HEIGHT.times do |y|
WIDTH.times do |x|
max = [map[y][x], max].max
min = [map[y][x], min].min
end
end
diff = max - min
if diff < 255
rate = 255.0 / diff
HEIGHT.times do |y|
WIDTH.times do |x|
map[y][x] = ((map[y][x] - min) * rate).to_i
end
end
end
# パレット生成(てきとー)
col = []
col[0] = [0, 0, 0x10]
col[64] = [0x40, 0x40, 0xff]
col[72] = [0xc0, 0xc0, 0xc0]
col[80] = [0x60, 0xc0, 0x60]
col[128] = [0x40, 0xc0, 0x40]
col[192] = [0x20, 0x90, 0x20]
col[208] = [0x80, 0x60, 0x60]
col[224] = [0x90, 0x80, 0x80]
col[255] = [0xff, 0xff, 0xff]
col.size.times do |n|
unless col[n]
x = n - 1
while true
prev = col[x]
break if col[x]
x -= 1
end
y = n + 1
while true
break if col[y]
y += 1
end
col[n] = []
col[n][0] = (col[x][0] + (col[y][0] - col[x][0]) * 1.0 / (y - x)).to_i
col[n][1] = (col[x][1] + (col[y][1] - col[x][1]) * 1.0 / (y - x)).to_i
col[n][2] = (col[x][2] + (col[y][2] - col[x][2]) * 1.0 / (y - x)).to_i
end
end
# PNG出力
# やってることの中身はmameさんの日記を参照
# http://d.hatena.ne.jp/ku-ma-me/20091003/
def chunk(hdr, data)
[data.bytesize, hdr, data, Zlib.crc32(hdr + data)].pack('NA4A*N')
end
open(PNG, 'wb') do |f|
f.print "\x89PNG\r\n\x1a\n"
f.print chunk('IHDR', [WIDTH, HEIGHT, 8, 2, 0, 0, 0].pack('NNCCCCC'))
data = ''
HEIGHT.times do |y|
data << [0, *map[y].map{|e| col[e]}.flatten].pack('C*')
end
f.print chunk('IDAT', Zlib.deflate(data, 9))
f.print chunk('IEND', '')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment