9.5. Algorytmy
W tym scenariuszu spróbujemy pokazać w Minecrafcie Pi algorytm symulujący ruchy Browna oraz algorytm stosujący metodę Monte Carlo do wyliczenia przybliżonej wartości liczby Pi.
9.5.1. Ruchy Browna
Za pomocą wybranego edytora utwórz pusty plik, umieść w nim podany niżej kod i zapisz
w katalogu mcpi-sim
pod nazwą mcpi-rbrowna.py
:
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import os
5import numpy as np # import biblioteki do obliczeń naukowych
6import matplotlib.pyplot as plt # import biblioteki do tworzenia wykresow
7from random import randint
8from time import sleep
9import mcpi.minecraft as minecraft # import modułu minecraft
10import mcpi.block as block # import modułu block
11
12os.environ["USERNAME"] = "Steve" # wpisz dowolną nazwę użytkownika
13os.environ["COMPUTERNAME"] = "mykomp" # wpisz dowolną nazwę komputera
14
15mc = minecraft.Minecraft.create("192.168.1.10") # połączenie z serwerem
16
17
18def plac(x, y, z, roz=10, gracz=False):
19 """
20 Funkcja tworzy podłoże i wypełnia sześcienny obszar od podanej pozycji,
21 opcjonalnie umieszcza gracza w środku.
22 Parametry: x, y, z - współrzędne pozycji początkowej,
23 roz - rozmiar wypełnianej przestrzeni,
24 gracz - czy umieścić gracza w środku
25 Wymaga: globalnych obiektów mc i block.
26 """
27
28 podloga = block.SAND
29 wypelniacz = block.AIR
30
31 # podloga i czyszczenie
32 mc.setBlocks(x, y - 1, z, x + roz, y - 1, z + roz, podloga)
33 mc.setBlocks(x, y, z, x + roz, y + roz, z + roz, wypelniacz)
34 # umieść gracza w środku
35 if gracz:
36 mc.player.setPos(x + roz / 2, y + roz / 2, z + roz / 2)
37
38
39def wykres(x, y, tytul="Wykres funkcji", *extra):
40 """
41 Funkcja wizualizuje wykres funkcji, której argumenty zawiera lista x
42 a wartości lista y i ew. dodatkowe listy w parametrze *extra
43 """
44 if len(extra):
45 plt.plot(x, y, extra[0], extra[1]) # dwa wykresy na raz
46 else:
47 plt.plot(x, y, "o:", color="blue", linewidth="3", alpha=0.8)
48 plt.title(tytul)
49 plt.grid(True)
50 plt.show()
51
52
53def rysuj(x, y, z, blok=block.IRON_BLOCK):
54 """
55 Funkcja wizualizuje wykres funkcji, umieszczając bloki w pionie/poziomie
56 w punktach wyznaczonych przez pary elementów list x, y lub x, z
57 """
58 czylista = True if len(y) > 1 else False
59 for i in range(len(x)):
60 if czylista:
61 print(x[i], y[i])
62 mc.setBlock(x[i], y[i], z[0], blok)
63 else:
64 print(x[i], z[i])
65 mc.setBlock(x[i], y[0], z[i], blok)
66
67
68def ruchyBrowna():
69
70 n = int(raw_input("Ile ruchów? "))
71 r = int(raw_input("Krok przesunięcia? "))
72
73 x = y = 0
74 lx = [0] # lista odciętych
75 ly = [0] # lista rzędnych
76
77 for i in range(0, n):
78 # losujemy kąt i zamieniamy na radiany
79 rad = float(randint(0, 360)) * np.pi / 180
80 x = x + r * np.cos(rad) # wylicz współrzędną x
81 y = y + r * np.sin(rad) # wylicz współrzędną y
82 x = int(round(x, 2)) # zaokrągl
83 y = int(round(y, 2)) # zaokrągl
84 print(x, y)
85 lx.append(x)
86 ly.append(y)
87
88 # oblicz wektor końcowego przesunięcia
89 s = np.fabs(np.sqrt(x**2 + y**2))
90 print "Wektor przesunięcia: {:.2f}".format(s)
91
92 wykres(lx, ly, "Ruchy Browna")
93 rysuj(lx, [1], ly, block.WOOL)
94
95
96def main():
97 mc.postToChat("Ruchy Browna") # wysłanie komunikatu do mc
98 plac(-80, -20, -80, 160)
99 plac(-80, 0, -80, 160)
100 ruchyBrowna()
101 return 0
102
103
104if __name__ == '__main__':
105 main()
Większość kodu powinna być już zrozumiała. Importy bibliotek, nawiązywanie połączenia
z serwerem MC Pi, funkcje plac()
, wykres()
i rysuj()
omówione zostały w poprzednim
scenariuszu Funkcje w mcpi.
W funkcji ruchyBrowna()
na początku pobieramy od użytkownika ilość ruchów cząsteczki
do wygenerowania oraz ich długość, co ma znaczenie podczas ich odwzorowywania w świecie MC Pi.
Następnie w pętli:
losujemy kąt wskazujący kierunek ruchu cząsteczki,
wyliczamy współrzędne kolejnego punktu korzystając z funkcji cos() i sin() (np.
x = x + r * np.cos(rad)
),zaokrąglamy wyniki do 2 miejsc po przecinku (np.
x = int(round(x, 2))
) i drukujemy,na koniec dodajemy obliczone współrzędne do list odciętych i rzędnych (np.
lx.append(x)
).
Po wyjściu z pętli obliczamy długość wektora przesunięcia, korzystając z twierdzenia Pitagorasa,
i drukujemy wynik z dokładnością do dwóch miejsc po przecinku (wyrażenie formatujące: {:.2f}
).
Po tych operacjach pozostaje wykreślenie ruchu cząsteczki w matplotlib i wyznaczenie go w Minecrafcie.

