Python 3.4.3 Diamond-Square算法产生了奇怪的结果

时间:2016-05-18 00:27:02

标签: python algorithm

我目前在我的代码中被一个人工制品难住了。它似乎在网格图案中产生非常尖锐的点,与其邻居的价值有显着差异。

我正在关注http://www.bluh.org/code-the-diamond-square-algorithm/上的博文并转换他们使用的任何语言(假设是C#或Java),并仔细检查我正在做的事情应该匹配。

是否有人可以浏览这个,看看我做错了什么?我已经在较小的级别上逐步完成它,并在算法的特定迭代中停止它(通过展开顶部循环,并明确地调用算法一定次数)并且一切似乎都有效,直到我们到达最后一组点/像素。

我使用一个类(称为Matrix)来访问列表,并包装任何超出范围的值。

算法的代码如下:

class World :
def genWorld (self, numcells, cellsize, seed):
    random.seed(seed)
    self.dims = numcells*cellsize
    self.seed = seed
    self.cells = Matrix(self.dims, self.dims)

    # set the cells at cellsize intervals
    half = cellsize/2
    for y in range(0, self.dims, cellsize):
        for x in range(0, self.dims, cellsize):
            self.cells[x,y] = random.random()

    scale = 1.0
    samplesize = cellsize
    while samplesize > 1:
        self._diamondSquare(samplesize, scale)
        scale *= 0.8
        samplesize = int(samplesize/2)

    # I need to sort out the problem with the diamond-square algo that causes it to make the weird gridding pattern

def _sampleSquare(self, x, y, size, value):
    half = size/2
    a = self.cells[x-half, y-half]
    b = self.cells[x+half, y-half]
    c = self.cells[x-half, y+half]
    d = self.cells[x+half, y+half]

    res = min(((a+b+c+d+value)/5.0), 1.0)
    self.cells[x, y] = res

def _sampleDiamond(self, x, y, size, value):
    half = size/2
    a = self.cells[x+half, y]
    b = self.cells[x-half, y]
    c = self.cells[x, y+half]
    d = self.cells[x, y-half]

    res = min(((a+b+c+d+value)/5.0), 1.0)
    self.cells[x, y] = res

def _diamondSquare(self, stepsize, scale):
    half = int(stepsize/2)
    for y in range(half, self.dims+half, stepsize):
        for x in range(half, self.dims+half, stepsize):
            self._sampleSquare(x, y, stepsize, random.random()*scale)

    for y in range(0, self.dims, stepsize):
        for x in range(0, self.dims, stepsize):
            self._sampleDiamond(x+half, y, stepsize, random.random()*scale)
            self._sampleDiamond(x, y+half, stepsize, random.random()*scale)

并通过以下方式调用:

w = World()
w.genWorld(16, 16, 1) # a 256x256 square world, since the numcells is multiplied by the cellsize to give us the length of ONE side of the resulting grid

然后我保存到文件以检查结果:

file = io.open("sample.raw",'wb')
arr = [int(i * 255) for i in w.cells.cells] # w.cells.cells should not have a value >= 1.0, so what's going on?
ind = 0
for a in arr:
    if a > 255:
        print ("arr["+str(ind)+"] ::= "+str(a))
    ind += 1
file.write(bytearray(arr))
file.close()

给出了结果:

http://i.stack.imgur.com/fQHCY.png

编辑:好的,似乎我设法让它运转起来。我使用函数来处理菱形和方形步骤,在_diamondSquare()函数中完成所有操作,但这不是唯一的事情。我还发现random.random()提供了范围[0.0 - > 1.0]的值,当我期望值范围为[-1.0 - > 1.0)。在我纠正了这一点之后,一切都开始正常运转,这是一种解脱。

感谢大家的建议,这里是工作代码,万一其他人正在努力解决类似问题:

随机功能

