Médio · Jogo do caos

Lição 4: Loops que se lembram

Construa em Python o padrão “Jogo do caos” e aprenda pelo caminho:

  • um loop que leva o seu estado de um passo para o seguinte
  • números inteiros aleatórios com rng.integers
  • um loop while para uma condição
  • arrays de pontos e fatiamento
  • np.column_stack

Veja-o primeiro

É reproduzido a partir do YouTube depois de um clique.

chaos-game.py
"""Chaos game: jump a part r of the way to a random corner of a polygon, again and again.
Run: python chaos-game.py   (needs: pip install numpy matplotlib)
"""
import numpy as np
import matplotlib.pyplot as plt

plt.style.use("dark_background")

corners, r, no_repeat = 3, 0.5, False  # triangle, halfway: the Sierpinski triangle
steps = 60000
rng = np.random.default_rng()

angles = np.pi / 2 + 2 * np.pi * np.arange(corners) / corners
vertex = np.column_stack([np.cos(angles), np.sin(angles)])

points, chosen = np.zeros((steps, 2)), np.zeros(steps, dtype=int)
x, last = np.array([0.0, 0.0]), -1
for i in range(steps):
    c = rng.integers(corners)
    while no_repeat and c == last:  # the restricted game: never the same corner twice
        c = rng.integers(corners)
    x = x + r * (vertex[c] - x)  # the whole rule
    points[i], chosen[i], last = x, c, c

plt.figure(figsize=(6, 6))
plt.scatter(points[20:, 0], points[20:, 1], s=0.3, c=chosen[20:], cmap="rainbow")
plt.axis("equal")
plt.axis("off")
plt.show()

# Try: corners, r = 5, 0.618 (a pentagon) or corners, no_repeat = 4, True (a square, restricted)

Não tem Python neste computador? O notebook executa o mesmo script, os exercícios e as respostas no navegador, no Google Colab. O notebook está em inglês.

Linha a linha

  1. vertex = np.column_stack([np.cos(angles), np.sin(angles)])

    Os vértices do polígono: os seus valores de x e de y lado a lado, uma linha por vértice.

  2. c = rng.integers(corners)

    Um número inteiro aleatório de 0 a corners − 1: o vértice para onde saltar.

  3. while no_repeat and c == last:

    O jogo com restrição: enquanto o novo vértice for o último, sorteia-se outra vez.

  4. x = x + r * (vertex[c] - x)

    A regra: avançar a parte r do caminho entre o ponto e o vértice. Com r = 0.5, até meio do caminho.

  5. points[i], chosen[i], last = x, c, c

    Guardar o ponto e o seu vértice, e lembrar o vértice para o passo seguinte.

  6. plt.scatter(points[20:, 0], points[20:, 1], s=0.3, c=chosen[20:], cmap="rainbow")

    Saltar os primeiros 20 pontos, que ainda estão a caminho do fractal, e dar aos restantes a cor do seu vértice.

Experimente

  1. Desenhe um pentágono cujas cinco cópias apenas se toquem.

    Pista

    Mude corners e r numa só linha.

    Resposta

    corners, r, no_repeat = 5, 0.618, False

  2. Por que razão o gráfico salta os primeiros 20 pontos?

    Pista

    Onde começa o ponto?

    Resposta

    Começa no centro, que não está no fractal. Cada salto reduz a metade a sua distância ao fractal, por isso, depois de 20 saltos, está a menos de um milionésimo (2⁻²⁰) da imagem.

  3. Jogue o jogo do quadrado com e sem no_repeat. O que muda?

    Pista

    corners = 4, r = 0.5.

    Resposta

    Sem a restrição, os pontos limitam-se a preencher o quadrado; com no_repeat = True aparece um fractal.

Quiz

1. O que pode devolver rng.integers(3)?
2. O que é x + 0.5 * (corner - x)?
3. Por que razão o loop guarda a variável last?
4. O que seleciona points[20:, 0]?
5. Por que razão uma ordem ao acaso desenha mesmo assim uma imagem precisa?

Flashcards

Leia a frente, tente recordar o verso e só depois abra o cartão.

  • rng.integers(n)

    Um número inteiro aleatório de 0 a n − 1.

  • while condition:

    Repete o seu bloco enquanto a condição for True.

  • a[20:, 0]

    As linhas de 20 até o fim, coluna 0, de um array 2D.

  • Contração

    Um passo que aproxima quaisquer dois pontos, como um salto até meio caminho de um vértice.

  • Atrator

    A forma para onde passos repetidos puxam qualquer ponto: aqui, o triângulo de Sierpiński.

Estes flashcards numa página à parte →