Wskazówka
Przed uruchomieniem wizualizacji warto ustawić Steve’a w tryb lotu (dwukrotne naciśnięcie spacji).
9.5.1.1. (Nie)powtarzalność
Kilkukrotne uruchomienie dotychczasowego kodu pokazuje, że za każdym razem generowany jest inny tor ruchu cząsteczki. Z jednej strony to dobrze, bo to potwierdza przypadkowość symulowanych ruchów, z drugiej strony przydatna byłaby możliwość zapamiętania wyjątkowo malowniczych sekwencji.
Zmienimy więc funkcję ruchyBrowna()
tak, aby zapisywała i ewentualnie
odczytywała wygenerowany i zapisany ruch cząsteczki. Musimy też dodać dwie funkcje narzędziowe
zapisujące i czytające dane.
68def ruchyBrowna(dane=[]):
69
70 if len(dane):
71 lx, ly = dane # rozpakowanie listy
72 x = lx[-1] # ostatni element lx
73 y = ly[-1] # ostatni element ly
74 else:
75 n = int(raw_input("Ile ruchów? "))
76 r = int(raw_input("Krok przesunięcia? "))
77
78 x = y = 0
79 lx = [0] # lista odciętych
80 ly = [0] # lista rzędnych
81
82 for i in range(0, n):
83 # losujemy kąt i zamieniamy na radiany
84 rad = float(randint(0, 360)) * np.pi / 180
85 x = x + r * np.cos(rad) # wylicz współrzędną x
86 y = y + r * np.sin(rad) # wylicz współrzędną y
87 x = int(round(x, 2)) # zaokrągl
88 y = int(round(y, 2)) # zaokrągl
89 print(x, y)
90 lx.append(x)
91 ly.append(y)
92
93 # oblicz wektor końcowego przesunięcia
94 s = np.fabs(np.sqrt(x**2 + y**2))
95 print "Wektor przesunięcia: {:.2f}".format(s)
96
97 wykres(lx, ly, "Ruchy Browna")
98 rysuj(lx, [1], ly, block.WOOL)
99 if not len(dane):
100 zapisz_dane((lx, ly))
101
102
103def zapisz_dane(dane):
104 """Funkcja zapisuje dane w formacie json w pliku"""
105 import json
106 plik = open('rbrowna.log', 'w')
107 json.dump(dane, plik)
108 plik.close()
109
110
111def czytaj_dane():
112 """Funkcja odczytuje dane w formacie json z pliku"""
113 import json
114 dane = []
115 nazwapliku = raw_input("Podaj nazwę pliku z danymi lub naciśnij ENTER: ")
116 if os.path.isfile(nazwapliku):
117 with open(nazwapliku, "r") as plik:
118 dane = json.load(plik)
119 else:
120 print "Podany plik nie istnieje!"
121 return dane
122
123
124def main():
125 mc.postToChat("Ruchy Browna") # wysłanie komunikatu do mc
126 plac(-80, -20, -80, 160)
127 plac(-80, 0, -80, 160)
128 ruchyBrowna(czytaj_dane())
129 return 0
Z powyższego kodu wynika, że jeżeli funkcja ruchyBrowna()
otrzyma niepustą listę danych
(if len(dane):
), wczyta z niej dane współrzędnych x i y. W przeciwnym wypadku
generowane będą nowe, które zostaną zapisane: zapisz_dane((lx, ly))
.
Funkcja zapisz_dane()
, pobiera tuplę zawierającą listę współrzędnych x i y,
otwiera plik o podanej nazwie do zapisu (open('rbrowna.log', 'w')
) i zapisuje
w nim dane w formacie json.
Funkcja czytaj_dane()
prosi o podanie nazwy pliku z danymi, jeśli istnieje,
zwraca dane zapisane w formacie json, które w funkcji ruchyBrowna()
rozpakowywane są jako listy wartości x i y: lx, ly = dane
.
Jeżeli podany plik z danymi nie istnieje, zwracana jest pusta lista,
a w funkcji ruchyBrowna()
generowane są nowe dane.
W funkcji głównej zmieniamy wywołanie funkcji na ruchyBrowna(czytaj_dane())
i testujemy zmieniony kod. Za pierwszym razem wciskamy Enter, generujemy
i zapisujemy dane, za drugim razem podajemy nazwę pliku rbrowna.log
.