# since random.random() gives a value in the range [0.0 -> 1.0), I need to change it to [-1.0 -> 1.0)
def rand():
    mag = random.random()
    sign = random.random()
    if sign >=0.5:
        return mag
    return mag * -1.0

矩阵课

class Matrix:
    def __init__(self, width, height):
        self.cells = [0 for i in range(width*height)]
        self.width = width
        self.height = height
        self.max_elems = width*height

    def _getsingleindex(self, ind):
        if ind < 0:
            ind *= -1
        while ind >= self.max_elems:
            ind -= self.max_elems
        return ind

    def _getmultiindex(self, xind, yind):
        if xind < 0:
            xind *= -1
        if yind < 0:
            yind *= -1

        while xind >= self.width:
            xind -= self.width
        while yind >= self.height:
            yind -= self.height
        return xind + (yind*self.height)

    def __getitem__(self, inds):
        # test that index is an integer, or two integers, and throw an indexException if not
        if hasattr(inds, "__len__"):
            if len(inds) > 1:
                return self.cells[self._getmultiindex(int(inds[0]), int(inds[1]))]
        return self.cells[self._getsingleindex(int(inds))]

    def __setitem__(self, inds, object):
        # test that index is an integer, or two integers, and throw an indexException if not
        if hasattr(inds, "__len__"):
            if len(inds) > 1:
                self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))] = object
                return self.cells[self._getmultiindex(int(inds[0]),int(inds[1]))]
        self.cells[self._getsingleindex(int(inds))] = object
        return self.cells[self._getsingleindex(int(inds))]

    def __len__(self):
        return len(self.cells)

实际钻石广场代

# performs the actual 2D generation
class World:
    def genWorld (self, numcells, cellsize, seed, scale = 1.0):
        random.seed(seed)
        self.dims = numcells*cellsize
        self.seed = seed
        self.cells = Matrix(self.dims, self.dims)
        mountains = Matrix(self.dims, self.dims)

        # set the cells at cellsize intervals
        for y in range(0, self.dims, cellsize):
            for x in range(0, self.dims, cellsize):
                # this is the default, sets the heights randomly
                self.cells[x,y] = random.random()


        while cellsize > 1:
            self._diamondSquare(cellsize, scale)
            scale *= 0.5
            cellsize = int(cellsize/2)

        for i in range(len(mountains)):
            self.cells[i] = self.cells[i]*0.4 + (mountains[i]*mountains[i])*0.6

    def _diamondSquare(self, stepsize, scale):
        half = int(stepsize/2)
        # diamond part
        for y in range(half, self.dims+half, stepsize):
            for x in range(half, self.dims+half, stepsize):
                self.cells[x, y] = ((self.cells[x-half, y-half] + self.cells[x+half, y-half] + self.cells[x-half, y+half] + self.cells[x+half, y+half])/4.0) + (rand()*scale)

        # square part
        for y in range(0, self.dims, stepsize):
            for x in range(0, self.dims, stepsize):
                self.cells[x+half,y] = ((self.cells[x+half+half, y] + self.cells[x+half-half, y] + self.cells[x+half, y+half] + self.cells[x+half, y-half])/4.0)+(rand()*scale)
                self.cells[x,y+half] = ((self.cells[x+half, y+half] + self.cells[x-half, y+half] + self.cells[x, y+half+half] + self.cells[x, y+half-half])/4.0)+(rand()*scale)

主要功能(为完整性而添加)

# a simple main function that uses World to create a 2D array of diamond-square values, then writes it to a file
def main():
    w = World()
    w.genWorld(20, 16, 1)

    mi = min(w.cells.cells)
    ma = max(w.cells.cells) - mi

    # save the resulting matrix to an image file
    file = io.open("sample.raw",'wb')
    maxed = [(i-mi)/ma for i in w.cells.cells]
    arr = [int(i * 255) for i in maxed]

    file.write(bytearray(arr))
    file.close()

0 个答案:

没有答案