WstΩp
Wszyscy chyba wiemy, co to s▒ fraktale. Te piΩkne,
kolorowe obrazy i algorytmy do ich tworzenia s▒
bardzo znane. Niewielu jednak wie, ┐e obok nich
istnieje jeszcze wiele innych r≤wnie fascynuj▒cych
dziedzin grafiki komputerowej. Jedn▒ z nich s▒
tzw. automaty kom≤rkowe (cellular automats).
Po dw≤ch latach eksperyment≤w z nimi postanowi│em
napisaµ artyku│ o tej grupie algorytm≤w.
Automat kom≤rkowy to specjalny algorytm oraz
struktura danych, na kt≤rej on operuje. S│u┐y do
generowania grafiki 2D. Jak sama nazwa wskazuje, owa
struktura danych sk│ada siΩ z kom≤rek.
Deklarujemy wiΩc tablicΩ:
var
Tab: array[0..TabWidth-1, 0..TahHeight-1] of TCell;
Mo┐e ona byµ kwadratowa lub prostok▒tna. Typ
TCell to typ danych, jakie przechowuje ka┐da kom≤rka.
BΩdzie o tym mowa ni┐ej. Czy ka┐da kom≤rka
tablicy reprezentuje jeden piksel? Mo┐e, ale nie
musi. Czasami efekt bΩdzie lepszy, je┐eli ka┐da z
nich bΩdzie odrysowywana na ekranie jako kwadrat o
wymiarach kilku pikseli.
Czym jest ≤w algorytm, kt≤ry na tej tablicy
operuje? Mo┐e on wygl▒daµ naprawdΩ bardzo r≤┐nie.
Og≤lnie chodzi o to, ┐eby w pΩtli przetwarzaµ
wszystkie lub niekt≤re kom≤rki (w okre╢lonej
kolejno╢ci) zmieniaj▒c odpowiednio ich warto╢µ.
Da to w efekcie pewien trudny do przewidzenia efekt
graficzny. Ciekaw▒ cech▒ wsp≤ln▒ automat≤w kom≤rkowych
i fraktali jest, ┐e proste algorytmy potrafi▒
generowaµ ca│kiem skomplikowane wzory. Poni┐ej
przedstawiam 2 znane mi typy automat≤w kom≤rkowych.
Automat kom≤rkowy 1
Ka┐da kom≤rka bΩdzie typu logicznego:
var
Tab: array[0..TabWidth-1, 0..TahHeight-1] of Boolean;
Znaczy to, ┐e mo┐e byµ w jednym z 2 stan≤w.
Na ekranie bΩdziemy to przedstawiali jako kom≤rka
wygaszona (o kolorze t│a np. czarna) lub za╢wiecona
(o zdefiniowanym kolorze np. bia│a). W tej grupie
algorytm≤w najlepiej ka┐d▒ kom≤rkΩ na ekranie
prezentowaµ jako ma│y kwadracik o wymiarach kilka
na kilka pikseli robi▒c miΩdzy kom≤rkami
jednopikselowe odstΩpy.
Na pocz▒tku inicjalizujemy tablicΩ zupe│nie
losowymi warto╢ciami:
Randomize;
for Y := 0 to TabHeight-1 do
for X := 0 to TabWidth-1 do
Tab[X, Y] := (Random(2) = 0);
Mo┐esz te┐ spr≤bowaµ rozmie╢ciµ warto╢ci
pocz▒tkowe wg jakiego╢ okre╢lonego algorytmu. Ja
tego nie pr≤bowa│em. Mo┐e otrzymasz jakie╢
ciekawe efekty?
G│≤wny algorytm to pΩtla, w kt≤rej wykonywane
s▒ kolejne cykle obliczeniowe. W ka┐dym takim
cyklu przetwarzane s▒ wszystkie kom≤rki. Nie jest
przy tym wa┐na kolejno╢µ tzn. czy s▒
przetwarzane od g≤ry czy od do│u, od lewej czy od
prawej strony.
for I := 0 to CycleCount-1 do
for Y := 0 to TabHeight-1 do
for X := 0 to TabWidth-1 do
ProcessCell(X, Y);
Oczywi╢cie ┐eby widzieµ jak automat dzia│a,
warto co jaki╢ czas pokazaµ na ekranie bie┐▒cy
stan tablicy. W toku kolejnych cykli oblicze± zupe│nie
losowy na pocz▒tku uk│ad kom≤rek zaczyna siΩ
porz▒dkowaµ tworz▒c pewne wzory i motywy. Kolejne
cykle zmieniaj▒ w obrazie ju┐ coraz mniej. Trwa to
a┐ ca│o╢µ osi▒gnie swoisty stan r≤wnowagi, w
kt≤rym kolejne przeliczenie nie zmieniaj▒ ju┐ nic
lub prawie nic. Stanie siΩ tak po ok. kilku lub
kilkunastu cyklach. W zasadzie za efekt dzia│ania
automatu uznaµ nale┐y obraz wygenerowany po tych
cyklach, po kt≤rych nic ju┐ siΩ w nim nie
zmienia. Samo powstawanie tego obrazu jest jednak na
tyle ciekawe i efektowne, ┐e warto r≤wnie┐ sam
ten proces obserwowaµ. Co jest charakterystyczne:
za ka┐dym razem otrzymujemy inny obraz (bo zale┐y
on od danych pocz▒tkowych, kt≤re s▒ przecie┐
losowane), ale zawsze wystΩpuj▒ w nim te same
motywy i ma on ten sam, jakby, wz≤r (bo ten zale┐y
od algorytmu). Za pomoc▒ tej kategorii algorytm≤w
mo┐na otrzymaµ np. wz≤r przypominaj▒cy │aty
niepopularnego ostatnio zwierzΩcia, jakim jest
krowa.
Co robi procedura ProcessCell? Przetwarza
pojedyncz▒ kom≤rkΩ. Przetwarza j▒ wg pewnego
algorytmu. To on w│a╢nie stanowi istotΩ automatu.
I tu jest co╢ naprawdΩ wspania│ego: mo┐esz w
zasadzie wymy╢laµ dowolne algorytmy, a ka┐dy z
nich da w efekcie inny wz≤r. Obliczaj▒c nowy stan
dla przetwarzanej aktualnie kom≤rki pod uwagΩ mo┐esz
wzi▒µ m.in.:
- Stan kom≤rki przetwarzanej przed jej
przetworzeniem.
- Stany kom≤rek s▒siaduj▒cych (tylko w
poziomie i w pionie lub tak┐e na ukos). Mo┐esz
np. zliczaµ, ile s▒siednich kom≤rek jest w
stanie True i na tej podstawie podejmowaµ jakie╢
dzia│anie. UwzglΩdnij tylko co bΩdzie, je╢li
rozpatrywana kom≤rka le┐y na skraju tablicy (┐eby
nie by│o Access Violation).
Ja wymy╢li│em 3 algorytmy:
Algorytm 1
var
Count: Integer;
begin
//OBLICZENIA
Count := 0;
//Powy┐ej
if Y > 0 then
if Tab[X, Y-1] = True then
Inc(Count);
//Poni┐ej
if Y < TabHeight-1 then
if Tab[X, Y+1] = True then
Inc(Count);
//Z lewej
if X > 0 then
if Tab[X-1, Y] = True then
Inc(Count);
//Z prawej
if X < TabWidth-1 then
if Tab[X+1, Y] = True then
Inc(Count);
//Zasada I
//L + 3H = H
if Count = 3 then
Tab[X, Y] := True;
//II zasada
//H + 1H = L
if Count = 1 then
Tab[X, Y] := False;
//III zasada
if Count = 4 then
Tab[X, Y] := False;
Zliczana jest liczba kom≤rek w stanie True, z
jakimi s▒siaduje kom≤rka przetwarzana w pionie
oraz w poziomie. Je╢li ta liczba wynosi 1 lub 4 -
kom≤rka przechodzi w stan False. Je╢li wynosi 3 -
w stan True. Je╢li za╢ 2 - pozostaje bez zmian.
Zauwa┐, ┐e nie jest tu brane pod uwagΩ, jak▒
warto╢µ mia│a poprzednio kom≤rka przetwarzana.
Algorytm 2
var
Count: Integer;
begin
//OBLICZENIA
Count := 0;
//Powy┐ej
if Y > 0 then
if Tab[X, Y-1] = True then
Inc(Count);
//Poni┐ej
if Y < TabHeight-1 then
if Tab[X, Y+1] = True then
Inc(Count);
//Z lewej
if X > 0 then
if Tab[X-1, Y] = True then
Inc(Count);
//Z prawej
if X < TabWidth-1 then
if Tab[X+1, Y] = True then
Inc(Count);
//Z lewej - u g≤ry
if (X > 0) and (Y > 0) then
if Tab[X-1, Y-1] = True then
Inc(Count);
//Z prawej - u g≤ry
if (X < TabWidth-1) and (Y > 0) then
if Tab[X+1, Y-1] = True then
Inc(Count);
//Z lewej - u do│u
if (X > 0) and (Y < TabHeight-1) then
if Tab[X-1, Y+1] = True then
Inc(Count);
//Z prawej - u do│u
if (X < TabWidth-1) and (Y < TabHeight-1) then
if Tab[X+1, Y+1] = True then
Inc(Count);
//Zasada I
if Count > 4 then
Tab[X, Y] := True;
//II zasada
if Count < 4 then
Tab[X, Y] := False;
//III zasada
if Count = 4 then
Tab[X, Y] := Tab[X, Y];
W tym algorytmie zliczana jest ilo╢µ aktywnych
(True) kom≤rek s▒siaduj▒cych z rozpatrywan▒ tak┐e
na ukos. Mo┐e wiΩc ich byµ od 0 do 8. Je╢li ich
liczba jest mniejsza od 4 - kom≤rka przetwarzana
przechodzi w stan False. Je╢li wiΩcej od 4 - w
stan True. Je╢li za╢ wynosi dok│adnie 4 - warto╢µ
kom≤rki pozostaje bez zmian.
Algorytm 3
var
Count: Integer;
begin
//OBLICZENIA
Count := 0;
//Powy┐ej
if Y > 0 then
if Tab[X, Y-1] = True then
Inc(Count);
//Poni┐ej
if Y < TabHeight-1 then
if Tab[X, Y+1] = True then
Inc(Count);
//Z lewej
if X > 0 then
if Tab[X-1, Y] = True then
Inc(Count);
//Z prawej
if X < TabWidth-1 then
if Tab[X+1, Y] = True then
Inc(Count);
//Zasada I
if Count < 2 then
Tab[X, Y] := False;
//II zasada
if Count > 2 then
Tab[X, Y] := True;;
Tu zliczane s▒ tylko kom≤rki s▒siaduj▒ce w
pionie i w poziomie. Je╢li ich liczba jest mniejsza
od 2 - kom≤rka przechodzi w stan False. Je╢li wiΩksza
- w stan True. Je╢li jest r≤wna 2 - pozostaje bez
zmian.
ZachΩcam do samodzielnego eksperymentowania z t▒
klas▒ automat≤w kom≤rkowych - naprawdΩ warto. Z
pewno╢ci▒ uda Ci siΩ wymy╢liµ jeszcze lepsze,
│adniejsze, ciekawsze algorytmy. Nie jest to
trudne. ZachΩcam tak┐e wszystkich, kt≤rzy ciekawi
s▒ jak to wygl▒da do ╢ci▒gniΩcia i
zainstalowania wygaszacza ekranu mojego autorstwa - ProgrameX
Cellular Automat Screensaver.
Automat kom≤rkowy 2
Tutaj ka┐da kom≤rka tablicy reprezentuje jeden
piksel. W zasadzie to mo┐e byµ zar≤wno typu
Boolean (2 kolory), Byte (256 odcieni szaro╢ci - te┐
ca│kiem fajnie wychodzi), jak i TColor (16 milion≤w
kolor≤w). Tyle ┐e tablica nie jest obrazem samym w
sobie. Mo┐e mieµ ca│kiem ma│e wymiary - jak np.
20 x 20. Cech▒ charakterystyczn▒ tego automatu
jest, ┐e generuje on tekstury, kt≤re s▒ rozk│adalne
s▒siaduj▒co tzn. roz│o┐one jedna obok drugiej
daj▒ jednolity wz≤r i nie s▒ widoczne │▒czenia
miΩdzy nimi. TablicΩ t▒ inicjalizujemy warto╢ci▒
0, czyli kolorem czarnym.
Inny jest zupe│nie algorytm - tu nie ma cykli, w
kt≤rych przeliczane by│yby wszystkie kom≤rki po
kolei. Jest natomiast "robaczek". Chodzi
on sobie po tablicy i modyfikuje ka┐dy piksel, na
kt≤rym stanie. »eby tekstura by│a rozk│adalna s▒siaduj▒co,
kiedy robaczek wyjdzie za tablice musi tym samym wr≤ciµ
z drugiej strony. Opisuj▒ go 3 zmienne: bie┐▒ca
pozycja na X i na Y oraz tzw. azymut. Ta ostatnia to
liczba z zakresu od 0 do 7 opisuj▒ca bie┐▒cy
zwrot robaka - a wiΩc kierunek, w kt≤rym przemie╢ci
siΩ on w nastΩpnym kroku. Dla przyk│adu: 0 mo┐e
oznaczaµ zwrot do g≤ry, 1 po skosie do g≤ry na
prawo, 2 w prawo, 4 na d≤│, 6 w lewo itd. Oczywi╢cie
mo┐esz sobie napisaµ tak, ┐eby zwrot m≤g│ byµ
tylko do g≤ry, w d≤│, w prawo lub w lewo - bez 4
kierunk≤w po skosie. Ja tego nie pr≤bowa│em.
Automat kom≤rkowy tej kategorii charakteryzuj▒
2 algorytmy. Pierwszy to obliczanie, jaki azymut ma
byµ nadany naszemu robaczkowi do ruchu w nastΩpnej
turze. I w│a╢nie tu jest co╢ wspania│ego - aby
go obliczyµ, mo┐esz u┐yµ praktycznie dowolnych
danych. Oto moje pomys│y:
- Kolor piksela, na kt≤rym robaczek stoi (jako
ca│o╢µ b▒d╝ jedna ze sk│adowych)
- Licznik, kt≤rego warto╢µ bΩdzie zwiΩkszana
po ka┐dym kroku
- Jaka╢ sta│a liczba zdefiniowana dla ca│ej
operacji
- Warto╢µ losowa (ta bardzo du┐o zmienia -
bez jej u┐ycia tekstura ma kszta│t regularny i
uporz▒dkowany, po jej zastosowaniu wygl▒da na
chaotyczn▒ i jest za ka┐dym wygenerowaniem
trochΩ inna)
- Poprzednia warto╢µ azymutu (czyli nie nadawaµ
mu nowej warto╢ci, ale modyfikowaµ j▒ wzglΩdem
poprzedniej).
Mo┐esz te dane wykorzystywaµ w dowolny spos≤b
- dowolnie przetwarzaµ ich warto╢ci za pomoc▒
operacji bitowych, arytmetycznych czy
trygonometrycznych i dowolnie │▒czyµ ze sob▒
tworz▒c niezliczone ilo╢ci r≤┐nych algorytm≤w.
Ka┐dy z nich da w efekcie zupe│nie inny obraz.
Ciekawym rozwi▒zaniem jest te┐ stworzenie wg
jakiego╢ algorytmu tablicy, w kt≤rej ka┐dej warto╢ci
jednego parametru bΩd▒ przypisane odpowiednie
warto╢ci dla wyniku operacji.
Zauwa┐, ┐e nawet niewielka zmiana szeroko╢ci
lub wysoko╢ci obrazka czy sta│ej (je╢li taka jest
u┐ywana w algorytmie) spowoduje zupe│n▒ zmianΩ
obrazu. Pomy╢l wiΩc: ilo╢µ r≤┐nych ich
kombinacji jest praktycznie niesko±czona!
Drugi algorytm opisuje, w jaki spos≤b
modyfikowany ma byµ piksel, na kt≤rym robaczek
stoi. Mo┐e to byµ zwyk│e rozja╢nianie - np. dla
obrazu w grayscale. Dla obrazu kolorowego mo┐esz
zrobiµ co╢ takiego: wykonaµ tych kilka (-dziesi▒t?
-set?) tysiΩcy krok≤w dla ka┐dej ze sk│adowych
RGB za ka┐dym razem modyfikuj▒c jedn▒ z nich.
Albo - po prostu operowaµ na warto╢ci liczbowej
koloru piksela jako ca│o╢ci. Jedno jest pewne -
musisz uwzglΩdniaµ kolor, jaki mia│ piksel przed
dokonaniem na nim operacji. Mo┐esz np. rozja╢niaµ
czy jako╢ inaczej modyfikowaµ - ale zawsze wzglΩdem
poprzedniej warto╢ci. Jest to konieczne dlatego, ┐e
na ka┐dy piksel robaczek staje po kilkaset albo
nawet kilka tysiΩcy razy.
Nie bΩdΩ tu kopiowa│ kodu ╝r≤d│owego
procedur - zamiast tego do│▒czam do artyku│u plik
CAdemo.rar.
My╢lΩ, ┐e kod dla wszystkich oka┐e siΩ czytelny
i zrozumia│y. Zwr≤µ uwagΩ na jedn▒ rzecz: taki
prosty program (jeden ma│y modu│) potrafi generowaµ
tak r≤┐norodne i ciekawe tekstury. W zasadzie mo┐na
je podzieliµ na 2 grupy: te zawieraj▒ce regularne
geometryczne wzory (bez u┐ycia warto╢ci losowej)
oraz plazmoidalne struktury o charakterze raczej
nieregularnym (z u┐yciem warto╢ci losowej). Oto
przyk│ady:

Zako±czenie
Tak w│a╢nie prezentuj▒ siΩ efekty mojej pracy
z automatami kom≤rkowymi oraz m≤j aktualny stan
wiedzy o nich. Nie masz chyba po tym wszystkim ju┐
w▒tpliwo╢ci, ┐e jest to dziedzina grafiki
komputerowej 2D r≤wnie fascynuj▒ca jak fraktale i
inne algorytmy? Mo┐na te┐ znale╝µ dla niej
ogromne zastosowanie. Pomy╢l: po co zapisywaµ r≤┐ne
tekstury w plikach graficznych, jak mo┐na je sobie
za ka┐dym razem wygenerowaµ?
Literatura:
- "Wirtualne ┐ycie" - PC Shareware Nr
04/99 str. 15
- "Kurs C++ czΩ╢µ 7" - CD-Action Nr
11/2000 str. 125
Adam Sawicki
sawickiap@poczta.onet.pl
|