9.5.1.2. Ruch cząsteczki
Do tej pory ruch cząsteczki wizualizowane był jako pojedyncze punkty.
Możemy jednak pokazać pokonaną trasę liniowo, używając omawianej już
biblioteki minecraftstaff. Pod funkcją rysuj()
umieszczamy
następującą funkcję:
68def rysuj_linie(x, y, z, blok=block.IRON_BLOCK):
69 """
70 Funkcja wizualizuje wykres funkcji, umieszczając bloki w pionie/poziomie
71 w punktach wyznaczonych przez pary elementów list x, y lub x, z
72 przy użyciu metody drawLine()
73 """
74 import local.minecraftstuff as mcstuff
75 mcfig = mcstuff.MinecraftDrawing(mc)
76 czylista = True if len(y) > 1 else False
77 for i in range(len(x) - 1):
78 x1 = int(x[i])
79 x2 = int(x[i + 1])
80 if czylista:
81 y1 = int(y[i])
82 y2 = int(y[i + 1])
83 mc.setBlock(x2, y2, z[0], block.GRASS)
84 mc.setBlock(x1, y1, z[0], block.GRASS)
85 mcfig.drawLine(x1, y1, z[0], x2, y2, z[0], blok)
86 mc.setBlock(x2, y2, z[0], block.GRASS)
87 mc.setBlock(x1, y1, z[0], block.GRASS)
88 print (x1, y1, z[0], x2, y2, z[0])
89 else:
90 z1 = int(z[i])
91 z2 = int(z[i + 1])
92 mc.setBlock(x1, y[0], z1, block.GRASS)
93 mc.setBlock(x2, y[0], z2, block.GRASS)
94 mcfig.drawLine(x1, y[0], z1, x2, y[0], z2, blok)
95 mc.setBlock(x1, y[0], z1, block.GRASS)
96 mc.setBlock(x2, y[0], z2, block.GRASS)
97 print (x1, y[0], z1, x2, y[0], z2)
98 sleep(1) # przerwa na reklamę :-)
99 mc.setBlock(0, 1, 0, block.OBSIDIAN)
100 if czylista:
101 mc.setBlock(x2, y2, z[0], block.OBSIDIAN)
102 else:
103 mc.setBlock(x2, y[0], z2, block.OBSIDIAN)
Jak widać, jest to zmodyfikowana funkcja, której użyliśmy po raz pierwszy w scenariuszu
Funkcje. Zmiany dotyczą dodatkowych instrukcji
typu mc.setBlock(x2, y2, z[0], block.GRASS)
, których zadaniem jest zaznaczenie
innymi blokami wylosowanych punktów reprezentujących ruch cząsteczki.
Instrukcja sleep(1)
wstrzymując budowanie na 1 sekundę wywołuje wrażenie
animacji i pozwala śledzić na bieżąco budowany tor.
Końcowe instrukcje służą zaznaczeniu początku i końca ruchu blokami obsydianu.
Na koniec trzeba w funkcji ruchyBrowna()
zmienić wywołanie rysuj()
na
rysuj_linie()
.
Eksperymenty
Uruchamiamy kod i eksperymentujemy. Dla 100 ruchów z krokiem przesunięcia 5 możemy uzyskać np. takie rezultaty:


