Średnio zaawansowane · Gra w chaos

Lekcja 4: Pętle, które pamiętają

Zbuduj w Pythonie wzór „Gra w chaos” i po drodze naucz się:

  • pętla, która przenosi swój stan z kroku na krok
  • losowe liczby całkowite z rng.integers
  • pętla while z warunkiem
  • tablice punktów i wycinki
  • np.column_stack

Najpierw obejrzyj

Film gra z YouTube po kliknięciu.

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)

Nie masz Pythona na tym komputerze? Notatnik uruchamia ten sam skrypt, zadania i odpowiedzi w przeglądarce, w Google Colab. Notatnik jest po angielsku.

Linijka po linijce

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

    Wierzchołki wielokąta: ich wartości x i y obok siebie, po jednym wierszu na wierzchołek.

  2. c = rng.integers(corners)

    Losowa liczba całkowita od 0 do corners − 1: wierzchołek, do którego skaczemy.

  3. while no_repeat and c == last:

    Gra z ograniczeniem: dopóki nowy wierzchołek jest tym samym co ostatnio, losuj jeszcze raz.

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

    Reguła: przesuń punkt o część r drogi do wierzchołka. Przy r = 0.5 w połowę drogi.

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

    Zapamiętaj punkt i jego wierzchołek, a wierzchołek zachowaj na następny krok.

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

    Pomiń pierwsze 20 punktów, które są jeszcze w drodze do fraktala, a resztę pokoloruj według wierzchołka.

Twoja kolej

  1. Narysuj pięciokąt, którego pięć kopii ledwo się styka.

    Podpowiedź

    Zmień corners i r w jednej linijce.

    Odpowiedź

    corners, r, no_repeat = 5, 0.618, False

  2. Dlaczego wykres pomija pierwsze 20 punktów?

    Podpowiedź

    Gdzie zaczyna punkt?

    Odpowiedź

    Zaczyna w środku, który nie leży na fraktalu. Każdy skok zmniejsza o połowę jego odległość od fraktala, więc po 20 skokach jest od niego dalej niż o jedną milionową (2⁻²⁰) obrazka.

  3. Zagraj w kwadrat z no_repeat i bez. Co się zmienia?

    Podpowiedź

    corners = 4, r = 0.5.

    Odpowiedź

    Bez ograniczenia punkty po prostu wypełniają kwadrat; przy no_repeat = True pojawia się fraktal.

Quiz

1. Co może zwrócić rng.integers(3)?
2. Czym jest x + 0.5 * (corner - x)?
3. Po co pętla przechowuje zmienną last?
4. Co wybiera points[20:, 0]?
5. Dlaczego losowa kolejność i tak rysuje dokładny obraz?

Fiszki

Przeczytaj przód, powiedz sobie, co jest z tyłu, potem otwórz kartę.

  • rng.integers(n)

    Losowa liczba całkowita od 0 do n − 1.

  • while condition:

    Powtarza swój blok, dopóki warunek jest True.

  • a[20:, 0]

    Wiersze od 20 do końca, kolumna 0, tablicy dwuwymiarowej.

  • Odwzorowanie zwężające

    Krok, który zbliża do siebie dowolne dwa punkty, jak skok w połowę drogi do wierzchołka.

  • Atraktor

    Kształt, na który powtarzane kroki ściągają każdy punkt: tutaj trójkąt Sierpińskiego.

Te fiszki na osobnej stronie →