首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >玩混沌游戏

玩混沌游戏
EN

Code Review用户
提问于 2016-10-14 01:58:36
回答 1查看 1.3K关注 0票数 1

根据罗塞塔码的说法:

混沌博弈是迭代函数系统(IFS)吸引子的一种生成方法。其中最著名和最简单的例子之一,创建分形,使用多边形和一个初始点随机选择。任务玩混沌游戏,以等边三角形的角为参照点。随机添加一个起始点(最好在三角形内)。然后在起点和一个参考点中间添加下一个点。这个参照点是随机选择的。经过足够的迭代后,Sierpinski三角形的图像就会出现。

下面是我用Python的解决方案:

代码语言:javascript
复制
"""This module performs the Chaos Game."""

from random import choice
from PIL import Image


def midpoint(p1, p2):
    """
    Takes 2 points and calculates the midpoint.
    Args:
        p1 (real, real): A point in space.
        p2 (real, real): Another point in space.
    Returns:
        (real, real): The midpoint between p1 and p2.
    """
    return (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2


def translate(point, screen_size):
    """
    Takes a point and converts it to the appropriate coordinate system.
    Note that PIL uses upper left as 0, we want the center.
    Args:
        point (real, real): A point in space.
        screen_size (int): Size of an N x N screen.
    Returns:
        (real, real): Translated point for Pillow coordinate system.
    """
    return point[0] + screen_size / 2, point[1] + screen_size / 2


def image_rep(point, img_size):
    """
    Returns a representation of the point that can be used by Pillow.
    Args:
        point (real, real): A point in space.
        img_size (int): The size of an N x N image
    """
    # Convert the point to the correct coordinate system.
    translated = translate((point[0], point[1]), img_size)
    # Make it an integer so Pillow can use it.
    return int(translated[0]), int(translated[1])


def play_chaos(guiders, seed, img, steps=1000):
    """
    Play the Chaos Game:
    1. Have a collection of n (ordered) "guider" points.
    2. Start with a random seed some where on the screen.
    3. Roll die that has n sides
    4. Make a new point that is halfway between the appropriate gudier and the
       previous point.
    5. Repeat the game from the new point
    Args:
        guiders ([(real, real)]): List of guider points
        seed (real, real): Initial seed, be sure to be within the screens range
        img (Image): Image to write spiral to.
        steps (int): The amount of times the process is repeated.
        (default: 1000)
    """
    prev_point = seed
    for _ in range(steps):
        # Select the next guider to move closer to
        guider = choice(guiders)
        new_point = midpoint(prev_point, guider)
        img.putpixel(image_rep(new_point, img.size[0]), 1)
        prev_point = new_point


def main():
    """
    Main method, start of the program. Creates an image and populates it with
    chaos.
    """
    IMAGE_SIZE = 300, 300
    img = Image.new('1', IMAGE_SIZE)
    SEED = (0.0, 0.0)
    GUIDERS = [(-100.0, -100.0),
               (100.0, -100.0),
               (0.0, 100.0)]
    play_chaos(GUIDERS, SEED, img)
    img.save('chaos.png')


if __name__ == '__main__':
    main()
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-10-14 13:59:52

中点()

这个函数可以使用zip()编写得更优雅,而且它可以工作在任意数量的维度上。(不过,我怀疑速度可能会慢一些。)

代码语言:javascript
复制
def midpoint(p1, p2):
    """
    Find the midpoint of two cartesian points.
    """
    return tuple((c1 + c2) / 2 for c1, c2 in zip(p1, p2))

转换()和image_rep()

因为translate()给出了一个枕头坐标的结果,所以我认为这个结果应该被量化为整数。您应该舍入最近的整数,而不是截断。

枕头坐标向右和向底部增加。按照惯例,笛卡尔坐标向右和向顶部方向增加。因此,我将在翻译中加入垂直轴的反映。

我不明白为什么图像必须是正方形的。

您可以只传递point,而不是将它打包成一个新的元组。

代码语言:javascript
复制
translated = translate(point, img_size)

我建议将这两个助手函数隐藏在绘图例程中。(见下文)

play_chaos()

我会把它分解成数学概念和它的可视化。

代码语言:javascript
复制
def chaos_points(attractors, start_point):
    attractor_stream = (random.choice(attractors) for _ in itertools.count())
    return itertools.accumulate(itertools.chain([start_point], attractor_stream), midpoint)

def plot(img, points):
    half_width, half_height = img.size[0] / 2, img.size[1] / 2
    to_pillow = lambda p: (int(round(half_width + p[0])), int(round(half_height - p[1])))
    for point in points:
        img.putpixel(to_pillow(point), 1)

Demo

您的GUIDERS不像建议的那样形成等边三角形。

代码语言:javascript
复制
def main():
    """
    Create an image and populate it with chaos.
    """
    IMAGE_SIZE = 300, 300
    SEED = (0.0, 0.0)
    GUIDERS = [(-100.0, -50 * 3**.5),
               (+100.0, -50 * 3**.5),
               (   0.0, +50 * 3**.5)]
    img = Image.new('1', IMAGE_SIZE)
    plot(img, itertools.islice(chaos_points(GUIDERS, SEED), 1000))
    img.save('chaos.png')


if __name__ == '__main__':
    main()
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/144190

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档