Nic nie stoina przeszkodzie, żeby cząsteczka „ruszała się” w pionie nad i… pod wodą:


9.5.2. Liczba Pi
Mamy koło o promieniu r, którego środek umieszczamy w początku układu współrzędnych (0, 0).
Na kole opisany jest kwadrat o boku 2r. Spróbujmy to zbudować w MC Pi. W pliku mcpi-lpi.py
umieszczamy kod:
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4import os
5import random
6from time import sleep
7import mcpi.minecraft as minecraft # import modułu minecraft
8import mcpi.block as block # import modułu block
9import local.minecraftstuff as mcstuff
10
11os.environ["USERNAME"] = "Steve" # nazwa użytkownika
12os.environ["COMPUTERNAME"] = "mykomp" # nazwa komputera
13
14mc = minecraft.Minecraft.create("192.168.1.10") # połączenie z serwerem
15
16
17def plac(x, y, z, roz=10, gracz=False):
18 """Funkcja wypełnia sześcienny obszar od podanej pozycji
19 powietrzem i opcjonalnie umieszcza gracza w środku.
20 Parametry: x, y, z - współrzędne pozycji początkowej,
21 roz - rozmiar wypełnianej przestrzeni,
22 gracz - czy umieścić gracza w środku
23 Wymaga: globalnych obiektów mc i block.
24 """
25
26 podloga = block.STONE
27 wypelniacz = block.AIR
28
29 # kamienna podłoże
30 mc.setBlocks(x, y - 1, z, x + roz, y - 1, z + roz, podloga)
31 # czyszczenie
32 mc.setBlocks(x, y, z, x + roz, y + roz, z + roz, wypelniacz)
33 # umieść gracza w środku
34 if gracz:
35 mc.player.setPos(x + roz / 2, y + roz / 2, z + roz / 2)
36
37
38def model(promien, x, y, z):
39 """
40 Fukcja buduje obrys kwadratu, którego środek to punkt x, y, z
41 oraz koło wpisane w ten kwadrat
42 """
43
44 mcfig = mcstuff.MinecraftDrawing(mc)
45 obrys = block.SANDSTONE
46 wypelniacz = block.AIR
47
48 mc.setBlocks(x - promien, y, z - promien, x +
49 promien, y, z + promien, obrys)
50 mc.setBlocks(x - promien + 1, y, z - promien + 1, x +
51 promien - 1, y, z + promien - 1, wypelniacz)
52 mcfig.drawHorizontalCircle(0, 0, 0, promien, block.GRASS)
53
54
55def liczbaPi():
56 r = float(raw_input("Podaj promień koła: "))
57 model(r, 0, 0, 0)
58
59
60def main():
61 mc.postToChat("LiczbaPi") # wysłanie komunikatu do mc
62 plac(-50, 0, -50, 100)
63 mc.player.setPos(20, 20, 0)
64 liczbaPi()
65 return 0
66
67
68if __name__ == '__main__':
69 main()
Funkcja model()
działa podobnie do funkcji plac()
, czyli na początku
budujemy wokół środka układu współrzędnych płytę z bloku, który będzie zarysem kwadratu.
Później budujemy drugą płytę o blok mniejszą z powietrza. Na koniec rysujemy koło.

9.5.2.1. Deszcz punktów
Teraz wyobraźmy sobie, że pada deszcz. Część kropel upada w obrębie kwadratu,
ich ilość oznaczymy zmienną ileKw
, a część również w obrębie koła – oznaczymy
je zmienną ileKo
. Ponieważ znamy promień koła, możemy ułożyć proporcję, zakładając, że
stosunek pola koła do pola kwadratu równy będzie stosunkowi kropel w kole do kropel
w kwadracie:
Z prostego przekształcenia tej równości możemy wyznaczyć liczbę Pi:
Uzupełniamy więc kod funkcji liczbaPi()
:
55def liczbaPi():
56 r = float(raw_input("Podaj promień koła: "))
57 model(r, 0, 0, 0)
58
59 # pobieramy ilość punktów w kwadracie
60 ileKw = int(raw_input("Podaj ilość losowanych punktów: "))
61 ileKo = 0 # ilość punktów w kole
62
63 blok = block.SAND
64 for i in range(ileKw):
65 x = round(random.uniform(-r, r))
66 y = round(random.uniform(-r, r))
67 print x, y
68 if abs(x)**2 + abs(y)**2 <= r**2:
69 ileKo += 1
70 # umieść blok w MC Pi
71 mc.setBlock(x, 10, y, blok)
72
73 mc.postToChat("W kole = " + str(ileKo) + " W Kwadracie = " + str(ileKw))
74 pi = 4 * ileKo / float(ileKw)
75 mc.postToChat("Pi w przyblizeniu: {:.10f}".format(pi))
76
Jak widać w nowym kodzie, na początku pobieramy od użytkownika ilość „kropel” deszczu,
czyli punktów do wylosowania. Następnie w pętli losujemy ich współrzędne
w przedziale <-r;r> w instrukcji typu: x = round(random.uniform(-r, r), 10)
.
Funkcja uniform()
zwraca wartości zmiennoprzecinkowe, które zaokrąglamy
do 10 miejsca po przecinku.
Korzystając z twierdzenia Pitagorasa układamy warunek pozwalający sprawdzić,
które punkty „wpadły” do koła: if abs(x)**2 + abs(y)**2 <= r**2:
– i zliczamy je.
Instrukcja mc.setBlock(x, 10, y, blok)
rysuje punkty w MC Pi za pomocą
bloków piasku (SAND), dzięki czemu uzyskujemy efekt spadania.
Wyliczenie wartości Pi i wydrukowanie jej jest prostą formalnością.
Uruchomienie powyższego kodu dla promienia 30 i 1000 punktów dało następujący efekt:

Jak widać, niektóre punkty po zaokrągleniu ich współrzędnych w MC Pi nakładają się na siebie.
9.5.2.2. Podkolorowanie
Punkty wpadające do koła mogłyby wyglądać inaczej niż poza nim. Można by to
osiągnąć przez ustawienie różnych typów bloków w pętli for
, ale tylko
blok piaskowy daje efekt spadania. Zrobimy więc inaczej. Zmieniamy funkcję liczbaPi()
:
55def liczbaPi():
56 r = float(raw_input("Podaj promień koła: "))
57 model(r, 0, 0, 0)
58
59 # pobieramy ilość punktów w kwadracie
60 ileKw = int(raw_input("Podaj ilość losowanych punktów: "))
61 ileKo = 0 # ilość punktów w kole
62 wKwadrat = [] # pomocnicza lista punktów w kwadracie
63 wKolo = [] # pomocnicza lista punktów w kole
64
65 blok = block.SAND
66 for i in range(ileKw):
67 x = round(random.uniform(-r, r))
68 y = round(random.uniform(-r, r))
69 wKwadrat.append((x, y))
70 print x, y
71 if abs(x)**2 + abs(y)**2 <= r**2:
72 ileKo += 1
73 wKolo.append((x, y))
74
75 mc.setBlock(x, 10, y, blok)
76
77 sleep(5)
78 for pkt in set(wKwadrat) - set(wKolo):
79 x, y = pkt
80 mc.setBlock(x, i, y, block.OBSIDIAN)
81 for i in range(1, 3):
82 print x, i, y
83 if mc.getBlock(x, i, y) == 12:
84 mc.setBlock(x, i, y, block.OBSIDIAN)
85
86 mc.postToChat("W kole = " + str(ileKo) + " W Kwadracie = " + str(ileKw))
87 pi = 4 * ileKo / float(ileKw)
88 mc.postToChat("Pi w przyblizeniu: {:.10f}".format(pi))
Deklarujemy dwie pomocnicze listy, do których zapisujemy w pętli współrzędne
punktów należących do kwadratu i koła, np. wKwadrat.append((x, y))
.
Następnie wstrzymujemy wykonanie kodu na 5 sekund, aby bloki piasku
zdążyły opaść. W wyrażeniu set(wKwadrat) - set(wKolo)
każda lista zostaje
przekształcona na zbiór, a następnie zostaje obliczona ich różnica.
W efekcie otrzymujemy współrzędne punktów należących do kwadratu, ale nie do koła.
Ponieważ niektóre bloki piasku układają się jeden na drugim, wychwytujemy je w pętli
wewnętrznej if mc.getBlock(x, i, y) == 12:
– i zmieniamy na obsydian.
9.5.2.3. Trzeci wymiar
Siła MC Pi tkwi w 3 wymiarze. Możemy bez większych problemów go wykorzystać. Na początku warto zauważyć, że w algorytmie wyliczania wartości liczby Pi nic się nie zmieni. Stosunek pola koła do pola kwadratu zastępujemy bowiem stosunkiem objętości walca, którego podstawa ma promień r, do objętości sześcianu o boku 2r. Otrzymamy zatem:
Po przekształceniu skończymy na takim samym jak wcześniej wzorze, czyli:
Aby to wykreślić, zmienimy funkcje model()
, liczbaPi()
i main()
. Sugerujemy, żeby
dotychczasowy plik zapisać pod inną nazwą, np. mcpi-lpi3D.py
, i wprowadzić następujące zmiany:
38def model(r, x, y, z, klatka=False):
39 """
40 Fukcja buduje obrys kwadratu, którego środek to punkt x, y, z
41 oraz koło wpisane w ten kwadrat
42 """
43
44 mcfig = mcstuff.MinecraftDrawing(mc)
45 obrys = block.OBSIDIAN
46 wypelniacz = block.AIR
47
48 mc.setBlocks(x - r - 10, y - r, z - r - 10, x +
49 r + 10, y + r, z + r + 10, wypelniacz)
50 mcfig.drawLine(x + r, y + r, z + r, x - r, y + r, z + r, obrys)
51 mcfig.drawLine(x - r, y + r, z + r, x - r, y + r, z - r, obrys)
52 mcfig.drawLine(x - r, y + r, z - r, x + r, y + r, z - r, obrys)
53 mcfig.drawLine(x + r, y + r, z - r, x + r, y + r, z + r, obrys)
54
55 mcfig.drawLine(x + r, y - r, z + r, x - r, y - r, z + r, obrys)
56 mcfig.drawLine(x - r, y - r, z + r, x - r, y - r, z - r, obrys)
57 mcfig.drawLine(x - r, y - r, z - r, x + r, y - r, z - r, obrys)
58 mcfig.drawLine(x + r, y - r, z - r, x + r, y - r, z + r, obrys)
59
60 mcfig.drawLine(x + r, y + r, z + r, x + r, y - r, z + r, obrys)
61 mcfig.drawLine(x - r, y + r, z + r, x - r, y - r, z + r, obrys)
62 mcfig.drawLine(x - r, y + r, z - r, x - r, y - r, z - r, obrys)
63 mcfig.drawLine(x + r, y + r, z - r, x + r, y - r, z - r, obrys)
64
65 mc.player.setPos(x + r, y + r + 1, z + r)
66
67 if klatka:
68 mc.setBlocks(x - r, y - r, z - r, x + r, y + r, z + r, block.GLASS)
69 mc.setBlocks(x - r + 1, y - r + 1, z - r + 1, x +
70 r - 1, y + r - 1, z + r - 1, wypelniacz)
71 mc.player.setPos(0, 0, 0)
72
73 for i in range(-r, r + 1, 5):
74 mcfig.drawHorizontalCircle(0, i, 0, r, block.GRASS)
75
76
77def liczbaPi(klatka=False):
78 r = int(raw_input("Podaj promień koła: "))
79 model(r, 0, 0, 0, klatka)
80
81 # pobieramy ilość punktów w kwadracie
82 ileKw = int(raw_input("Podaj ilość losowanych punktów: "))
83 ileKo = 0 # ilość punktów w kole
84 wKwadrat = [] # pomocnicza lista punktów w kwadracie
85 wKolo = [] # pomocnicza lista punktów w kole
86
87 for i in range(ileKw):
88 blok = block.OBSIDIAN
89 x = round(random.uniform(-r, r))
90 y = round(random.uniform(-r, r))
91 z = round(random.uniform(-r, r))
92 wKwadrat.append((x, y, z))
93 print x, y, z
94 if abs(x)**2 + abs(z)**2 <= r**2:
95 blok = block.DIAMOND_BLOCK
96 ileKo += 1
97 wKolo.append((x, y, z))
98
99 mc.setBlock(x, y, z, blok)
100
101 mc.postToChat("W kole = " + str(ileKo) + " W Kwadracie = " + str(ileKw))
102 pi = 4 * ileKo / float(ileKw)
103 mc.postToChat("Pi w przyblizeniu: {:.10f}".format(pi))
104 mc.postToChat("Stan na kamieniu!")
105
106 while True:
107 poz = mc.player.getPos()
108 x, y, z = poz
109 if mc.getBlock(x, y - 1, z) == block.STONE.id:
110 for pkt in wKolo:
111 x, y, z = pkt
112 mc.setBlock(x, y, z, block.SAND)
113 sleep(3)
114 mc.player.setPos(0, r - 1, 0)
115 break
116
117
118def main():
119 mc.postToChat("LiczbaPi") # wysłanie komunikatu do mc
120 plac(-50, 0, -50, 100)
121 liczbaPi(False)
122 return 0
Zadaniem funkcji model()
jest stworzenie przestrzeni dla obrysu sześcianu i jego szkieletu.
Opcjonalnie, jeżeli przekażemy do funkcji parametr klatka
równy True
,
ściany mogą zostać wypełnione szkłem. Walec wizualizujemy w pętli for
rysując kilka okręgów blokami trawy.
W funkcji liczbaPi()
najważniejszą zmianą jest dodanie trzeciej zmiennej.
Wartości wszystkich trzech współrzędnych losowane są w takim samym zakresie,
ponieważ za środek całego układu przyjmujemy początek układu współrzędnych.
Ważna zmiana zachodzi w funkcji warunkowej: if abs(x)**2 + abs(z)**2 <= r**2:
.
Do sprawdzenia, czy punkt należy do koła wykorzystujemy zmienne x i z,
uwzględniając fakt, że w MC Pi wyznaczają one położenie w poziomie.
Bloki należące do sześcianu rysujemy za pomocą obsydianu, te w walcu – za pomocą diamentów.
Na końcu funkcji dodajemy nieskończoną pętlę (while True:
), której zadaniem jest
sprawdzanie, na jakim bloku znajduje się gracz: if mc.getBlock(x, y - 1, z) == block.STONE.id:
.
Jeżeli stanie on na kamieniu, wszystkie bloki należące do walca zamieniamy
w pętli for pkt in wKolo:
w piasek, a gracza teleportujemy do środka sześcianu.
Dla promienia o wielkości 20 i 1000 bloków uzyskać można poniższe budowle:



Pozostaje eksperymentować z rozmiarami, typami bloków czy parametrem klatka
określanym w wywołaniu funkcji liczbaPi()
w funkcji głównej.
Źródła:
Materiały Python 101
udostępniane przez
Centrum Edukacji Obywatelskiej na licencji
Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowa.
- Utworzony:
2025-04-12 o 10:21 w Sphinx 7.3.7
- Autorzy: