<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6324716039497767765</id><updated>2011-08-14T20:38:22.270+02:00</updated><category term='Studia'/><category term='Programowanie deklaratywne'/><category term='Go'/><category term='AutoIt'/><category term='Matematyka'/><category term='Sport'/><category term='Framework 3D'/><category term='Relacje'/><category term='Algorytmy'/><category term='Literatura'/><category term='Narzędzia'/><category term='Projekt RPG'/><category term='Technikalia'/><category term='Graphrator'/><category term='Java'/><category term='Struktura kodu'/><category term='Prolog'/><category term='Inne projekty'/><category term='Dev-video'/><category term='PHP'/><category term='Inżynieria oprogramowania'/><category term='Skrypty'/><category term='Linux'/><category term='Projektowanie'/><category term='Filozofia programowania'/><category term='Wielki Mistrz'/><category term='Robot'/><category term='Programowanie niskopoziomowe'/><category term='Silnik 3D'/><category term='Proste gry i casuale'/><category term='Podsumowania'/><category term='LaTeX'/><category term='Magic: the Gathering'/><category term='Gry'/><category term='OpenGL'/><category term='Apokalips'/><title type='text'>Jak NIE robić RPG-a (i innych rzeczy również)</title><subtitle type='html'>Czyli devblog takiego jednego będący relacją wydarzeń, często przypadkowych, które miały miejsce przy okazji tworzenia gry (lub gier czy aplikacji).</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default?start-index=101&amp;max-results=100'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>159</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-8107541015096028200</id><published>2011-07-31T17:31:00.001+02:00</published><updated>2011-07-31T17:31:08.143+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Przywitanie gości, czyli znowu o inżynierii oprogramowania</title><content type='html'>&lt;p&gt;Skończył się czwarty tydzień praktyk, a przez to skończyły się same praktyki. Czy to oznacza, że nie musimy już trzymać się rygoru przychodzenia codziennie o 8 rano? Tak. A czy oznacza też, że już nie pracujemy? Nie.&lt;/p&gt;  &lt;p&gt;Pracować nadal trzeba, bo projekt jest nadal nieskończony, ale to akurat było w planie. Problem w tym, iż wydaje mi się, że prace idą odrobinę wolniej, niż to sobie zakładaliśmy – wniosek z tego taki, że trzeba będzie je przyspieszyć (elementarne, drogi Watsonie). I nie myśleć o pisaniu własnego &lt;a href="http://minecraft.net/"&gt;Minecrafta&lt;/a&gt; (tak nas wzięło, gdyż w gruncie rzeczy większość obiektów w tej grze to po prostu sześciany, co banalnie łatwo przygotować).&lt;/p&gt;  &lt;p&gt;Ostatni tydzień przyniósł też parę dyskusji o wykorzystaniu różnych dziwnych rozwiązań w projekcie – między innymi chyba trzeba będzie się zapoznać bliżej z sieciami neuronowymi oraz przypomnieć sobie założenia algorytmów genetycznych. Swoją drogą, jako człowiek – delikatnie mówiąc – nieprzepadający za biologią (nie twierdzę, że to nieużyteczna nauka, tylko strasznie pamięciowa) troszkę boję słysząc nazwy “algorytm genetyczny”, “sztuczny mózg” czy “do pierwszego starczy”. Wiem, że to niegroźne, ale brzmi strasznie biologicznie.&lt;/p&gt;  &lt;p&gt;Prawdziwą atrakcją okazał się jednak zapowiedziany wcześniej najazd drugiej grupy z SDS. Tak się bowiem składa, że nasz pokój przeznaczony jest dla dwóch grup piszących różne inżynierki i widać, że będzie trzeba troszkę się skondensować, aby się pomieścić choć pokój jest dość duży. Cóż, z tego co mi wiadomo, będziemy się na razie raczej mijać aniżeli siedzieć razem, zatem nie powinno być tak źle. Na razie.&lt;/p&gt;  &lt;p&gt;Nie zapominajmy też, że są wakacje, a wakacje oznaczają odpoczynek (czyli więcej czasu na zajęcie się MTG czy futbolem, bo NBA chwilowo ma lokaut (a w NFL się skończył parę dni temu)). Nie będziemy zatem teraz ciągle siedzieć w pracy, co sprawia, że będziemy tam chodzić po to, aby rzeczywiście pracować pełną parą, gdy tylko tego będziemy chcieli lub będziemy czuć wenę. A zostało jeszcze sporo do zrobienia. &lt;/p&gt;  &lt;p&gt;Z innej beczki – osoby, które mnie znają, wiedzą, iż nie przepadam za serwisami typu &lt;a href="http://pl-pl.facebook.com/"&gt;Facebook&lt;/a&gt;, które skupiają sporą liczbę użytkowników różnej maści, którzy to w mniejszym czy większym stopniu udostępniają informacje, których w normalnych warunkach nikomu by nie przekazali. Doszło do takiego paradoksu, że na wszystkie spotkania czy zgromadzenia ludzie umawiają się na Facebooku, “bo wszyscy tam siedzą”. A guzik prawda, posiadanie tam konta nie jest obowiązkiem. Nie twierdzę, że to nieprzydatne, ale w granicach rozsądku. Za to, jak pewnie też już wiecie, Google wypuściło do szerszego użytkowania testową wersję serwisu &lt;a href="https://plus.google.com/"&gt;Google+&lt;/a&gt;, który również ma być portalem społecznościowym o nieco większym bezpieczeństwie i braku inwazyjności. Nie ukrywam – skusiłem się, zwłaszcza, że lubię googlowe narzędzia i choć na razie niewiele się na tym serwisie dzieje, to fajnie jest sobie tam siedzieć od czasu do czasu. Zamierzam tam głównie rozwijać nieco tę magicową część mojego żywota, a zatem troszkę łączyć użytkowników &lt;a href="http://karcianki.polter.pl/"&gt;karciankowego działu Poltera&lt;/a&gt; oraz innych Magicowców. Od czasu do czasu umieszczę też dziwne notki związane z programowaniem. O ile mi starczy cierpliwości. I serwis nie padnie. I mi się będzie chciało. &lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-8107541015096028200?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/8107541015096028200/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=8107541015096028200' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/8107541015096028200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/8107541015096028200'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/07/przywitanie-gosci-czyli-znowu-o.html' title='Przywitanie gości, czyli znowu o inżynierii oprogramowania'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-1838824034458397559</id><published>2011-07-22T23:44:00.002+02:00</published><updated>2011-07-22T23:45:16.296+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Folia na drzwiach, czyli znowu o inżynierii oprogramowania</title><content type='html'>&lt;p&gt;Przyszedł zatem czas na refleksje dotyczące trzeciego tygodnia praktyk. Tytuł jest nieprzypadkowy, gdyż z okazji wakacji budynek, w którym stacjonujemy, został poddany diabelskiemu zjawisku zwanego remontem. Oczywiście, nie cały budynek – jedynie jedno piętro, a konkretnie to, na którym się znajdujemy. Tak po prostu, aby było wesoło. Oprócz cudownego dźwięku wwiercającej się w sąsiednią ścianę wiertarki oraz wszechobecnego brudu (który potem nanosimy do naszego pokoju), pewnego dnia po przyjściu do pracy ujrzałem nasze zafoliowane drzwi i stojącego nieopodal robotnika komunikującego, iż dzisiaj niestety będą gipsować i na razie do pokoju nie wejdziemy. Jak się okazało, po południu już można było wejść, jednak cały dzień przesiedziałem u innej grupy w pokoju (dziękuję za gościnę), oddając się tak zwanemu researchowi, czyli badaniu czeluści Internetu w poszukiwaniu “ctheghoś”. Żeby nie było nieporozumień – nie mam pretensji do nikogo. Robotnicy wykonują swoją pracę, a budynki uczelniane (czy szkolne) zwykle remontuje się w okresie wakacyjnym. Szkoda tylko, że musimy w tym uczestniczyć.&lt;/p&gt;  &lt;p&gt;Im dalej w las z praktykami, tym lżej się je znosi. Może dlatego, że jest coraz poważniejsza praca nad inżynierką i człowiekowi po jakimś czasie kończą się pomysły, a jak się kończą pomysły, to przychodzą inne dziwne rzeczy do głowy, a jak przychodzą inne dziwne rzeczy do głowy, to zwykle kończy się to dyskusjami o pokładełku &lt;a href="http://pl.wikipedia.org/wiki/Kiry%C5%9Bnik_czarnoplamy"&gt;Kiryśnika&lt;/a&gt; (swoją drogą polecam akwarystom, bardzo wdzięczne i sympatyczne rybki, szczególnie jak przez szybę zobaczą jadłopodawcę) czy eksplorowaniu Youtube. A problemów jest niestety sporo, gdyż – jak już wspominałem – wymyślamy pewien(ne) algorytm(y), który(e) ma(ją) yntelygnetnie rozpoznawać pewne wzorce. Sporo się przy tym nauczymy, ale też sporo pomarudzimy i się “podepresjonujemy”. Taki urok pracy.&lt;/p&gt;  &lt;p&gt;Najważniejszą zmianą związaną z inżynierią oprogramowania w tym tygodniu stały się codzienne stand-up meetings, czyli spotkania informacyjne na stojąco, które zaproponowałem wprowadzić, abyśmy mieli jeszcze lepszy przepływ informacji. Dwie osoby z naszej czwórki zajmują się jednym zagadnieniem, a dwie pozostałe – tym drugim. Jedna dwójka niewiele wie o postępach drugiej dwójki, zatem 5-minutowe rozmowy o tym, co zrobiliśmy i co zamierzamy robić powinny być przydatne, aby mieć ogólny obraz sytuacji (lub &lt;a href="http://en.wikipedia.org/wiki/Snapshot_algorithm"&gt;stanu globalnego&lt;/a&gt; – jak kto woli, co dla kogo mądrzej brzmi). Dzięki takim spotkaniom okazało się zresztą, że niektórzy szli ze swoim zagadnieniem w nieco innym kierunku – przy mniejszej integracji z resztą systemu – a problem pojawił się dosyć wcześnie, dzięki czemu można jeszcze raz przedyskutować założenia i pomyśleć nad rozwiązaniem. Oprócz tego pojawili się również nasi opiekunowie (pozdrawiamy) i spotkanie, na którym przedyskutowano pewne kwestie sporne. W przyszłym tygodniu też takie się odbędzie – tego typu obrady są o tyle potrzebne, że opiekunowie dysponują dużo większą wiedzą i rozeznaniem, zatem zawsze służą radą i nas nakierowują, jeśli zboczymy z trasy. Przy okazji jest też zawsze dużo humoru, a to zawsze się przyda – naprawdę lepiej się pracuje, jeżeli dobrze się wszyscy bawią.&lt;/p&gt;  &lt;p&gt;W najbliższym czasie czeka nas także zmierzenie się z innym problemem logistycznym – do naszego pokoju wprowadza się druga grupa “inżynierkowa”, w efekcie czego w pomieszczeniu zrobi się ciut ciaśniej i nieco więcej zamieszania, bowiem dojdzie kolejne biurko i komputery. Zobaczymy jak to będzie – prawdopodobnie będziemy się wymieniać składem w pokoju, bo przepływ informacji jednej grupy może przeszkadzać przepływowi drugiej, a rozmowy przez ciche komunikatory internetowe nie będą aż tak efektywne (za to będą skutecznie rozpraszać). &lt;/p&gt;  &lt;p&gt;Dzisiaj krótko, ale chciałem napisać w końcu coś luźniejszego. Troszkę nie czuję tych wakacji, ale chyba nie jestem w tym odosobniony. Za to niezmiernie usatysfakcjonowany, nawet, kiedy nie wychodzi.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-1838824034458397559?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/1838824034458397559/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=1838824034458397559' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1838824034458397559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1838824034458397559'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/07/folia-na-drzwiach-czyli-znowu-o.html' title='Folia na drzwiach, czyli znowu o inżynierii oprogramowania'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-4534431577553617991</id><published>2011-07-16T21:12:00.002+02:00</published><updated>2011-07-16T21:12:50.589+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Internet dla mas, czyli znowu o inżynierii oprogramowania</title><content type='html'>&lt;p&gt;Ponad tydzień temu podzieliłem się z Wami moimi pierwszymi wrażeniami z realizacji projektu w war-roomie, zatem wypadałoby pociągnąć ten wątek w choćby minimalnym stopniu. Zwłaszcza, że w końcu uzyskaliśmy dostęp do internetu, z czego jesteśmy bardzo, ale to bardzo zadowoleni. W końcu można wczytywać filmy z YouTube z niezłą prędkością. Za to na korytarzu rozpoczął się totalny remont, zatem podróż do i z pokoju przez jakiś czas wiązała się z przymusowym ubieleniem (bynajmniej nie w Perwollu ani Vizirze), wchodzeniu do sali i komentarzem “o kurdę, ale naniosłem”.&lt;/p&gt;  &lt;p&gt;W tym tygodniu praca zaczęła się na poważnie. Można to głównie poznać po coraz mniej czytelnych notatkach na tablicy - to oznaka, że nasze myśli są coraz bardziej pokręcone i zachowujemy się nienormalnie. Zaczęła się w końcu implementacja niektórych rozwiązań. Jest to o tyle fascynujące, że nasz projekt jest bardziej badawczy aniżeli zwykły projekt inżynierski (co nie znaczy, że tamte są złe), zatem siłą rzeczy niektóre rzeczy trzeba wymyślić. A potem kod wymaga dogłębnej refaktoryzacji, bo myśli wiją się w niesamowity sposób.&lt;/p&gt;  &lt;p&gt;Ale nie o tym chciałem pisać - jeśli trafi się jakiś ciekawy problem techniczno-myślowo-implementacyjny, który będzie neutralny (nie będzie za bardzo "odkrywał" projektu), to pewnie o tym napiszę, ale główną misją tych notek jest dyskusja o inżynierii oprogramowania w praktyce. &lt;/p&gt;  &lt;p&gt;Najpierw może przypomnę jak wygląda u nas struktura zespołu. Na samej górze jest promotor, który akurat nie bierze większego udziału w samych pracach (co nie oznacza, że nie jest nimi zainteresowany). Pod nim jest nasz główny opiekun (bezpośrednio zainteresowany projektem i jego rozwojem), którego wspiera inny opiekun, notabene koordynator poprzedniej wersji naszego systemu (ponieważ - niestety - rozbudowujemy coś, co zostało już w części napisane - pewnie o tym jeszcze pomarudzę). Kolejnym poziomem są nasi opiekunowie z IV roku, studenci specjalności Software Engineering, u których mnogość dokumentów, jakie muszą sporządzić, przekracza wszelkie oczekiwania wszelkich komisji i urzędników. Właśnie dlatego uważam, że proces powstawania gier komputerowych jest przyjemniejszy - o wiele mniej formalności, a jaka radość i zabawa. &lt;a href="http://pl.wikipedia.org/wiki/Przypadek_u%C5%BCycia"&gt;Przypadki użycia&lt;/a&gt; są dobre, ale uciążliwe w pisaniu, a w grach chodzi tylko o grywalność, fabułę i efekty (w tej kolejności). Ostatnim poziomem w strukturze jesteśmy my, programiści. Czasami odwiedzają nas właśnie opiekunowie - wtedy praca (i przeglądanie Internetu) schodzi na dalszy plan, a zaczyna się panel dyskusyjny o tym, co jest do zrobienia, jak to trzeba zrobić, po co i co to jest ten cholerny futbol amerykański, a także dlaczego tym jajem się tak ciężko rzuca. Przynajmniej jest weselej. Bo wiedzcie, że problemy są z grubsza interesujące w pierwszej fazie, czyli przy myśleniu nad nim, wstępnym projektowaniu. W samym projektowaniu oraz rozwiązywaniu problem staje się coraz mniej fascynujący, aż do pierwszych błędów typu "nie-wiadomo-dlaczego-to-nie-działa", kiedy człowiekowi nic się nie chce, bo nie wie co się dzieje (a Youtube kusi). Gdy w końcu uda się wyjść z takiego bagienka po mniejszych czy większych trudach, następuje znaczny wzrost fascynacji problemem, gdyż w końcu został rozwiązany (wtedy można też się chwalić wszem i wobec co się udało zrealizować). Można powiedzieć, iż jest to &lt;a href="http://pl.wikipedia.org/w/index.php?title=Plik:Normal_Distribution_PDF.svg&amp;amp;filetimestamp=20090922171939%20"&gt;rozkład Gaussa&lt;/a&gt;, ale odwrócony do góry nogami. &lt;/p&gt;  &lt;p&gt;Jak już wspomniałem, pracujemy na poprzedniej wersji systemu. Problemów z tym jest parę: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Trzeba zwyczajnie "wbić" się w kod poprzedników, zobaczyć gdzie co jest &lt;/li&gt;    &lt;li&gt;Trzeba poznać technologię i biblioteki, jakich użyli &lt;/li&gt;    &lt;li&gt;Jest się trochę "zarażonym" architekturą poprzedniej wersji, nawet tymi niedobrymi elementami &lt;/li&gt;    &lt;li&gt;W naszym przypadku był problem, gdyż jedna biblioteka była przestarzała i już nie była w użyciu, a nowa nie była z nią zbytnio kompatybilna &lt;/li&gt;    &lt;li&gt;Był sam problem z importem do nowszej wersji IDE &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Na szczęście, okazało się, że nie trzeba wykorzystywać całego kodu poprzedników, a jedynie poprzerabiać, w ostateczności napisać wszystko od nowa. Innym problemem jest technologia Web Services, z którą dotychczas nie mieliśmy do czynienia, a tutaj (i nie tylko tutaj) jest w szerokim użyciu. Na szczęście nie okazuje się to tak strasznie trudne, jak się wydaje, a zawsze lepiej wiedzieć coś więcej.&lt;/p&gt;  &lt;p&gt;Niestety, jak dotąd nasza praca z metodologią XP nie ma zbyt wiele wspólnego, ale w gruncie rzeczy nie uważam, aby było to złe – na tym etapie projektu. Poniżej parę moich uwag odnośnie pracy w pierwszym i drugim tygodniu praktyk:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Nie programujemy w parach, preferujemy podejście side-by-side, czyli “programowanie obok siebie”. Nie ma co prawda kontroli pisanego kodu, jednak w obecnym stadium, kiedy trzeba poznać wiele technicznych rzeczy (założyć i skonfigurować bazę danych, wczytać się w dokumentacje używanych bibliotek) nie miałoby to po prostu sensu. Side-by-side przyspiesza za to pracę w znacznym stopniu, gdyż każdy ma do dyspozycji swój komputer i zajmuje się konkretną częścią projektu. &lt;/li&gt;    &lt;li&gt;W naszym czteroosobowym zespole jesteśmy akurat tak podzieleni, że dwie osoby zajmują się jednym głównym “ficzerem” projektu, a dwie pozostałe – drugim głównym “ficzerem”. Ponieważ jedna i druga para siedzi koło siebie, przepływ informacji jest bardzo dobry, gdyż dwie osoby pracujące nad tym samym (w ogólności, gdyż najczęściej każda robi coś innego (np. pierwszy pisze, drugi ogląda Youtube, a potem pierwszy ogląda filmiki, a ten drugi pokazuje mu które)) mają bezpośredni wgląd w swoje monitory.&lt;/li&gt;    &lt;li&gt;Co prawda nie mamy obowiązku składania scrumowych raportów z poszczególnych dni/tygodni, jednak uznaliśmy, że jest to dobra metoda dokumentowania postępów i ewentualnie wymuszenie na nas korekt, jeśli nie idziemy “tą” drogą. Poza tym, pisząc o tym, co robiliśmy, co nas blokuje i co zamierzamy robić, niejako porządkujemy własną pracę, widzimy, jak daleko już zaszliśmy i czy nie trzeba czasem wzmóc tempa. &lt;/li&gt;    &lt;li&gt;Nie ma u nas stand-up meetings, czyli codziennych kilku- lub kilkunastominutowych rozmów na stojąco o tym, co nas czeka lub co już zrobiliśmy. To znaczy tego typu rozmowy się odbywają, ale nie są regularne, a jedynie pojawiają się wtedy, kiedy zachodzi taka konieczność. Przy ważniejszych problemach dana osoba mająca problem lub po prostu wątpliwość wstaje, podchodzi do tablicy, po czym zaczyna się przy niej dyskusja, do której dołączają zainteresowane osoby. Zaletą tego jest to, że choć drobna część dyskusji dotrze do ucha osób mniej zainteresowanych, a dodatkowe bodźce w postaci rysunków na tablicy czy chociażby podrzucania piłeczki wzmagają proces myślenia, kojarzenia i zapamiętywania. &lt;/li&gt;    &lt;li&gt;Właśnie – piłeczka. Niby drobna rzecz, ale bardzo potrzebna, co zresztą widać również przy burzy mózgów pod kierunkiem doktora Chałupy w znanym serialu. Kontakt z odbijającym się kulistym obiektem pożądania, podrzucanie go, ściskanie, odbijanie wpływa pozytywnie na człowieka. W dodatku można się na niej wyżyć, pogryźć ją, rzucić o ścianę i zrobić multum innych rzeczy. Wierzcie mi – taka piłeczka to skarb. Ile razy podczas rozmyślań nad kolejnymi etapami algorytmu zacząłem biegać po pokoju kopiąc piłkę przed sobą, odbijając ją od szafy, sufitu, ściany, aż w końcu wpadał mi pomysł, który mogłem zapisać i ruszyć dalej. Ogólnie przerwy w pracy są bardzo potrzebne, ale trzeba uważać, aby nie zajęły nas w pełni.&lt;/li&gt;    &lt;li&gt;Wspomniałem o wymyślaniu algorytmu i o tym, że trudno wejść w kod poprzedników, zwłaszcza, jak się nie zna technologii. Integracja nowych pomysłów ze starym kodem jest o tyle utrudniona, iż nie mieliśmy chociażby dostępu do bazy danych, która była niezbędna. Dlatego nie bójcie się pisać osobnych aplikacji, w których będziecie testować Wasze nowe rozwiązania i dostrajać je tak, aby skopiowanie kodu do właściwego projektu i ewentualne drobne przeróbki nie były zbyt bolesne. W tym czasie, kiedy pisany jest nowy kod przez jedną osobę, druga przygotowuje stare źródła do współdziałania z nowoutworzoną bazą danych – tak przynajmniej u nas to wygląda i na razie się sprawdza. Na razie, bo jeszcze nie integrowaliśmy naszych prac. Dlatego pewnie następne notki będą cenzurowane.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak widzicie, znowu o niczym konkretnym nie napisałem, aczkolwiek mam nadzieję, że rzucam coraz więcej światła na praktyki znane z inżynierii oprogramowania… w praktyce właśnie. Oby dalej nie było gorzej niż jest. I obym miał siłę pisać kolejne notki.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-4534431577553617991?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/4534431577553617991/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=4534431577553617991' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/4534431577553617991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/4534431577553617991'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/07/internet-dla-mas-czyli-znowu-o.html' title='Internet dla mas, czyli znowu o inżynierii oprogramowania'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5812538751357580547</id><published>2011-07-06T22:05:00.002+02:00</published><updated>2011-07-06T22:06:48.067+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Wrażenia z praktyk, czyli znowu o inżynierii oprogramowania – w war-roomie</title><content type='html'>&lt;p&gt;Ostatni wpis dodałem dość dawno temu i nie był o grach ani grafice komputerowej. Ten dodaję teraz, pewnie znowu okupiony długą przerwą o nim i znowu nie będzie ani o grach ani o grafice komputerowej. W życiu każdego studenta informatyki na Politechnice przychodzi czas, kiedy trzeba realizować pracę inżynierską. Znajdzie się również miejsce na wepchnięcie konieczności odbycia praktyk w jakiejś firmie bądź uczelni. I naprawdę zacną rzeczą jest połączyć te dwie rzeczy w jedną – nie dość, że praktyki spędza się na uczelni (-"Wiesz, pracuję na uczelni”, –“Oj, jakiś ty mądry…”), wśród znajomych twarzy, to jeszcze można umysłowo popracować nad czymś, co i tak trzeba by było robić w semestrze.&lt;/p&gt;  &lt;p&gt;Ostatnio pisałem już o programie SDS (Software Development Studio), które działa pod patronatem &lt;a href="http://www.se.cs.put.poznan.pl/"&gt;zespołu Software Engineering&lt;/a&gt; w &lt;a href="http://www.cs.put.poznan.pl/"&gt;Instytucie Informatyki&lt;/a&gt; na &lt;a href="http://www.fc.put.poznan.pl/"&gt;Wydziale Informatyki&lt;/a&gt; &lt;a href="http://www.put.poznan.pl/"&gt;Politechniki Poznańskiej&lt;/a&gt; (to już koniec litanii) i w którym chodzi o to, że studenci IV roku (specjalności magisterskiej SE) uczą się zarządzać zespołem niesfornych programistów, a studenci III roku (przyszli inżynierowie – my) uczą się być zarządzanym, jeszcze bardziej niesfornym, a przy okazji trochę się pośmiać i spróbować stworzyć jakiś ciekawy system, który może nawet będzie działał. Sęk w tym, że SDS często umożliwia studentom skorzystanie z jednego z pokojów uczelnianych, dzięki czemu możemy pracować wspólnie w tak zwanym war-roomie, a co za tym idzie – poznać smak prawdziwej pracy. &lt;/p&gt;  &lt;p&gt;W związku z powyższym naszło mnie, aby podsumować pierwsze parę dni wspólnej egzystencji i (nie)pracy nad projektem, a także zawrzeć parę swoich uwag, które być może pomogą paru osób w tego typu sytuacjach lub dadzą do myślenia. Dlaczego piszę o (nie)pracy? To się wyjaśni. Choć większość z poniższych uwag to banały, znane każdemu z autopsji, bądź nietrudne do wyobrażenia sobie.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Dostaliśmy komputery, działają, wszystko jest dobrze, za wyjątkiem jednej rzeczy, niestety niezbędnej, gdy nie ma się pojęcia o technologiach, a ponadto co chwilę trzeba ściągać biblioteki – nie ma dostępu do Internetu. Przynajmniej przez jakiś czas. W związku z tym, pomijając nasze laptopy z własnym, mobilnym, dostępem do neta (własnym, gdyż dla sieci uczelnianej również nie ma zasięgu w pokoju), nie mamy za bardzo możliwości przerabiania tutoriali i porad, które są zwykle w sieci. Dobrze, że zostaje nam praca umysłowa nad rozbudową schematu bazy danych czy algorytmami – zawsze jest spokój sumienia, że coś robimy. I satysfakcja.&lt;/li&gt;    &lt;li&gt;Tablica z pisakami i gąbką to bardzo dobra rzecz. Nie dość, że można na niej wyżyć się artystycznie, rozpisać różne przypadki algorytmiczne. Tablica zespala też zespół – wszyscy się przy niej produkują, wychodzi z tego istotny wkład i poczucie, że jesteśmy zespołem. &lt;/li&gt;    &lt;li&gt;Wróćmy do koncepcji “jesteśmy zespołem”. Jest to dużo ważniejsze niż nawet czterech najlepszych specjalistów z danych dziedzin współpracujących razem, ale nieczujących ze sobą chemii. Wolę wspólną walkę z problemami, wspieranie się, miłą atmosferę, aniżeli szybkie posuwanie się do przodu, ale w dość chłodnym lub neutralnym nastroju. Poczucie zespołowości sprawia, iż przyjemniej siedzi się w pokoju parę godzin dziennie. Nawet krótkie podjechanie z krzesłem do kolegi obok i zapytanie się “co tam robisz ciekawego?” jest potrzebne. &lt;/li&gt;    &lt;li&gt;Energia. Jestem wielkim miłośnikiem teorii o tym, że energia (w różnej postaci) powoduje, iż można zrobić wiele (jeśli nie wszystko), a ona sama pozwala lepiej się czuć. Kto ogląda &lt;a href="http://www.zaklinaczpsow.pl/"&gt;Zaklinacza Psów&lt;/a&gt;, ten również często słyszy tam słowo “energia”, dzięki której można lepiej zrozumieć psy. W sporcie przed meczami odbywają się &lt;a href="ttp://www.youtube.com/watch?v=y0Hv7Tc1VoE"&gt;rytuały&lt;/a&gt; mające zmotywować graczy, podnieść poziom adrenaliny, a przez to nakłonić do lepszej gry i podtrzymania ducha zespołowości. Także w informatyce lepiej tworzy się projekt wiedząc, iż zespół stoi za nami murem, coś nam wychodzi (choćby mała rzecz), a może wyjść jeszcze więcej. Wtedy przebija się pozytywna energia. Tak samo działają wspólne żarty i rozmowy. Wystarczy, że ktoś zacznie rzucać piłką o ścianę, a już skacze adrenalina i rośnie energia. Zwłaszcza u osoby, która stoi na linii rzutu.&lt;/li&gt;    &lt;li&gt;Nie wolno zapominać o herbacie oraz gorących posiłkach. Na samych kanapkach trudno przeżyć parę godzin, podobnie jak na wodzie mineralnej. Choćby niezdrowa zupka z paczki sprawia, iż jesteśmy mniej senni. Podobnie jak przerwy spędzone na wyszukiwaniu ciekawych filmów na Youtube. A także oczywiście o partyjkach Magic: the Gathering.&lt;/li&gt;    &lt;li&gt;Wyżej rzeczona tablica może (a nawet powinna) stać się również tak zwanym radiatorem informacji, czyli miejscem, gdzie zapisywane byłyby postępy prac w danej iteracji lub uwagi, które wyniknęły w realizacji postawionych zadań. Nawet systemy śledzenia bugów nie wpływają aż tak motywująco jak widok kolejno odkreślonych zadań na tablicy. One mogą jedynie ułatwić pamiętanie o tym, co należy załatać, ale chwilowo nie ma na to czasu/możliwości/pomysłu.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cóż, jak już wspomniałem, dla większości są to banały, ale mam nadzieję, że co jakiś czas będzie mi się udawać przemycić tutaj nieco swoich spostrzeżeń i porad, a być może nawet rozwiązań, które wyjdą same w trakcie powstawania projektu. Własny pokój jest o tyle świetnym rozwiązaniem, że ma się spokój, własne komputery i można się w pełni skupić na pracy. Zdaję sobie sprawę, że nie wszyscy mają niestety takie możliwości, ale nie należy się tym przejmować – nawet na odległość sporo z powyższych uwag można zastosować w praktyce.&lt;/p&gt;  &lt;p&gt;Pozdrawiam, dziękuję i do napisania – SceNtriC&lt;/p&gt;  &lt;p&gt;Ps. Mam nadzieję, że nie odrzuciliście devbloga z RSS-ów tylko dlatego, iż dawno nie był aktualizowany. Przepraszam za brak konsekwencji, ale niestety – nie zawsze znajduję ciekawe tematy, aby pisać. A tych ciekawych tematów brak, bo uczelnia niestety narzuca swoje tempo.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5812538751357580547?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5812538751357580547/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5812538751357580547' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5812538751357580547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5812538751357580547'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/07/wrazenia-z-praktyk-czyli-znowu-o.html' title='Wrażenia z praktyk, czyli znowu o inżynierii oprogramowania – w war-roomie'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-973164923206790821</id><published>2011-04-24T22:07:00.002+02:00</published><updated>2011-04-24T22:07:47.034+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>A teraz coś o stringach</title><content type='html'>&lt;p&gt;Jak widać, moja teoretyczna regularność nie ma nic wspólnego z faktycznym stanem rzeczy i odstępy między notkami przypominają bardziej blogi bardziej znanych osób, które piszą coś dłuższego i mądrego raz na jakiś czas. Różnica jest zasadnicza – moje teksty nie są ani długie ani mądre, ale można powiedzieć, że jeden punkt już spełniłem.&lt;/p&gt;  &lt;p&gt;Za silnik, a tym samym trawę, zasadniczo się nie brałem – zbyt wiele atrakcji działo się na początku semestru i dzieje się teraz, nie tylko związanych z informatyką. Chociażby udało się przywrócić niektórym wspomnienia o grze Magic: the Gathering i co jakiś organizować “magicowe okienka” na uczelni, aby towarzysko sobie pograć. Tym niemniej największym wydarzeniem były wybory prac inżynierskich, w efekcie czego pod koniec marca następowały istne cuda w dobieraniu się zespołów (“Masz już zespół? Masz? NIE MASZ?! To chodź do nas, chodź, chodź, no choooooodź… Aha, temat Cię nie interesuje…”) czy atakowaniu promotorów/opiekunów/kogokolwiek w celu zdobycia interesującego tematu czy też zdobycia czegokolwiek z puli “jeszcze te mogę robić”. &lt;/p&gt;  &lt;p&gt;Była też pewna pula tematów tworzonych w ramach Software Development Studio (SDS). SDS to idea, w której następuje pewna współpraca pomiędzy studentami różnych lat w celu zdobycia dodatkowych umiejętności. Mówiąc mniej enigmatycznie – dwaj studenci IV roku ze specjalności magisterskiej Software Engineering (specjalność inżynierii oprogramowania na Politechnice Poznańskiej jest w języku angielskim)  mają za zadanie opiekować się i wspomóc wytwarzanie jednego z wybranych tematów inżynierskich, które z kolei są realizowane przez czterech studentów III roku (to my). Jeżeli doliczymy do tego promotora i dwóch opiekunów z dziekanatu, wychodzi na to, że jest aż 9 osób (tzw. Drużyna Pierścienia). Każdy na tym zyskuje – pracownicy uczelni ciekawy (mam nadzieję) projekt, który można gdzieś dalej pokazać (zwykle projekty w ramach SDS są ważne dla uczelni, wydziału czy instytutu), studenci IV roku doświadczenie w zarządzaniu projektem i grupką czasami energicznie reagujących osób, a my – tytuł inżyniera. Oczywiście, nie wszystkie projekty są takie, ale 7 grup akurat realizuje swoje inżynierki w ramach SDS. Fajna sprawa, gdyż można się sprawdzić w takim grupowym projekcie. No i sam temat też jest bardzo interesujący, choć na razie nie będę o nim mówił, gdyż nie wiem, czy mogę. &lt;/p&gt;  &lt;p&gt;Po co ten wstęp? Po prostu chciałem się pochwalić. Przy okazji pozdrawiam wszystkie osoby zaangażowane w projekt i mam nadzieję, że będzie nam się dobrze pracowało.&lt;/p&gt;  &lt;p&gt;W niniejszej notce chciałem co nieco powiedzieć o sposobach porównywania łańcuchów (czyli właśnie rzeczonych stringów z tytułu – być może ktoś wszedł z myślą o innych stringach, w sumie też bym tak zrobił). Ostatnio myślałem nad myśleniem o myśleniu o możliwości logicznego porównywania łańcuchów. Kontekst zadania jest taki – mamy dwa tytuły książek czy artykułów i chcemy zobaczyć na ile są sobie bliskie tematycznie. Pewnie wielu z Was słusznie powie tutaj “hej, ale tego nie można sprawdzić samymi łańcuchami”. Owszem, najlepiej by było, jakby uruchomiło się tutaj wiedzę dziedzinową chociażby w rodzaju słów kluczowych. Nie mówię – być może będzie to także wykorzystane, jednak wymagałoby dodatkowych mechanizmów, o których nie wiadomo, czy by się opłaciły. &lt;/p&gt;  &lt;p&gt;Tym niemniej pozostańmy przy samych łańcuchach, gdyż z nich też można dużo wyciągnąć. Dlaczego? Weźmy chociażby tytuły publikacji o inżynierii oprogramowania. A konkretnie dwa przykłady publikacji pana profesora Jerzego Nawrockiego (pozdrawiam).&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.19.1689&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;&lt;em&gt;Experimental evaluation of pair programming&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.springerlink.com/content/y0448145h3212443/"&gt;&lt;em&gt;Pair programming vs. side-by-side programming&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Patrząc na tytuły można już wysnuć całkiem sporo wniosków. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Oba dotyczą programowania, a zatem – teoretycznie – informatyki &lt;/li&gt;    &lt;li&gt;W obu mamy do czynienia w pracą w parach, co w powiązaniu z programowaniem może znaczyć “programowanie w parach” &lt;/li&gt;    &lt;li&gt;Być może oba teksty dotyczą inżynierii oprogramowania &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Wszystkie wnioski uczyniliśmy tylko i wyłącznie na podstawie tytułów, a zatem łańcuchów (ciągów znaków, rzeczonych stringów). Pora sprawdzić to doświadczalnie.&lt;/p&gt;  &lt;p&gt;Przez ostatnie dwa dni miałem chęci (przede wszystkim chęci – jak sobie coś ubzduram, bo mnie ekscytuje, to nie ma siły, abym przestał o tym myśleć), aby stworzyć jakiś prosty algorytm porównujący dwa ciągi pod względem podobieństwa. Oczywistym podejściem, na które równie oczywiste jest to, iż na nie nie wpadłem, jest liczenie tzw. odległości, która mówi o tym ile potrzeba operacji, aby jeden ciąg zamienić w drugi. Jednak zapominanie o tak prostych sprawach ma również dobre strony – będzie więcej algorytmów na tym świecie. A przynajmniej na tym blogu. Algorytmów? Owszem – bowiem wpadłem na dwa sposoby mierzenia łańcuchów.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Algorytm porównywania łańcuchów&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Operacja porównania ciągów (w obu ignorujemy białe znaki) polega na kolejnym wyszukiwaniu coraz większych podciągów ciągu pierwszego, a następnie szukaniu ich w ciągu drugim. W drugim etapie zamienia się łańcuchy ze sobą i ponownie przeszukuje w poszukiwaniu podciągów. Wynikiem każdego jest procent (a konkretnie wartość z przedziału [0, 1]) trafionych poszukiwań w stosunku do wszystkich, a wynik łączny to średnia z tych dwóch pomiarów.&lt;/p&gt;  &lt;p&gt;Powyższy opis wygląda dosyć mętnie, ale udokumentowałem go przykładem, na który składają się słowa “hala” oraz “hola”.&lt;/p&gt;  &lt;table border="0" cellpadding="2" cellspacing="0" width="406"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="404"&gt;         &lt;table border="1" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;             &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;&lt;b&gt;Łańcuch pierwszy (który dzielimy na podciągi i porównujemy z drugim)&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;&lt;b&gt;Długość podciągu&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;&lt;b&gt;Rozpatrywany podciąg&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;&lt;b&gt;Wynik (czy dany podciąg występuje w ciągu drugim)&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;h&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;l&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;ha&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;al&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;la&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;3&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;hal&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;3&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;ala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;4&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;hala&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt; &lt;/td&gt;                &lt;td width="84"&gt; &lt;/td&gt;                &lt;td width="124"&gt; &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;Trafione: 5/10 = 0,5&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt; &lt;/td&gt;                &lt;td width="84"&gt; &lt;/td&gt;                &lt;td width="124"&gt; &lt;/td&gt;                &lt;td width="96"&gt; &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;h&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;o&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;l&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;1&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;ho&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;ol&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;2&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;la&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;3&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;hol&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;3&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;ola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="84"&gt;                 &lt;p&gt;4&lt;/p&gt;               &lt;/td&gt;                &lt;td width="124"&gt;                 &lt;p&gt;hola&lt;/p&gt;               &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="85"&gt; &lt;/td&gt;                &lt;td width="84"&gt; &lt;/td&gt;                &lt;td width="124"&gt; &lt;/td&gt;                &lt;td width="96"&gt;                 &lt;p&gt;Trafione: 4/10 = 0,4&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;           &lt;/tbody&gt;&lt;/table&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Wynik końcowy: (0,5 + 0,4) / 2 = 0,45&lt;/p&gt;  &lt;p&gt;Jak widać, według tej miary podobieństwo między tymi dwoma wyrazami wynosi 45%, co nie jest zbyt fascynującym wynikiem. Zwłaszcza, że optycznie słowa “hala” i “hola” są do siebie bardzo podobne i choć mają inne znaczenie, to różnica jednej literki może wskazywać na to, że nastąpiła tutaj zwyczajna literówka. Jest tutaj zatem wiele możliwości poprawy – warto na przykład zauważyć, że jeżeli przykładowe słowa byłyby dłuższe i różniłyby się paroma literami, końcowy wynik byłby bliższy jedynce (gdzie 1 oznacza równość ciągów). Troszkę gorzej wygląda to w momencie, kiedy staramy porównać się dwa tytuły (autorstwa innego pana profesora Jerzego Nawrockiego) ze sobą:&lt;/p&gt;  &lt;p&gt;1. &lt;a href="http://www.sciencedirect.com/science?_ob=ArticleURL&amp;amp;_udi=B6V61-3SWR6HN-F&amp;amp;_user=10&amp;amp;_coverDate=11%2F30%2F1997&amp;amp;_rdoc=1&amp;amp;_fmt=high&amp;amp;_orig=gateway&amp;amp;_origin=gateway&amp;amp;_sort=d&amp;amp;_docanchor=&amp;amp;view=c&amp;amp;_searchStrId=1729123448&amp;amp;_rerunOrigin=scholar.google&amp;amp;_acct=C000050221&amp;amp;_version=1&amp;amp;_urlVersion=0&amp;amp;_userid=10&amp;amp;md5=2f77a60d456897368e6964ef481bccdb&amp;amp;searchtype=a"&gt;&lt;em&gt;Permian to Early Triassic magnetostratigraphy from the Central European Basin in Poland: Implications on regional and worldwide correlations&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;2. &lt;a href="http://www.sciencedirect.com/science?_ob=ArticleURL&amp;amp;_udi=B6V61-418PP8V-6&amp;amp;_user=10&amp;amp;_coverDate=10%2F15%2F2000&amp;amp;_rdoc=1&amp;amp;_fmt=high&amp;amp;_orig=gateway&amp;amp;_origin=gateway&amp;amp;_sort=d&amp;amp;_docanchor=&amp;amp;view=c&amp;amp;_searchStrId=1729124491&amp;amp;_rerunOrigin=scholar.google&amp;amp;_acct=C000050221&amp;amp;_version=1&amp;amp;_urlVersion=0&amp;amp;_userid=10&amp;amp;md5=2bd1e981b6355714dd289bd03ceb208c&amp;amp;searchtype=a"&gt;&lt;em&gt;The Middle Triassic magnetostratigraphy from the Peri-Tethys basin in Poland&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Jak widać, w dość długich tytułach mamy wspólne słowa (magnetostratigraphy czy Poland), aczkolwiek widać, iż zdania są dosyć różne. Rzeczywiście, algorytm podaje wynik porównania 0,203932 – cóż, mogłoby być gorzej. Jeżeli weźmiemy z kolei jeden z poprzednio podawanych tytułów z inżynierii oprogramowania i  jeden z tych medycznych, to ich wynik będzie oscylował wokół 0,05-0,1. Tym niemniej, jeśli chcielibyśmy zaklasyfikować publikacje 1. i 2., to byłoby to trudne na podstawie wyniku 0,2. Cóż, trzeba będzie popracować.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Algorytm mapowania znaków&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Operacja mapowania znaków polega na szukaniu kolejnych znaków z jednego ciągu w drugim, a następnie usuwaniu tego znaku w obu łańcuchach. Wynikiem jest jeden minus stosunek liter pozostałych (niedopasowanych) do długości jednego ciągu. Jeśli łańcuchy mają różną długość, krótszy jest dopełniany białymi znakami.&lt;/p&gt;  &lt;p&gt;Tutaj także mamy przykład – zbadamy mapowanie słów “anarchia” i “arena”. Jak widać, ten drugi wyraz należy dopełnić trzema białymi znakami, aby oba ciągi miały równą długość.&lt;/p&gt;  &lt;table border="0" cellpadding="2" cellspacing="0" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="400"&gt;         &lt;table border="1" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;             &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;&lt;b&gt;Łańcuch pierwszy&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;&lt;b&gt;Łańcuch drugi&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;&lt;b&gt;Rozpatrywany znak&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;&lt;b&gt;Wynik (czy rozpatrywany znak występuje w łańcuchu drugim)&lt;/b&gt;&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;anarchia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;arena&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;narchia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;rena&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;n&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;archia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;rea&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;rchia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;re&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;r&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;TAK&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;chia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;e&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;c&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;chia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;e&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;h&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;chia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;e&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;i&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;              &lt;tr&gt;               &lt;td width="154"&gt;                 &lt;p&gt;chia&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;e&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;a&lt;/p&gt;               &lt;/td&gt;                &lt;td width="154"&gt;                 &lt;p&gt;NIE&lt;/p&gt;               &lt;/td&gt;             &lt;/tr&gt;           &lt;/tbody&gt;&lt;/table&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Wynik końcowy: 1 – (4 / 8) = 1 - 0,5 = 0,5&lt;/p&gt;  &lt;p&gt;Idea polega na tym, aby zobaczyć, ile liter (formalnie znaków) nie zostanie dopasowanych między dwoma łańcuchami (wliczając w to także spacje). Jak widać, tutaj są to: c, h, i oraz trzecie a, gdyż te litery nie występują w słowie “arena”. &lt;/p&gt;  &lt;p&gt;To badanie wydaje mi się rozsądniejsze od poprzedniego, choćby dlatego, że podczas testów wyszły nieco “mądrzejsze” wyniki. Choćby dla publikacji medycznych podanych wcześniej wynik tego algorytmu to 0,55 – na tej podstawie istotnie można wnioskować, że oba teksty zostały napisane dla potrzeb jednej dziedziny nauki. Ten algorytm wymaga jeszcze więcej testów, ale wyniki są obiecujące – jest on także znacznie krótszy i mniej skomplikowany niż poprzedni algorytm. &lt;/p&gt;  &lt;p&gt;Tym niemniej myślę, że stosując obie techniki można przygotować prosty klasyfikator dla tytułów czy nazwisk autorów.&lt;/p&gt;  &lt;p&gt;Oczywiście, jak to ja, nie pomyślałem o tym, aby wcześniej sprawdzić w Internecie, czy ktoś nie wymyślił czegoś lepszego. Owszem, iż wymyślił, przygotował całą bibliotekę, oparł na wcześniej wspomnianej odległości i całej teorii przestrzeni metrycznych. I wyszło to dużo lepiej – istnieje biblioteka &lt;a href="http://alias-i.com/lingpipe/index.html"&gt;LingPipe&lt;/a&gt;, a konkretny tutorial znajduje się &lt;a href="http://alias-i.com/lingpipe/demos/tutorial/stringCompare/read-me.html"&gt;tutaj&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Jeżeli macie jakieś uwagi, komentarze, rady czy własne pomysły – jak najbardziej zapraszam do pisania pod notką.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-973164923206790821?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/973164923206790821/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=973164923206790821' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/973164923206790821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/973164923206790821'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/04/teraz-cos-o-stringach.html' title='A teraz coś o stringach'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-203426465236853668</id><published>2011-03-08T11:53:00.002+01:00</published><updated>2011-03-08T11:53:35.155+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Projektowanie'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>Praca silnikowa delikatnie wre</title><content type='html'>&lt;p&gt;W końcu! Przepraszam, że tak długo trzeba było czekać na nową notkę. Wbrew pozorom, nie zapomniałem o tym miejscu w sieci – po prostu poprzedni semestr na uczelni był niesamowicie intensywny (chyba najtrudniejszy ze wszystkich, jakie dotąd miały miejsce), ale szczęśliwie udało mi się na nim skupić i mieć wszystko za sobą. Co prawda, to półrocze też na łatwe się nie zapowiada, ale istnieje szansa, że będę miał więcej ciekawych materiałów, o których mógłbym parę rzeczy napisać. Nie chcę już obiecywać (sami (nie) widzieliście co się działo), ale nie chcę, abyście myśleli, że zostawiam blogowanie. Także proszę mnie nie usuwać z czytników kanałów RSS czy innych zakładek.&lt;/p&gt;  &lt;p&gt;Przy okazji – nadal trwają prace nad tłumaczeniem Wielkiego Mistrza na angielski. Idzie to powoli, ale co jakiś czas ktoś coś przetłumaczy, a inni się cieszą. Przypomnę może linka:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wielkimistrz.wikispaces.com/"&gt;Tutaj można tłumaczyć Wielkiego Mistrza&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I jeszcze raz zapraszam do dzielenia się z nami swoim czasem i umiejętnościami językowymi. Być może dzięki Wam Wielki Mistrz zostanie zauważony poza granicami naszego kraju.&lt;/p&gt;  &lt;p&gt;Z innych ciekawostek – jak stosunkowo niedawno się dowiedziałem, na naszej uczelni działa nieformalne koło naukowe dotyczące gier komputerowych. Miejmy nadzieję, że wkrótce ruszą spotkania i zostanie dokończona procedura formalizacji organizacji. Jeżeli będę mógł Wam przekazać więcej informacji, z chęcią to zrobię w osobnej notce. Profil naszego koła (to znaczy tak – zacząłem chodzić na spotkania stosunkowo później, z powodu uprzedniej niewiedzy o istnieniu tej inicjatywy), jak nietrudno się domyślić, obejmuje wszystko, co jest związane z grami komputerowymi. Także nie jest to tylko grafika komputerowa, ale także fizyka, sztuczna inteligencja, komunikacja sieciowa, ale także takie sprawy jak organizacja pracy zespołu developerskiego, architektury gry (i generalnie większość rzeczy, które można podpiąć pod inżynierię oprogramowania), a myślę, że czasami będziemy też zahaczać o promocję czy ogólnie sprawy nieinformatyczne. Przynajmniej tak to sobie wyobrażam – koło dopiero się rozkręca. Warto też nadmienić, że jeśli ktoś po prostu chce zaprezentować swój powstający (lub też ukończony) projekt, to także jest mile widziany. Jak mówię jednak – więcej informacji postaram się dostarczyć wkrótce. No, może trochę później.&lt;/p&gt;  &lt;p&gt;To, na czym chciałbym się skupić w tej notce (aczkolwiek nie będę się też jakoś długo skupiał, bo jeszcze jest to w fazie abstrakcji [a przynajmniej proporcje tego fragmentu nie będą znacznie większe od poprzedniego (znowu zakopuję się z nawiasami)]), to projekt, który troszkę już został zapomniany, także przeze mnie. Jednak cały czas istnieje i od czasu do czasu myślę, co w nim zrobić. Niestety, z powodu natłoku zajęć na uczelni przez ostatnie pół roku praktycznie nic się w nim nie działo, ale ponieważ przez parę pierwszych tygodni tego półrocza nie mam wielu rzeczy do roboty, toteż (poważnie się to pisze razem?) mogę sobie pofantazjować naukowo. O czym mówię? O silniku graficznym Scav.&lt;/p&gt;  &lt;p&gt;Te osoby, które mnie znają, wiedzą, że z elementów graficznych interesują mnie (choć niestety czasami tylko koncepcyjne) obiekty naturalne sceny. Mówiąc bardziej po ludzku – wszelkiego rodzaju rendering trawy, wody, nieba, drzewek, trolli. Nie mam na tym polu dużych dokonań, gdyż nie jestem na tyle zaawansowany i umotywowany, aby wszystkiego próbować, ale swego czasu poczyniłem pewne kroki w wyświetlaniu trawy. &lt;a href="http://www.warsztat.gd/articles.php?x=view&amp;amp;id=298"&gt;Pamiętacie&lt;/a&gt;? Na devblogu artykuł &lt;a href="http://pseudodev.blogspot.com/2009/01/proste-generowanie-trawy.html"&gt;też oczywiście się pojawił&lt;/a&gt; (właściwie to najpierw się tutaj pojawił) i został w nim opisany sposób generacji, wyświetlania i animacji trawy, który został z kolei oparty na przeróżnych źródłach dostępnych w Internecie, które zostały tam wymienione (w tym zwłaszcza na &lt;a href="http://www.asawicki.info/productions/gry/the_final_quest.php5"&gt;silniku Regedita&lt;/a&gt; (pozdrawiam)). Co prawda, moja trawa wygląda bardziej jak pole marchewek, ale jakoś to jednak działało i niektórym się nawet podobało. Ponieważ właśnie elementy trawiaste jakoś najbardziej mnie intrygują, postanowiłem kontynuować implementację silnika Scav właśnie w tym kierunku. Co prawda, pominąłem wiele innych bardziej potrzebnych rzeczy (na przykład to, aby aplikacje w Scavie  jakoś w ogóle rozsądnie działały), ale wolę pisać coś, co mi się podoba, gdyż jest wtedy nieco większa szansa na ukończenie tej partii kodu. A przy okazji można sobie dywagować o tym na blogu czy właśnie kole naukowym.&lt;/p&gt;  &lt;p&gt;Poprzednie podejście opierało się na tym, iż każda kępka była reprezentowana za pomocą trzech skrzyżowanych czworokątów, które zostały obłożone teksturą z kanałem alfa i tak przygotowane kępki kołysały się na wietrze przy dźwiękach rock and rolla wygrywanych przez shadera. Jak to wyglądało, możecie tam ujrzeć na screenach, ale chciałbym się skupić na tym, co było złe w tym podejściu. Pomijając fakt, iż sama koncepcja była w miarę prosta w implementacji, to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;wyglądało to brzydko i nierealistyczne – jak już mówiłem, kojarzy mi się z polem marchewek (i to takich niesmacznych)&lt;/li&gt;    &lt;li&gt;shader obsługiwał tylko animację, ale już nie oświetlenie i współgranie z resztą terenu, choć to akurat była po części wina samej (de)konstrukcji frameworka Yesta&lt;/li&gt;    &lt;li&gt;teren wyglądał bardzo regularnie i były zbyt duże odległości pomiędzy poszczególnymi kępkami&lt;/li&gt;    &lt;li&gt;wygląd kępki mocno zależał od użytej tekstury – tę wadę można zatuszować poprawieniem poprzednich punktów (zagęszczeniem kępek, zastosowanie oświetlenia, zrandomizowaniem (mimo że to angielskojęzyczna kalka, to tutaj bardziej pasuje) ułożenia kępek), to warto by było wprowadzić jakiś poziom szczegółowości i część trawy oprzeć nie na kępkach, ale na pojedynczych źdźbłach&lt;/li&gt;    &lt;li&gt;generacja trawy była bardzo długa i można iść zrobić sobie herbatę, której tej trawa w dodatku sama nie robiła. Skandal&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Generalnie jest dość dużo aspektów do poprawy. Zatem niedawno zabrałem się do wstępnego projektu nowej implementacji, która byłaby rozszerzeniem klasy CStaticMesh i jedno pole marchew… trawiaste byłoby traktowane jako jeden osobny mesh, na który składają się wierzchołki tworzące źdźbła czy kępki. Co prawda, przy wstępnym podejściu do kodu okazało się, że znowu konstrukcja silnika stoi nam na drodze, ale część już udało się zrefaktoryzować, część na to czeka, a część “umownie” ominąć (np. poziomy szczegółowości to osobne materiały – dziwne, ale myślę, że zadziała. O ile nie zapomnę, o co mi chodziło). Dla każdej kępki będą generowane trzy reprezentacje – (1) quady składające się na poszczególne źdźbła, (2) trzy skrzyżowane quady tak jak poprzednio, (3) jeden quad zwrócony w kierunku obserwatora – natomiast decyzja, który poziom będzie wyświetlany, będzie zależał od odległości od oka kamery. Ponadto postanowiłem przyłożyć się do algorytmu rozmieszczania kępek i dać większą możliwość ich zagęszczania, aczkolwiek tutaj właśnie są pewne problemy natury matematycznej, z którymi jednak mam nadzieję, że sobie poradzę (i znajdę na to czas). Trudno będzie natomiast wypracować szybkość generowania i wyświetlania tej trawy przy takich założeniach – to również pozostaje kwestią wewnętrznych dyskusji w mojej głowie. &lt;/p&gt;  &lt;p&gt;Ale być może będziecie mieli jakieś własne przemyślenia lub też gotowe rozwiązania, które już na pierwszy rzut oka wydają się znacznie lepsze od moich zamysłów? Tak czy inaczej, jak zwykle, zapraszam do komentowania i krytykowania w komentarzach.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję za cierpliwość - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-203426465236853668?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/203426465236853668/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=203426465236853668' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/203426465236853668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/203426465236853668'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2011/03/praca-silnikowa-delikatnie-wre.html' title='Praca silnikowa delikatnie wre'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-65714870624925030</id><published>2010-11-16T11:23:00.002+01:00</published><updated>2010-11-16T11:23:57.101+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sport'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Spostrzeżenia z nowego semestru</title><content type='html'>&lt;p&gt;Tak, wiem, że znowu zawalam sprawę z notkami. Wiem też, że miałem napisać artykuł o cieniach, jeżeli uda mi się je zrobić. Niestety – chwilowo się poddałem. Całe szczęście, że teraz lepiej planuję silnik i mogłem po prostu zakomentować jedną klasę i parę linijek w SceneManager, aby wyzwolić się od ciemności stosowanej. Cóż, trudno – pewnie wrócę do tego tematu w przyszłości, ale póki co nie znalazłem rozwiązania mojego problemu (dosyć standardowego, czyli “nie działa tak jak powinno”). Tym niemniej nadal podtrzymuję wypowiedź, że jak się uda, to powstanie tekst. Aby inni nie mieli takich problemów jak ja. I w końcu devblog rzeczywiście stanie się devblogiem i będzie więcej technicznych notek.&lt;/p&gt;  &lt;p&gt;Z uwagi na semestr chwilowo został zarzucony silnik – siła wyższa, niestety. Wolę skupić się bardziej na obowiązkach, a przyjemności zostawić na czas, kiedy obowiązki zostaną spełnione. To nie oznacza oczywiście brak projektów – oprócz dwóch pobocznych (jedna gra i &lt;a href="http://pseudodev.blogspot.com/2010/10/tumacze-i-ochotnicy-aczcie-sie.html"&gt;tłumaczenie Wielkiego Mistrza&lt;/a&gt; (w którym niestety osłabłem, ale samo tłumaczenie idzie do przodu)) trwa w końcu nowy semestr, a w nim wiele atrakcji. Ponieważ w poprzednich etapach drogi uczelnianej także Was uraczałem opowieściami o poszczególnych przedmiotach, tak będzie też i tym razem. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Inżynieria Oprogramowania 1&lt;/strong&gt; – historię zaczynamy od przedmiotu, z którym osobiście wiążę wielkie nadzieje w dalszym toku studiów. IO, czyli nauka o tym jak poprawnie pisać kod, zarządzać projektem, modelować, projektować i obracać się w dobrze poukładanym zespole. Niestety, to także zahacza o zarządzanie, ale sam przedmiot wydaje się interesujący. Może nie konkretnie pierwsza część, ale później tak.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Komunikacja Człowiek-Komputer&lt;/strong&gt; – wbrew pozorom nie chodzi o mówienie do komputera, choć to też dałoby się zaimplementować. Mamy tutaj do czynienia z oddziaływaniami psychofizycznymi pomiędzy komputerem (w ogólności maszyną) a człowiekiem, czyli wszelkiego rodzaju podatność na barwy, rozpoznawanie zaburzeń ruchu, dźwięk i tym podobne sprawy. Generalnie chodzi o projektowanie urządzeń/oprogramowania, które ułatwiają życie (przykładem jest chociażby projekt informatora komunikacyjnego dla osób niewidomych – to oczywiście nie nasze zadanie, ale pokazuje mniej więcej ukierunkowanie ego przedmiotu).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Wspomaganie Decyzji&lt;/strong&gt; – dalsza opowieść o regułach decyzyjnych, w ogóle o regułach, tworzeniu zbiorów, rozwiązywaniu równań i takim doradzaniu, aby preferencje użytkownika zostały spełnione. Najłatwiej wyobrazić sobie zagadnienia z tego przedmiotu na prostym przykładzie – zamierzamy kupić samochód. Wiemy mniej więcej, jaki nam się podoba, ale jest zbyt dużo technicznych szczegółów i kombinacji, abyśmy to wszystko mogli sami uwzględnić. Rolą takich systemów decyzyjnych jest właśnie pomoc w podjęciu decyzji. A technik ku temu jest co niemiara. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Przetwarzanie Równoległe&lt;/strong&gt; – choć za ten przedmiot jest najmniej ECTS-ów, to jest chyba główną “atrakcją” na tym semestrze z uwagi na poziom trudności. Dla mnie to tym większy próg ze względu na moją niechęć do sprzętu i czysto technicznych zabaw. Choć pierwszy projekt jest nawet ciekawy, choć nietrywialny – należy ułożyć zadanie programowania liniowego dla zadanego układu węzłów przetwarzających. Brzmi groźnie? No właśnie.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Podstawy Automatyki&lt;/strong&gt; – opowieść o matematycznym i technicznym aparacie stosowanym w automatyce, czyli transmitancje, przekształcenia Laplace’a, Matlab + Simulink i tego typu narzędzia. Też nie jestem fanem tego typu rzeczy, ale to nie jest znowu coś takiego, czego nie idzie się nauczyć. Zwłaszcza, że to tylko podstawy. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Sieci Komputerowe 2&lt;/strong&gt; – druga część przedmiotu o sieciach. W tym semestrze zajmujemy się bardziej implementacją architektury klient-serwer, a jako projekt z kolegą mamy IRC, czyli znany i lubiany system czatowania. Wbrew pozorom, nie jest to bardzo skomplikowane, ale swoją złożoność ma, co jednak czyni projekt ciekawszym. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Systemy Baz Danych 2&lt;/strong&gt; – także druga część opowieści o bazach danych i wszystkim, co jest z nimi związane. Obecnie bardziej skupiamy się na technicznych aspektach Oracle’a (na laboratoriach) oraz na transakcjach (na wykładzie). Egzamin z tego przedmiotu jest dosyć specyficzny i potężny (10 zadań na 3 godziny), ale same bazy danych już przynajmniej nie kojarzą się z Accessem i lekcjach w szkole.&lt;/p&gt;  &lt;p&gt;Mam nadzieję, że choć troszkę zaciekawiłem kolejnych adeptów chcących udać się na studia informatyczne. I nie tylko (nie tylko adeptów i nie tylko informatyczne).&lt;/p&gt;  &lt;p&gt;Do końca Fantasy NFL zostały już cztery kolejki sezonu regularnego i dwa mecze Playoff (o ile nic mi się nie myli – ostatnio terminarz mnie zadziwił). Ze stanu 2-6 wyszedłem na 4-6 – małe zwycięstwa, a cieszą. Pewnie za te cztery lub więcej tygodni zacznę cykl notek przedstawiających przemyślenia na temat mojego pierwszego sezonu Fantasy. Mam nadzieję, że się nie obrazicie, że znowu zaniedbuję programowanie, a postaram się, aby analiza była zaawansowana na tyle, na ile mogę sobie na to pozwolić (czyli nie bardzo). Na pewno będę zachęcał do brania udziału w zabawie w przyszłym sezonie i postaram się, aby ten start był łatwiejszy.&lt;/p&gt;  &lt;p&gt;Dziękuję i pozdrawiam - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-65714870624925030?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/65714870624925030/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=65714870624925030' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/65714870624925030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/65714870624925030'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/11/spostrzezenia-z-nowego-semestru.html' title='Spostrzeżenia z nowego semestru'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-949879708909121527</id><published>2010-10-08T13:05:00.001+02:00</published><updated>2010-10-08T13:05:56.521+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wielki Mistrz'/><title type='text'>Tłumacze i ochotnicy, łączcie się!</title><content type='html'>&lt;p&gt;Dzisiaj post lekko propagandowy, ale w słusznym celu. &lt;img style="margin: 0px 0px 0px 5px; display: inline" align="right" src="http://www.gamedev.pl/screens/685f2c33e45be511d332f7f816f46f2f.jpg" width="184" height="138" /&gt; Mianowicie, mam nadzieję, że pamiętacie jeszcze projekt, w który był zaangażowany nieformalny zespół SystemSzok – tak jest, chodzi o &lt;a href="http://www.gamedev.pl/projects.php?x=view&amp;amp;id=699"&gt;Wielkiego Mistrza&lt;/a&gt;. Mianowicie powstał pomysł, aby wszystkie dialogi, tudzież inne formy tekstowe w tej grze przetłumaczyć z naszego ojczystego języka na angielski. Zadanie o tyle ambitne, że jest to całkiem spora dawka tekstu, która choć nie może się równać z tysiącami stron w Baldur’s Gate czy Neverwinter Nights, to jak na warunki amatorskie stanowi duży zbiór. Jednak nie ma jakiegoś specjalnego deadline’u, a tak naprawdę sam pomysł jest jeszcze w fazie rozwoju. Więcej informacji bez wątpienia znajdziecie na poniżej podanej stronie.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wielkimistrz.wikispaces.com/"&gt;O, to jest ta strona&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Możecie na niej znaleźć odezwę Toxica do narodu jak i część dialogów do przetłumaczenia. Część, gdyż nie wszystko jeszcze zostało wrzucone. Chciałem jednocześnie zaapelować do wszystkich, którzy czują się na siłach i mają troszkę czasu i zapału, aby spróbowali potłumaczyć część dialogów (lub część części dialogów). Jednocześnie proszę też, aby:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Nie było to tłumaczenie “mechaniczne”, czyli wklepujemy tekst do &lt;a href="http://translate.google.pl/#"&gt;translate.google.pl&lt;/a&gt; i patrzymy co nam wyjdzie. Nie mówię (a raczej piszę), że to niedobre narzędzie, gdyż sam z niego czasami korzystam i sobie chwalę, jednak są pewne zwroty czy konteksty, z którymi ten tłumacz sobie nie poradzi. Dlatego zawsze (absolutnie zawsze) proszę jeszcze raz przejrzeć tłumaczony tekst, tłumaczenie i dokonać niezbędnych korekt.&lt;/li&gt;    &lt;li&gt;Pewnie po jakimś czasie powstanie na tej stronie jakaś lista nazw własnych i specyficznych rzeczy oraz “jak je tłumaczyć”, której proszę się trzymać.&lt;/li&gt;    &lt;li&gt;Fajnie by było, jakby został zachowany klimat Wielkiego Mistrza, czyli taki lekko surrealistyczny, absurdalny, ze specyficznymi smaczkami. Tutaj jeszcze raz apeluję o niemechaniczność, żeby nie zabić atmosfery.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cóż, mam nadzieję, że nie przestraszyłem tym zbytnio (jeżeli Toxic, Krajek czy ktoś inny będą mieli coś do dodania, to postaram się tutaj wrzucić), ale nie martwcie się – tak naprawdę to bardziej zabawa i forma sprawdzenia się, czy umielibyśmy pracować w firmie lokalizacyjnej. Jak już wspomniałem, pomysł jest w fazie rozwoju, prace powoli pewnie będą szły do przodu. Oczywiście, jeżeli ktoś nie chce tłumaczyć tekstów, ale ma nosa do poprawiania angielskiego, to również zapraszamy go do współpracy. Nie trzeba nam też nic mówić – na stronie można nawet przeczytać, że można śmiało wrzucać swoje propozycje.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i zapraszam - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-949879708909121527?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/949879708909121527/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=949879708909121527' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/949879708909121527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/949879708909121527'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/10/tumacze-i-ochotnicy-aczcie-sie.html' title='Tłumacze i ochotnicy, łączcie się!'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-3666055890794883471</id><published>2010-09-30T19:18:00.002+02:00</published><updated>2010-09-30T19:19:19.196+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sport'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>O problemach, zapowiedź i oczywiście NFL</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/TKTGXz_qzkI/AAAAAAAAAf0/6lgPHK4y5lI/s1600-h/nieudane_cienie%5B3%5D.png"&gt;&lt;img style="border: 0px none; margin: 0px 5px 0px 0px; display: inline;" title="nieudane_cienie" alt="nieudane_cienie" src="http://lh4.ggpht.com/_R2ix0MLn8lM/TKTGaoxF95I/AAAAAAAAAf8/9bYT5zneleY/nieudane_cienie_thumb%5B1%5D.png?imgmax=800" align="left" border="0" width="244" height="191" /&gt;&lt;/a&gt; To co widzicie z boku to nie wymysł jakiegoś szalonego artysty, ale screen z aplikacji testowej silnika Scav. A co &lt;/p&gt;  &lt;p&gt;jest obecnie na tapecie? To co zawsze - cienie. &lt;/p&gt;  &lt;p&gt;O ile działa pierwsza faza, czyli generowanie mapy cienia z punktu widzenia światła na dany obiekt (to prawe okienko), to gorzej jest już z drugą fazą, czyli generowania tekstury z ocieniowaną sceną (lewe okienko). Co mam na myśli pisząc o fazach? Otóż, polecam zajrzeć do &lt;a href="http://www.gamedev.net/reference/articles/article2193.asp"&gt;tego artykułu&lt;/a&gt;, z którego namiętnie korzystam. Generalnie chodzi mi o to, aby były spełnione postulaty: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Programista miał do wyboru ustawienia cienia (twarde, miękkie, jaki poziom miękkości, nijakie)    &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Oddziaływanie na wiele różnych źródeł światła    &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Możliwość wyboru właściwości mesha (rzucania i/lub odbieranie cienia)    &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Różnokolorowe światła &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak widać, na razie jednak męczę się nad tym, aby wygenerować jeden prosty cień. Co z powyższej listy zostanie potem zrealizowane - nie wiem, prawdę mówiąc, ale postaram się, aby jak najwięcej. Jeżeli już uda mi się ze wszystkim uporać, to bądźcie pewni, że zaatakuję Was artykułem-tutorialem. Mało jest takich tekstów po polsku, więc taki jeden nie zaszkodzi. Nawet, jeżeli nie będę specjalistą z tego zakresu. Można też zajrzeć na &lt;a href="http://developer.nvidia.com/object/doc_shadows.html"&gt;stronę NVIDIA&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Choć przyznacie, że ciekawy efekt, prawda? Wielokrotny cień (jakby się przyjrzeć z bliska). Światło punktowe na scenie jest umiejscowione odrobinę w lewo od kamery i bliżej tej kostki - akurat tekstura głębi (jeszcze raz - prawe okienko) jest generowana dobrze (mam nadzieję), więc na tym można się opierać. Cały problem tkwi pewnie gdzieś w przekształceniach macierzowych i samych macierzach - nie mam niestety podstaw matematycznych i typowego umysłu ścisłego, więc pewnie znowu będę tworzył w specyficzny sposób - empirycznie. Życzcie mi szczęścia. &lt;/p&gt;  &lt;p&gt;Czas na kolejny raport z Fantasy NFL. Zdaję sobie sprawę, że niewielu to interesuje, ale być może ktoś lubi takie pseudomanagerskie wywody i będzie zaciekawiony kolejnymi wnioskami. Poza tym czuję nieodpartą chęć pisania, dlatego proszę o wybaczenie i ewentualnie pominięcie akapitu. &lt;/p&gt;  &lt;p&gt;Jesteśmy już po trzeciej kolejce ligi NFL. Po tym czasie mam bilans 2-1-0 - w ostatnim meczu moi gracze niezbyt się popisali i przegrałem z drużyną, która miała same porażki, ale po obliczeniach wyszło mi, że jakkolwiek nie ustawiłbym mojego składu to i tak bym poniósł porażkę - mój oponent miał Aarona Rodgersa, Anquana Boldina (3 przyłożenia w minionym tygodniu) oraz bestię Adriana Petersona, który zaliczył 80-jardowe przyłożenie mijając przeciwników jak w slalomie (co możemy zobaczyć &lt;a href="http://www.youtube.com/watch?v=0qMb5kjEDNw"&gt;tutaj&lt;/a&gt;&lt;a href="http://www.youtube.com/watch?v=0qMb5kjEDNw%29"&gt;)&lt;/a&gt;. W drugiej kolejce natomiast odniosłem pewne zwycięstwo, ale nie ma o czym mówić. &lt;/p&gt;  &lt;p&gt;Quarterbackowie &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;W drugim tygodniu postawiłem na Eli Manninga zamiast Matta Schauba. Efekt był taki, że Eli zaliczył takie sobie spotkanie (161 jardów, 2 przyłożenia, 1 przechwyt), za to Matt rzucił 497 jardów, 3 przyłożenia i także 1 przechwyt. Zdobył ponad 20 punktów Fantasy więcej niż Eli. Wiedział kiedy. &lt;/li&gt;    &lt;li&gt;Siłą rzeczy, w trzecim tygodniu wróciłem do swojego pierwotnego rozgrywającego z Houston. Niestety, nie bardzo sobie dawał radę z obroną Dallas i jego statystyki to 241 jardów, 1 przyłożenie (w samej końcówce, gdy wynik był już rozstrzygnięty) i 2 przechwyty. Podobnie Eli Manning, z tym że bez przyłożenia, ale z 386 jardami. Zdobył trochę więcej punktów niż mój starter Matt, ale nie na tyle, abym żałował wyboru.&lt;/li&gt;    &lt;li&gt;Na kogo stawiam w nadchodzący weekend? Ponieważ mam dosyć tej przeplatanki, pozostanę konsekwentny i wystawię Matta Schauba grającego przeciwko Oakland. Może znowu przegram, ale trudno. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Running Backowie &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;W obu tygodniach postawiłem na duet Shonn Greene-Pierre Thomas. Nie byli zanadto rewelacyjni, choć Thomas przekroczył w drugim tygodniu łącznie 100 jardów (licząc bieg i podania). Shonn, jak na mój pierwszy wybór w drafcie, spisuje się kiepsko - wyraźnie odstaje od legendarnego kolegi z zespołu, Laidaniana Tomlinsona. Rezerwowy debiutant, C.J. Spiller nie spisywał się zbyt dobrze, za to mój były wybór - Marion Barber - całkiem nieźle, dlatego ponownie sprowadziłem go do zespołu.&lt;/li&gt;    &lt;li&gt;Jaki był efekt? C.J.Spiller w następnym tygodniu zdobył dwa przyłożenia - jedno po returnie, a drugie po podaniu. Chyba tylko czekał aż go wyrzucę ze składu. Marion Barber też się nieźle spisał (60 jardów i jedno przyłożenie), a na pewno lepiej niż mój startowy duet - Greene osiągnął 36 jardów, a Thomas łącznie 91 w dramatycznym meczu z Atlantą. Należy wspomnieć, iż Pierre grał całkiem nieźle, ale i tak przydałoby się jakieś przyłożenie. &lt;/li&gt;    &lt;li&gt;W tym tygodniu nie mam problemu kogo wystawić - Barber i tak odpoczywa ze swoim zespołem i nie gra. Pierre Thomas natomiast cierpi po kontuzji kostki. Na razie nie wiadomo, na ile poważny jest to uraz, a jego start w meczu z Carolina Panthers jest niepewny. Najwyżej będę mocno kombinował przed samym meczem. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Wide Receiverzy &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;W drugim tygodniu ponownie świetnie zagrał Miles Austin, zdobywając 142 jardy. Przeciwnie Chad Ochocinco, który zaliczył jedynie 44 i całkiem poważnie myślę, czy go nie wyrzucić ze składu (gdyż w trzecim tygodniu też wiele lepiej nie zagrał). Johnny Knox standardowo - 86 jardów, aczkolwiek jest głównym celem rozgrywającego Chicago Bears Jaya Cutlera. Jakby łapał więcej rzucanych do niego piłek (bo dostaje ich naprawdę dużo), miałbym jedną z gwiazd Fantasy, ale i tak nie narzekam. Znowu pozostawiony na ławce Dez Bryant osiągnął 52 jardy, ale za to touchdown po returnie. Santonio Holmes tradycyjnie nie grał i do czwartego tygodnia (włącznie) sobie nie zagra (zawieszenie dyscyplinarne).&lt;/li&gt;    &lt;li&gt;W trzecim tygodniu strasznie rozczarował mnie Miles - tylko 20 jardów i 2 podania. Nie widziałem meczu, więc nie wiem, czy to wina słabej dyspozycji Austina czy zabiegi defensorów Houston Texans, którzy skutecznie odcięli gwiazdę Dallas Cowboys od podań (zapominając jednak o Royu Williamsie, który zdobył dwa przyłożenia i pozwalając na więcej Dezowi Bryantowi - 50 jardów). Ochocinco 34 jardy - daję mu jeszcze szansę w tym tygodniu. Johnny Knox standardowo - 96 jardów, czyli całkiem solidnie.&lt;/li&gt;    &lt;li&gt;Ze skrzydłowymi w tym tygodniu był nielichy problem - zarówno Miles jak i Dez pauzują wraz z całym Dallas, Santonio ma ostatni tydzień zawieszenia i zostało tylko dwóch zawodników na czwartą kolejkę - Chad Ochocinco i Johnny Knox. Dlatego na ten tydzień wyrzuciłem ze składu tight enda Anthony'ego Fasano i zakontraktowałem Legedu Naanee z San Diego Chargers. W sumie jakiś rewelacyjnych osiągnięć nie miał (jedynie 110 jardów i touchdown w pierwszym tygodniu), ale San Diego gra z Arizoną, która powinna pozwolić na całkiem dużo świetnej ofensywie Chargers. Do wyboru miałem jeszcze dobrze grającego Louisa Murphy z Oakland Raiders, ale ten ma jakiś uraz i wolałem nie ryzykować. Choć niewykluczone, że jeszcze przed samym meczem dokonam jakiegoś transferu. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Tight Endzi (ale to fatalnie brzmi...) &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;W obu tygodniach postawiłem na Tony'ego Gonzaleza z Atlanta Falcons, którego umiejętności nie można przecenić. O ile w drugim tygodniu zagrał słabo (tylko 19 jardów), to zgodnie z oczekiwaniami ekspertów w meczu z New Orleans Saints zagrał rewelacyjnie - 110 jardów i przyłożenie. To także jego gra przyczyniła się do wygranej Atlanty w tym trudnym meczu. W tym czasie Anthony Fasano zdobył łącznie 14 jardów i przyłożenie.&lt;/li&gt;    &lt;li&gt;Wyżej napisałem, że zamieniłem Fasano na skrzydłowego Naanee. Byłem do tego zmuszony z powodu konieczności (chcę chociaż walczyć o dodatkowe punkty w trudnym czwartym tygodniu), a do czasu, jak Gonzalez będzie pauzował, znajdę na zastępstwo innego tight enda. Anthony nie spisywał się za dobrze (oprócz touchdownu), a w Miami nie jest tak często wykorzystywany, zatem miło całej sympatii musiałem powiedzieć "papa". &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Kicker &lt;/p&gt;  &lt;p&gt;Sebastian Janikowski jak zwykle solidnie punktuje w rozgrywkach Fantasy, choć z jego formą coś jest ostatnio nie tak - zepsuł parę rzutów wolnych w ciągu ostatniego meczu z Arizoną, łącznie z decydującym kopem w ostatnich sekundach. No trudno, miejmy nadzieję, że nasz rodak się odbuduje i nadal będzie trafiał często i z daleka. &lt;/p&gt;  &lt;p&gt;Defensywa &lt;/p&gt;  &lt;p&gt;Mam dostęp zarówno do defensywy Dallas Cowboys jak i Philadephii Eagles, a że obie (punktowo) stoją na podobnym poziomie, mogę ze spokojnym sumieniem swobodnie dobierać obronę do przeciwników. W obu tygodniach zagrała Philadelphia i to był niezły wybór - łącznie te drużyny zdobyły tyle samo punktów, a różnice nie wpłynęłyby na ogólny wynik całego zespołu Fantasy. W przyszłym tygodniu wystartuje Philadelphia - jak pamiętamy, Dallas ma wolne, a ja masochistą nie jestem.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-3666055890794883471?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/3666055890794883471/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=3666055890794883471' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3666055890794883471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3666055890794883471'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/09/o-problemach-zapowiedz-i-oczywiscie-nfl.html' title='O problemach, zapowiedź i oczywiście NFL'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_R2ix0MLn8lM/TKTGaoxF95I/AAAAAAAAAf8/9bYT5zneleY/s72-c/nieudane_cienie_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2445139230343775227</id><published>2010-09-18T20:29:00.003+02:00</published><updated>2010-09-20T08:29:04.978+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Magic: the Gathering'/><category scheme='http://www.blogger.com/atom/ns#' term='Sport'/><category scheme='http://www.blogger.com/atom/ns#' term='Gry'/><title type='text'>Relacja z gry za 12,49 zł, a poza tym relacja z pierwszej kolejki Fantasy NFL</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.microsoft.com/games/fable/img/ss/ss4.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 239px; height: 179px;" src="http://www.microsoft.com/games/fable/img/ss/ss4.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt; Wiem, że bardzo dawno nie pisałem nic na blogu. Niestety, za bardzo nie mam o czym – programowanie silnika trochę odstawiłem po tym, jak wyznaczyłem sobie punkt, aby zająć się cieniami. Troszkę jeszcze chyba potrwa zanim dojdę do:&lt;br /&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;odpowiedniego poziomu motywacji, żeby to zrobić&lt;/li&gt;    &lt;li&gt;pomyśleć, jak to napisać dla wielu różnych świateł, obiektów rzucających i odbierających cień&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cóż, niestety, zająłem się innymi sprawami w tym czasie. Zamiast programować…&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;pisałem kolejne artykuły na Poltera (czytaj – zajmowałem się Magiciem)&lt;/li&gt;    &lt;li&gt;testowałem (i nadal testuję) talie do ligi Poltera w Magic: the Gathering (przy okazji serdecznie zapraszam wszystkich zainteresowanych &lt;a href="http://forum.polter.pl/liga-poltera-vt60722.html"&gt;tutaj&lt;/a&gt;)&lt;/li&gt;    &lt;li&gt;oglądałem koszykówkę (mistrzostwa świata) oraz NFL (czyli gra w Fantasy, o czym jeszcze wspomnę w tej notce)&lt;/li&gt;    &lt;li&gt;grałem (o czym w sumie jest ta dziwna notka)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak widać, wakacje ciekawe. Ale mało efektywne.&lt;/p&gt;  &lt;p&gt;Jeszcze raz zapraszam chętnych na spróbowanie swoich magicowych sił do ligi Poltera w dosyć nietypowym formacie (szczegóły w linku, który podałem wyżej). Jeżeli chodzi o NFL – odbyła się już pierwsza kolejka sezonu zasadniczego, a zatem również pierwsza kolejka &lt;a href="http://pseudodev.blogspot.com/2010/08/drzewka-dzielone-na-osiem-obejoty-oraz.html"&gt;Fantasy NFL&lt;/a&gt;. Pierwszy mecz i pierwsze zwycięstwo, aczkolwiek wielu graczy mnie zawiodło. Do rzeczy:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Matt Schaub, mój podstawy quarterback, nie zdobył dla mnie zbyt wielu punktów, gdyż nie musiał za bardzo podawać -  okazało się, że w fantastycznej formie w spotkaniu z Indianapolis był Arian Foster, który zdobył ponad 200 jardów biegiem. W tym tygodniu sadzam Matta na ławce, a do składu wskakuje Eli Manning, który w tym tygodniu powinien grać dobrze. Także przeciwko Indianapolis.&lt;/li&gt;    &lt;li&gt;O ile Pierre Thomas zagrał nawet powyżej oczekiwań, o tyle mój podstawowy running back – Shonn Greene – był bezlitośnie powstrzymywany przez defensywę Baltimore Ravens. Nie dość, że zdobył bardzo mało jardów, to jeszcze dwa razy upuścił piłkę (a raz stracił). Rezerwowy C.J. Spiller, rewelacyjny debiutant z Buffalo, którego pobrałem zamiast nierokującego (według mnie) Mariona Barbera, także się nie popisał – 6 jardów na 7 prób. Mam nadzieję, że w tym tygodniu będzie lepiej.&lt;/li&gt;    &lt;li&gt;Za to na wysokości zadania stanęli skrzydłowi – zarówno Miles Austin jak i Chad Ochocinco zdobyli bardzo dużo punktów (żeby było jasne – mówię tutaj o punktach fantasy, a nie w samym meczu). Zwłaszcza Chad mnie zaskoczył, choć sporą ilość jardów uzyskał dopiero w czwartej kwarcie, kiedy wynik był rozstrzygnięty na niekorzyść Cincinatii. Miles jest natomiast w niesamowitej formie – można było to zobaczyć oglądając mecz (w poniedziałek na Polsat Sport Extra – w najbliższym tygodniu też coś tam będzie leciało). Jeśli chodzi o trzeciego skrzydłowego, to postawiłem na Johnny Knoxa, który spisał się nie najgorzej, ale był minimalnie gorszy od debiutanta Deza Bryanta. Na razie jednak stawiam na Knoxa, gdyż jest on głównym celem podań w swoim zespole (Chicago), a zatem ma większą szansę na uzyskiwanie kolejnych jardów. Santonio Holmes i tak pauzuje do czwartej kolejki włącznie, więc na razie się nim nie przejmuję.&lt;/li&gt;    &lt;li&gt;Tony Gonzalez złapał tysięczne podanie w swojej karierze i tym samym wszedł do grona najlepszych receiverów w historii ligi. Problem w tym, że w całym meczu Atlanta nie mogła sprostać świetnej defensywie Pittsburgh i tych piłek Tony dużo nie złapał. Rezerwowy tight end, Anthony Fasano spisał się troszkę lepiej, ale w przyszłym tygodniu także stawiam na Gonzaleza – Falcons będą walczyć z Arizona Cardinals, którzy są znacznie łatwiejszym przeciwnikiem.&lt;/li&gt;    &lt;li&gt;Sebastian Janikowski wykorzystał te sytuacje, które wypracowali mu koledzy i zdobył solidne 7 punktów. Defensywa Dallas, mimo iż w ogóle jest jedną z lepszych w lidze, spisała się odrobinę gorzej (w punktach Fantasy) aniżeli Philadelphia, ale nie żałuję – trudno było przewidzieć tak małą różnicę, a Cowboys naprawdę zagrali dobrze w obronie. W następnej kolejce na pierwszy ogień idą jednak Eagles, którzy walczą ze słabym ofensywnie (zwłaszcza po stracie podstawowego rozgrywającego) Detroit Lions, podczas gdy Dallas będą podejmować Chicago Bears.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak widać, w NFL dzieje się dużo, podobnie jak w Fantasy. Przynajmniej człowiek ma trochę emocji i rywalizacji.&lt;/p&gt;  &lt;p&gt;Głównym tematem dzisiejszej notki jest gra z 2005 roku, którą niedawno wyhaczyłem w jednym sklepie za 12,49 zł. Jak na tak chwalony tytuł jest to dosyć niewiele, dlatego skusiłem się i nabyłem &lt;a href="http://www.gry-online.pl/S016.asp?ID=4732"&gt;Fable: Zapomniane Opowieści&lt;/a&gt;. Pewnie wielu z Was zna tę pozycję, dlatego wspomnę tylko, że jest to gra cRPG autorstwa jednego z najlepszych designerów w branży, Petera Molyneuxa. Słysząc (a raczej czytając) to nazwisko możemy się już domyślać, iż gra standardowa nie jest. Za to wprowadza wiele nowych rozwiązań, co do których można mieć różne zdanie.&lt;/p&gt;  &lt;p&gt;Niedawno (jakąś godzinę temu) ukończyłem grę i mimo tego można dalej grać (jak się przeczeka napisy końcowe). Mogę już też w punktach wypisać moje przemyślenia o grze.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pierwsze i najważniejsze – niezależnie od tego, co napiszę potem o technicznych sprawach (jeżeli chodzi o mechanikę gry), to muszę oddać jedno – ta gra ma niesamowity klimat. Widać wyraźnie dorastanie, szkolenie, podnoszenie poprzeczki w kolejnych zadaniach, wzrost sławy i możliwości. NPC-e w grze żyją, zatrzymują się na nasz widok i biją brawo (jak to ja, grałem oczywiście dobrą postacią. Podejrzewam, że nawet jakbym grał złą, to i tak bym wylądował u psychologa). W miarę upływu czasu jesteśmy coraz bardziej rozpoznawalni w całej krainie, a my z kolei poznajemy historię świata Albionu i słuchamy o dawnych bohaterach i legendach. Do tego ta baśniowa atmosfera – spełnienie ideału bohatera i dobrze poprowadzona historia. Naprawdę, pod tym względem Fable jest rewelacyjne.&lt;/li&gt;    &lt;li&gt;W grze możemy w miarę dowolnie kształtować nasze ciało, charakter, umiejętności i postrzeganie w oczach innych. Możliwe, że w obecnych grach jest to powszechne, ale stykam się z tym w Fable pierwszy raz i stwierdzam, że to świetna droga w rozwoju bohatera w grach komputerowych. Może troszkę więcej poziomów doświadczenia w poszczególnych umiejętnościach by się przydało (za szybko doszedłem do maksymalnego poziomu w sile, a potem nie miałem co robić z punktami doświadczenia. No bo co, łukiem nie będę walczył).&lt;/li&gt;    &lt;li&gt;System magii jest za to dziwny. Rozumiem ideę twórców, aczkolwiek osobiście wolę aktywną pauzę, spokojne wybieranie czarów myszką, a dodatkiem do tego może być system z Fable (shift + przycisk myszy). System walko z kolei przypomina za bardzo typową grę akcji, ale nie ukrywam, że tak jak w Wiedźminie podobało mi się machanie mieczem, tak jest też tutaj. Jedyne co mnie razi to wylatujące zielone gwiazdki będące punktami doświadczenia – niby można to wytłumaczyć (pobieramy cząstki energii z martwych), ale bywa uciążliwe i generalnie wolę zwykłe punkty.&lt;/li&gt;    &lt;li&gt;Od strony technicznej gra jest niezła. Nie spotkałem jakiś większych niedoróbek, a bardzo częsty w użyciu jest bloom, co buduje miejscami naprawdę baśniowy klimat (nie pytajcie jak – nie umiem pewnych rzeczy racjonalnie wyjaśnić). Muzyka, wstawki w ważniejszych wydarzeniach – również należy ocenić na ocenę “bardzo dobry”.&lt;/li&gt;    &lt;li&gt;Za to dialogi są gorsze niż w Wielkim Mistrzu! No dobrze, żartuję, ale rzeczywiście, wolę głębsze rozmowy z czymś więcej niż wyborami Tak/Nie. Zdaję sobie sprawę, że to upraszcza rozgrywkę i trudniej byłoby to rozwiązać przy obecnym w Fable koncepcie, ale jednak jest to niedosyt. Na plus trzeba zaliczyć dwie rzeczy – tak skromne dialogi nie psują możliwości “zakręcania” swoją ścieżką rozwoju bohatera, a poza tym jest w nich dosyć dużo humoru. Przynajmniej w niektórych. Polecam też poczytać nieco uważniej napisy końcowe – można się dowiedzieć ile pizz zostało zjedzonych podczas prac nad grą. W opisach przedmiotów również da się wyczytać ciekawe rzeczy. Nie mówiąc już o gestach, jakie możemy wykonywać przed Wyrocznią pod koniec gry.&lt;/li&gt;    &lt;li&gt;Wrócę jeszcze do opowiadanej historii. Być może jest ona zbyt liniowa (bo tak naprawdę wyborami możemy wpływać tylko na siebie, a nie na akcję), ale za to jaka fascynująca. Rzadko czuję podczas gry, że rzeczywiście muszę wykonać jakieś zadanie, aby pomścić bliskiego mi NPC-a albo że nie idę na potwory tylko dla doświadczenia i złota – tutaj autentycznie niektóre sceny chwytają za serce i każą działać w sposób bardziej ludzki, a nie “idę sobie poekspić”. Wielki plus dla twórców fabuły – to też wiąże się bezpośrednio z baśniowością.&lt;/li&gt;    &lt;li&gt;System gestów też jest coraz bardziej powszechny w grach, ale tutaj naprawdę został bardzo mocno rozwinięty. Ciekawa rzecz, choć nie używałem ich jakoś bardzo często. Są one potrzebne w sumie jeśli chcemy się czegoś dowiedzieć od Wyroczni lub zamierzamy się ożenić i ewentualnie w jakiś pomniejszych zadaniach.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Podsumowując – polecam Fable. Jest to ciekawy cRPG, na pewno inny niż te spod znaku Dungeons and Dragons, Fallouta czy The Elder Scrolls. Dużo bardziej baśniowy (co mi się akurat podoba, ale to rzecz gustu) oraz nastawiony na klimat. A cena 12,49 zł jest po prostu śmieszna jak na taką grę.&lt;/p&gt;  &lt;p&gt;Cóż, miejmy nadzieję, że następny wpis ukaże się szybciej niż ten i będzie dotyczył programowania. Chyba że ktoś woli, jak piszę o wszystkim, tylko nie o programowaniu.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2445139230343775227?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2445139230343775227/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2445139230343775227' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2445139230343775227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2445139230343775227'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/09/relacja-z-gry-za-1249-z-poza-tym.html' title='Relacja z gry za 12,49 zł, a poza tym relacja z pierwszej kolejki Fantasy NFL'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-9102701900746627754</id><published>2010-08-16T16:24:00.002+02:00</published><updated>2010-08-16T16:31:17.025+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technikalia'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Overlaye skończone</title><content type='html'>&lt;p&gt;W końcu, po tygodniowych wakacjach, zdobyłem się na &lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/TGlKGUQ8fxI/AAAAAAAAAfY/b5NX_GDLZ9M/s1600-h/scr%5B3%5D.png"&gt;&lt;img style="border: 0px none; margin: 0px 0px 0px 5px; display: inline;" title="scr" alt="scr" src="http://lh6.ggpht.com/_R2ix0MLn8lM/TGlKI8u5WHI/AAAAAAAAAfc/uSebuy2gG2c/scr_thumb%5B1%5D.png?imgmax=800" align="right" border="0" width="244" height="184" /&gt;&lt;/a&gt; poprawienie systemu overlayów w silniku. Gwoli wyjaśnienia – overlay (jak to przetłumaczyć na polski, “nakładka”?) to dwuwymiarowy element sceny, który jest tak jakby nakładany na ekran – świetnym przykładem będzie tu &lt;a href="http://www.otofotki.pl/img6/obrazki/qd8996_quake1hz5.jpg"&gt;HUD&lt;/a&gt; (informacje o zdrowiu, pancerzu, amunicji), &lt;a href="http://www.benchmark.pl/uploads/backend_img/fotki_recenzje/1974_gry_ktore_zmienily_komputer_cz2/nwn2_d.jpg"&gt;portret postaci&lt;/a&gt; czy też inny &lt;a href="http://www.gamedev.pl/screens.php?x=view&amp;amp;id=4993#"&gt;HUD z pewnej nieznanej gry&lt;/a&gt;. Tak były też robione efekty czarów i obrażeń w Wielkim Mistrzu. Overlay można ustawić z pewną przezroczystością, dzięki czemu można zrobić &lt;a href="http://pl.wikipedia.org/wiki/Cyfrowy_znak_wodny"&gt;coś w rodzaju znaku wodnego&lt;/a&gt;, co widać również w screenie przy nagłówku.&lt;/p&gt;  &lt;p&gt;Od technicznej strony sprowadza się to zapamiętaniu wartości macierzy rzutowania i wprowadzeniu projekcji dwuwymiarowej (w OpenGL-u odpowiada za to funkcja &lt;a href="http://pyopengl.sourceforge.net/documentation/manual/gluOrtho2D.3G.html"&gt;gluOrtho2D&lt;/a&gt;, chyba że ktoś chce samemu sobie liczyć). Ponadto macierz model-widok staje się macierzą jednostkową i po tych operacjach można już rysować nasze świecidełka. Z ciekawostek powiem, że w podobny sposób (choć nie aż tak łatwo - można tutaj równie dobrze zahaczyć o postprocessing) można uzyskać &lt;a href="http://regedit.gamedev.pl/Download/Galeria/Rozne%20screeny/LensFlare.jpg"&gt;efekt soczewek (lens flare)&lt;/a&gt;, co zostało opisane w Perełkach Programowania Gier (tom 1.).&lt;/p&gt;  &lt;p&gt;Cały problem u mnie polegał jednak na tym, że koniecznie chciałem, aby każdy overlay mógł również być powiązany z wyświetlaniem tekstu. Oczywiście, dałoby się to zrobić otwierając folder z frameworkiem i ściągając cały kod. Problem jednak w tym, że to działania zahaczające o bezpośredni tryb przekazywania danych (glVertex i te sprawy – proste, ale ble, więc nie chcę się narażać) oraz funkcje windowsowe (a my nie chcemy się ograniczać do produktu Microsoftu, choć przyznaję uczciwie, że na Linuxie wersji testowych nie sprawdzałem). Kwestią oczywistą jest to (kurczę, zbyt ładnie ostatnio piszę, muszę spuścić z tonu), że skoro korzystamy z SDL-a, to należy poszperać tu i ówdzie (i pomiędzy) za funkcjami tej biblioteki, które pomagają w ukazaniu liryki słownej na monitorze. Okazało się, że istnieje taka pomocnicza biblioteka jak &lt;a href="http://www.libsdl.org/projects/SDL_ttf/"&gt;SDL_ttf&lt;/a&gt;, która pozwala na proste wczytywanie czcionek TrueType Font i wyświetlanie tekstu z ich udziałem. Fakt, że są to dodatkowe wpisy w linkerze, ale mówi się trudno. Pierwsze podejście odbywało się zgodnie z &lt;a href="http://info.wsisiz.edu.pl/%7Eszymank0/doku.php?id=public:programowanie:sdl:sdltutorial7"&gt;tym tutorialem&lt;/a&gt;. Po przejrzeniu, podekscytowaniu się (spodobało mi się to słowo po odpowiedzi gry Neverwinter Nights, gdy po walce chciałem podjąć rozmowę - “Jesteś zbyt podekscytowany, aby teraz rozmawiać”) i wpisaniu odpowiedniego kodu okazało się, że jednak nie działa – wszystkie inicjalizacje zostały przeprowadzone prawidłowo, a jednak tekst się nie wyświetla. Nie pomógł debugger ani usilne wpatrywanie się w kod – SDL_BlitSurface wyraźnie miał wobec mnie niecny zamiar zdenerwowania mnie. Podejrzewając, iż wina leży po stronie tego, że SDL wykorzystuję tylko jako fundament, a całość hula na samym OpenGL-u, począłem poszukiwanie informacji o innych sposobach już samego wyświetlenia tekstu (a nie tylko przygotowania czcionki i powierzchni tekstu). Wtedy pomocną dłoń wyciągnęło &lt;a href="http://wiki.gamedev.net/index.php/Main_Page"&gt;wiki.gamedev.net&lt;/a&gt;, które przedstawiło mi taki oto &lt;a href="http://wiki.gamedev.net/index.php/SDL_ttf:Tutorials:Fonts_in_OpenGL"&gt;tekst&lt;/a&gt;. Muszę przyznać, że podczas poprzednich wędrówek po zasobach Internetu spotkałem się już z podejściem tworzenia tekstury z powierzchni SDL_Surface i korzystaniu z niej przy renderowaniu, ale nie potraktowałem tego nigdy poważnie – choćby ze względu na wydajność, która wydawała mi się wątpliwa. Cóż, nadal tak mi się wydaje, ale w końcu sposób przedstawiony na tej wikistronie zadziałał i to nawet z użyciem tablic wierzchołków. Dzięki temu w grze można wrzucić pasek HUD z żądaną przez nas teksturą i obok pisać “Zdrowie: 114, Pancerz: 100, Satysfakcja: bezcenne”. &lt;/p&gt;  &lt;p&gt;Overlaye można ustawiać już w kodzie, ale można też wczytać definicję z pliku, podobnie jak meshe. Jest też możliwość ustawienia jedną zmienną overlaya pełnoekranowego, co pozwoli zrealizować na przykład efekt krwi. Idąc dalej można spróbować robić prymitywne GUI. Bardzo prymitywne. Bardziej prymitywnego nie widzieliście. Przynajmniej wątpię.&lt;/p&gt;  &lt;p&gt;Wspomniałem na początku o tygodniowych wakacjach – nawet nie wiecie jak to czasami dobrze wypocząć bez komputera. Choć było ciężko. Tym niemniej nie oznacza to jednak, że nie myślałem o silniku czy w ogóle o projektowaniu. Przeciwnie, na podręcznych brulionach powstało wiele koncepcji oznaczonych jako “co dalej”.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;System cząsteczkowy na wzór &lt;a href="http://informatyka.wroc.pl/node/637/systemy-czasteczkowe"&gt;tego&lt;/a&gt;, podobnego lub innego (i tralalatego, aby do rymu było)&lt;/li&gt;    &lt;li&gt;Bump mapping (pierwsze podejście zostało już spacyfikowane przez nieprzyjazne wobec mnie siły matematyki, zbieram siły na kolejne)&lt;/li&gt;    &lt;li&gt;Klasa singletona (przyda się dwóch poniższych klas)&lt;/li&gt;    &lt;li&gt;Klasa managera logów, który automatycznie zapisywałby pewne rzeczy w pliku (inicjalizacje itp.). Byłby to singleton dostępny z każdego miejsca w programie&lt;/li&gt;    &lt;li&gt;Klasa profilera, który też byłby singletonem i służył do testowania wydajności. Bardziej zabawka, aby ładnie wyglądało&lt;/li&gt;    &lt;li&gt;Cienie (do których zabieram się od jakiegoś czasu, ale z bardzo miernym skutkiem)&lt;/li&gt;    &lt;li&gt;Cały system tzw. meshy naturalnych (teren, niebo, drzewa, trawy, wody, trolle), na razie w zamyśle wybitnie koncepcyjnych (czyli jak napisać klasy)&lt;/li&gt;    &lt;li&gt;Parę pomniejszych przeróbek&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ile z tego uda się wykonać przed rozpoczęciem kolejnego roku akademickiego – trudno rzec, bardziej to zależy od chęci do testowania. I od tego, ile jeszcze filmików na YouTube mnie zaciekawi.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-9102701900746627754?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/9102701900746627754/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=9102701900746627754' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/9102701900746627754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/9102701900746627754'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/08/overlaye-skonczone.html' title='Overlaye skończone'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_R2ix0MLn8lM/TGlKI8u5WHI/AAAAAAAAAfc/uSebuy2gG2c/s72-c/scr_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5126172727340403145</id><published>2010-08-03T20:32:00.002+02:00</published><updated>2010-08-03T20:34:17.087+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sport'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>Drzewka dzielone na osiem, OBeJoty oraz… Fantasy NFL</title><content type='html'>&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/TFhgt_V_mdI/AAAAAAAAAfA/dyQC7mXxJ08/s1600-h/screen%5B3%5D.png"&gt;&lt;img style="border: 0px none; margin: 0px 5px 0px 0px; display: inline;" title="screen" alt="screen" src="http://lh6.ggpht.com/_R2ix0MLn8lM/TFhgwYBwYoI/AAAAAAAAAfE/5jX1tDEzNKk/screen_thumb%5B1%5D.png?imgmax=800" align="left" border="0" width="244" height="184" /&gt;&lt;/a&gt; Dzisiaj troszkę nietypowa notka. Nie dlatego, że napisana po dłuższej nieobecności na blogu (bo to właściwie norma – niestety), ale dlatego, że lwią część notki nie zajmie nic związanego z działalnością developerską, ale z grami “przeglądarkowymi”, a konkretnie – &lt;a href="http://football.fantasysports.yahoo.com/"&gt;futbolową wersją Yahoo! Fantasy&lt;/a&gt;, dotyczącej ligi NFL i składem, którym spróbuję swoich sił w nadchodzącym sezonie. Przy okazji postaram się opisać co i jak w sposób bardzo prosty – być może kogoś uda się zachęcić chociażby do zainteresowania się tą niepopularną w Polsce dyscypliną (choć coś się zaczyna zmieniać w tej kwestii w naszym kraju).&lt;/p&gt;  &lt;p&gt;Zacznijmy jednak od spraw silnikowych.&lt;/p&gt;  &lt;p&gt;Siłą rzeczy, silnik graficzny powinien zapewniać, iż obiekty dodanie do sceny wyświetlają się poprawnie, podlegają zdefiniowanym efektom, ale przede wszystkim – są bardzo szybko renderowane. A przynajmniej na tyle szybko, na ile to możliwe. Oczywiście, w Scavie nie będzie aż tak szybko – to nie ta półka programistyczna. Tym niemniej, jeżeli przyjdzie silnikowi zmierzyć się z dość dużym obiektem (np. terenem wczytanym z pliku), programista jest w stanie zażyczyć sobie, aby taki czasonieumilacz był renderowany z użyciem drzewa ósemkowego, czyli trójwymiarowej struktury kostki, która rekurencyjnie dzieli się ciągle na osiem mniejszych kostek, dzieląc także wielokąty, z których składa się teren na mniejsze partie. Dzięki potrafimy odrzucić niewidoczne polygony i wyświetlać tylko część. Proste i wygodne, choć nie zaprzeczam, że nie wykorzystałem całego potencjału wykorzystania tego mechanizmu – drzewa ósemkowe są zakładane na obiekty, a nie na całą scenę, w wyniku czego każdy obiekt ma własne drzewo. Jest to o wiele prostsze implementacyjnie w moim przypadku, choć niekoniecznie dobre dla wydajności – widocznie trzeba będzie zrobić potężną refaktoryzację kodu. Jeżeli chodzi o kwestię techniczną – ponieważ zakładam, że nie tylko drzewo ósemkowe się przyda, mamy główną klasę bazową CPartitioningNode (reprezentującą jeden węzeł w takim drzewie), a z niej klasy pochodne COctreeNode (już jest), CLooseOctreeNode (&lt;a href="http://regedit.gamedev.pl/news_1024_swobodne_drzewo_osemkowe.html"&gt;co zaimplementował w swoim silniku Regedit&lt;/a&gt; (pozdrawiam)), CBSPNode i inne (miejmy nadzieję, że w przyszłości starczy mi sił na nie). &lt;/p&gt;  &lt;p&gt;Drugą rzeczą jest wczytywanie obiektów z plików zapisanych w popularnych formatach, jak na przykład OBJ. Tutaj kluczową kwestią okazało się to, żeby wczytywanie takiego modelu odbywało się swoim rytmem, ale dane tak naprawdę były zapisane w samym meshu, dzięki czemu na danym obiekcie można działać tak samo jak na wszystkich innych. Wydaje się to oczywiste i logiczne, ale w frameworku Yesta tak nie było (zresztą co tam było…), dlatego o tym wspominam. Co więcej, wczytanie pliku odbywa się za pomocą wywołania tej samej metody Import co zawsze, natomiast ważne jest rozszerzenie pliku, gdyż to na jego podstawie algorytm rozpoznaje, którego loadera ma użyć. W planach są oczywiście loadery innych formatów, jak na przykład md2, jednak tutaj pojawia się mały problem projektowy – co zrobić z animacją. Hmm, trzeba będzie znowu popisać sobie na kartce…&lt;/p&gt;  &lt;p&gt;Tak czy inaczej, prace idą spokojnym tempem, choć w ostatnim czasie odeszła mi chęć na kodowanie – ze znacznie większa efektywnością wróciłem do gry w Neverwinter Nights oraz Tony Hawk’s Pro Skater 4 – taki urok wakacji. &lt;/p&gt;  &lt;p&gt;W porządku, a teraz część eksperymentalna, czyli Yahoo! Fantasy Football Game. Generalnie większość ludzi gra w fantasy na &lt;a href="http://www.nfl.com/"&gt;NFL.com&lt;/a&gt;, gdyż na &lt;a href="http://www.yahoo.com/"&gt;Yahoo!&lt;/a&gt; sporo ludzi gra tylko do pewnego momentu, a potem zostawia drużynę samą sobie. Pomyślałem jednak, że prościej będzie zacząć od Yahoo!, zwłaszcza, że nie wiem czy mnie to pociągnie.&lt;/p&gt;  &lt;p&gt;Ale czym jest tak naprawdę to Fantasy Game? Jak wiemy, w Ameryce Północnej działa parę większych sportowych lig – NBA (moja ulubiona (ta pierwsza) i także zastanawiam się nad uczestnictwem Fantasy NBA, ale to wymaga o wiele więcej zaangażowania), NHL, NFL (czyli nasz przypadek), MLB, MLS i inne. Każdy uczestnik tworzy drużynę i czeka na przydział do ligi (chyba że zapisuje się do konkretnej prywatnej). W większości wypadków kulminacyjnym momentem sezonu (a zarazem pierwszym większym punktem) jest draft, w którym pobieramy zawodników do naszej drużyny – draftować można bezpośrednio (trzeba być obecnym przy komputerze w danej chwili, aby wybierać poszczególnych graczy) lub ustawić swój ranking i zdać się na AutoPick (opcja, którą wybrałem, komputer sam pobierze zawodników zgodnie z ich dostępnością i naszym ustalonym rankingiem). Później, jeżeli już mamy drużynę, czekamy na sezon (ten realny), na każdą kolejkę (w przypadku NFL, gdyż w przypadku NBA i NHL drużyny rozgrywają więcej meczów i dlatego wymagane jest większe zaangażowanie) ustawiamy skład z naszych zawodników (których możemy później wymieniać, wyrzucać, podpisać itd.) i modlimy się. W każdej kolejce gramy z innym uczestnikiem danej ligi i wygrywa ten, którego zawodnicy na prawdziwych boiskach uzyskają więcej punktów (według punktacji w danej lidze). Słowem – musimy wykazać się zmysłem menedżerskim i tak ustawić nasz skład, aby zawodnicy, których wybraliśmy, w realnej kolejce NFL zagrali jak najlepiej i dostarczyli nam jak najwięcej punktów. &lt;/p&gt;  &lt;p&gt;Jak widać, jest to świetna zabawa, choć zabiera sporo czasu (szczególnie w przypadku NBA, gdzie codziennie rozgrywane są mecze) i nerwów (gdy naszym graczom nie układa się rozgrywka). Jest to jednak raj dla managerów, którzy narzekają na brak adrenaliny.&lt;/p&gt;  &lt;p&gt;Jeżeli chodzi o zasady futbolu amerykańskiego – polecam parę linków:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.nfl.com/"&gt;Oficjalna strona NFL&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.pzfa.pl/"&gt;Strona Polskiego Związku Futbolu Amerykańskiego&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.nfl24.pl/news.php"&gt;Strona NFL24 (po polsku)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.vimeo.com/7989666"&gt;Filmik przedstawiający zasady tej dyscypliny&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://pl.wikipedia.org/wiki/Futbol_ameryka%C5%84ski"&gt;Odpowiednią stronę na Wikipedii&lt;/a&gt; oraz &lt;a href="http://pl.wikipedia.org/wiki/Kategoria:Futbol_ameryka%C5%84ski"&gt;całą kategorię&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Tutaj mała uwaga – pewnie w większości z Was ten sport kojarzy się z jajowatą piłką, potężnymi zawodnikami w zbrojach i hełmach, którzy nawalają się między sobą tworząc istny chaos na boisku, na którym w dodatku ktoś narysował dziwne linie co 10 jardów. Tak naprawdę futbol amerykański to piękny przykład na grę zespołową, gdzie każdy blok partnera z drużyny ma znaczenie, a taktyka musi zostać perfekcyjnie zrealizowana, aby zdobywać kolejne jardy oraz – co istotniejsze – touchdowny (przyłożenia) czy pozycje do rzutów wolnych. Tutaj nieważne jest to, że ktoś jest piekielnie szybki i zwrotny – bez wsparcia całego zespołu nic nie znaczy, gdyż pamiętajmy, że po drugiej stronie, w formacji defensywnej czekają już ludzie, którzy tylko czekają, aby dorwać zawodnika z piłką. Nie da się ukryć – to sport wybitnie kontaktowy (zresztą podobnie jak koszykówka, choć tam przynajmniej nikt specjalnie nie rzuca przeciwnikami o ziemię).&lt;/p&gt;  &lt;p&gt;W naszej grze Fantasy nie wybieramy całego składu, a jedynie 15 zawodników – &lt;a href="http://pl.wikipedia.org/wiki/Quarterback"&gt;quarterbacka&lt;/a&gt; (mózg formacji ofensywnej, podający piłkę do przodu, odpowiedzialny za przeprowadzenie całej umówionej zagrywki), dwóch &lt;a href="http://pl.wikipedia.org/wiki/Running_back"&gt;running backów&lt;/a&gt; (dostają piłkę niemal do rąk i biegną z nią do przodu omijając obronę i wykorzystując bloki partnerów), trzech &lt;a href="http://pl.wikipedia.org/wiki/Wide_receiver"&gt;wide receiverów&lt;/a&gt; (biegnący do przodu i łapiący piłki rzucane przez quarterbacka), &lt;a href="http://pl.wikipedia.org/wiki/Tight_end"&gt;tight enda&lt;/a&gt; (członek tzw. &lt;a href="http://pl.wikipedia.org/wiki/Offensive_line"&gt;linii ofensywnej&lt;/a&gt;, ale wyróżniający się tym, że może łapać piłki od quarterbacka), &lt;a href="http://pl.wikipedia.org/wiki/Placekicker"&gt;kickera&lt;/a&gt; (kopacz, jak nietrudno się domyślić, kopiący piłkę wznawiając grę oraz zdobywając punkty (tak, to on kopie pomiędzy te dwa wysokie słupki)), formacji defensywnej (tutaj traktowanej jako jeden zawodnik, wychodzi ona na boisko wtedy, kiedy atakuje przeciwnik) oraz pięciu zawodników na rezerwę. Oto krótki opis, tego, co mi się udało wydraftować w ciągu 15 rund na podstawie utworzonego wcześniej rankingu – troszkę naiwnego, ale zabawa to zabawa).&lt;/p&gt;  &lt;p&gt; Moim numerem jeden (5. w całym drafcie) okazał się &lt;a href="http://www.nfl.com/players/shonngreene/profile?id=GRE510029"&gt;Shonn Greene&lt;/a&gt; z New York Jets (180 cm/102 kg), drugoroczny running back, który co prawda jest bardzo ryzykownym wyborem, ale w Jets, którzy bardzo dużo biegają, powinien mieć świetny statystycznie sezon (a o to chodzi w Fantasy), mimo przyjścia do zespołu legendy, &lt;a href="http://www.nfl.com/players/ladainiantomlinson/profile?id=TOM683150"&gt;LaDainiana Tomlinsona&lt;/a&gt;. Greene w minionym sezonie w 108 próbach biegu osiągnął 540 jardów (5,0 na próbę), zdobywając dwa touchdowny (dobiegł z piłką do końcowej linii przeciwnika, co jest warte 6 punktów) i trzy razy tracąc piłkę (gdy stracił ją upadając). Świetnie zaprezentował się w playoffach, gdzie zaliczał ponad 100-jardowe występy. Niestety, nie udało się zdobyć ani rewelacyjnego &lt;a href="http://www.nfl.com/players/chrisjohnson/profile?id=JOH127799"&gt;Chrisa Johnsona&lt;/a&gt; ani równie dobrego &lt;a href="http://www.nfl.com/players/adrianpeterson/profile?id=PET260705"&gt;Adriana Petersona&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt; Na drugi ogień (16. w ogólności) nieoczekiwanie z rankingu wpisał się &lt;a href="http://www.nfl.com/players/milesaustin/profile?id=AUS467198"&gt;Miles Austin&lt;/a&gt;, wide receiver Dallas Cowboys (188 cm/97 kg), który też nieźle sobie poczynał w zeszłym sezonie – 81 odbiorów piłki, 1320 jardów (tu się wliczają zarówno jardy, które pokonała piłka przy podaniu do zawodnika jak i sam bieg z nią), 11 touchdownów. To wynik ukierunkowania zespołu z Dallas (i jego quarterbacka, &lt;a href="http://www.nfl.com/players/tonyromo/profile?id=ROM787981"&gt;Tony’ego Romo&lt;/a&gt;) na grę podaniami. Austin w końcu zaczął być głównym ogniwem zespołu. &lt;/p&gt;  &lt;p&gt; Trzecim w kolejności (25. w ogóle) stał się &lt;a href="http://www.nfl.com/players/mattschaub/profile?id=SCH085186"&gt;Matt Schaub&lt;/a&gt;, quarterback Houston Texans (196 cm/108 kg), na którego mocno liczę. Na tyle mu ufam, że nie jest mi tak bardzo żal tego, że nie udało się zdobyć &lt;a href="http://www.nfl.com/players/peytonmanning/profile?id=MAN515097"&gt;Peytona Manninga&lt;/a&gt; czy &lt;a href="http://www.nfl.com/players/drewbrees/profile?id=BRE229498"&gt;Drew Breesa&lt;/a&gt;. Schaub to MVP ostatniego Meczu Gwiazd (Pro Bowl) oraz lider paru statystyk w poprzednim sezonie. Zdobył 4770 jardów, 29 touchdownów (czyli 29 razy podał na touchdown) przy skuteczności podań 68%. Na nieszczęście, jego podania były przechwytywane 15 razy, a sam Matt był sackowany (powalany przed podaniem piłki) 25-krotnie, choć to akurat bardziej wina formacji ofensywnej Texans.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt; Czwarty (36.), &lt;a href="http://www.nfl.com/players/pierrethomas/profile?id=THO085535"&gt;Pierre Thomas&lt;/a&gt; z New Orleans Saints (180 cm/97 kg) to biegacz, którego pamiętam z finału Super Bowl wygranego przez Saints z bardzo ładnego przyłożenia bodajże na początku trzeciej kwarty. W Nowym Orleanie rywalizuje o pozycję running backa z &lt;a href="http://www.nfl.com/players/reggiebush/profile?id=BUS294963"&gt;Reggie Bushem&lt;/a&gt;, ale jednak wydaje się bardziej pewnym punktem zespołu. 793 jardy przy 147 próbach (średnia 5,4 jarda), 6 touchdownów biegowych, 2 touchdowny po podaniach (tak, biegacze też mogą łapać – Thomas z podań zdobył 302 jardów) i dwie straty (tzw. fumble). Statystycznie wydaje się lepszy od Greene’a, ale od tego ostatniego oczekuję znacznego postępu w drugim sezonie. &lt;/p&gt;  &lt;p&gt; Na piątej pozycji (45.) zameldował się ekscentryczny skrzydłowy Cincinatti Bengals, &lt;a href="http://www.nfl.com/players/chadochocinco/profile?id=JOH104425"&gt;Chad Ochocinco&lt;/a&gt; (186 cm/87 kg), który wraz z przybywającym do zespołu gwiazdorem &lt;a href="http://www.nfl.com/players/terrellowens/profile?id=OWE755129"&gt;Terrellem Owensem&lt;/a&gt; powinien stworzyć najlepszy duet skrzydłowych w NFL. Ciekawe tylko, czy uda się pogodzić w jednym teamie zawodników o tak mocnych charakterach (a jeszcze paru się w Cincinatti takich znajdzie). Jeżeli tak, to może być świetny sezon dla Bengals. Jego statystyki to 1047 jardy przy 72 odbiorach i 9 przyłożeń.&lt;/p&gt;  &lt;p&gt;Szósty z kolei (56.) to weteran na pozycji tight-enda – &lt;a href="http://www.nfl.com/players/tonygonzalez/profile?id=GON587645"&gt;Tony Gonzales&lt;/a&gt; z Atlanta Falcons (196 cm/109 kg). Nie udało się polowanie na &lt;a href="http://www.nfl.com/players/antoniogates/profile?id=GAT194627"&gt;Antonio Gatesa&lt;/a&gt; ani &lt;a href="http://www.nfl.com/players/dallasclark/profile?id=CLA236596"&gt;Dallasa Clarka&lt;/a&gt;, ale i tak jestem zadowolony z tego zawodnika. W minionym sezonie zdobył 867 jardy przy 83 odbiorach, notując także 6 przyłożeń. Wydaje się niewiele, ale kariera tego zawodnika była znacznie bogatsza, więc można spodziewać się solidnego poziomu (choć pewnie nie fajerwerków). &lt;/p&gt;  &lt;p&gt;Siódmy (a w ogólności 65.) pojawił się &lt;a href="http://www.nfl.com/players/dezbryant/profile?id=BRY336027"&gt;Dez Bryant&lt;/a&gt; z Dallas Cowboys (188 cm/98 kg), debiutant, który nie ma chyba nawet podpisanego kontraktu (może się mylę), ale powinien dać parę punktów, gdyż zapowiada się na całkiem dobrego skrzydłowego. Zwłaszcza, że w Dallas grają sporo podaniami, więc piłki starczy. W razie czego wstawi się na tę pozycję kogoś z rezerwowych, kto dostarczy więcej punktów.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Na ósmej pozycji (76.) pojawiła się w końcu formacja defensywna w postaci obrońców Philadelphii Eagles. Nie jest to może wymarzony wybór, ale mogłem trafić gorzej, a obrona Eagles jest jedną z lepszych w lidze (12. w poprzednim sezonie). Minimalnie lepiej bronią grę dołem (bieganie) aniżeli górą (podania). Do wyróżniających się zawodników z tej formacji należą: &lt;a href="http://www.nfl.com/players/trentcole/profile?id=COL192262"&gt;Trent Cole&lt;/a&gt; (prawy &lt;a href="http://pl.wikipedia.org/wiki/Defensive_line"&gt;defensive end&lt;/a&gt; – 191 cm/121 kg), &lt;a href="http://www.nfl.com/players/asantesamuel/profile?id=SAM616410"&gt;Asante Samuel&lt;/a&gt; (&lt;a href="http://pl.wikipedia.org/wiki/Cornerback"&gt;cornerback&lt;/a&gt; – 178 cm/83 kg) oraz &lt;a href="http://www.nfl.com/players/brodrickbunkley/profile?id=BUN459212"&gt;Brodrick Bunkley&lt;/a&gt; (defensive tackle – 188 cm/138 kg).&lt;/p&gt;  &lt;p&gt;Na dziewiątej pozycji (w ogólności 85.) pozwoliłem sobie na prywatę, a mianowicie najlepszego (moim skromnym zdaniem), a przynajmniej najsilniejszego kopacza w NFL, a przy okazji najlepiej opłacanego, czyli (tadam) &lt;a href="http://www.nfl.com/players/sebastianjanikowski/profile?id=JAN400354"&gt;Sebastiana Janikowskiego&lt;/a&gt; z Oakland Raiders (188 cm/112 kg). Kopacz z Wałbrzycha w zeszłym sezonie trafił z odległości 61 jardów (1 jard = 0,91 m), co jest bodajże czwartym najlepszym rezultatem w historii ligi. Bardzo silne kopnięcie powiązane jest z dość dobrą skutecznością (89,7%) oraz honorowym miejscem najlepiej punktującego zawodnika  historii klubu z Oakland.&lt;/p&gt;  &lt;p&gt;Następnie mamy graczy rezerwowych, dlatego tylko ich wymienię (być może z krótkim opisem).&lt;/p&gt;  &lt;p&gt;10. (96.) &lt;a href="http://www.nfl.com/players/elimanning/profile?id=MAN473170"&gt;Eli Manning&lt;/a&gt;, quarterback New York Giants (brat Peytona – 193 cm/101 kg), 4021 jardów, 62,3% skuteczności, 27 touchdownów, 14 przechwytów, 30 sacków.&lt;/p&gt;  &lt;p&gt;11. (105.) &lt;a href="http://www.nfl.com/players/marionbarber/profile?id=BAR059695"&gt;Marion Barber&lt;/a&gt;, running back Dallas Cowboys (180 cm/98 kg), 214 prób, 932 jardy (średnia 4,4), 7 przyłożeń, dwie straty.&lt;/p&gt;  &lt;p&gt;12. (116.) &lt;a href="http://www.nfl.com/players/johnnyknox/profile?id=KNO571695"&gt;Johnny Knox&lt;/a&gt;, wide receiver Chicago Bears (183 cm/83 kg), 45 odbiorów, 527 jardów, 5 przyłożeń. Rozwija się, to drugoroczniak, podobnie jak Greene.&lt;/p&gt;  &lt;p&gt;13. (125.) &lt;a href="http://www.nfl.com/players/santonioholmes/profile?id=HOL657297"&gt;Santonio Holmes&lt;/a&gt;, wide receiver New York Jets (180 cm/86 kg), 79 odbiorów, 1248 jardów, 5 przyłożeń (kandydat do zastąpienia Bryanta w pierwszym składzie).&lt;/p&gt;  &lt;p&gt;14. (136.) Formacja defensywna Dallas Cowboys, 9. miejsce w poprzednim sezonie (prawdopodobnie lepiej na tym wyszedłem aniżeli na Eagles, choć to wybitnie zależy od przeciwnika), zdecydowanie lepiej bronią akcje biegowe niż podania. Najbardziej znani zawodnicy to &lt;a href="http://pl.wikipedia.org/wiki/Linebacker"&gt;linebacker&lt;/a&gt; &lt;a href="http://www.nfl.com/players/demarcusware/profile?id=WAR350675"&gt;DeMarcus Ware&lt;/a&gt; (dla niego tę formację chciałem zdobyć – jeden z najlepszych defensorów w lidze, 193 cm/118 kg), nose tackle (masywny gracz na środku trzyosobowej wersji linii defensywnej) &lt;a href="http://www.nfl.com/players/jayratliff/profile?id=RAT586227"&gt;Jay Ratliff&lt;/a&gt; (193 cm/136 kg) i cornerback &lt;a href="http://www.nfl.com/players/terencenewman/profile?id=NEW475575"&gt;Terence Newman&lt;/a&gt; (178 cm/87 kg).&lt;/p&gt;  &lt;p&gt;15. (145.) &lt;a href="http://www.nfl.com/players/anthonyfasano/profile?id=FAS072076"&gt;Anthony Fasano&lt;/a&gt;, tight-end Miami Dolphins (193 cm/115 kg), 31 złapanych piłek, 339 jardów, 2 przyłożenia.&lt;/p&gt;  &lt;p&gt;Cóż, automat tak mi wybrał (choć według moich zaleceń) i mogę jedynie naprawić coś poprzez wymiany i podpisanie wolnych agentów. Czasu mam jednak co niemiara, bo do 9. września, kiedy zaczyna się nowy sezon – do tego czasu mogę spokojnie się zastanowić nad wszystkim. Jeżeli kogoś zanudził ten fragment o futbolu amerykańskich, to gorąco przepraszam. To była pierwsza taka notka, pewnie nieostatnia, ale na pewno będzie ich bardzo mało (chyba, że sobie życzycie więcej). Nadal jest to w końcu devblog.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5126172727340403145?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5126172727340403145/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5126172727340403145' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5126172727340403145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5126172727340403145'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/08/drzewka-dzielone-na-osiem-obejoty-oraz.html' title='Drzewka dzielone na osiem, OBeJoty oraz… Fantasy NFL'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_R2ix0MLn8lM/TFhgwYBwYoI/AAAAAAAAAfE/5jX1tDEzNKk/s72-c/screen_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-4731126457396335356</id><published>2010-07-19T21:49:00.002+02:00</published><updated>2010-07-19T21:50:04.107+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Jedna metoda i wszystko oświetlone – już dziś w Twoim silniku</title><content type='html'>&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/TESsJeG2V4I/AAAAAAAAAe4/W6WLt1Q-8jI/s1600-h/scr0003.png"&gt;&lt;img style="border-width: 0px; margin: 0px 5px 0px 0px; display: inline;" title="scr000" alt="scr000" src="http://lh6.ggpht.com/_R2ix0MLn8lM/TESsLn3P9VI/AAAAAAAAAe8/zBnluDvUKXU/scr000_thumb1.png?imgmax=800" align="left" border="0" width="244" height="191" /&gt;&lt;/a&gt; Sporo czasu minęło od notki związanej z połączeniem materiałów z meshami, ale nie był to czas do końca stracony (choć mamy wakacje). Od około tygodnia (a może i nawet dłużej) męczyłem bowiem się z ładnym modułem oświetlenia w Scavie, który:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jest implementacją oświetlenia per fragment (plus pewne dodatki, których na razie nie ma) &lt;/li&gt;    &lt;li&gt;W prosty sposób umożliwia dodawanie źródeł światła na scenę &lt;/li&gt;    &lt;li&gt;Dokładniej – w taki, żebym nie zapomniał jak to się robi &lt;/li&gt;    &lt;li&gt;Źródeł światła może być tyle, na ile pozwala dana technologia oraz możliwości komputera (domyślnie – nieskończenie wiele) &lt;/li&gt;    &lt;li&gt;W jednym momencie scena może być oświetlana zarówno przez światła punktowe, kierunkowe jak i stożkowe &lt;/li&gt;    &lt;li&gt;Ma to po prostu działać &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Dziwnym trafem udało się te postulaty zrealizować. Ale nie powiem, żeby było to strasznie proste, chociażby z tego względu, że trzeba było dopisać mnóstwo kodu, a poza tym klasa managera sceny nie wygląda już tak klarownie, gdyż pojawiły się odwołania do parametrów shadera (napisanego w języku Cg). &lt;/p&gt;  &lt;p&gt;Zacznijmy może od górnej warstwy kodu, czyli tzw. klas pomocniczych.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Klasa CShader&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Jak się można domyślać, niezbędne stało się stworzenie jakiegoś interfejsu, który umożliwiałby łatwiejsze posługiwanie się shaderami. Poza tym, była też osobista motywacja – we frameworku Yesta nie było to do końca przemyślane (jak większość zresztą) i każda klasa, która miała do czynienia z programami na GPU (na przykład oświetlenie, niebo, trawa, woda) same sobie implementowały wszystkie metody i je powtarzały z nieznacznymi modyfikacjami. Dlatego niemal od razu zdecydowałem się zadbać o odpowiednie mechanizmy rządzące shaderami, stąd też mamy klasę CShader (klasa abstrakcyjna) oraz jej dwie pochodne – CShaderCg (dla shaderów napisanych w języku Cg) oraz nieco mniej rozbudowaną CShaderGLSL (analogicznie dla GLSL-a – mniej rozbudowaną, gdyż rzadziej korzystam z GLSL-a, zatem to raczej kwestia czasu). Co istotne, klasy dają się w prosty sposób rozszerzać (inaczej – komplikować implementację) poprzez kolejne funkcje, które jedynie ułatwiają dalsze pisanie kodu i hermetyzację (wraz z hasłem “niech żyje obiektowość, oj oj”).&lt;/p&gt;  &lt;p&gt;Każdy obiekt shadera to tak naprawdę kontekst wraz z programami cieniującymi wierzchołki oraz fragmenty (póki co nie interesowałem się shaderami geometrii). Tutaj warto wspomnieć, że ktoś, kto chce sam manipulować shaderami, musi pamiętać o odpowiednich inicjalizacjach czy ręcznych kompilacjach (jeśli takie sobie ustawi). Na szczęście (dla mnie), domyślnie jest wszystko ustawiane automatycznie, a jedynie w specjalnym przypadku (który oczywiście dotyczył mnie w sprawie dynamicznych tablic) trzeba samemu specjalnie poustawiać. Tym niemniej, jest to możliwe. Wszystkie parametry podzielone są na: parametry najzwyklejsze, parametry macierzowe oraz parametry teksturowe. Wszystkie te rodzaje są w osobnym mapach, które ułatwiają wstawianie (klucz, pod jakim wstawiamy jest taki sam jak nazwa parametru w shaderze) oraz wyszukiwanie. Także shadery mamy załatwione.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Klasa CLight&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Z drugiej strony musimy pamiętać, iż czeka nas konfrontacja ze światłem. Nie polega to bynajmniej na obsłudze i liczeniu długości tuneli, w których znajdziemy to światełko ani liczeniu zużycia świeczki, ale musimy skupić się na (niespodzianka) prawdziwych źródłach światła. Podobnie jak w przypadku CShader, mamy tutaj do czynienia z jedną klasą abstrakcyjną (CLight) oraz pochodnymi: CPointLight (światło punktowe – umiejscowione w jednym miejscu i świecące we wszystkich kierunkach (przykład – pochodnia w Wielkim Mistrzu)), CSpotlight (światło stożkowe, pochodne z CPointLight, świecące w dodatku w jednym konkretnym kierunku (przykład – latarka, której nie da się wymacać w ciemnym pomieszczeniu)) oraz CDirectionalLight (światło kierunkowe – nieskończenie oddalone, oświetlające równomiernie w zadanym kierunku (przykład – &lt;a href="http://www.rodzynki.net/4724/Anal-%28analiza-matematyczna%29-z-dr-G."&gt;Księżyc, który jest bardziej potrzebny od Słońca&lt;/a&gt;)). Każdy rodzaj światła ma własne parametry, które mogą być ustawiane oraz pobierane i właściwie to wszystko – CLight z dziećmi nie są zbyt inteligentnymi stworzeniami. Zastosowałem jednak jeszcze jeden mały trik (który jest pewnie każdemu znany), a mianowicie każda klasa pochodna reprezentuje pewną odmianę zwykłego światła (w tym przypadku światła, w innym shadera, efektu czy nutrii), zatem ma swój typ, który można pobrać za pomocą GetType. W czym to nam pomaga? Otóż, nasze światełka będą przechowywane w mapie &amp;lt;std::string, CLight*&amp;gt;. Sprecyzuję – wszystkie nasze światełka, niezależnie, jakiego typu są. Czasami jednak musimy dojść do tego, do czego przypisać dany obiekt i owszem, można próbować Cudów Na Kiju (CNK) z sizeof czy innymi zabawkami, ale prościej po prostu pamiętać tę informację w każdym obiekcie i sprawdzić, że “oho – obiekt zapisany pod kluczem “flashlight” ma typ LT_SPOTLIGHT, więc jest światłem stożkowym. A do czego nam to będzie potrzebne – napiszę dalej.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Klasa CEffect&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Pozostała jeszcze jedna cegiełka w naszej drabince (a nie, to szczebelek, a nie cegiełka). Trzeba przyznać, że głupio byłoby nakazać programiście samemu zarządzać shaderem w sytuacji, gdy moduł oświetlenia ma działać niemalże automatycznie i niezauważalnie (oprócz oczywiście samego rezultatu działania światła). Dlatego też powstał typ obiektów, które są pośrednikami pomiędzy zleceniodawcą a shaderem, trzymają większość potrzebnych informacji i ogólnie sprawiają dobre reprezentacyjne wrażenie – są to twory nazwane przeze mnie efektami (nie mylić z plikami efektów .fx i podobnymi). Z założenia klasa CEffect – podobnie jak wcześniej to było z CShader oraz CLight – będzie miała swoje dzieci, które będą tymi właściwymi efektami. Póki co jest tylko CLightingEffect, który jest klasą oświetlenia i tak naprawdę jest obiektem Standardowego Modułu Oświetlenia (SMO – w innych kręgach System Masowej Obsługi). To właśnie ten obiekt zawiera w sobie mapę świateł, udostępnia obiekt shadera, ale tak prawdę mówiąc – w przypadku samego modułu prawie całość operacji przypada na manager sceny, gdyż to on zawiera szczegółowe informacje gdzie czego użyć. Fakt, wygląda to trochę jak pomieszanie country z metalem (nierdzewnym) i być może będzie trzeba to zmienić, gdyż w CSceneManager zrobił się mały bałagan. Czyżby kolejna klasa pochodna tylko-dla-SMO (mamy oświetlenie, które sobie sam może zdefiniować użytkownik, ale także SMO zarządzane przez sam silnik)? W sumie nie jest to nawet takie głupie…&lt;/p&gt;  &lt;p&gt;Widzicie jaką inspiracją jest pisanie notek na devbloga?&lt;/p&gt;  &lt;p&gt;Teraz słowo o tym jak to tak naprawdę przebiega. Domyślnie nie ma żadnego oświetlenia, jednak większość będzie chciała dodać takowe na własną scenę. Załóżmy, że jest to zwykłe, białe światło punktowe bez skomplikowanego równania tłumienia i umieszczone na pozycji (0, 0, 0). Zatem tadam:&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;GetSceneManager().AddLight(“punkcik1”, LT_POINT);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;I to wystarczy – od tej pory SMO już wie, że jest jakieś światło i trzeba odkurzyć program shadera. Jak widać, całość została osadzona w managerze sceny – oświetlenie tyczy się całej sceny, więc uznałem, że tak jest miejsce SMO. W dodatku są parametry, które nie wchodzą w skład efektu – mam na myśli kolor światła otaczającego oraz pozycję oka kamery. Jednak głównym składnikiem oświetlenia są oczywiście źródła światła, zatem dodanie choćby jednego uruchamia całą lawinę związaną z generacją efektu i inicjalizacją shadera. Finał tej zabawy odbywa się w momencie pierwszego renderowania sceny (niestety, założyłem póki co, że wszystkie światła są znane od początku), gdzie shadery są kompilowane… A właśnie – kompilacja. Wspominałem o tym, że zostało umożliwione kompilowanie shaderów ręcznie (w skrócie – wrapper na funkcję &lt;a href="http://transit.iut2.upmf-grenoble.fr/cgi-bin/man/man2html?query=cgSetAutoCompile"&gt;cgSetAutoCompile&lt;/a&gt;) i to z bardzo konkretnego powodu. Jedno z założeń mówi “Źródeł światła może być tyle, na ile pozwala dana technologia oraz możliwości komputera (domyślnie – nieskończenie wiele) “. Oznacza to również, iż shader nie ma sztywnej wielkości tablicy świateł – należy ją ustalić w locie. Wcześniej nawet nie wiedziałem, że takie coś jest możliwe, ale nawet się uśmiechnąłem (a to się rzadko zdarza, wierzcie mi), jak przeczytałem w dokumentacji o &lt;a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch32.html"&gt;“unsized arrays” (pod linkiem w przykładzie 32-3)&lt;/a&gt;. Oczywiście, okazało się, że tak prosto nie będzie – materiały w sieci nie są zbyt bogate i po wielu bezowocnych próbach udało mi się w końcu doprowadzić proces runtime’u do stanu używalności (pamiętajcie, najpierw inicjalizacja wielkości tablic, potem inicjalizacja elementów tablicy, a dopiero na końcu kompilacja). Tak czy inaczej, w końcu się jednak udało i pod tym względem shader (prawie 200-linijkowy) zyskał na uniwersalności. &lt;/p&gt;  &lt;p&gt;Chciałem również umożliwić inną rzecz – osobne shadery/efekty dla poszczególnych meshów. Istnieje bowiem możliwość chwilowego zastąpienia głównego shadera sceny shaderem konkretnym dla danego obiektu, który działa tylko dla niego.&lt;/p&gt;  &lt;p&gt;Podsumowując – zagadnienie SMO niewątpliwie ciekawe i bardzo nerwowe (zarówno pozytywnie ('”ojej, uda się”) jak i negatywnie (“no ja łapię nogi motyli!”)), ale niewątpliwie wprowadził nieco zamieszania do kodu managera łamiąc parę punktów zasad obiektowości. Czy uda się to jakoś okiełznać? Czy zostaną wprowadzone nowe modyfikacje? Czy Rysiek z Klanu będzie umiał napisać cRPG-a opierając się na Scavie? O tym w następnych odcinkach cyklu “Jak nie robić silnika”.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-4731126457396335356?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/4731126457396335356/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=4731126457396335356' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/4731126457396335356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/4731126457396335356'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/07/jedna-metoda-i-wszystko-oswietlone-juz.html' title='Jedna metoda i wszystko oświetlone – już dziś w Twoim silniku'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_R2ix0MLn8lM/TESsLn3P9VI/AAAAAAAAAe8/zBnluDvUKXU/s72-c/scr000_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2797257338447345297</id><published>2010-07-13T19:35:00.002+02:00</published><updated>2010-07-13T19:38:32.522+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Programowanie niskopoziomowe'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Programowania na kolanach część druga</title><content type='html'>&lt;p&gt;&lt;a href="http://pseudodev.blogspot.com/2010/07/programowania-na-kolanach-czesc.html"&gt;Powiedziało się A&lt;/a&gt;, wypada powiedzieć B. Zatem, bez zbędnych &lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/TDyj46fnDCI/AAAAAAAAAew/kP2qztf88XM/s1600-h/atmega8l1%5B2%5D.png"&gt;&lt;img style="border: 0px none; margin: 0px 5px 0px 0px; display: inline;" title="atmega8l1" alt="atmega8l1" src="http://lh6.ggpht.com/_R2ix0MLn8lM/TDyj5wBe67I/AAAAAAAAAe0/_w3nJdzK99w/atmega8l1_thumb%5B2%5D.png?imgmax=800" align="right" border="0" width="276" height="244" /&gt;&lt;/a&gt; ceregieli, przejdźmy do tematu, którym jest “jak zaprogramować mikrokontroler, aby robot jeździł”. Była to druga część naszego zadania projektowego i okazała się troszkę łatwiejsza od pierwszej. Może dlatego, że z góry wie się, z czym ma się do czynienia, program jest krótszy, a sprzęt już działający.&lt;/p&gt;  &lt;p&gt;W bardzo wielkim uproszczeniu &lt;a href="http://pl.wikipedia.org/wiki/Mikrokontroler"&gt;mikrokontroler&lt;/a&gt; to bardzo mały prymitywny komputerek, który możemy zainstalować dowolnemu urządzeniu na grzbiecie i go zaprogramować (tzn. mikrokontroler, a nie grzbiet). Jak nietrudno się domyślić, to właśnie będzie robili z naszym pojazdem.  A raczej starali się zrobić.&lt;/p&gt;  &lt;p&gt;Pozwolę sobie pominąć część techniczną-sprzętowo – z elektroniki reprezentuję poziom kreta na Żuławach, więc mogę tylko polecić &lt;a href="http://www.kursc.dioda.com.pl/str001.html"&gt;bardzo dobry kurs&lt;/a&gt;, według którego zresztą wszystko zostało u nas przygotowane (i do przeczytania którego gorąco Was zachęcam, chociażby tej pierwszej części). Program, który będziemy obsługiwać (a którego opis również znajduje się w wyżej wymienionym kursie) to &lt;a href="http://winavr.sourceforge.net/"&gt;WinAVR&lt;/a&gt;, który okazał sie bardzo sympatyczny w działaniu (dobre wychowanie i te sprawy – zawsze kompilował). Jeżeli chodzi o sam mikrokontroler, to z tym był nielichy problem – wszyscy koniecznie chcieli skorzystać z ATMega8, ze względu na dostępność tutoriali i prostotę programowania, ale niestety, sklepy poznańskie nie przewidziały nagłego tłumu żądnych sprzętu studentów. Jednak na całe szczęście naszą grupę uratował kolega (dzięki Ci, Arturze), który przyniósł własny mikrokontroler &lt;a href="http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf"&gt;ATMega8L&lt;/a&gt;. Tak naprawdę, różnica jest minimalna i program powinien działać na większości mikrokontrolerów (choć nie bierzcie tego tak strasznie poważnie – w linkerze idzie wiele rzeczy skonfigurować, stąd to wnioskuję).&lt;/p&gt;  &lt;p&gt;Jeszcze jedna uwaga na początek – nie pamiętam, czy było o tym wspomniane w pierwszej części, ale tam korzystaliśmy z dobrodziejstw logiki ujemnej (w uproszczeniu – sygnał zerowy był traktowany jako “prawda”). Tym razem jednak będziemy się bawić zwykłą logiką dodatnią (sygnał “jeden” to “prawda”), co właściwie zmienia tylko pozycjonowanie wykrzykników w instrukcjach warunkowych.&lt;/p&gt;  &lt;p&gt;Zacznijmy zatem naszą krótką opowieść (krótką, ponieważ kodu będzie dużo mniej niż poprzednio, a poza tym – o zgrozo! – zadam Wam zadanie domowe).&lt;/p&gt;  &lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;   &lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;     &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; F_CPU 1000000L&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; #include &amp;lt;avr/io.h&amp;gt; &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; #include &amp;lt;avr/interrupt.h&amp;gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt; #include &amp;lt;util/delay.h&amp;gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LEFT_SENSOR        PD3&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; RIGHT_SENSOR    PD2&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; STOP            0x0a&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; UP                0x3a&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LEFT            0x2a&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; RIGHT            0x1a&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; SENSORS_SOURCE  PIND&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; ENGINE_CONTROL     PORTC&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Zatem mamy definicje. Jeżeli chodzi o makra – tego nie będę tłumaczył, gdyż było to już wyszczególnione poprzednio (z tym, że w logice ujemnej), jedynie wspomnę o F_CPU. Jak widzicie, definicja ta znajduje się przed instrukcjami dołączenia plików nagłówkowych i to w istocie jest wymuszone – F_CPU bowiem mówi mikrokontrolerowi o odstępie, co jest niezmierne ważne w przypadku stosowania funkcji sleep i podobnych. Nie chcemy bowiem, aby to, co według nas ma trwać 0,5 sekundy trwało 30 minut i w dodatku nie zadziałało.&lt;/p&gt;&lt;p&gt;Widzimy także SENSORS_SOURCE oraz ENGINE_CONTROL. PIND oraz PORTC do zdefiniowane już dla mikrokontrolerów AVR makra do portów tego układu. Z tym, że PIN oznacza tylko wejście, a PORT to po prostu cały port. Od sensorów potrzebujemy tylko dane wejściowe na port D, dlatego piszemy PIND.&lt;/p&gt;&lt;p&gt;Każdy program jest niepowtarzalny, jednak większość aplikacji napisanych w języku C cechuje jedna rzecz – funkcja main.&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; main()&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     DDRD &amp;amp;= ~_BV(PD2); &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;     DDRD &amp;amp;= ~_BV(PD3);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;     PORTD |= _BV(PD2); &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;     PORTD |= _BV(PD3); &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;     DDRC = 0xFF;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;     GICR |= _BV(INT0);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;     GICR |= _BV(INT1);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;     MCUCR |= _BV(ISC10);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;     MCUCR |= _BV(ISC00);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;     _delay_ms(1000);&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;     sei();&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;     ENGINE_CONTROL = UP;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// Pusta Wieczna Pętla (w skrócie PWP)&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;while&lt;/span&gt; (1)&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;        &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Widzimy tu znowu dużo makr i pełno operatorów logicznych, co w sumie jest uzasadnione, gdyż do tego sprowadza się zabawa na tak niskim poziomie. Jeżeli spojrzycie na schemat z drugiej strony dokumentacji bądź po prostu na obrazek na początku notki, to zauważycie, że wejścia przerwań INTO oraz INT1, które będziemy wykorzystywać, znajdują się na bitach 2. i 3. portu D. W rejestrze DDRD podajemy zatem 0 na odpowiednie pozycje (właśnie na bity 2. i 3.) co oznacza, że będą to wejścia, a nie wyjścia. Co ciekawe jednak, na całym PORTD znowu ustawiamy bity 2. i 3. – jest to tak zwane &lt;a href="http://pl.wikipedia.org/wiki/Pull-up"&gt;pull-up&lt;/a&gt; i jest sprawą czysto elektroniczną – nie wiem, ja tu tylko programuję. Siłą rzeczy, jeżeli chcemy, aby port C pracował jako wyjście, na DDRC ustawiamy jedynki.&lt;/p&gt;&lt;p&gt;Teraz przeanalizujmy w ogóle co chcemy zrobić. Oczywiście, moglibyśmy w wiecznej pętli sprawdzać stan naszych czujników i odpowiednio reagować silnikami, ale to byłoby za proste, mało profesjonalne i w ogóle be. Zamiast tego oczywiście skomplikujemy sobie życie i zastosujemy przerwania. W ATMega8L, jak już wspomniałem, mamy dwa wejścia na przerwania zewnętrzne – INT0 i INT1. Tak ciekawie się składa, że liczba naszych czujników niuchających trasę również wynosi 2, zatem prostą logiczną konkluzją jest przypisanie jednego czujnika do jednego źródła przerwań i drugiego do drugiego. Co więcej, nasz mikrokontroler umożliwia zastosowanie takiego mechanizmu, że przerwanie wywołuje się nie tylko, gdy stan zmieni się z o na 1, ale przy każdej zmianie stanu logicznego na wejściu (czyli zarówno z 0 na 1, jak i z 1 na 0). To czyni nas Panami Kabelków i zaraz urzeczywistnimy nasz plan.&lt;/p&gt;&lt;p&gt;Rejestr GICR właśnie odmaskowuje nam nasze przerwania, a MCUCR pozwala wskazać nam, że dowolna zmiana stanu logicznego wywołuje przerwania. Co do MCUCR – polecam zajrzeć do dokumentacji, gdyż tam jest dużo więcej możliwości konfiguracyjnych. Następnie czekamy sekundę (właśnie po to było nam potrzebne F_CPU), aby odsunąć się od maszyny, włączamy za pomocą sei cały system przerwań, a silniki przez port C dostają informacje “gaz do dechy”. Teraz następuje urocze zjawisko, które nazywa się Pustą Wieczną Pętlą, z której nijak nie idzie wyjść nie odłączając zasilania. Tym niemniej, o to właśnie nam chodzi – mikrokontroler ma cały czas sterować silnikami, więc program cały czas musi działać i przyjmować przerwania w międzyczasie. &lt;/p&gt;&lt;p&gt;No dobrze, zatem nasz program może przyjmować przerwania i coś z nimi zrobić. Pytanie – co?&lt;/p&gt;&lt;p&gt;Jak się nietrudno domyślić, obsługa przerwania będzie polegała na jednokrotnym (to jest ważne – jednokrotnym, gdyż przerwania i tak będą się wywołać przy jakiejkolwiek zmianie stanu) sprawdzeniu stanu czujników i odpowiednio dyrygować silnikiem. Sama konstrukcja obsługi przerwań jest z góry narzucona i wygląda to tak:&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; ISR(INT0_vect)&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// Dalej, dalej, ręko Gadżeta!&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; ISR(INT1_vect)&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// A to Ci SceNtriC wredny&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;ISR(INTX_vect) to nagłówek funkcji, będącej obsługą przerwania przerwania dochodzącego do INTX, gdzie X należy do zbioru {0, 1}. Dlaczego jednak te funkcje są puste? Ano właśnie – to jest to zadanie domowe. Tak naprawdę, w każdej z tych funkcji będzie taka sama instrukcja warunkowa z czterema ifami-elsami (to ze Wschodu) sprawdzająca stan czujników. Pamiętając o tym, że tym razem logika jest dodatnia, zajrzyjcie do &lt;a href="http://pseudodev.blogspot.com/2010/07/programowania-na-kolanach-czesc.html"&gt;poprzedniego odcinka naszego kursu satyrycznego&lt;/a&gt; i postarajcie się sami napisać obsługę przerwań.&lt;/p&gt;&lt;p&gt;Cóż, to właściwie tyle, co chciałem Wam przekazać. Temat programowania takich urządzeń jak chociażby mikrokontrolery jest bardzo rozległy i nieco zagmatwany. Przyznaję uczciwie – całkowicie wolę C++ i problemy obiektowości, choć takiego Assemblera czy niskie C wspominam również miło ze względu na to, że człowiek autentycznie się cieszy, gdy mały robot robi to, co trzeba. I chociażby do takich zabaw zachęcam – wyobraźcie sobie robota kroczącego z dwunastoma nogami, gdzie każda ma swój mikrokontroler, a wszystkie są podległe &lt;a href="http://pl.wikipedia.org/wiki/Jedyny_Pier%C5%9Bcie%C5%84"&gt;Jednemu, By Wszystkimi Rządzić&lt;/a&gt;. Teraz nie dość, że trzeba je zaprogramować, to jeszcze zsynchronizować. Fascynujące. Choć ja chyba wolę mój mały skromny silniczek, w którym męczę się nad zaprojektowaniem oświetlenia, aby było wygodne i uniwersalne.&lt;/p&gt;&lt;p&gt;Pozdrawiam, dziękuję i zachęcam do komentarzy. Jeżeli również tutaj ktoś uważa, że te kody absolutnie nie powinny się pojawić, proszę śmiało dać znać na maila – SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2797257338447345297?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2797257338447345297/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2797257338447345297' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2797257338447345297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2797257338447345297'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/07/programowania-na-kolanach-czesc-druga.html' title='Programowania na kolanach część druga'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_R2ix0MLn8lM/TDyj5wBe67I/AAAAAAAAAe0/_w3nJdzK99w/s72-c/atmega8l1_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-1016085259163352574</id><published>2010-07-10T16:03:00.002+02:00</published><updated>2010-07-10T16:06:28.761+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Projektowanie'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>Materiały osadzone na meshach</title><content type='html'>&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/TDh9slAAUOI/AAAAAAAAAeg/043N7fxPhKU/s1600-h/scav13.png"&gt;&lt;img style="border-width: 0px; margin: 0px 5px 0px 0px; display: inline;" title="scav1" alt="scav1" src="http://lh5.ggpht.com/_R2ix0MLn8lM/TDh9tWrniPI/AAAAAAAAAek/DhhnKAsxcL0/scav1_thumb1.png?imgmax=800" width="244" align="left" border="0" height="191" /&gt;&lt;/a&gt; Wspominałem parę dni temu o tym, że stworzenie systemu materiałów i światła będzie dla mnie czymś nowym – nigdy przedtem nie projektowałem takiego mechanizmu (zawsze wystarczało mi to, co standardowo było oferowane) i tak naprawdę (tak, wiem, wstyd się przyznawać) nigdy nie zastanawiałem się “po co jest taki parametr i dlaczego”. A teraz już wiem.&lt;/p&gt;  &lt;p&gt;Tak poważnie, to ważnym problemem było po prostu zdefiniowanie parametrów, jakie wchodzą w skład materiału. To akurat nie było specjalnie skomplikowane – otworzyłem przykłady dotyczące Cg, zobaczyłem, co jest przydatne, zebrałem, pogrupowałem, pomyślałem (tak, nowość) i uznałem, że i tak pewnie potem będę dodawał nowe parametry (co ma być w miarę elastyczne, zgodnie z ideą obiektowości [co i tak do końca nie wyszło]), więc nic nie szkodzi.&lt;/p&gt;  &lt;p&gt;Jakie założenia przyjąłem odnośnie materiałoznawstwa w Scavie?&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/TDh9u0FaBUI/AAAAAAAAAeo/6K8PhKTfWHk/s1600-h/8f_0113.jpg"&gt;&lt;img style="border-width: 0px; margin: 0px 0px 0px 5px; display: inline;" title="8f_011" alt="8f_011" src="http://lh3.ggpht.com/_R2ix0MLn8lM/TDh9v_K_III/AAAAAAAAAes/Qy4G04Ie7x0/8f_011_thumb1.jpg?imgmax=800" width="244" align="right" border="0" height="184" /&gt;&lt;/a&gt; Postudiowałem trochę &lt;a href="http://www.google.pl/url?sa=t&amp;amp;source=web&amp;amp;ct=res&amp;amp;cd=2&amp;amp;ved=0CCAQFjAB&amp;amp;url=http%3A%2F%2Fdeveloper.nvidia.com%2Fobject%2Fcg_tutorial_home.html&amp;amp;ei=o3I4TPGSH8LgOJDjyIoK&amp;amp;usg=AFQjCNFfXeqe57TWab9n3l__2ZFhUp1ifQ"&gt;książkę o Cg&lt;/a&gt;, &lt;a href="http://regedit.gamedev.pl/Download/Productions/Adam%20Sawicki%20-%20Praca%20mgr.pdf"&gt;pracę magisterską Regedita&lt;/a&gt; (pozdrawiam), &lt;a href="http://pl.wikibooks.org/wiki/OGRE/Kamera,_%C5%9Bwiat%C5%82a_i_cienie"&gt;tutoriale Ogre’a&lt;/a&gt; (choć tutaj bardziej już o światło zahaczałem), powypytywałem mojego glonojada (gdzieś tu obok się kręci – nie był zbyt zainteresowany rozmową) i o to, co mi wyszło.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jeden obiekt w grze (mesh) może mieć przypisanych więcej niż jeden materiał &lt;/li&gt;    &lt;li&gt;Jeden materiał oznacza jedną teksturę wraz z przyległościami (reakcja na odpowiednie światło, zdolność do odbijania itd.) &lt;/li&gt;    &lt;li&gt;Programista korzystający z silnika nie może aż tak bardzo przejmować się tym, jak zarządzane są materiały wewnątrz mesha (choć oczywiście powinien mieć możliwość przypisania “tak, chcę aby ta część miała taki materiał”) &lt;/li&gt;    &lt;li&gt;Obsługa materiałów powinna być prosta – jako wzór powinna służyć struktura pliku OBJ (po nazwie materiału wszystkie dane korzystają właśnie z tego materiału)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;W sumie to tyle. Jak widać, idea szczytna (i dosyć standardowa), ale w trzeba było to jakoś sprytnie zaimplementować. Cóż, sprytnie nie wyszło, ale za to skutecznie.&lt;/p&gt;  &lt;p&gt;Otóż, dla każdego mesha generowane są bufory VBO, żeby rendering przebiegał szybciej, a wszystko wygląda bardzo profesjonalnie. Dlatego trzeba było coś zrobić z tymi buforami, aby można wyświetlać obiekt partiami. Czy najprostsze rozwiązanie już Wam przyszło do głowy? Owszem, stwórzmy więcej buforów.&lt;/p&gt;  &lt;p&gt;W tej chwili informacje o wierzchołkach, zamiast w wektorach, są zapisywanie w mapach wektorów.&lt;/p&gt;  &lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;   &lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;     &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; std::map&amp;lt;std::&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;, std::vector&amp;lt;CVertex*&amp;gt; &amp;gt; dane;&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Gdzie std::string określa nazwę materiału, dla którego mamy dane informacje. Co ciekawe, przy wydobywaniu informacji o współrzędnych z wektorów użytkownik tak naprawdę nie wie, do którego materiału należy dany punkt – według mojego toku myślenia nie powinno go to interesować, gdyż raczej nie będzie chciał zmieniać umiejscowienia materiałów w locie. &lt;/p&gt;&lt;p&gt;Owszem, rozwiązanie to jest nieco mniej efektywne niż można by było przypuszczać, ale wada nie jest potworna, a elastyczność i wygoda korzystania – znaczna. Spójrzmy bowiem na dodawanie informacji o danym meshu do węzła sceny o nazwie scene_node.&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;1:&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;      &lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;float&lt;/span&gt; vert[] = { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0 };&lt;br /&gt; &lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;float&lt;/span&gt; tex[] = { 0, 0, 1, 0, 1, 1, 0, 1 };&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;float&lt;/span&gt; norm[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 };&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;  &lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt; CStaticMesh* mesh = scene_node-&amp;gt;AddMesh(&lt;span style="color: rgb(0, 96, 128);"&gt;"kwadrat"&lt;/span&gt;);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; CMaterial* mat = mesh-&amp;gt;AddMaterial(&lt;span style="color: rgb(0, 96, 128);"&gt;"drewno"&lt;/span&gt;);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; mat-&amp;gt;SetTexture(texture); &lt;span style="color: rgb(0, 128, 0);"&gt;// gdzie texture to wskaźnik do obiektu tekstury&lt;/span&gt;&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// te informacje, które teraz podajemy, odnoszą się do aktualnie&lt;/span&gt;&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// ustanowionego materiału o nazwie "drewno"&lt;/span&gt;&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt; mesh-&amp;gt;AddVertex(vert, 4);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; mesh-&amp;gt;AddTexCoord(tex, 4);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; mesh-&amp;gt;AddNormal(norm, 4);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt; mesh-&amp;gt;SetMeshType(MT_QUADS);&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A teraz zróbmy to samo wczytując mesha z pliku tekstowego (taką formę reprezentacji wybrałem na razie, pewnie potem ulegnie to modyfikacji).&lt;br /&gt; &lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 20px 0px 10px; width: 97.5%; max-height: 200px; overflow: auto; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; CStaticMesh* mesh = scene_node-&amp;gt;AddMesh(&lt;span style="color: rgb(0, 96, 128);"&gt;"kwadrat"&lt;/span&gt;);&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: rgb(244, 244, 244); margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; mesh-&amp;gt;Import(&lt;span style="color: rgb(0, 96, 128);"&gt;"kwadrat.mesh"&lt;/span&gt;); &lt;span style="color: rgb(0, 128, 0);"&gt;// gdzie kwadrat.mesh to wcześniej wyeksportowany&lt;/span&gt;&lt;/pre&gt;  &lt;pre    style="border-style: none; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; overflow: visible;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// plik z danymi, które wcześniej podaliśmy w sposób jawny w kodzie&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Jak widać, przypomina to nieco inne silniki, a jednocześnie jest w miarę intuicyjne – pobieramy sobie wskaźnik na nowo utworzony obiekt i modyfikujemy go według potrzeb. W drugim przypadku nie musimy nawet zajmować się materiałem, gdyż informacja o nim znajduje się w pliku .mesh, a importer sam próbuje znaleźć plik o nazwie [nazwa_materiału].material w bieżącym katalogu i go wczytać. Jeżeli mu się nie uda – musimy sami zadbać o dostarczenie danych, ale przy dobrej organizacji nie powinno być problemu.&lt;/p&gt;&lt;p&gt;A co, jeżeli nie chce nam się dla mesha definiować osobno materiału? Wtedy zawsze pozostanie utworzony materiał o nazwie “default_material” (zdefiniowany pod makrem DEFAULT_MATERIAL), do którego również możemy się normalnie odwoływać.&lt;/p&gt;&lt;p&gt;Podsumowując, wprowadzenie materiałów troszeczkę zagmatwało sytuację z meshami, ale szczęśliwie, po wielu krzykach, nawoływaniach i różnego rodzaju motywowaniu się (i męczeniu kolegów) udało się wszystko pogodzić, żeby działało.&lt;/p&gt;&lt;p&gt;Teraz pozostaje implementacja światła. Czy również będzie tak “prosto” jak w przypadku materiałów? Zobaczymy.&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-1016085259163352574?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/1016085259163352574/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=1016085259163352574' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1016085259163352574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1016085259163352574'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/07/materiay-osadzone-na-meshach.html' title='Materiały osadzone na meshach'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_R2ix0MLn8lM/TDh9tWrniPI/AAAAAAAAAek/DhhnKAsxcL0/s72-c/scav1_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-6086197644883378598</id><published>2010-07-05T21:21:00.001+02:00</published><updated>2010-07-05T21:21:46.897+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Projektowanie'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>Brum brum, Scav się budzi</title><content type='html'>&lt;p&gt;Pod tym dość enigmatycznym tytułem budzi się pierwsza z cyklu (mam nadzieję, że cyklu) wakacyjnych krótkich notek o tym, dlaczego chcę, a nie mogę. Czyli o silniku Scav.&lt;/p&gt;  &lt;p&gt;Ponieważ obiecałem sobie, że do silnika wrócę jak skończę sesję (przynajmniej tę główną), zatem teraz nieubłaganie zacząłem bawić się kodem. Na czym skupiłem się przez pierwsze parę dni?&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Klasa dla FBO (czyli “to musi być ciekawa rzecz, skoro wszyscy jej używają”) &lt;/li&gt;    &lt;li&gt;Klasa shaderów, w tym dla tych napisanych w języku Cg (czyli “o, mam to z frameworka”) oraz GLSL (czyli “z zajęć coś się przepisze i… A dlaczego plik się nie wczytuje?”) &lt;/li&gt;    &lt;li&gt;Deferred (czyli “nie wychodzi mi i nie robię tego”) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Rzeczywiście, o ile FBO i shadery już są zaimplementowane i chyba działają (podkreślam słówko “chyba”), natomiast Deferred jakoś nie chce. Być może problem leży właśnie w FBO lub też po prostu za mało doczytałem o samym opóźnionym cieniowaniu – postaram się rozpocząć ten temat w silniku na nowo nieco później.&lt;/p&gt;  &lt;p&gt;Dzisiaj rozszerzyłem za to klasę odpowiedzialną za wyświetlanie i wczytywanie (niekoniecznie w tej kolejności) obiektów za pomocą VBO w taki sposób, iż możliwe stało się animowanie modeli (czyli po prostu zwykła zmiana współrzędnych). Miejmy nadzieję, że w przyszłości znacznie ułatwi to wdrożenie modeli wczytywanych z pliku i wszystko będzie dało się zoptymalizować w naprawdę dobry sposób. A ponadto będzie to działać. Co ciekawe, działało to już przy grze, którą pisaliśmy na zaliczenie przedmiotu Grafika Komputerowa i Wizualizacja, tylko tam musieliśmy się dostosować do istniejącego już kodu (a jakże, nie chciał nam się refaktoryzować całości). Przy okazji – na pokazanie samej gry mamy zgodę prowadzącego (pozdrawiam) (oczywiście bez kodu), ale muszę się jeszcze zorientować jak wygląda legalność zasobów, z których skorzystaliśmy. Coś się wymyśli.&lt;/p&gt;  &lt;p&gt;Prawdopodobnie na dniach będę projektował cały system materiałów i świateł, aby to, co się będzie działo, miało ręce, nogi, a dodawanie tego przez programistę było naprawdę proste. Muszę przyznać, że dla mnie aż taka obiektowa koncepcja jest pewną nowością, dlatego nie dziwcie się proszę, że poświęcam temu tyle miejsca – to prawie tak ekscytujące jak otwieranie boostera z kartami. A poza tym być może ktoś jest w takiej samej sytuacji jak ja i będzie potrzebował wprowadzenia – chętnie o tym napiszę w odpowiednim czasie.&lt;/p&gt;  &lt;p&gt;Generalnie mechanizm materiałów i świateł będzie bardzo mocno powiązany z meshami i węzłami sceny. Pewnie znowu zastosuję tu tyle wielodziedziczenia, że sam się w tym poplączę i będę musiał Toxica oraz Maskla (pozdrawiam obu) męczyć za pomocą różnych środków komunikacji.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-6086197644883378598?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/6086197644883378598/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=6086197644883378598' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/6086197644883378598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/6086197644883378598'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/07/brum-brum-scav-sie-budzi.html' title='Brum brum, Scav się budzi'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-9006807747353243380</id><published>2010-07-01T22:50:00.003+02:00</published><updated>2010-07-01T22:59:21.684+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Programowanie niskopoziomowe'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Programowania na kolanach część pierwsza</title><content type='html'>&lt;p&gt;Sesję mam za sobą, zostało tylko zbieranie wpisów (na szczęście, nie muszę się tym zajmować – dzięki Ci Asiu) i w spokoju można zająć się odpoczywaniem, czyli pisaniem silnika. Na razie nie ma jednak czego pokazywać, a ponadto obiecałem przecież, że napiszę coś o programowaniu na niskim poziomie, a konkretnie “jak napisać program, aby działał robot”. Postanowiłem podzielić ten minicykl na dwie części – w pierwszej pokażę jak wykorzystać port LPT, aby pojazd na smyczy mógł zasuwać, a w drugiej zajmiemy się programowaniem mikrokontrolera.&lt;/p&gt;  &lt;p&gt;Od razu chciałem coś wyjaśnić – z pewnością wielu z Was powie, że niepotrzebnie opisuję LPT, gdyż a) jest stare, b) jak ktoś będzie chciał zrobić coś konkretnego, to użyje mikrokontrolera, c) jest stare. Nie bez znaczenia pozostaje jednak fakt, że pierwszy etap tworzenia robota polega właśnie na wykorzystaniu portu LPT w jakimś starym komputerze, a dokładniej – należy odpowiednio reagować na przerwania. Poza tym to wyjście bardzo łatwo da się dostosować do naszych potrzeb i filozofia kodowania na tym złączu może przybliżyć także zainteresowanych do poradzenia sobie np. z USB (jednak ja do nich nie należę, jam skromny gracz-programista).&lt;/p&gt;  &lt;p&gt;Dobrze, na początku jednak troszeczkę przygotowań. Po lewej  &lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/TCz_bnQ181I/AAAAAAAAAeU/YWorS269quM/s1600-h/LPT%5B3%5D.png"&gt;&lt;img title="LPT" style="border-width: 0px; display: inline; margin: 0px 5px 0px 0px;" alt="LPT" src="http://lh6.ggpht.com/_R2ix0MLn8lM/TCz_duJ_MII/AAAAAAAAAeY/3bU2oSL2iIU/LPT_thumb%5B1%5D.png?imgmax=800" align="left" border="0" width="244" height="175" /&gt;&lt;/a&gt; widzimy rysunek portu równoległego, który pozwoliłem sobie skopiować z &lt;a href="http://pl.wikipedia.org/wiki/IEEE_1284"&gt;odpowiedniej strony Wikipedii&lt;/a&gt;. Widzimy zatem, że w standardowej wersji mamy 25 dziwnie wyglądających bolców (złącza zwane samcami) lub 25 otworów na te bolce (złącza zwane samicami – jak widać, informatycy też ludzie). Tak czy inaczej, część z tych wejść/wyjść należy wykorzystać do naszych celów. Naszym szczególnym zainteresowaniem będą cieszyć się wyjścia DATA oraz wejścia ACK, PE, SEL, ERROR. Generalnie polecam zaznajomić się z &lt;a href="http://www.lpt.strona.pl/"&gt;tą stroną&lt;/a&gt; – dowiemy się tutaj między innymi, że LPT podzielone jest na blok danych, statusowy oraz kontrolny. Każdą część wykorzystamy, zatem spokojnie, nie palić się tak bardzo do tych samiczek/samców.&lt;/p&gt;  &lt;p&gt;Być może część potrzebuje również wyjaśnienia co to jest to mistyczne “&lt;a href="http://pl.wikipedia.org/wiki/Przerwanie"&gt;przerwanie&lt;/a&gt;”. Otóż, mamy dwa możliwe podejście do reagowania na jakiekolwiek zdarzenia – odpytywanie (polling) oraz system przerwań. Posłużę się przykładem, który zaproponował nasz wykładowca (pozdrawiam). Załóżmy, że siedzimy sobie w domu i czekamy na gościa (ciocia/wujek przychodzą na nasze urodziny i czekamy na prezent). Aby jednak umilić sobie oczekiwanie, bierzemy jakąś fascynującą książkę i czytamy. Jeżeli będziemy odpytywać, polegać to będzie na tym, że co chwilę będziemy się zrywać z wygodnego fotela, odkładać książkę i podchodzić do drzwi, aby spojrzeć czy goście już przyszli. Jeżeli natomiast pomyślimy i zastosujemy system przerwań (dzwonek do drzwi), będziemy mogli w spokoju wgłębiać się w powieść, aby potem nagle zdenerwować się, jak zadzwoni dzwonek (bo akurat przyszedł rachunek za prąd). Przerwanie, jak sama nazwa wskazuje, przerywa aktualnie wykonywany program, skacze do miejsca, gdzie znajduje się obsługa przerwania, a następnie powraca tam, gdzie byliśmy poprzednio.&lt;/p&gt;  &lt;p&gt;Pozostaje jeszcze kwestia tego w czym będzie pisać. My akurat wykorzystywaliśmy (dzięki koledze – dzięki Ci Janie) &lt;a href="http://en.wikipedia.org/wiki/Turbo_C%2B%2B"&gt;Turbo C++&lt;/a&gt; i nie mieliśmy dzięki niemu problemów ani z dziwnymi funkcjami języka C ani wstawkami assemblerowymi. Podejrzewam jednak, iż istnieje cała masa środowisk, w których można z powodzeniem pisać. Będziemy też potrzebowali biblioteki dos.h, która zawiera odpowiednie funkcje niskopoziomowe (choć nie jest niezbędna), ale jest ona dołączona w większości środowisk, zatem nie powinno być problemów.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Chciałbym też zwrócić uwagę na pewną charakterystyczną filozofię. Programowanie niskopoziomowe (czyli tak naprawdę sprzętowe) opiera się głównie na podaniu sekwencji jednego (kilku) bajtu(/ów) pod określony adres w komputerze tudzież ustawieniu paru bitów. Przypominam również, że 1 bajt = 8 bitów (1B = 8b). W ogóle polecam troszeczkę zaznajomić się z samym sposobem działania systemu – takimi podstawami. Tym niemniej, jak mój dalszy opis będzie niezrozumiały (a obawiam się, że miejscami mogę dobrze nie tłumaczyć), to śmiało linczować mnie w komentarzach i prosić o prostowanie.&lt;/p&gt;  &lt;p&gt;Polecam naprawdę jeszcze raz &lt;a href="http://www.lpt.strona.pl/"&gt;tę stronę&lt;/a&gt;, dzięki której można dowiedzieć się wielu rzeczy, których tutaj nie opiszę dokładniej. Mam również pewne wątpliwości, czy mogę umieszczać przykładowe kawałki kodu – mam nadzieję, że nie będzie mi to poczytane za łamanie czegokolwiek i zdradę, ale jako chęć poduczenia zainteresowanych programowaniem niskopoziomowym – bądź co bądź, dosyć trudnym zagadnieniem, zwłaszcza dla osób, które przyzwyczajone są do obiektowości. I tak najważniejsze sprawy są tłumaczone na laboratoriach, wykładach, w książkach – warto mieć jednak również praktyczny poradnik przy sobie.&lt;/p&gt;  &lt;p&gt;Dobrze, zatem zacznijmy może. Naszym zadaniem jest odbieranie przerwania na wejściu ACK, a następnie sprawdzaniu stanu lewego i prawego czujnika i odpowiednie sterowanie naszym pojazdem, aby cały czas utrzymywał się na trasie. Jedynka na czujniku oznacza “hej, jestem na trasie po tej stronie”, a zero “zabierz mnie stąd!”. Na silniki będą podawane odpowiednie sekwencje w postaci:&lt;/p&gt;  &lt;p&gt;X X SP SL 1 0 1 0&lt;/p&gt;  &lt;p&gt;Gdzie X to dowolna wartość (czyli najlepiej 0), SP to włączenie silnika prawego, a SL – lewego (skręcanie robota bowiem odbywa się w ten sposób, że jeden z silników jest wyłączony – kwestie technologiczno-mechaniczne). Sekwencja 1010 mówi nam tylko tyle, że cały czas jedziemy do przodu, jeżeli silnik pracuje. Należy również jeszcze pamiętać o przyjętej logice ujemnej – tak naprawdę zero oznacza, że silnik pracuje, a 1 – stoi. Dlaczego? Tak zaproponowali nasi elektronicy i okazało się to zbawienne w skutkach. Proponuję zacząć od rzeczy błahej, a mianowicie załączenia plików nagłówkowych oraz makr, które nam ułatwią sprawę.&lt;/p&gt;  &lt;div   style="border: 1px solid gray; padding: 4px; margin: 20px 0px 10px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;   &lt;div   style="padding: 0px; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;     &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; #include &lt;span style="color: rgb(0, 96, 128);"&gt;"stdio.h"&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; #include &lt;span style="color: rgb(0, 96, 128);"&gt;"conio.h"&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; #include &lt;span style="color: rgb(0, 96, 128);"&gt;"dos.h"&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; #include &lt;span style="color: rgb(0, 96, 128);"&gt;"stdlib.h"&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LPT1_DATA 0x378&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LPT1_STATUS 0x379&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LPT1_CONTROL 0x37a&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; IRQ7 0x0f&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; EOI 0x20&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; PORT_8259 0x21&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LEFT_SENSOR 0x20&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; RIGHT_SENSOR 0x08&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; STOP 0x3a&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; UP 0x0a&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; LEFT 0x1a&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; RIGHT 0x2a&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; status_data;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; move_type;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; interrupt (*OldInterruptsLPT)();&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Jak widać, mamy do czynienia z dużą inwazją liczb w postaci szesnastkowej. Ponadto narzuciłem już pewną rzecz – lewy czujnik mamy podpięty pod wejście PE, a prawy – pod ERR. To jest kwestia umowy, a wartości 0x20 oraz 0x08 wynikają z tego, jak wygląda port statustowy LPT (ponownie polecam &lt;a href="http://www.lpt.strona.pl/"&gt;tę stronę&lt;/a&gt;). Warto sobie uzmysłowić, że cały czas musimy myśleć bitowo – poczynając od prawej mamy jedynka i zera reprezentujące wartości 2&lt;sup&gt;0&lt;/sup&gt;, 2&lt;sup&gt;1&lt;/sup&gt;, 2&lt;sup&gt;2&lt;/sup&gt;, … aż do 2&lt;sup&gt;7&lt;/sup&gt;. &lt;/p&gt;&lt;p&gt;Zacznijmy jednak pisać. Najpierw kod, a potem trochę opowiem.&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; margin: 20px 0px 10px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div   style="padding: 0px; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; cli&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt; outportb(LPT1_CONTROL, inporti(LPT1_CONTROL) | 0x10);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; outportb(PORT_8259, inporti(PORT_8259) &amp;amp; 0x7f);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; outportb(LPT1_DATA, STOP);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; printf(&lt;span style="color: rgb(0, 96, 128);"&gt;"Nacisnij ENTER, aby ruszyc\n"&lt;/span&gt;);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt; getch();&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt; OldInterruptsLPT = getvect(IRQ7);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; setvect(IRQ7, InterruptsLPT);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; outportb(LPT1_DATA, UP);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt; asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt; sti&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt; getch();&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt; asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt; cli&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt; outportb(LPT1_DATA, STOP);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt; outportb(LPT1_CONTROL, inporti(LPT1_CONTROL) &amp;amp; 0xef);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt; outportb(PORT_8259, inporti(PORT_8259) | 0x80);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt; asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt; sti&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Wygląda strasznie, prawda? Spokojnie, najgorsze jeszcze przed nami – trzeba to w końcu omówić.&lt;/p&gt;&lt;p&gt;Instrukcja assemblera “cli” na naszym procesorze oznacza, że wyłączamy w tej chwili obsługę wszystkich przerwań (analogicznie “sti” je włącza). Po co to robimy? Wyobraźmy sobie sytuację, że spokojnie konfigurujemy sobie nasz port LPT, aby działał tak, jak tego chcemy, a tu nagle wyskoczy nam jakieś zwierzę futerkowe i naciśnie klawisz. Naciśnięcie klawisza to również zgłoszenie przerwania do systemu, a co za tym idzie – nasza  konfiguracja zostaje przerwana i mimo, że zostanie wznowiona, to mogą pojawić się problemy, które trudno wyjaśnić (kolorowy ekran, kolorowy ekran z dziwnymi znaczkami, dym unoszący się ze stacji dyskietek itd.). Dlatego bezpieczniej jest czasami “zamknąć kolejkę”. &lt;/p&gt;&lt;p&gt;Następnie w końcu coś robimy z LPT – na piątym bicie (licząc od prawej) pod adresem portu kontrolnego LPT (0x37A) mamy informację, czy ACK będzie służyło jako źródło przerwań. Oczywiście, o to nam chodzi, zatem wykorzystujemy sumę bitową (operator |) i zmieniamy piąty bit na jedynkę. Jak widać, wykorzystujemy do tego funkcje z pakietu dos.h – outportb (wysłanie wartości na dany adres) i inportb (odebranie wartości z danego adresu). Dalej następuje odmaskowanie przerwania IRQ7 – ciekawe, prawda? Tak naprawdę, cały system przerwań dyrygowany jest przez układ w komputerze, który ma tajemniczy kryptonim 8259 (lub 8259A). Jeżeli chcemy cokolwiek mieszać przy przerwaniach, chcąc nie chcąc, musimy się tą “pięćdziesiątką dziewiątką” zainteresować. Tutaj, wykorzystując iloczyn bitowy (operator &amp;amp;), zmieniamy ósmy bit (pierwszy od lewej) na 0, co umożliwia odbieranie przerwań z tej strony (a jak się dalej okaże – z LPT). Na wszelki wypadek czekamy na reakcję użytkownika (aby przygotował sobie robota, wsadził mu baterie, nakarmił, itd.), a potem… Właśnie, co potem? Pod OldInterrupts zapisujemy naszą standardową procedurę obsługi przerwania (domyślną systemową), którą potem powrócimy. Odwołujemy się przy tym do wejścia IRQ7, pod które podpięte jest właśnie nasze LPT (pełną listę można znaleźć &lt;a href="http://students.mimuw.edu.pl/SO/Projekt03-04/temat3-g4/przerwania.html"&gt;tutaj&lt;/a&gt; – jak widać, port równoległy LPT jest pod adresem 0x0F). Dalej wrzucamy naszą obsługę przerwania, czyli InterruptsLPT (którą sobie potem pokażemy). Od tej pory, jeżeli przyjdzie przerwanie od portu LPT, zostanie podjęta akcja, którą sami sobie napiszemy w tej funkcji InterruptsLPT. Nie pozostaje nam teraz nic innego jak zadać pojazdowi jechanie do przodu (czyli wysłać na port danych LPT (adres 0x378) odpowiednią wartość) i czekać na naciśnięcie dowolnego klawisza (które przerwie nam program i zatrzyma robota).&lt;/p&gt;&lt;p&gt;Po getch() następuje oczywiście sprzątanie po sobie – zatrzymujemy robota, zerujemy wcześniej ustawione bity, przywracamy starą obsługę przerwań i voila. &lt;/p&gt;&lt;p&gt;Jeszcze taka ciekawostka – o ile funkcje setvect oraz getvect nie są takie bardzo łatwe do napisania (a przynajmniej nie mieliśmy na to za dużo czasu – przykładowy kod znajduje się &lt;a href="http://www.blogger.com/geezer.osdevbrasil.net/osd/intr/x86-16.c"&gt;tutaj&lt;/a&gt;), o tyle outport i inport możemy sami w prosty sposób zaimplementować (o ile oczywiście uznajemy assemblera za język zrozumiały i nadający się do dziennego spożycia):&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; margin: 20px 0px 10px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div   style="padding: 0px; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; unsigned &lt;span style="color: rgb(0, 0, 255);"&gt;char&lt;/span&gt; inporti (unsigned &lt;span style="color: rgb(0, 0, 255);"&gt;short&lt;/span&gt; port)&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     unsigned &lt;span style="color: rgb(0, 0, 255);"&gt;char&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;     asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;         mov dx, port&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; al, dx&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;         mov &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;, al&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; outporti (unsigned &lt;span style="color: rgb(0, 0, 255);"&gt;short&lt;/span&gt; port, unsigned &lt;span style="color: rgb(0, 0, 255);"&gt;char&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;)&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;     asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;         mov dx, port&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;         mov al, &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;out&lt;/span&gt; dx, al&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;  &lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;br /&gt;To jest po prostu wysłanie/odebranie odpowiedniej wartości za pomocą poleceń mov, in oraz out - prawdę mówiąc, jest to chyba jedna z kilku rzeczy, które umiem zrobić samodzielnie w assemblerze, zatem też nie mam się czym chwalić.&lt;br /&gt;&lt;p&gt;W porządku, w takim razie przejdźmy do naszej procedury obsługi przerwania (zwracam uwagę na słówko kluczowe “interrupt”).&lt;/p&gt;&lt;div   style="border: 1px solid gray; padding: 4px; margin: 20px 0px 10px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div   style="padding: 0px; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; interrupt InterruptsLPT()&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;     cli&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;while&lt;/span&gt; (1)&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;         status_data = inporti(LPT1_STATUS);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;         status_data &amp;amp;= 0x28;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;         &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; ((status_data &amp;amp; RIGHT_SENSOR) &amp;amp;&amp;amp; (status_data &amp;amp; LEFT_SENSOR))&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;             move_type = UP;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (!(status_data &amp;amp; RIGHT_SENSOR) &amp;amp;&amp;amp; (status_data &amp;amp; LEFT_SENSOR))&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;             move_type = LEFT;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; ((status_data &amp;amp; RIGHT_SENSOR) &amp;amp;&amp;amp; !(status_data &amp;amp; LEFT_SENSOR))&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;             move_type = RIGHT;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;             move_type = STOP;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt;         &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt;         outporti(LPT1_DATA, move_type);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  31:&lt;/span&gt;         &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  32:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (move_type == STOP || move_type == UP)&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  33:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  34:&lt;/span&gt;            &lt;span style="color: rgb(0, 0, 255);"&gt;break&lt;/span&gt;;&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  35:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  36:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  37:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  38:&lt;/span&gt;     outporti(0x20, EOI);&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  39:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  40:&lt;/span&gt;     asm {&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  41:&lt;/span&gt;     sti&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  42:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  43:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="padding: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-style: none; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  44:&lt;/span&gt;  &lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Znowu stosujemy myśl taktyczną związaną z blokowaniem przerwań i działamy w pętli. Pozornie wiecznej, ale nie do końca. Tutaj następuje zmieszanie systemu przerwań z pollingiem – po wejściu w stan obsługi przerwania zwyczajnie przepytujemy stan czujników podpięte do portu statusowego (dla ułatwienia wyciągamy z niego tylko odpowiednie bity), a następnie sprawdzamy stan i działamy zgodnie z założeniami z tabelki:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;table border="1" cellpadding="2" cellspacing="0" width="400"&gt;&lt;tbody&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Lewy czujnik&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Prawy czujnik&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Decyzja&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Na trasie&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Na trasie&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Do przodu&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Na trasie&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Poza trasą&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;W lewo&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Poza trasą&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Na trasie&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;W prawo&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Poza trasą&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Poza trasą&lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;td valign="top" width="133"&gt;Stop / Cofamy się&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Oczywiście, to tylko przykład – równie dobrze można zbudować robota na czterech czujnikach i w różny sposób sterować silnikami. Powyższe ma tylko na celu zobrazowanie samej mechaniki działania. Z pętli wychodzimy oczywiście, gdy pozycja robota jest bezpieczna i zaraz potem wysyłamy słowo sterujące EOI (które jest pewną odmianą słowa OCW2 (no nie mówcie, że pierwszy raz słyszycie te nazwy!)), mówiące “kończ waść przerwanie, wstydu oszczędź” na adres 0x20. &lt;/p&gt;&lt;p&gt;Oczywiście, do naszego programiku można również dodać obsługę dźwięków. Robi się to poprzez zmuszenie do współpracy PC Speakera (tego słynnego głośniczka) oraz układu 8253, który jest licznikiem systemowym. Jak to wykonać – jest świetnie opisane &lt;a href="http://www.delphi3000.com/articles/article_3773.asp?SK="&gt;tutaj&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To byłby koniec pierwszej części wesołego cyklu. Jeżeli teraz naszego robota przypniemy do złącza LPT i uruchomimy własnoręcznie napisany program, powinno być już lżej. Choć, znając życie, nie zadziała poprawnie za pierwszym razem.&lt;/p&gt;&lt;p&gt;W drugiej (i ostatniej) części powiemy o tym, jak pozbyć się kabla i załadować mikrokontroler z programem na grzbiet pojazdu. Co ciekawe, jest to dużo prostsze, aniżeli posługiwanie się naszym ogromnym komputerem – zresztą każdy oceni, jak zobaczy drugi artykuł.&lt;/p&gt;&lt;p&gt;Pozdrawiam, dziękuję i jak zawsze zachęcam do dyskusji – SceNtriC&lt;/p&gt;&lt;p&gt;Ps. Jeszcze raz proszę o wyrozumiałość, jeżeli chodzi o dzielenie się kodem źródłowym. Jeżeli jednak ktoś ma zastrzeżenia i uważa, że tego kodu tutaj nie powinno być (tzn. w takiej formie, jak jest teraz, że powinno być bardziej zaciemnione) - proszę śmiało mi dać znać. Za wszystkie kłopoty przepraszam.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-9006807747353243380?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/9006807747353243380/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=9006807747353243380' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/9006807747353243380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/9006807747353243380'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/07/programowania-na-kolanach-czesc.html' title='Programowania na kolanach część pierwsza'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_R2ix0MLn8lM/TCz_duJ_MII/AAAAAAAAAeY/3bU2oSL2iIU/s72-c/LPT_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-1859888787501249245</id><published>2010-06-17T19:15:00.001+02:00</published><updated>2010-06-17T19:15:06.498+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Programowanie niskopoziomowe'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Robot oddany, czyli jak się bawią na zajęciach na Politechnice</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/TBpXO5wQ_dI/AAAAAAAAAds/yqWlA1iTPB4/s1600-h/rw2%5B3%5D.jpg"&gt;&lt;img title="rw2" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 5px 0px 0px; border-left: 0px; border-bottom: 0px" height="172" alt="rw2" src="http://lh3.ggpht.com/_R2ix0MLn8lM/TBpXWRp_4jI/AAAAAAAAAdw/rrruGfj33Xc/rw2_thumb%5B1%5D.jpg?imgmax=800" width="244" align="left" border="0" /&gt;&lt;/a&gt; Przez ostatnie parę miesięcy zadręczałem Was informacjami o tym, jak chowa się nasz robot i co mu nowego zepsuliśmy. W ostatnich dwóch tygodniach odbyły się dwa ważne wydarzenia związane z naszą Krysią (jak nazwaliśmy pojazd) – wyjazd do Gorzowa i oddanie go prowadzącemu.&lt;/p&gt;  &lt;p&gt;Zacznijmy może od wyjazdu do Gorzowa. Naszym przeznaczeniem (9 osób udało się w podróż) było zaprezentowanie w tym mieście w średniej szkole (II Liceum Ogólnokształcące im. Marii Curie-Skłodowskiej [o ile się nie pomyliłem, jak tak, to przepraszam]) tego, Co-Robią-Studenci-Informatyki-Na-Zajęciach, ale zwłaszcza chodziło o promocję &lt;a href="http://www.put.poznan.pl"&gt;Politechniki Poznańskiej&lt;/a&gt;, &lt;a href="www.fcm.put.poznan.pl"&gt;Wydziału Informatyki&lt;/a&gt; (będzie nowa strona, bo to nowy odłam Wydziału Infomatyki i Zarządzania) oraz &lt;a href="http://www.pti.org.pl/"&gt;Polskiego Towarzystwa Informatycznego&lt;/a&gt; (a zwłaszcza gorzowskiej części, której przewodniczy nasz prowadzący laboratoria, dr. inż. Rafał Klaus (pozdrawiam). Na miejscu okazało się, że powierzono nam bardzo przestronną salę (najlepszą logistycznie salę informatyczną, z jaką spotkałem się w jakiejkolwiek szkole), rzutnik, komputer, a za godzinę nadejść miało około 40 uczniów. Jak się okazało, było ich 48, co osobiście wprawiło mnie w lekkie przerażenie, gdyż nie jestem osobą lubiącą cokolwiek prezentować, a tym bardziej przed większą ilością osób niż jedna (właściwie ta jedna też zawsze przyprawia mnie o zawstydzenie). Nie było jednak tak źle – podzieliliśmy się na role, niektórzy mówili o uczelni, inni o mechanice, elektronice, programowaniu (ciekawe kto o tym mówił, nieprawdaż?), a po prezentacji robota wszyscy byli w ekstazie – widzowie, że zobaczyli coś ciekawego, a my, że pojazd zadziałał za pierwszym &lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/TBpXqMybITI/AAAAAAAAAd0/hk11YjuqZBU/s1600-h/rw3%5B3%5D.jpg"&gt;&lt;img title="rw3" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px; border-left: 0px; border-bottom: 0px" height="217" alt="rw3" src="http://lh4.ggpht.com/_R2ix0MLn8lM/TBpXy-C-3PI/AAAAAAAAAd4/Px31bSaflr8/rw3_thumb%5B1%5D.jpg?imgmax=800" width="244" align="right" border="0" /&gt;&lt;/a&gt; razem. W międzyczasie niektórzy próbowali tykać robota i samodzielnie się nim bawić, także mieliśmy lekki strach w oczach (za dwa dni pojazd miał trafić do Pniew na podobną prezentację). Następnie przyszedł czas na pytania i w sumie – a nieczęsto to mówię – było całkiem sympatycznie, mogliśmy poopowiadać nieco o samym kierunku i zdążyć uspokoić młodzież, iż nie trzeba od razu być mistrzem całek, żeby przyjść do nas. Niestety, sama podróż tam była troszkę długa jak dla mnie (dopisek – dla mnie każda podróż trwająca więcej niż 10 minut jest długa). Kierowca samochodu znalazł jednak dla mnie zajęcie – bawiłem się nowinką techniczną (dla mnie), a mianowicie elektrycznie otwieranymi szybami. Zaiste, nie zabierajcie mnie do swojego samochodu, jeśli macie takie szyby, bo na pewno będę się bawił. Dziękuję i pozdrawiam wszystkich za udział i zainteresowanie (w poniższym filmiku właściwa jazda robota zaczyna się od 3:45 - swoją drogą ciekawe czy wychwycicie moją zakazaną twarz [wbrew pozorom nie jest to osoba, która na filmiku najczęściej siedzi przy komputerze]).&lt;/p&gt;  &lt;p&gt;&lt;object width="440" height="353"&gt;&lt;param name="movie" value="http://www.youtube.com/v/6BsO5SDMsU4&amp;amp;hl=pl_PL&amp;amp;fs=1&amp;amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/6BsO5SDMsU4&amp;amp;hl=pl_PL&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="410" height="329"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;  &lt;p&gt;A co właściwie zmieniło się w naszym robocie od ostatniego razu? Otóż, wreszcie Krysia stała się autonomiczna – nie potrzebuje kabla ani komputera, tylko dzięki specjalnemu układowi może sama sobie jeździć po trasie. Tym specjalnym układem (przepraszam – Specjalnym Układem) jest mikrokontroler &lt;a href="http://www.atmel.com/atmel/acrobat/doc2486.pdf"&gt;ATMega8L&lt;/a&gt;, który odpowiednio zaprogramowaliśmy i dzięki temu większa maszyna już nie jest potrzebna (choć sam kod był pisany, kompilowany i wgrywany za pomocą aplikacji &lt;a href="http://winavr.sourceforge.net/"&gt;WinAVR&lt;/a&gt;). Program&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/TBpX9FsNBuI/AAAAAAAAAd8/AcjSZ5Gvbjw/s1600-h/IMG_09993.jpg"&gt;&lt;img title="IMG_0999" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="244" alt="IMG_0999" src="http://lh4.ggpht.com/_R2ix0MLn8lM/TBpYDxD-HZI/AAAAAAAAAeA/hCYfvvxdDdU/IMG_0999_thumb1.jpg?imgmax=800" width="184" align="right" border="0" /&gt;&lt;/a&gt; ma około 40-50 linijek i opiera się na tym, że czujniki są podłączone do dwóch wejść przerwań zewnętrznych (INT0 oraz INT1), a następnie dowolna zmiana stanu logicznego na którymkolwiek sensorze wywołuje przerwanie, które decyduje o tym, czy dany silnik pracuje czy nie. Bardzo proste i szybkie – jeżeli ktoś będzie zainteresowany, mogę nieco więcej opisać, ale musicie mi dać znać, chociażby w komentarzach.&lt;/p&gt;  &lt;p&gt;Cóż, tak się kończy historia naszego robota. Czy będę miło wspominał projekt? Na pewno pozwolił poznać smak pracy zespołowej (niezdalnej) z podziałem obowiązków, dotrzymywania terminów, wydzierania się na współtowarzyszy oraz trochę aspektów związanych z programowaniem niskopoziomowym. Jednak nie ukrywam, że ten robot kosztował mnie (nie wiem jak innych) dużo stresu i wiele siwych włosów na głowie (te, które jeszcze nie wypadają). Jakoś jednak wolę gry. Choć sesja tak szybko nie da o sobie zapomnieć, więc z BG2 nici…&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-1859888787501249245?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/1859888787501249245/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=1859888787501249245' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1859888787501249245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1859888787501249245'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/06/robot-oddany-czyli-jak-sie-bawia-na.html' title='Robot oddany, czyli jak się bawią na zajęciach na Politechnice'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_R2ix0MLn8lM/TBpXWRp_4jI/AAAAAAAAAdw/rrruGfj33Xc/s72-c/rw2_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2786457533517908821</id><published>2010-06-02T22:01:00.001+02:00</published><updated>2010-06-02T22:01:36.774+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Jak to ściany mogą człowieka zdenerwować</title><content type='html'>&lt;p&gt;Semestr zbliża się ku końcowi, nic nie piszę na blogu – czyli mamy stan normalny. Na szczęście dwa z czterech projektów już są oddane, ale pozostały dwa najcięższe.&lt;/p&gt;  &lt;p&gt;Projekt z grafiki (przypominam – kolejny klon Dooma) jest już powoli na ukończeniu i obecnie pozostało wgryzienie się w shadery i różne małe rzeczy, które sprawią, że będzie się grało przyjemniej. Jako że modele mamy &lt;a href="http://tastyspleen.net/~quake2/http_linkfarm/rails/players/"&gt;z tej strony&lt;/a&gt;, broń &lt;a href="http://www.3dm3.com/modelsbank/"&gt;z tej&lt;/a&gt;, a dźwięki nie wiem, bo kolega ściągał, zatem nie wiem, czy będzie można projekt umieścić w sieci. Chciałem jednak napisać o pewnej rzeczy, z którą – jak pewnie pamiętacie – zawsze miałem osobiście problem, a mianowicie z kolizjami. Nie wiem, jak to się dzieje, że większość programistów przechodzi koło tego tematu całkiem spokojnie i nie ma żadnych problemów – u nas kłopot przejawiał się niejako w dwojaki sposób. Najpierw, przy odpowiednim poruszaniu się, można było wyjść poza planszę, co zdecydowanie nie sprzyjało grywalności projektu. Zwłaszcza, że ciężko było wrócić na planszę. Z drugiej strony, po zastosowaniu wielu różnych dziwnych sztuczek (odbijanie w przeciwną stronę z określonym współczynnikiem, blokowanie, zliczanie ostatnio poprawnych pozycji i inne cuda na kiju) okazało się, że postać jest w stanie zablokować się i za żadne skarby nie chce się ruszyć z całym majdanem od ściany. Testerzy (pozdrawiam) byli bliscy płaczu, kolega z duetu (pozdrawiam) był bliski gniewu, a ja byłem bliski stwierdzenia, że chyba zajmę się hodowaniem truskawek pod wiatr. &lt;/p&gt;  &lt;p&gt;Rozwiązanie, które nam pomogło było tak proste, że aż jestem zły, a zostało zaproponowane przez innego kolegę z roku (pozdrawiam). Otóż, mając całą geometrię ścian i kolizje zaimplementowane w całości na kostkach AABB, należało sprawić, aby postać, która chce wyjść poza ścianę, odbiła się od niej. O tym już wspomniałem, ale sposób, w jaki to odbicie następuje jest wręcz za prosty – jest to po prostu wykorzystanie wektora normalnego. Żadne liczenie współczynników, pełno instrukcji warunkowych, które przyprawiały nas o ból głowy. Po prostu wektory normalne, które i tak mieliśmy dostępne dla każdej ściany. Teraz zatem wygląda to tak:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Gracz wykonuje ruch w kierunku jakiejkolwiek ściany (zawsze wykona w kierunku jakiejkolwiek).&lt;/li&gt;    &lt;li&gt;Jeżeli kostki AABB gracza oraz ściany nie przetną się, kolizji nie ma i wykonywany jest normalny ruch.&lt;/li&gt;    &lt;li&gt;Jeśli jednak kolizja została wykryta, sprawdzamy wektor normalny ściany, z którą kolidujemy – będzie on o zwrocie przeciwnym do naszego ruchu. Normalizujemy go, mnożymy go razy odpowiedni współczynnik (u nas testowo jest to 0.1) i o taką pozycję przesuwamy naszego herosa. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Proste i skuteczne. Nie dość, że bardzo proste do zaimplementowania (o ile mamy dostęp do wektorów normalnych i indeksu kolizyjnej ściany, ale na 90% mamy), to jeszcze przy okazji rozwiązało nam inny problem – potwory wreszcie “szukają” drogi do gracza i potrafią unikać narożników korytarzy. Co prawda, koledze już raz udało się przez przypadek wyjść poza planszę, ale na razie tylko jemu – miejmy nadzieję, że to odosobniony przypadek.&lt;/p&gt;  &lt;p&gt;Drugi projekt, który nadal czeka w kolejce to jest oczywiście robot z mikrokontrolerem i tutaj jest nieco większy kłopot, gdyż większość grup (w tym my) została wysłana w delegację do szkół średnich w Gorzowie Wlkp., aby dumnie chwalić nasz wydział (teraz już nazywający się Wydział Informatyki) i przy okazji prezentować, co studenci informatyki potrafią zrobić z kawałkiem aluminium, elektroniką i starymi komputerami złożonymi w całość w robota. Cóż, nie ukrywam, że nie jest to może wymarzona podróż (za szybko ogłoszona i generalnie w ogóle nie lubię podróżować), ale przynajmniej jest to jakieś doświadczenie. Jak to wyszło – pewnie poinformuję.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2786457533517908821?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2786457533517908821/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2786457533517908821' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2786457533517908821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2786457533517908821'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/06/jak-to-sciany-moga-czowieka-zdenerwowac.html' title='Jak to ściany mogą człowieka zdenerwować'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-7116729463764303592</id><published>2010-05-22T14:53:00.001+02:00</published><updated>2010-05-22T14:53:17.110+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Projektowanie'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Nie róbcie tego w domu</title><content type='html'>&lt;p&gt;Semestr powolutku zbliża się do końca, pod koniec maja (czyli… o kurczę, to już teraz) i w czerwcu czeka nas copółroczna batalia z kolokwiami i egzaminami, zatem rozsądny student myśli już o tym, żeby pokończyć pozostałe projekty albo chociaż je zacząć. W tym także naszego FPS-a, którego klecimy z kolegą. Jak pewnie już kiedyś wspominałem, staraliśmy się go czynić zgodnie z zasadami OOP-u, żeby pisało się łatwo i przyjemnie i człowiek zasiadał do kodu jak do rozrywki (a nie musiał wcześniej grać 6 godzin w BG2). &lt;/p&gt;  &lt;p&gt;Jednakże domyślacie się pewnie, że nie do końca to wyszło – po pewnym czasie przychodzi zjawisko zwane ANieChceMiSięniem (ANCMS) i powstaje coraz bardziej redundantny kod, z powtarzającymi się sekwencjami, bałaganem i wcięciami przesuniętymi o jedną kolumnę w prawo. Chciałem zatem wymienić parę rzeczy, które w naszym kodzie nie są do końca w porządku, a na poprawianie ich nie ma już za bardzo czasu (bo trzeba kończyć projekt, a nie porządkować kod). Na pewno te spostrzeżenia nie przydadzą się bardziej doświadczonym specjalistom, ale początkujący mogą z tego coś wyciągnąć.&lt;/p&gt;  &lt;p&gt;1. Koniecznie trzeba mieć coś w rodzaju TimeManagera, który będzie trzymał w sobie naliczanie czasu i uruchamiał odpowiednie funkcje w innych managerach, które z kolei aktualizują stany (np. poruszanie się potworków, ich reakcje, ruch jakiś cząsteczek itd.). Nie dopuście do sytuacji, gdy różnice czasowe będą obliczane dla każdego managera osobno i każdy będzie sobie z tego coś wyciągał. Owszem, jest to wygodne i nie wymaga jakiś specjalnych zabiegów, ale przez to tracimy całą synchronizację gry. Tutaj dochodzą też inne kwestie (obliczanie szybkości poruszania się obiektów), ale to już temat na osobny rozdział.&lt;/p&gt;  &lt;p&gt;2. Starajcie się zachowywać jeden wzorzec. O co mi chodzi? Przy projekcie korzystamy z frameworka, którym kiedyś Was zamęczałem – z Yesty. Jak pewnie pamiętacie, był on tworzony w oparciu o tutoriale, które znalazłem w Internecie, czasami wręcz w beszczelny sposób. W ten sposób dorobiłem się klas ładujących modele w formatach OBJ i MD2, ale w nieco odmienny sposób. Do OBJ jest COBJManager, czyli cały zbiór modeli, a CMD2Model to osobna klasa dla jednego modelu. I to podejście niestety pokutuje u nas, przez co dla jednego rodzaju modeli mamy wektor, a dla drugiego osobny obiekt managera. Jeżeli tylko macie możliwość i czas – starajcie się wszystko ujednolicić, bo potem się naprawdę łatwiej pisze.&lt;/p&gt;  &lt;p&gt;3. Jak najmniej treści umieszczać w kodzie, chyba że jest to wybitnie wygodne i nie ma tego dużo (albo wiadomo, że czegoś się nie będzie zmieniać). Ten błąd akurat u nas nie występuje, ale warto o nim wspomnieć, gdyż właśnie całkowite oskryptowanie i przeniesienie do zewnętrznych plików treści sprawiło, że Wielkiego Mistrza przygotowywało się w prosty sposób. Co prawda, trzeba przygotować parsery (czego bardzo nie lubię), ale wierzcie mi – opłaca się. Nawet w Tetrisie (rodzaj klocków), &lt;a href="http://www.gamedev.pl/news,736.html"&gt;Pacmanie&lt;/a&gt; (układ planszy), nie mówiąc już o “Zgadnij o jakiej liczbie myślę”.&lt;/p&gt;  &lt;p&gt;4. Stwórzcie jakiś standard trzymania assetów (modeli, tekstur itd.) w projekcie, żeby nie było wszystko porozrzucane w różnych miejscach. Wydaje się oczywiste, ale jednak niekiedy porządek zostaje zaburzony i wchodzi Pani Entropia ze swoimi walizkami.&lt;/p&gt;  &lt;p&gt;5. Nie opierajcie jednej dziedziny gry na wyłącznie jednym mechaniźmie bez wcześniejszego zbadania, jak on się zachowuje. U nas tak postąpiliśmy (a raczej postąpiłem, bo to niestety ja popełniłem ten błąd) z systemem kolizji i wszystkie obiekty w grze oparliśmy radośnie na kostkach AABB, które jednak nie spełniają do końca swego zadania z jakiegoś względu. Chodzi tutaj o kompatybilność modeli z obiektami w grze, która u nas ucierpiała w wyniku transformacji. Długo by opowiadać, w każdym razie starajcie się obdarzać takie duże mechanizmy elastycznością, aby trzeba było jak najmniej zmieniać w wyniku modyfikacji. Może warto pomyśleć o dziedziczeniu?&lt;/p&gt;  &lt;p&gt;Ta krótka notka dobiegła końca. Niestety, znowu nastaje okres, kiedy nie za dużo będę się udzielał z uwagi na Politechnikę, ale myślę, że coś tam jeszcze w czerwcu poskrobię. Postaram się też zamieścić chociaż część “Dooma”, o ile będzie to możliwe. W międzyczasie naszło mnie też parę refleksji odnośnie pewnych kwestii w silniku, który w zamyśle gdzieś tam cały czas sobie wisi (i w którym już zapomniałem co gdzie jest) – jak wykrystalizują mi się myśli, to postaram się coś o tym napisać i przygotować na krytykę bardziej doświadczonych w tym temacie kolegów (pozdrawiam rzeczonych kolegów), którzy tego typu rzeczy mają już za sobą.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-7116729463764303592?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/7116729463764303592/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=7116729463764303592' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/7116729463764303592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/7116729463764303592'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/05/nie-robcie-tego-w-domu.html' title='Nie róbcie tego w domu'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5416851248574543014</id><published>2010-05-02T20:25:00.002+02:00</published><updated>2010-05-02T20:27:46.793+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Projektowanie'/><category scheme='http://www.blogger.com/atom/ns#' term='Inżynieria oprogramowania'/><title type='text'>Projektowanie w programowaniu ekstremalnym</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S93CxfKDyyI/AAAAAAAAAcE/Bsg4cTClQcY/s1600-h/lcd1%5B3%5D.png"&gt;&lt;img title="lcd1" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 5px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="154" alt="lcd1" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S93CyF6egGI/AAAAAAAAAcI/A6073rPVhiY/lcd1_thumb%5B1%5D.png?imgmax=800" width="244" align="left" border="0" /&gt;&lt;/a&gt; Jak pewnie wiecie, tematem jednego z projektów w tym semestrze jest stworzenie aplikacji graficznej z wykorzystaniem OpenGL, a konkretnie (w przypadku kolegi i moim) – strzelanka FPS w stylu Dooma. Traktuję nieco ten projekt jako pole doświadczalne dla mojego frameworka, ale nie tylko – taka aplikacja jest fantastyczna do testowania swoich umiejętności projektowania obiektowego i zdolności przewidywania tego, co może się zdarzyć. Co za tym idzie – projektowania w taki sposób, żeby potem trzeba było jak najmniej&lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S93C1r05gqI/AAAAAAAAAcM/YSUcsZhW884/s1600-h/doom0001%5B3%5D.png"&gt;&lt;img title="doom0001" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0001" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S93C22mvS4I/AAAAAAAAAcU/1I8ltk_vxDA/doom0001_thumb%5B1%5D.png?imgmax=800" width="166" align="right" border="0" /&gt;&lt;/a&gt; refaktoryzować. W praktyce i tak wychodzi, że trzeba refaktoryzować o 37,6123% więcej niż się przewidywało, ale w końcu po to są te projekty, aby następnym razem ten wskaźnik był mniejszy. I wynosił 37,5088%. &lt;/p&gt;&lt;p&gt;W tytule notki widzimy osławione hasło “w programowaniu ekstremalnym” – istotnie, większość projektów, w jakich uczestniczyłem (czytaj – Wielki Mistrz i nic poza tym) opierała się mniej lub bardziej na tej metodologii (która sama w sobie jest bardzo elastyczna, więc “mniej lub bardziej” jest tu terminem mniej lub bardziej dziwnym). Wspomniałem też wcześniej o refaktoryzacji kodu, co jest jednym z zamierzeniem XP. &lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S93C7JVof0I/AAAAAAAAAcY/q2VXd0Z_x0U/s1600-h/doom0002%5B3%5D.png"&gt;&lt;img title="doom0002" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 5px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0002" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S93C8bUddNI/AAAAAAAAAcc/HEO-Mk9xd8Y/doom0002_thumb%5B1%5D.png?imgmax=800" width="169" align="left" border="0" /&gt;&lt;/a&gt;Albowiem  zostało napisane: “Nie bój się refaktoryzować swego kodu” oraz “Poszerzaj możliwości aplikacji metodą małych kroczków (iteracji)” (oraz nieśmiertelne “Myj zęby po każdym posiłku i nie machaj zanadto rączkami, bo ci odpadną”). Rzeczywiście, w tej metodologii poleca się podejście w stylu:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;“Dzisiaj dodamy klasę stwora i jeden przykładowy model w dowolnym punkcie, aby zobaczyć, czy to w ogóle się uruchamia”&lt;/li&gt;&lt;li&gt;“Dwie godziny szukałem cholernego błędu z wyświetlaniem modelu, a potem się okazało, że pomyliłem radiany ze stopniami”&lt;/li&gt;&lt;li&gt;“To teraz dodajmy managera, żebyśmy mogli dodawać więcej takich potworów”&lt;/li&gt;&lt;li&gt;“To zadziałało za pierwszym razem – niemożliwe, na pewno coś poszło nie tak… Przecież prawa Murphy’ego mówią, że…”&lt;/li&gt;&lt;li&gt;“No trudno. To teraz  dajmy obracanie się modelu w kierunku gracza, a jak to się uda – strzelanie (na razie samoistne)”&lt;/li&gt;&lt;li&gt;“Jeżeli to nam się uda, to niech potwór kontroluje swoją strefę i rusza na gracza, jeżeli ten zbytnio się zbliży”&lt;/li&gt;&lt;li&gt;“Teraz trzeba pomyśleć, jak wykrywać kolizje stwora ze ścianami”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I tak dalej. Jeżeli nie stosowalibyśmy iteracyjnego podejścia, &lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S93DAKDJDFI/AAAAAAAAAcg/01IDfeGRvGI/s1600-h/doom0003%5B3%5D.png"&gt;&lt;img title="doom0003" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0003" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S93DCa2A_CI/AAAAAAAAAck/19M9uV95IOk/doom0003_thumb%5B1%5D.png?imgmax=800" width="169" align="right" border="0" /&gt;&lt;/a&gt; staralibyśmy w projekcie (albo nawet i bez projektu) zapiąć wszystko na ostatni guzik i dopiero potem wszystko pisać, a jeśli byłyby jakieś błędy, to mamy masę kodu do sprawdzenia. Przy takich małych kroczkach jesteśmy w stanie dosyć szybko znajdować błędy, a przynajmniej wiemy, gdzie należy szukać niedociągnięcia. Jest też aspekt psychologiczny – gdy kolejne etapy kończą się sukcesem, mamy poczucie spełnionego obowiązku. Nie tworzymy ponadto masę kodu, tylko to, co jest w danej chwili potrzebne. Po takiej udanej sesji z czystym sumieniem możemy zająć się grą w Baldur’s Gate 2.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S93DIXh4atI/AAAAAAAAAco/rhlN5URVWpA/s1600-h/doom0004%5B3%5D.png"&gt;&lt;img title="doom0004" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 5px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0004" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S93DKTET4UI/AAAAAAAAAcs/y45FjGxC9Qg/doom0004_thumb%5B1%5D.png?imgmax=800" width="166" align="left" border="0" /&gt;&lt;/a&gt; No dobrze, ale to kwestia iteracji i refaktoryzacji. Tak naprawdę jednak notka miała dotyczyć samego procesu projektowania. Jeżeli nie stało się nic złego, to obok możecie znaleźć kilka dziwnie zapisanych kartek (dwie z nich (te o oświetleniu) nie dotyczą gry, ale silnika, który nadal gdzieś tam sobie siedzi i odpoczywa). To nie są zapiski jakiegoś szalonego maga, tylko notatki, które sporządzam na uczelni, gdy mam jakąś przerwę, a akurat wpadnie mi do głowy pomysł na dodanie kolejnej funkcjonalności do projektu. Czyli w sumie zapiski szaleńca, ale nie maga, a – sądząc po estetyce i logice zapisków – jakiegoś demilisza.&lt;/p&gt;&lt;p&gt;Dobrze, ale tak poważnie – patrząc na te notatki można wyczuć schemat postępowania w projektowaniu. &lt;/p&gt;&lt;p&gt;Standardowo, w przypadku wszelkiego rodzaju obiektów – mamy klasę danego obiektu (np. CEnemy), ale także klasę managera, który zarządza wszystkimi obiektami danego typu (czyli np. obsługa przeciwników byłaby w klasie CEnemyManager). Co nam to daje? Nie musimy zajmować się wszystkimi sprawami związanymi z daną rzeczą. Przykładowo – manager przeciwników jest przez nas tylko inicjalizowany i podawany jest plik, z które mają być wczytane instancje (o tym za chwilę), a potem wywołujemy coś w rodzaju “Drogi Panie Managerze – aktualizuj wszystko i renderuj” i na tym nasza ingerencja się kończy. Całą resztę implementujemy już we wnętrzu klasy, gdzie manager obserwuje sytuację na podstawie wskaźników, które mu podajemy (np. pozycja gracza, pobliskie obiekty) i odpowiednio &lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S93DPIoMQQI/AAAAAAAAAcw/FWLRAzwgUGI/s1600-h/doom0005%5B3%5D.png"&gt;&lt;img title="doom0005" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0005" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S93DRNNsiVI/AAAAAAAAAc0/A8qhgqnZC70/doom0005_thumb%5B1%5D.png?imgmax=800" width="166" align="right" border="0" /&gt;&lt;/a&gt; reaguje. Właśnie w tym kierunku powinno iść nasze myślenie – jak najmniej my wykonujemy, a tylko podrzucamy “mięso” managerowi i on już sobie sam z tego wyciąga to, co jest mu potrzebne. Proste i wygodne – zwłaszcza, że mamy jedną klasę CWorldObject, z której wiele innych klas (przeciwnicy, pociski itd.) dziedziczy. Tak jakby dać dziecku dużo zabawek, a on nam z tego coś wykreuje. &lt;/p&gt;&lt;p&gt;Cała zabawa polega teraz na tym, aby te managery ze sobą poskładać i żeby ze sobą współgrały. To już zadanie typowo zależne od tego, co piszemy – przykładowo, obiekty przeciwników i gracza należy wrzucić (tzn. wskaźnik na nie) do Pan Wykrywacza Kolizji, a Pan Wykrywacz Kolizji zrobi “Łubudu” i wskaże nam te obiekty, których boli głowa po próbie przełamania powiedzenia “głową muru nie przebijesz”. &lt;/p&gt;&lt;p&gt;Klasy należy tworzyć umiejętnie. Nie zakładać z góry, że będziemy potrzebowali tego, tego, tego i jeszcze tamtego, ale dopisywać tylko to, co jest nam naprawdę potrzebne. Na tych szalonych zapiskach widzicie – co gdzie jest obsługiwane, co z czego wynika itd. Pomaga rozrysowywanie bloczków i myślenie nimi, ale nie mówię tutaj o czystym UML-u – przy projektowaniu aplikacji na tym poziomie (i do tego w XP) nie powinno się moim skromnym zdaniem trzymać ściśle standardu UML-a, a jedynie rozrysowywać tak, żeby wszystkim było wygodnie (jak komuś to pomaga, to może nawet kwiatki dodać). Jak widać, w takim modelu projektowym, jaki tutaj proponuję (który, nota bene, jest inspirowany konstrukcją kodu Wielkiego Mistrza (bardzo mocno inspirowany [no dobrze, niemalże identyczny, tylko bez pewnych mechanizmów w stylu singletona i Aż Takiej Obiektowości (ATO)])) rysowanie takich bloczków jest bardzo wygodne. Nazwałbym to “modelem chmurkowym”, gdyż tak naprawdę te wszystkie “odnogi” to takie chmurki, które mogą się między sobą mieszać i odwiedzać znajomych (“Cześć, co u Ciebie słychać? O, widzę że jestem potrzebny przy wykrywaniu stanu potwora?”). Podejrzewam jednak, że taki model ma już jakąś nazwę i to dużo mądrzejszą. Może bąbelki?&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S93DVEhzfRI/AAAAAAAAAc4/DYcm_k11xg4/s1600-h/doom0006%5B3%5D.png"&gt;&lt;img title="doom0006" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 5px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0006" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S93DXqvLs2I/AAAAAAAAAc8/S4y8MkiOCHU/doom0006_thumb%5B1%5D.png?imgmax=800" width="169" align="left" border="0" /&gt;&lt;/a&gt; Wcześniej wspomniałem o wczytywaniu instancji z pliku. Tak naprawdę jest to zabieg, który nie poprawia efektywności działania aplikacji, za to daje nam wręcz gigantyczny postęp w zakresie testowania aplikacji i wprowadzania poprawek. Nie trzeba bowiem rekompilować projektu (co troszkę czasu zabiera), a wprowadzanie modyfikacji jest znacznie przyjemniejsze. Oczywiście, wiąże się to z pisaniem parsera, co zbyt przyjemnych zajęciem nie jest (choć niektórzy to lubią), ale czego się nie robi dla zaoszczędzenia czasu pracy (który można poświęcić na Baldur’s Gate 2). Jeżeli dobrze skojarzycie, to Wielki Mistrz był całości oparty na danych pobranych z pliku (jak większość produkcji) – u nas jest to “większość” (bo nie chce nam się pisać zaawansowanego parsera do wszystkiego, a czas goni). &lt;/p&gt;&lt;p&gt;Wróćmy na chwilę do samego kodu. Jak więc widać, w wielu &lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S93Dc-kszhI/AAAAAAAAAdA/Deds_zFTNn0/s1600-h/doom0007%5B3%5D.png"&gt;&lt;img title="doom0007" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="244" alt="doom0007" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S93DfAMq-OI/AAAAAAAAAdE/4Zm8f5a3ty0/doom0007_thumb%5B1%5D.png?imgmax=800" width="194" align="right" border="0" /&gt;&lt;/a&gt; miejscach korzystamy z podobnych obiektów (o podobnych typach), które w podobnych metodach pełnią podobne role i stwarzają podobne problemy. Ale pamiętajmy, że tak naprawdę to jest jeden i ten sam obiekt. Właśnie to jest potęga wskaźników. Inna ich zaleta objawia się przy planie “includowania” plików nagłówkowych – dzięki wskaźnikom w parametrach metod w pliku .h (deklaracji klasy i jej ciała) możemy dać jedynie deklarację zapowiadającą (np. “class CCamera;”), a dopiero w pliku .cpp załączać odpowiedni plik z definicją (np. klasy CCamera). Pozwala to zapobiec błędom linkowania i uprzyjemnić kompilację. I wcześniej zacząć sesję z Baldurem.&lt;/p&gt;&lt;p&gt;Cóż, mam nadzieję, że nieco rozjaśniłem parę kwestii. Pewnie powstaną jakieś inne notki na temat projektowania, ale w tej chwili nie mam pomysłu, o czym w nich można napisać. Może Wy macie jakieś idee? Może komuś się w ogóle podobała ta notka? A który macie poziom w BG2?&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5416851248574543014?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5416851248574543014/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5416851248574543014' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5416851248574543014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5416851248574543014'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/05/projektowanie-w-programowaniu.html' title='Projektowanie w programowaniu ekstremalnym'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_R2ix0MLn8lM/S93CyF6egGI/AAAAAAAAAcI/A6073rPVhiY/s72-c/lcd1_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5883783748025771192</id><published>2010-04-22T20:58:00.002+02:00</published><updated>2010-04-22T21:00:01.609+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Ten marudny robot</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S9CcAm3D1bI/AAAAAAAAAbc/uohUS8h5Bi0/s1600-h/IMG_17003.jpg"&gt;&lt;img title="IMG_1700" style="border-width: 0px; display: inline; margin: 0px 5px 0px 0px;" alt="IMG_1700" src="http://lh5.ggpht.com/_R2ix0MLn8lM/S9CcCJWwnII/AAAAAAAAAbg/f_rIGir7cG8/IMG_1700_thumb1.jpg?imgmax=800" align="left" border="0" width="244" height="184" /&gt;&lt;/a&gt; Pisałem ostatnio o projekcie, który robiliśmy całą grupą laboratoryjną, a mianowicie o robocie. Po tygodniu opóźnienia, spowodowanym nieprzewidzianymi problemami technicznymi (o których za chwilę), udało się w końcu pokazać dzieło prowadzącemu. Przy tej okazji został też nakręcony film.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div align="center"&gt;&lt;object width="450" height="361"&gt;&lt;param name="movie" value="http://www.youtube.com/v/a1bzsNDwKhs&amp;amp;hl=pl_PL&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/a1bzsNDwKhs&amp;amp;hl=pl_PL&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="420" height="337"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Jak widać, nie jest to może R2D2, ale i tak wszystkie grupy są dumne ze swoich robotów. Taka już cecha autorów. Chociażby dlatego, że większość wie, ile pracy, nerwów, czasu, nerwów i &lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcEGJzB-I/AAAAAAAAAbk/QB7wiZFk9m0/s1600-h/IMG_70324.jpg"&gt;&lt;img title="IMG_7032" style="border-width: 0px; display: inline; margin: 0px 0px 0px 5px;" alt="IMG_7032" src="http://lh5.ggpht.com/_R2ix0MLn8lM/S9CcFHj8pTI/AAAAAAAAAbo/SLvTuTIWzjU/IMG_7032_thumb2.jpg?imgmax=800" align="right" border="0" width="207" height="156" /&gt;&lt;/a&gt; jeszcze raz czasonerwów należy włożyć w taki pojazd, aby w końcu jechał wyznaczoną trasą. &lt;/p&gt;  &lt;p&gt;Problemy techniczne były generalnie natury filozoficzno-egzystancjalno-elektronicznej. Generalnie bywały dni, kiedy robot jeździł jak mu trasa polecała i był bardzo posłuszny. Niestety, miał bardzo sinusoidalny humor i w następnych dniach zmuszał całą grupę do denerwowania się, bo nagle uznawał skręcanie w lewo za zbyt pospolite zachowanie i jechał prosto wprost na ścianę/krzesło/plecak/cokolwiek. Wprawdzie robocik jest dosyć &lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcHbnWemI/AAAAAAAAAbs/bigzJRr_Fgc/s1600-h/IMG_70414.jpg"&gt;&lt;img title="IMG_7041" style="border-width: 0px; display: inline; margin: 0px 5px 0px 0px;" alt="IMG_7041" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcIk-JxZI/AAAAAAAAAbw/qTFysJP-TZc/IMG_7041_thumb2.jpg?imgmax=800" align="left" border="0" width="216" height="163" /&gt;&lt;/a&gt; masywny i mógłby przepchnąć ścianę (z papieru)/krzesło (z tektury)/ plecak (taki dla 4-latka)/cokolwiek (a tutaj co napisać?), ale jednak nie chcieliśmy ryzykować jego uszkodzenia. &lt;/p&gt;  &lt;p&gt;W czym zatem był problem i dlaczego siedzieliśmy nad nim tydzień (niemalże cały)? To, że jeden z czujników (dzięki którym robot rozpoznaje czarne pole mówiąc “aha, skręć w przeciwną stronę”) był nieskalibrowany można było wybaczyć. To, że sygnały od czujników okazywały się “szpilkami” (tzw. zjawisko hazardu) i tak naprawdę program widział je tylko przez chwilę, a robot i tak radośnie (aż mu bateria podskakiwała) jechał w kierunku zachodzącego słońca – dało się jakoś zamaskować programem (chodziło o to, że do tak zwanej pętli ruchu program &lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S9CcKsiEkHI/AAAAAAAAAb0/f-6e48wYTzg/s1600-h/IMG_70474.jpg"&gt;&lt;img title="IMG_7047" style="border-width: 0px; display: inline; margin: 0px 0px 0px 5px;" alt="IMG_7047" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcNoTpxAI/AAAAAAAAAb4/Ec5RnqrOiL0/IMG_7047_thumb2.jpg?imgmax=800" align="right" border="0" width="207" height="156" /&gt;&lt;/a&gt; wchodził przy stanie “jedź prosto” i tak też natychmiastowo wychodził, gdyż czujniki nie zdążyły przesłać danych o terenie). Ale to, że aby zaczął porządnie działać wystarczyło mocniej przycisnąć jeden element na obudowie – to już przerosło nerwy najbardziej zaangażowanych (bo jednak trzeba uczciwie przyznać – przy szesnastu osobach, delikatnie mówiąc, nie wszyscy pracują). Tak naprawdę, w ostatnim dniu przed oddaniem udało się to naprawić i od tej pory nie wolno było oddychać w pobliżu robota ani chwytać go za intymne części obudowy. Dokonanie tego było grożone tym, że będę dobierał muzykę do filmu z procesu powstawania robota (a ja z kolei uważam, że death metal/grindcore doskonale podkreśla nasze dzieło). Pomysł pomalowania robota na różowo również został postawiony przed oblicze tej samej kary (żeby nie było – nie byłem żadnym kierownikiem grupy, tylko głównym programistą-od-siedmiu-boleści lub “Tym, Który Się Wydzierał, A Niewiele Robił” (TKSW,ANR)). &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcP7i0SsI/AAAAAAAAAb8/AvTt5-CfaMM/s1600-h/IMG_70493.jpg"&gt;&lt;img title="IMG_7049" style="border-width: 0px; display: inline; margin: 0px 5px 0px 0px;" alt="IMG_7049" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S9CcTEmfTAI/AAAAAAAAAcA/msbmPtGNNsI/IMG_7049_thumb1.jpg?imgmax=800" align="left" border="0" width="244" height="184" /&gt;&lt;/a&gt; Z samym robotem będzie nas jeszcze czekała zabawa pod koniec semestru, gdyż druga część tzw. warsztatów będzie polegała na zastąpieniu kabla podłączonego do portu LPT poprzez mikroprocesor umieszczony w samym robocie. Cóż, o postępach pewnie też będę informował, gdyż to również będzie rozrywkowa część tego semestru.&lt;/p&gt;  &lt;p&gt;Jeżeli chodzi o inne projekty – klon Dooma się tworzy (obiektowo jak jasna cholera – od jakiegoś czasu nie wiem, które obiekty z którymi się porozumiewają, ale doświadczenie z obserwowania kodu Wielkiego Mistrza się przydaje), inne projekty również, silnik stoi w miejscu (historia lubi się powtarzać). Za to bardzo jasnym punktem ostatniej egzystencji jest (w końcu) zainstalowanie Baldur’s Gate 2 i rozkoszowanie się jedną z najlepszych gier wszechczasów (moim skromnym zdaniem). Oczywiście, pod Vistą są pewne problemy natury technicznej, więc po włączeniu odpowiednich opcji korygujących komputer niesamowicie zwalnia przy dużej ilości obiektów, ale dla takiej gry naprawdę warto.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5883783748025771192?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5883783748025771192/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5883783748025771192' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5883783748025771192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5883783748025771192'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/04/ten-marudny-robot.html' title='Ten marudny robot'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_R2ix0MLn8lM/S9CcCJWwnII/AAAAAAAAAbg/f_rIGir7cG8/s72-c/IMG_1700_thumb1.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5841888847657699665</id><published>2010-04-02T13:43:00.003+02:00</published><updated>2010-04-02T22:17:00.134+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Robot'/><category scheme='http://www.blogger.com/atom/ns#' term='Programowanie niskopoziomowe'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Dwa tygodnie spod znaku robota</title><content type='html'>&lt;p&gt;Jak pewnie zdążyliście zauważyć (i się przyzwyczaić), od dłuższego czasu nie było notki na blogu. Nie będę jednak ukrywał, że nie jest to nic dziwnego – takiego sajgonu, jaki mieliśmy od dwóch tygodni na uczelni, jeszcze nie moje oczy nie widziały.&lt;/p&gt;&lt;p&gt;Nie lubię się rozwodzić nad szczegółami, dlatego napiszę wprost w czym rzecz – otóż, w 1,5 tygodnia (przynajmniej taki był planowany okres) mieliśmy całą grupą laboratoryjną stworzyć robota, który będzie sam jechał po trasie złożonej z białych kartek i skręcał po wykryciu zboczenia z trasy przez czujniki, które miał na sobie rozmieszczone. Kontrola ruchu miała się odbywać poprzez program komputerowy (C + Assembler), z którym robot miałby się komunikować przy pomocy portu LPT (takiego, jakiego kiedyś stosowało się przy drukarkach). Istniało założenie minimalizacji kosztów z tego względu, iż robot zostanie nam odebrany po oddaniu.&lt;/p&gt;&lt;p&gt;Brzmi groźnie, prawda? Sama zabawa jest przednia (szczególnie, że musieliśmy się zorganizować), ale termin 1,5 tygodnia już do najprzyjemniejszych nie należy. Na szczęście, w ostatnim dniu udało się nakłonić prowadzącego do wyznaczenia innego terminu, dzięki czemu wiele grup będzie mogło spokojnie jeszcze nad robotem popracować. Ja bym chciał jednak opowiedzieć, jak przebiega praca nad takim robocikiem od strony organizacyjno-programistycznej. Zarówno zdjęcia jak i (być może) filmik przedstawię Wam już po oddaniu (wiecie, tajemnice technologiczne i takie tam).&lt;/p&gt;&lt;p&gt;Grupa laboratoryjna liczy sobie 16 osób i to automatycznie generuje nam pierwszy wniosek – nie dla wszystkich znajdzie się praca, a ponadto nie wszyscy będą chcieli pracować. Tak to zawsze bywa. Pomijając jednak ten fakt, podzieliliśmy się na cztery bataliony:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Mechanika&lt;/li&gt;&lt;li&gt;Elektronika&lt;/li&gt;&lt;li&gt;Oprogramowanie&lt;/li&gt;&lt;li&gt;Filmowanie (do robota mieliśmy dołączyć film z jego powstawania)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Zadanie każdego batalionu było w miarę przejrzyste. Mechanicy mieli skonstruować robota, zainstalować w nim silniki (które – chlip – przyniosłem z własnego modelu pojazdu opancerzonego na radio), kółka i generalnie przygotować go do poruszania się. Elektronicy mieli – moim skromnym zdaniem – najcięższą robotę, gdyż musieli przygotować cały układ elektroniczny robota, dający napięcie na silniki oraz pobierający informację od czujników fototranzystorowych. Programiści musieli z kolei stworzyć program, który poprzez port LPT będzie przyjmował przerwania (zjechanie z trasy) oraz na podstawie stanu czujników wysyłał odpowiednie wartości na silniki, aby te skręciły pojazdem.&lt;/p&gt;&lt;p&gt;Jak widać, odpowiednie grupy musiały ze sobą współpracować, dzięki czemu mieliśmy typowy projekt oparty na pracy zespołowej (przy okazji – wiele zdań piszę w czasie przeszłym, jednak nie dajcie się zwieść – przy robociku czeka nas jeszcze troszkę pracy).&lt;/p&gt;&lt;p&gt;Jako że jestem w (skromnym) batalionie programistów (większość grupy od razu rzuciła się na mechanikę), przedstawię nieco obszerniej nasze zadania:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Przyjmowanie przerwania przez wejście ACK portu LPT&lt;/li&gt;&lt;li&gt;Przyjmowanie informacji od czujników (na odpowiednie wejścia)&lt;/li&gt;&lt;li&gt;Obsługa przerwania poprzez układ 8259A w komputerze oraz takie skręcanie pojazdem, aby ten wyszedł na prostą&lt;/li&gt;&lt;li&gt;Wykorzystanie układu liczącego 8253 lub 8254 do czegokolwiek (u nas jest to brzęczyk w komputerze przy wykryciu przez czujnik zjechania z trasy)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Generalnie, do boju został rzucony kompilator Turbo C++ w wersji 3.0, dzięki któremu mogliśmy zrobić wstawki asemblerowe wymagane przez prowadzącego. Przy okazji samej konfiguracji komputera, większość grup żałowała, że przy laptopach nie mamy wbudowanej stacji dyskietek. Dlaczego? Komputery, których używamy do robota są zwykle stare i od biedy działa w nich napęd CD – o pendrive’ach nie ma mowy, a jedynym słusznym rozwiązaniem są dyskietki. Zabawy było z tym co nie miara (dawanie kolegom dyskietek do domu, gdzie ci mieli komputer stacjonarny, a następnie przesłanie kodu źródłowego do nas, dokonanie zmian, przesłanie z powrotem do kolegi z dyskietką itd.).&lt;/p&gt;&lt;p&gt;Jeżeli zaś chodzi o samo programowanie na niskim poziomie – przyznam uczciwie, że nie jest to mój ulubiony sposób spędzania czasu. Kodowanie na samych prymitywnych układach jest dosyć ciężkie i na pewno parę razy zdarzy się Wam przeklnąć, jeżeli coś takiego będziecie musieli zrobić. Tym bardziej, jak na parę dni (czy nawet godzin) przed oddaniem projektu nagle coś Wam padnie. Jeszcze gorzej mieli elektronicy, którzy po parę godzin szukali błędów w swoim układzie. &lt;/p&gt;&lt;p&gt;Jeżeli jednak zainteresował Was ten temat (albo w przyszłości zamierzacie być na 4. semestrze Informatyki na Politechnice Poznańskiej), to mogę polecić parę linków:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.lpt.strona.pl/"&gt;Programowanie portu LPT (dobrze wytłumaczona teoria)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.freefm.kni.pl/mike/lpt.html"&gt;Programowanie portu LPT (tutaj macie dobry schemat portu)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.delphi3000.com/articles/article_3773.asp?SK="&gt;Uruchomienie PC Speakera w komputerze (poprzez 8253)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://poli.cs.vsb.cz/c/help/dos.htm"&gt;Informacje o funkcjach z biblioteki dos.h&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;No dobrze, a jak wygląda ogólny schemat takiego programu?&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Na wejście IRQ7 kontrolera 8259(A) podajecie własną obsługę przerwań (o której później)&lt;/li&gt;&lt;li&gt;Inicjalizujecie porty LPT i inne takie&lt;/li&gt;&lt;li&gt;Czekacie na przerwanie od czujników robota (który wcześniej miał zadane “jedź prosto”)&lt;/li&gt;&lt;li&gt;Po przyjęciu przerwania w pętli obserwujecie stan czujników i sprawdzacie, w którą stronę robot powinien skręcić (tu już są kwestie, które trzeba omówić z elektronikami)&lt;/li&gt;&lt;li&gt;Jeżeli robot wjedzie z powrotem na trasę (lub całkowicie z niej zboczy) – kończycie obsługę przerwania i czekacie na następne&lt;/li&gt;&lt;li&gt;Przywracacie poprzednie ustawienia swoich układów i kończycie pracę&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;To naprawdę skrótowy opis – wiele pytań pewnie Wam się nasuwa, np. “co to znaczy, że ‘robot powrócił na trasę’?” lub też “jak inicjalizujecie port LPT?” (a zwłaszcza “po co mi to wiedzieć?”). W każdym razie – zabawy przy tym jest bardzo dużo, a przy okazji możecie się dowiedzieć, jak się objawia stres grupowy przy pracy z nadciągającym deadline’em. Zaprawdę, emocje są bardzo duże. Dlatego przepraszam niektórych, że na nich, delikatnie mówiąc, się wydarłem.&lt;/p&gt;&lt;p&gt;Śmiało piszcie komentarze i uwagi – z pewnością powstanie jeszcze jedna notka o takim robocie i jeżeli ktoś chciałby się dowiedzieć czegoś bardziej szczegółowego (ale w granicach rozsądku), to chętnie postaram się odpowiedzieć.&lt;/p&gt;&lt;p&gt;Pozdrawiam, dziękuję i życzcie nam szczęścia - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5841888847657699665?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5841888847657699665/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5841888847657699665' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5841888847657699665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5841888847657699665'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/04/dwa-tygodnie-spod-znaku-robota.html' title='Dwa tygodnie spod znaku robota'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-1246501643639630002</id><published>2010-03-15T08:24:00.001+01:00</published><updated>2010-03-15T08:24:08.519+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Rzut izometryczny – od góry, od boku i implementacja kamery warcraftowej</title><content type='html'>&lt;p&gt;&lt;img style="display: inline; margin: 0px 5px 0px 0px" height="148" src="http://pcmedia.ign.com/pc/image/warcraft3frozen_012203_006_640w.jpg" width="197" align="left" /&gt; Pisałem już o tym, że zacząłem pisać silniczek Scav, który będzie niejako rozwinięciem i bardziej racjonalną postacią frameworka Yesta, którym męczyłem Was dość długi czas. Tym razem jednak postanowiłem podejść do tematu projektowania poważniej, czyli faktycznie najpierw zaprojektować, a później implementować. Co prawda, cierpliwości starczyło mi na jakieś dwa dni, ale i tak widać postęp – kod jest dużo bardziej poukładany i przyjemniejszy.&lt;/p&gt;  &lt;p&gt;Jeżeli projekt silnika podzielimy sobie na takie bąbelki (nazwa inspirowana &lt;a href="http://www.cs.brown.edu/people/acb/codebubbles_site.htm"&gt;tym pomysłem&lt;/a&gt;), które swoją wielkością mówią nam też o tym, ile uwagi powinno im się poświęcić, to jednym z ważniejszych fragmentów pierwszej odsłony Scava jest obsługa kamery. Założyłem bowiem, że dobrym pomysłem będzie utworzenie bazowej klasy CCamera, z której dziedziczyć będą klasy reprezentujące poszczególne projekcie i perspektywy (FPP, TPP, izometria, itd.). Z FPP nie było specjalnego problemu, gdyż kod odpowiedzialny za tę perspektywę mam już gotowy od dawna. Podejrzewam, że TPP dużo odbiegać od FPP nie będzie (choć jeszcze nie implementowałem), natomiast w przypadku rzutu izometrycznego próbowałem eksperymentować. I stąd też ten artykuł.&lt;/p&gt;  &lt;p&gt;Jeżeli ktoś jednak już od razu “napalił” się na rzut izometryczny i właśnie otworzył edytor z zamiarem szybkiego klepania kodu – polecam &lt;a href="http://en.wikipedia.org/wiki/Isometric_projection"&gt;odpowiednią stronę na Wikipedii&lt;/a&gt;, gdzie pokazana jest prosta macierz, przez którą należy mnożyć współrzędne punktów, aby uzyskać oczekiwany efekt. Przyznam uczciwie, że starając się pomyśleć nad implementacją nie spoglądałem na żadne inne źródła. Takie coś czasami pomaga człowiekowi – siedzieć przez parę wieczorów nad notesem i wymyślać wzory, aby choć przez chwilę poczuć się dobrym matematykiem.&lt;/p&gt;  &lt;p&gt;Ogólnie rzecz biorąc, kamera miała:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Przyjmować dowolny kąt nachylenia względem osi X &lt;/li&gt;    &lt;li&gt;Przyjmować dowolny kąt nachylenia względem osi Z &lt;/li&gt;    &lt;li&gt;Znajdować się na dowolnej wysokości &lt;/li&gt;    &lt;li&gt;Umożliwiać przesuwanie względem osi X i Z &lt;/li&gt;    &lt;li&gt;Pozwalać na wskazywanie kursorem myszki obszaru na scenie &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak widać, nie założyłem nigdzie obracania całej sceny (uznałem, że zwykła rotacja dobrze się sprawdzi), a przy przyjmowaniu dowolnego kąta nachylenia nie testowałem wartości spoza zakresu [-90, 90] stopni. Nie przedstawię też póki co wskazywania kursorem myszki obszaru na scenie – jest to zaimplementowane, ale nie działa tak, jak to sobie założyłem, więc na to przyjdzie pora. Tak czy inaczej, efekt końcowy nie jest najgorszy. Zatem – do dzieła.&lt;/p&gt;  &lt;p&gt;Najpierw musimy założyć, jak zdefiniujemy kąty nachylenia w &lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S53gWvjt1FI/AAAAAAAAAak/qIban9OFVqU/s1600-h/plane13.png"&gt;&lt;img title="plane1" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 5px; border-right-width: 0px" height="173" alt="plane1" src="http://lh5.ggpht.com/_R2ix0MLn8lM/S53gX3IkIGI/AAAAAAAAAao/wvsii7YwgtY/plane1_thumb1.png?imgmax=800" width="244" align="right" border="0" /&gt;&lt;/a&gt; stosunku do osi X i Z. Pewnie bardziej intuicyjne (w pierwszej chwili) byłoby założenie numer 1 (pokazane gdzieś obok). Kąt alfa to nachylenie wzgędem osi x, a kąt beta – względem osi z. Do tego mamy również daną wysokość h, na której znajduje się kamera. Zadaniem naszego algorytmu będzie obliczenie, na jaki punkt V będzie spoglądała kamera, jeżeli punkt obserwatora to E. Krótko mówiąc – gdzie znajdować się będzie “centrum” sceny, na które będziemy patrzeć przy odpowiednim nachyleniu i wysokości. Wielkości, które będziemy obliczać, to OffsetX i OffsetZ. Patrząc na sytucję ukazaną na rysunku pierwszym widzimy, że im bardziej kąt alfa będzie zbliżał się do 90 stopni, tym bardziej pionowo będziemy patrzeć na np. teren (przyjmijmy, że to nasza&amp;#160; scena).&amp;#160; Podobnie z kątem beta. Jak widać, jest to dosyć intuicyjne założenie, ale nie wykorzystamy go w naszym &lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S53gZNbfAtI/AAAAAAAAAas/aejJ1lXWgPE/s1600-h/plane27.png"&gt;&lt;img title="plane2" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 5px 0px 0px; border-right-width: 0px" height="173" alt="plane2" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S53ga__-oBI/AAAAAAAAAaw/Guo0a6jLUf0/plane2_thumb3.png?imgmax=800" width="244" align="left" border="0" /&gt;&lt;/a&gt; algorytmie. Powód? W momencie, jak pisałem kolejne wzorki, przyjąłem, iż “widok z lotu ptaka” (nie wiem dlaczego, ale to sformułowanie niektórych śmieszy) będzie przy kątach równych 0, natomiast “wychylać się” będziemy w zakresie [-90, 90] stopni. Dlatego w naszym algorytmie, skupimy się na sytuacji numer 2 (nigdzie nie wspominałem, że to, co opisuję, jest jak najbardziej logiczne). &lt;/p&gt;  &lt;p&gt;Dobrze, zatem teraz przyda nam się trygonometria. Przypatrzmy się poniższemu rysunkowi.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S53gb1rBinI/AAAAAAAAAa0/gqeOoGNavyQ/s1600-h/plane4.png"&gt;&lt;img title="plane" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="203" alt="plane" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S53geCu271I/AAAAAAAAAa4/gkg63dJLIec/plane_thumb2.png?imgmax=800" width="286" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Jeżeli nic byśmy nie mieszali, kamera (zawieszona w punkcie E) patrzyłaby normalnie na punkt S. Jednakże, ponieważ ustawiliśmy ją pod pewnym kątem i na odpowiedniej wysokości, będzie ona spoglądała na inny punkt, oznaczony tutaj jako V. Naszym zadaniem pozostaje wyliczyć odległość na osi X i Z punktu V od punktu S. Jeżeli popatrzymy uważniej na powyższy szkic oraz wcześniej przedstawiony szkic z numerem drugim, to zobaczymy, że mamy dwa trójkąty – każdy z nich ma przyprostokątną h oraz określony kąt (alfa lub beta). Korzystając z funkcji tangens, łatwo możemy obliczyć nasze przesunięcia (offsety):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S53ge5mlXPI/AAAAAAAAAa8/qptMp6FmSn4/s1600-h/offsets3.png"&gt;&lt;img title="offsets" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="103" alt="offsets" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S53gf8DHpTI/AAAAAAAAAbA/LU1Vw7VxycA/offsets_thumb1.png?imgmax=800" width="244" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Nie widać tego może na pierwszy rzut okna, ale jak rozrysujecie sobie tę sytuację na kartce, to jest to jasne. Teraz możemy odpowiednio zdefiniować kamerę, na przykład za pomocą OpenGL-owej funkcji gluLookAt.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/S53ggj9JgwI/AAAAAAAAAbE/M_YRCEDlaCw/s1600-h/glulookat4.png"&gt;&lt;font color="#956839"&gt;&lt;/font&gt;&lt;img title="glulookat" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="132" alt="glulookat" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S53gh17XlYI/AAAAAAAAAbI/ZJhVCjd-PpA/glulookat_thumb2.png?imgmax=800" width="392" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Dobrze, mamy zatem już naszą kamerę i się bardzo nią cieszymy. W grach strategicznych możemy też często naszą kamerą sterować na dowolne sposoby. Tak jest chociażby w Warcrafcie III – screen przy nagłówku notki nie został dodany przypadkowo. W dalszej części skupimy się zatem na przesuwaniu naszej kamery w czterech kierunkach (np. za pomocą strzałek).&lt;/p&gt;  &lt;p&gt;Jeżeli chodzi o przesuwanie, to związana z nim jest całkiem ciekawa właściwość – uniwersalność. Sposób, który za chwilę przedstawię, jest także wykorzystywany przy kamerze FPP, gdyż nie ma dla niego różnicy, pod jakim kątem względem osi X i Z patrzymy, a jedynie to, jakie mamy punkty E i S. Taka całkiem miła ciekawostka.&lt;/p&gt;  &lt;p&gt;Pierwsze, co należy zrobić, to obliczyć sobie początkowy wektor Dir, który będzie różnicą punktów S i E (czyli Dir = S – E). Teraz skupmy się na poruszaniu do przodu i tyłu o pewną “szybkość” speed. Ponieważ będziemy przesuwać punkty E i S o ten sam wektor, formuły będą bardzo podobne. Poniżej widzimy, jak to rozpisać na ruch do przodu&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S53gif3x8PI/AAAAAAAAAbM/sG0k934wk3o/s1600-h/kod13.png"&gt;&lt;img title="kod1" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="97" alt="kod1" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S53gjMR2xQI/AAAAAAAAAbQ/pahPy8d6k0w/kod1_thumb1.png?imgmax=800" width="220" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;W przypadku cofania się wystarczy, że zamienimy plus na minus. Jakby tłumaczyć to “na chłopski rozum” – współrzędne x i z wektor Dir mówią nam jaka odległość w płaszczyźnie XZ dzieli punkty E i S, co przekłada się na sformułowanie “w jakim kierunku mamy ruszyć do przodu, aby użytkownik nie bluzgał na SceNtriCa”. Nie musimy też przejmować się tym, że w OpenGL mamy układ prawoskrętny i często idąc do przodu tak naprawdę poruszamy się po coraz mniejszych wartościach na osi z – wektor Dir przyjmie wtedy współrzędną z mniejszą od zera i całość zadziała dobrze.&lt;/p&gt;  &lt;p&gt;Nieco więcej zabawy jest przy poruszaniu na boki, czyli “strafe’owaniu”. W tym przypadku musimy jeszcze obliczyć wektor prostopadły P do wektora Dir, co będzie się przedstawiało tak:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S53gkPGu3wI/AAAAAAAAAbU/SRLcHWPKFXY/s1600-h/kod23.png"&gt;&lt;font color="#956839"&gt;&lt;/font&gt;&lt;img title="kod2" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="151" alt="kod2" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S53glAp6oXI/AAAAAAAAAbY/nJA22Vvlz0M/kod2_thumb1.png?imgmax=800" width="210" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Formuła niemalże się nie zmieniła. Powyżej widać implementację ruchu w prawo i – myśląc tak samo jak wyżej – wystarczy zmienić plus na minus, aby nasza kamera podreptała w lewo. &lt;/p&gt;  &lt;p&gt;Jak widać, poruszanie się nasza kamerę nie jest specjalnie wyuzdane intelektualnie. Sam pomysł wziąłem z przykładu ze strony &lt;a href="http://www.morrowland.com"&gt;www.morrowland.com&lt;/a&gt; i kamera FPP, która była w frameworku (a także jest w silniku) również opiera się na tym algorytmie. &lt;/p&gt;  &lt;p&gt;Pisząc ten artykuł, moim głównym celem nie jest pokazanie niesamowitej kamery z rzutem izometrycznym, która zawładnie światem i pozwoli Wam jeść czekoladowe płatki codziennie na śniadanie. Chciałem głównie pokazać, jaki jest proces pisania algorytmu i choć przedstawiam już końcowy rezultat, to musicie wiedzieć, że sa one wynikiem wielu różnych prób. Dlaczego mówię o tym teraz? Gdyż chciałem opisać wskazywanie pola kursorem myszki. Naprawdę chciałem. Jednak, jak już wspomniałem, to zadanie było dosyć skomplikowane Każde zadanie robi się dosyć skomplikowane, jeśli 2-3 pierwsze algorytmy, które rozpisywało się przez dwie godziny nie działają. Ani obejmowanie czterema promieniami widocznych “rogów” terenu nie zadziałało tak jak trzeba, ani obliczanie podświetlenia względem punktu V, choć te dwa rozwiązania coś z siebie dały, aby powstało takie, które w końcu przyzwoicie działa. Może nierewelacyjnie - “przyzwoicie” to bardzo dobre słowo w tym przypadku. Jednak jeszcze nie na tyle przyzwoicie, abym je tutaj opisywał – wymaga jeszcze trochę pracy w przyszłości. &lt;/p&gt;  &lt;p&gt;Cóż, niestety, notka nie jest do końca kompletna. Mam jednak nadzieję, że znajdę chwilę, aby dokładniej przetestować swoją kamerę i pokusić się o napisanie czegoś związanego z obsługą myszki.&lt;/p&gt;  &lt;p&gt;A jak idzie sam silnik? Na razie stoi – jeden z naszych projektów na uczelnię to gra FPS w stylu Dooma, zatem framework Yesta znajdzie zastosowanie, choć to nie jest to, co najbardziej mnie gnębi na studiach w tym semestrze. Tym niemniej zacząłem już nieco planować konstrukcję shaderów w Scavie, aby nie było tak jak poprzednio, gdzie każda klasa korzystająca z nich (oświetlenie, wody, trawa) musiała sobie sama wszystko przygotowywać. Podejście obiektowe jak jasny piorun.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-1246501643639630002?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/1246501643639630002/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=1246501643639630002' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1246501643639630002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1246501643639630002'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/03/rzut-izometryczny-od-gory-od-boku-i.html' title='Rzut izometryczny – od góry, od boku i implementacja kamery warcraftowej'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_R2ix0MLn8lM/S53gX3IkIGI/AAAAAAAAAao/wvsii7YwgtY/s72-c/plane1_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-1705839616672427718</id><published>2010-03-11T09:15:00.001+01:00</published><updated>2010-03-11T09:17:57.388+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Framework 3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Silnik 3D'/><title type='text'>Wejście leniwca (a spodziewaliście się smoka?)</title><content type='html'>&lt;p&gt;Chciałem Wam dzisiaj pokazać coś takiego:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S5imd3W416I/AAAAAAAAAac/-XnM69-kU0I/s1600-h/scr000%5B3%5D.png"&gt;&lt;img title="scr000" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="191" alt="scr000" src="http://lh5.ggpht.com/_R2ix0MLn8lM/S5imfPfkLXI/AAAAAAAAAag/MCCKFIeFawQ/scr000_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Interesujące? Nie, wcale – w oteksturowanym prymitywie można zauważyć same prymitywne (jak sama nazwa mówi) rzeczy. Spójrzcie zatem na kod.&lt;/p&gt;  &lt;p&gt;&lt;a title="http://nopaste.gamedev.pl/?id=6481" href="http://nopaste.gamedev.pl/?id=6481"&gt;http://nopaste.gamedev.pl/?id=6481&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Nadal nie powinno być to interesujące. Toż taka mieszanina obiektowości silnika oraz biblioteki GLUT…&lt;/p&gt;  &lt;p&gt;Chwilka – napisałem “silnika”? Owszem, napisałem – tak się bowiem składa, że kod ten nie jest wymysłem pracowników CERNu, ani kolejnym projektem badawczym jakiejkolwiek uczelni technicznej. Nie jest to nawet rozgrzewkowy kod pisany przez bardziej zaawansowanego programistę ani prognoza pogody na następny wtorek. Mało tego – nie podpada to pod egzamin z metod probabilistycznych. To jest po prostu pierwszy (skromny) etap pisania silnika, który niedawno zaczął powstawać. Jak widać, na razie nie prezentuje niczego nadzwyczajnego – po prostu jest. Nazwałem go Scav – głównie dlatego, że podoba mi się ten skrótowiec, zwłaszcza po rozwinięciu (Scavenger). Mam nadzieję, że nikomu nie wszedłem w paradę nazwą. &lt;/p&gt;  &lt;p&gt;Scav na razie umożliwia/posiada/zawiera:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;W pełni (dobrze, w 90%) obiektową strukturę&lt;/li&gt;    &lt;li&gt;Opiera się na bibliotece &lt;a href="http://www.libsdl.org/" target="_blank"&gt;SDL&lt;/a&gt; (choć jeszcze całkowicie nie przeszedłem z &lt;a href="http://pl.wikipedia.org/wiki/Windows_API" target="_blank"&gt;WinAPI&lt;/a&gt;)&lt;/li&gt;    &lt;li&gt;Korzysta z &lt;a href="http://www.opengl.org/" target="_blank"&gt;OpenGL&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Tak właściwie, to Scav = OpenGL + konstrukcja silnika&lt;/li&gt;    &lt;li&gt;Ma konstrukcję podobną do &lt;a href="http://www.ogre3d.org/" target="_blank"&gt;Ogre’a&lt;/a&gt; (choć są różnice)&lt;/li&gt;    &lt;li&gt;Pisanie aplikacji z użyciem tego silnika jest niesamowicie wkurzające&lt;/li&gt;    &lt;li&gt;Teksturowanie z użyciem plików graficznych w formacie .tga i .pcx&lt;/li&gt;    &lt;li&gt;Manager scen(y/tric) z węzłami sceny&lt;/li&gt;    &lt;li&gt;Wyświetlanie nieanimowanych meshy (z użyciem VBO)&lt;/li&gt;    &lt;li&gt;Dwa rodzaje kamery (FPP i izometria)&lt;/li&gt;    &lt;li&gt;Obsługa klawiszy, okna, myszy&lt;/li&gt;    &lt;li&gt;&lt;a href="http://sirius.cs.put.poznan.pl/~inf89817/Scav_doc/" target="_blank"&gt;Dokumentacja w Doxygenie&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Moduł matematyczny&lt;/li&gt;    &lt;li&gt;Frustum culling&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Tak naprawdę, to większość rzeczy, które robiłem (i będę robić) polegają na popatrzeniu w framework Yesta, a następnie wciągnięcie tego do silnika według jakiegoś planu i schematu. Jak widać, projekt nie jest jest przesadnie rozwinięty, choć coś tam już potrafi (doprowadzić do śmiechu). To jest pierwszy etap – nie wszystko zrobiłem co chciałem, zostały jeszcze ze dwa błędy, ale na razie muszę to niestety zostawić – uczelnia wzywa i nie będzie czekała. Tym niemniej, drugi etap pisania silnika (tak, od czasu do czasu będę Was tym zamęczał) będzie pewnie dotyczył shaderów i jakiś modeli oświetlenia, choć jeszcze niczego nie planuję. W najbliższej przyszłości postaram się też nieco napisać o implementacji rzutu izometrycznego z dowolnymi (sensownymi) kątami nachylenia kamery, z tego względu, że męczyłem się nad tym fragmentem nieco czasu i choć nadal nie jest idealny, to artykuł powstać musi (bo tak). &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Oczywiście, jeżeli ktoś by zajrzał w kod/dokumentację i zobaczył coś bardzo podejrzanego, co rozwiązałby dużo lepiej i prościej – proszę śmiało mówić. Nie mam żadnego ograniczenia czasowego na ten projekcik i nikt nade mną nie stoi, zatem mogę sobie w nim rzeźbić do woli. Oczywiście, jeśli uczelnia pozwoli…&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-1705839616672427718?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/1705839616672427718/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=1705839616672427718' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1705839616672427718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/1705839616672427718'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/03/wejscie-leniwca-spodziewaliscie-sie.html' title='Wejście leniwca (a spodziewaliście się smoka?)'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_R2ix0MLn8lM/S5imfPfkLXI/AAAAAAAAAag/MCCKFIeFawQ/s72-c/scr000_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-8995129253819231258</id><published>2010-03-03T21:06:00.002+01:00</published><updated>2010-03-03T21:16:36.246+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Kontynuujemy cykl “Proste Algorytmy Sztucznej Inteligencji, Czyli SceNtriC Się Obudził”</title><content type='html'>&lt;p&gt;Sesja jakoś poszła (a sio!), zaczął się nowy semestr, a w nim architektura systemów komputerowych (czyli “tylko nie sprzętówka” i asemblacja wzdłuż i wszerz), badania operacyjne (czyli między innymi różne sposoby programowania, którego nie są programowaniem w sensie programowania, ale też są używane do programowania), sieci komputerowe 1 (czyli pierwsza część o podtytule “dowiadujemy się co to IP”), systemy baz danych 1 (czyli pierwsza część opowieści o tabelkach zwanych relacjami i SQL), statystyka i analiza danych (czyli “jeszcze tego nie miałem, ale podobno bawimy się w Excelu”), elementy analizy numerycznej (czyli liczymy błędy przedziałowe w przedziałach popychanych przedziałami, a wszystko na formatkach Delphi), grafika komputerowa i wizualizacja (czyli “o, ciekawy przedmiot” przed zobaczeniem tematów projektów) oraz język angielski (czyli “this is obvious”). Zapewne perypetie semestralne nasuną wiele pomysłów na notki (choć pewnie większości nie uda się zrealizować), więc będzie jeszcze czas o tym porozmawiać. Dzisiaj o czymś innym.&lt;/p&gt;  &lt;p&gt;A dzisiaj kontynuacja tematu z 21 lutego br., kiedy popisałem sobie o algorytmie alfa-beta. Jak pewnie możecie też zauważyć, Regedit (pozdrawiam) napisał w komentarzu coś takiego:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Ja chyba czuję się doinformowany :) Szkoda tylko, że wszędzie gdzie piszą o tym algorytmie opisują tylko ogólną ideę, a nie proponują żadnego konkretnego rozwiązania na struktury danych, w jakich przechowywać te stany podczas obliczeń. Bo chyba nie tworzy się w pamięci za każdym razem prawdziwego drzewa z dynamicznie zaalokowanymi węzłami, a w każdym pełny stan gry?!&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Czyli wygląda na to, że mamy kolejny materiał na notkę. &lt;/p&gt;  &lt;p&gt;Najchętniej wrzuciłbym tutaj grę, którą robiłem na projekt zaliczeniowy z tego przedmiotu, ale nie mam do niego pełnych praw autorskich (mieliśmy &lt;a href="http://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi/25271?do=show;id=666" target="_blank"&gt;Oxelbergen&lt;/a&gt;, ale nie mamy (jeszcze) błogosławieństwa dystrybucyjnego od prawowitego autora). Wobec tego, wymyślmy sobie prostą (i debilną) grę (właściwie to bardziej debilną niż prostą), która posłuży nam jako przykład. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S47BMCG1znI/AAAAAAAAAZ0/r9sLIuuJBJI/s1600-h/plansza4.png"&gt;&lt;img title="plansza" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="plansza" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S47BNOjw_cI/AAAAAAAAAZ4/l4QdA46-NV0/plansza_thumb2.png?imgmax=800" width="179" border="0" height="179" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Dwóch graczy ustawia swoje pionki (przyjmijmy, że pierwszy gracz – Max – gra pionkiem niebieskim, a drugi – Min – pionkiem zielonym) na przeciwległych rogach planszy o wymiarach 3x3. Celem jest dojście pionkiem do tego pola, w którym na początku stał przeciwnik (czyli niebieski wędruje do tego jasnoniebieskiego, a zielony – do jasnozielonego). Gracze wykonują ruchy naprzemiennie, poruszając się o jedno pole do góry, na dół, w lewo lub prawo (nie wolno skakać na skos).&lt;/p&gt;  &lt;p&gt;Jak widać, gra jest trywialna i tak naprawdę zawsze powinien wygrać ten gracz, który zaczynał rozgrywkę. Oczywiście, aby gra była nieco sensowniejsza, można by było powiększyć planszę, dodać kolejne pionki każdemu z graczy i wtedy można by było grać. Tymczasem nam chodzi jedynie o pokazanie idei, więc taka prosta (i debilna) się nadaje.&lt;/p&gt;  &lt;p&gt;Dobrze, zatem mamy grę z określonymi zasadami. Wypadałoby zatem przejść do implementacji algorytmu alfa-beta. Zanim jednak zanurzymy się w rekurencję, trzeba określić reprezentację stanu naszej gry, czyli strukturę, w której będzie zapisana sytuacja na planszy (przy okazji – chciałbym zaznaczyć, że prawdopodobnie sposób pokazany niżej nie jest najlepszy, ale chcę pokazać jedynie ideę). W większości gier planszowych idealna ku temu będzie [tadam]macierz[/tadam] – na przykład taka jak poniżej.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S47BN4X2b2I/AAAAAAAAAZ8/NJ_8qUH5TTs/s1600-h/macierz13.png"&gt;&lt;img title="macierz1" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="macierz1" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S47BPE_pgYI/AAAAAAAAAaA/kTlL6Qo2FIY/macierz1_thumb1.png?imgmax=800" width="75" border="0" height="71" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Patrząc na obrazek wyżej i tę macierz, można łatwo wywnioskować, jak kodujemy nasz stan. Pionek gracza Max dostał wartość 1, a pionek gracza Min jest oznaczany jako 2. Wolne pole podajemy z kolei jako 0. Musimy jeszcze oznaczyć sobie wiersze i kolumny naszej macierzy, a także wypadałoby nadać indeksy poszczególnym polom. Dlaczego? Chociażby ze względu na to, żebyśmy mieli wszystko w jednowymiarowej tablicy, a poza tym dzięki temu mamy unikalny identyfikator jednowartościowy dla każdego pola. Jak to się przekłada na implementację – być może (jak nie zapomnę) pod koniec notki o tym wspomnę. Tak czy inaczej – na razie popatrzmy na to, jak nasza macierz jest zbudowana.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S47BPws1TpI/AAAAAAAAAaE/L3Tdzhi70Bo/s1600-h/macierz23.png"&gt;&lt;img title="macierz2" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="macierz2" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S47BRBOFb4I/AAAAAAAAAaI/l7M2JUeO664/macierz2_thumb1.png?imgmax=800" width="114" border="0" height="103" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Widać, że mamy współrzędną x rosnącą w prawo i współrzędną y rosnącą w dół. Indeks pola obliczymy za pomocą prostego wzorku:&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S47BR1Yw3PI/AAAAAAAAAaM/JMdOLQxzH1s/s1600-h/wzor13.png"&gt;&lt;img title="wzor1" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="wzor1" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S47BSwf0X-I/AAAAAAAAAaQ/Iv1Q6jNhRkI/wzor1_thumb1.png?imgmax=800" width="243" border="0" height="83" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Oczywiście, to da się przedstawić od razu jako 3 * y + x, ale chciałem sobie odświeżyć rachunek różniczkowy i całkowy. Tak, dla żartów.&lt;/p&gt;  &lt;p&gt;Mamy zatem już środowisko pracy, zatem należy teraz przejść do sytuacji, kiedy komputer będzie wykonywał nasz algorytm. Wcześniej wypada jeszcze jednak wspomnieć o jednym – generowaniu następników. Właściwie to dwóch – jeszcze ocena heurystyczna nam została. Załóżmy, że rozgrywkę zaczyna gracz Max i musimy wygenerować wszystkie jego następniki. Prezentują się one następująco:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S47BTvA6jlI/AAAAAAAAAaU/v2NUPAQIae0/s1600-h/nastepniki3.png"&gt;&lt;img title="nastepniki" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="nastepniki" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S47BU5WUoMI/AAAAAAAAAaY/1JKeVjHKVX4/nastepniki_thumb1.png?imgmax=800" width="192" border="0" height="73" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Jak widać, jedynka może się ruszyć tylko na dwa sposoby – w prawo (przesunięcie na osi x o 1) lub w dół (przesunięcie na osi y o 1). Nie daje nam to dużego pola manewru, ale ważne jest to, abyśmy wiedzieli, o co chodzi.&lt;/p&gt;  &lt;p&gt;Z tego też powodu trzeba napisać kod odpowiedzialny za generowanie tych następników. Będziemy tworzyć wszystkie stany następujące dla danego stanu i zapisywać do jakiegoś wektora – nie wiemy z góry ile ich będzie, zatem wektor będzie tu bardzo odpowiednią strukturą danych.&lt;/p&gt;  &lt;div   style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;   &lt;div   style="border-style: none; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;     &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;struct&lt;/span&gt; CPoint &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; x, y;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; };&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; GetField (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; x, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; y)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; 3 * y + x;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; CPoint GetPoint (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; field)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;     CPoint p;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;     p.x = field / 3;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;     p.y = field % 3;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; p;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt; }    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; CopyTables (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* src, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* dest)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 9; ++i)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;         dest[i] = src[i];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; GenerateStates (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* state, std::vector&amp;lt;&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;*&amp;gt;* next, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; player_index) &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// player_index: 1 - Max, 2 - Min&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// state oraz elementy wektora next to 9-elementowe tablice&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  31:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  32:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// pole do lokalizowania obecności naszego pionka&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  33:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; field = -1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  34:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  35:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (player_index == 1)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  36:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  37:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// sprawdzamy, gdzie jest gracz Max&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  38:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 9; ++i)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  39:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  40:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (state[i] == 1)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  41:&lt;/span&gt;             {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  42:&lt;/span&gt;                 field = i;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  43:&lt;/span&gt;                 &lt;span style="color: rgb(0, 0, 255);"&gt;break&lt;/span&gt;; &lt;span style="color: rgb(0, 128, 0);"&gt;// możemy wyjść, szkoda czasu&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  44:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  45:&lt;/span&gt;         }    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  46:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  47:&lt;/span&gt;         CPoint p = GetPoint(field);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  48:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  49:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// to teraz patrzymy na cztery możliwości ruchu naszego pionka&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  50:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// w lewo&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  51:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (p.x - 1 &amp;gt;= 0 &amp;amp;&amp;amp; state[p] == 0)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  52:&lt;/span&gt;         {    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  53:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// ruch jest możliwy, czyli taki wyimaginowany stan kopiujemy do wektora&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  54:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; tab[9];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  55:&lt;/span&gt;             CopyTables(state, tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  56:&lt;/span&gt;             tab[field] = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  57:&lt;/span&gt;             tab[GetField(p.x - 1, p.y)] = 1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  58:&lt;/span&gt;             next-&amp;gt;push_back(tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  59:&lt;/span&gt;         }    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  60:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// w prawo&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  61:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (p.x + 1 &amp;lt;= 2 &amp;amp;&amp;amp; state[p] == 0)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  62:&lt;/span&gt;         {    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  63:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// ruch jest możliwy, czyli taki wyimaginowany stan kopiujemy do wektora&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  64:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; tab[9];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  65:&lt;/span&gt;             CopyTables(state, tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  66:&lt;/span&gt;             tab[field] = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  67:&lt;/span&gt;             tab[GetField(p.x + 1, p.y)] = 1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  68:&lt;/span&gt;             next-&amp;gt;push_back(tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  69:&lt;/span&gt;         }   &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  70:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// w górę&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  71:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (p.y - 1 &amp;gt;= 0 &amp;amp;&amp;amp; state[p] == 0)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  72:&lt;/span&gt;         {    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  73:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// ruch jest możliwy, czyli taki wyimaginowany stan kopiujemy do wektora&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  74:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; tab[9];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  75:&lt;/span&gt;             CopyTables(state, tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  76:&lt;/span&gt;             tab[field] = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  77:&lt;/span&gt;             tab[GetField(p.x, p.y - 1)] = 1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  78:&lt;/span&gt;             next-&amp;gt;push_back(tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  79:&lt;/span&gt;         }     &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  80:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// w dół&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  81:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (p.y + 1 &amp;lt;= 2 &amp;amp;&amp;amp; state[p] == 0)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  82:&lt;/span&gt;         {    &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  83:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// ruch jest możliwy, czyli taki wyimaginowany stan kopiujemy do wektora&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  84:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; tab[9];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  85:&lt;/span&gt;             CopyTables(state, tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  86:&lt;/span&gt;             tab[field] = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  87:&lt;/span&gt;             tab[GetField(p.x, p.y + 1)] = 1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  88:&lt;/span&gt;             next-&amp;gt;push_back(tab);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  89:&lt;/span&gt;         }     &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  90:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  91:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  92:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  93:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// analogicznie robimy tutaj jak przy player_index równym 1, tylko&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  94:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// przesuwamy pole z wartością 2, a nie 1&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  95:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  96:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Coś w tym stylu będzie nam potrzebne. Pewnie jest tu dużo nadpisanego kodu, ale najważniejsze to pokazać pomysł. Jak widać, zmuszeni jesteśmy poruszać sie pomiędzy dwiema reprezentacjami – za pomocą koordynat (jak przeczytałem, koordynata jest rodzaju żeńskiego), a następnie patrzymy, jakie mamy możliwości ruchu danym pionkiem i taki nowy stan zapisujemy do wektora następników. Jak widać, nowych stanów będzie od dwóch do czterech, także przestrzeń stanów naszej gry będzie niewielka. Ale po kolei – player_index to oczywiście indeks gracza, state – aktualny stan, a wskaźnik na wektor next – wektor z naszymi następnikami. Przy okazji mała uwaga – nie kompilowałem tego i obawiam się, że coś pomieszałem ze wskaźnikami, ale i tak każda gra wymaga innego podejścia (wiem, że się usprawiedliwiam, przepraszam). Na początku sprawdzamy, gdzie znajduje się nasz pionek, a później patrzymy na cztery sąsiednie pola, gdzie ewentualnie moglibyśmy się przesunąć (dane pole musi istnieć (nie możemy być na skraju planszy) oraz musi być wolne – abstrahujemy od tego, czy ruch jest sensowny). Jeżeli taki ruch jest możliwy, tworzymy odpowiednią tablicę, zapisujemy do niej nasz stan, a następnie modyfikujemy odpowiednie pola (co symuluje nasze przesunięcie pionka) i zapisujemy taki stan do podanego wskaźnika na wektor następników.&lt;/p&gt;&lt;p&gt;Teraz co nieco o funkcjach pomocniczych – GetField daje nam indeks pola na podstawie podanych współrzędnych, a operacją odwrotną jest GetPoint (które wymaga zdefiniowania prostej struktury). CopyTables natomiast kopiuje nam jedną tablicę do drugiej.&lt;/p&gt;&lt;p&gt;Dobrze, zatem mamy generowanie następników. Następnym krokiem jest określenie funkcji oceny heurystycznej. Powinna być ona stosunkowo prosta, aby można było ją szybko obliczyć, a jednocześnie powinna odpowiadać nam na pytanie “jak blisko jesteśmy zakończenia gry”. Przyjmujemy, że im wyższa ocena sytuacji, tym bardziej korzystna jest ona dla gracza Max, a im niższa – dla gracza Min. W naszym przypadku może to być najkrótsza odległość do pola docelowego. Oto przykładowy kod:&lt;/p&gt;&lt;div   style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div   style="border-style: none; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; Evaluate (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* state)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// pola docelowe dla każdego gracza&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; max_dest = 8;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; min_dest = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// poszukanie pozycji graczy&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; max, min;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 9; ++i)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (state[i] == 1) max = i;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (state[i] == 2) min = i;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// obliczenie najkrótszej odległości (liczonej w polach) do miejsca docelowego&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; max_length = GetShortestDistance(1, max, max_dest, state);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; min_length = GetShortestDistance(2, min, min_dest, state);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// ponieważ tutaj im dłuższa odległość tym gorzej, zatem musimy&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// odwrotnie policzyć wartości - od min_length odjąć max_length&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// wtedy, jeżeli min_length będzie dłuższe (większe) od max_length,&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// to wyjdzie wartość dodatnia, czyli faktycznie gracz Max będzie miał&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// krótszą drogę do celu&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; min_length - max_length;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Specjalnie zostawiłem funkcję GetShortestDistance, gdyż z nią byłoby więcej zabawy, a że całą notkę wymyślam na bieżąco (podobnie zresztą jak samą grę), dlatego pozwolę sobie na takie pójście na łatwiznę – mea culpa.&lt;/p&gt;&lt;p&gt;Jest jeszcze jedna kwestia – ocena dla stanu terminalnego (takiego, że jeden z graczy wygrał). Powinna być ona duża – odpowiednio większa w stosunku do wartości, które normalnie jesteśmy w stanie uzyskać. Czyli na przykład 100 dla wygranej gracza Max, a –100 dla wygranej Min. Odpowiednia funkcja sprawdzająca wygraną znajduje się poniżej.&lt;/p&gt;&lt;p&gt;Teraz możemy przystąpić do samej alfa-bety. Poniżej zastosujemy tzw. notację minimaksową, która wymaga informacji o indeksie gracza, który wykonuje ruch. Istnieje również notacja negamaksowa, która powstaje poprzez negowanie i odwracanie poszczególnych wartości, co dwukrotnie skraca zapis, ale nie będziemy się nic tutaj zajmować.&lt;/p&gt;&lt;div   style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;div   style="border-style: none; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; IsEndOfGame (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* state)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; max_dest = 8;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; min_dest = 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; max, min;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 9; ++i)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (state[i] == 1) max = i;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (state[i] == 2) min = i;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli Max jest w swoim punkcie docelowym, to zwracamy 1&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (max == max_dest)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; 1;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli Min jest w swoim punkcie docelowym, to zwracamy 2&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (min == min_dest)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; 2;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli inaczej - rozgrywka trwa&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; AlphaBeta (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; player_index, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* state, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; depth)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// zapisujemy początkową głębokość przeszukiwania, aby wiedzieć,&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  31:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// kiedy zapisać najlepszy stan&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  32:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// g_Depth to jakaś zmienna globalna &lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  33:&lt;/span&gt;     g_Depth = depth;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  34:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  35:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// -1000 i 1000 to nasze wartości alfy oraz bety&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  36:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// podajemy na początku jakieś skrajne wartości zaporowe&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  37:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// wywołujemy właściwą funkcję AB&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  38:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; AlphaBeta(player_index, state, -1000, 1000, depth);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  39:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  40:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  41:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; AlphaBeta (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; player_index, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;* state, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; alpha, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; beta, &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; depth)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  42:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  43:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli nie mamy już głębiej szukać, lub mamy stan terminalny &lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  44:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (depth == 0 || IsEndOfGame(state))&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  45:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  46:&lt;/span&gt;         &lt;span style="color: rgb(0, 128, 0);"&gt;// zwracamy ocenę heurystyczną&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  47:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; Evaluate(state);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  48:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  49:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  50:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// wektor następników dla danego stanu&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  51:&lt;/span&gt;     std::vector&amp;lt;&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;*&amp;gt;* next;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  52:&lt;/span&gt;     GenerateStates(state, next, player_index);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  53:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  54:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// będziemy iterować po wszystkich następnikach&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  55:&lt;/span&gt;     std::vector&amp;lt;&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;*&amp;gt;::iterator it = next.begin();&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  56:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  57:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// dla gracz Max&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  58:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (player_index == 1)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  59:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  60:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;while&lt;/span&gt; (it != states.end())&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  61:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  62:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// pobieramy wartość z rekurencji dla drugiego gracza (schodzimy niżej i rozpatrujemy obecny następnik)&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  63:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt; = AlphaBeta(!player_index, *it, alpha, beta, depth - 1);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  64:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli mamy wartość poprawiającą alfę&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  65:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt; &amp;gt; alpha)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  66:&lt;/span&gt;             {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  67:&lt;/span&gt;                 &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli jesteśmy najwyżej i zmieniliśmy przedział, to mamy najlepszy możliwy jak na razie ruch&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  68:&lt;/span&gt;                 &lt;span style="color: rgb(0, 128, 0);"&gt;// zapisujemy go sobie w zmiennej globalnej g_BestState&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  69:&lt;/span&gt;                 &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (g_Depth == depth) g_BestState = *it;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  70:&lt;/span&gt;                 alpha = &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  71:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  72:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli powinno nastąpić odcięcie alfa&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  73:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (alpha &amp;gt;= beta) &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  74:&lt;/span&gt;             {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  75:&lt;/span&gt;                 &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; beta;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  76:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  77:&lt;/span&gt;             it++;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  78:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  79:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; alpha;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  80:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  81:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// dla gracza Min&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  82:&lt;/span&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;else&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  83:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  84:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;while&lt;/span&gt; (it != states.end())&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  85:&lt;/span&gt;         {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  86:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt; = AlphaBeta(!player_index, *it, alpha, beta, depth - 1);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  87:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli mamy wartość poprawiającą betę&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  88:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt; &amp;lt; beta)&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  89:&lt;/span&gt;             {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  90:&lt;/span&gt;                 &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (g_Depth == depth) g_BestState = *it;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  91:&lt;/span&gt;                 beta = &lt;span style="color: rgb(0, 0, 255);"&gt;value&lt;/span&gt;;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  92:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  93:&lt;/span&gt;             &lt;span style="color: rgb(0, 128, 0);"&gt;// odcięcie beta&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  94:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (alpha &amp;gt;= beta) &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  95:&lt;/span&gt;             {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  96:&lt;/span&gt;                 &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; alpha;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  97:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  98:&lt;/span&gt;             it++;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  99:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt; 100:&lt;/span&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; beta;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt; 101:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt; 102:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Jeżeli ktoś dziwi się “co tutaj SceN napisał”, to można otworzyć sobie &lt;a href="http://pseudodev.blogspot.com/2010/02/z-cyklu-proste-algorytmy-sztucznej.html" target="_blank"&gt;stronę z poprzednią notką&lt;/a&gt; i tak próbować to rozgryźć. Jest to cały kod Alfa-Bety wraz z funkcją sprawdzającą, czy nastąpił koniec rozgrywki. Iterujemy po następnikach dla danego stanu i sprawdzamy kolejne poddrzewa naszej przestrzeni stanów. Teorii nie ma co omawiać po raz drugi – wystarczy, jak przejrzycie sobie kod i spróbujecie rozwiązać to sobie np. na kartce.&lt;/p&gt;&lt;p&gt;Oczywiście, operacje te wykonujemy po to, żeby dowiedzieć się, jak komputer powinien się poruszyć, aby jak najbardziej zagrozić przeciwnikowi. Dlatego zapisujemy najlepszy możliwy bezpośredni następnik do zmiennej g_BestState, dzięki czemu mamy następny stan, który powinien wystąpić po ruchu.&lt;/p&gt;&lt;p&gt;Mam nadzieję, że ta notka jest udanym dopowiedzeniem poprzedniej (bardziej teoretycznej). Zdaję sobie sprawę z tego, że wiele rzeczy uprościłem, o wielu nie powiedziałem – proszę o wybaczenie. Mam nadzieję, że komuś moje wypociny się przydadzą, czy to w domowych projektach czy na uczelni.&lt;/p&gt;&lt;p&gt;Zapraszam oczywiście do zgłaszania uwag.&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję – SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-8995129253819231258?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/8995129253819231258/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=8995129253819231258' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/8995129253819231258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/8995129253819231258'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/03/kontynuujemy-cykl-proste-algorytmy.html' title='Kontynuujemy cykl “Proste Algorytmy Sztucznej Inteligencji, Czyli SceNtriC Się Obudził”'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_R2ix0MLn8lM/S47BNOjw_cI/AAAAAAAAAZ4/l4QdA46-NV0/s72-c/plansza_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-3099502273277720205</id><published>2010-02-21T00:37:00.001+01:00</published><updated>2010-02-21T00:37:32.568+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Z cyklu “Proste Algorytmy Sztucznej Inteligencji, Czyli SceNtriC Się Obudził”</title><content type='html'>&lt;p&gt;Technika, którą przedstawię w dzisiejszej notce nie jest z pewnością czymś nowatorskim. Nie budzi nawet wielkich emocji wśród braci programistycznej, gdyż znane są o wiele lepsze algorytmy. Nie da się jednak ukryć, że metoda opisana poniżej jest bazą dla wszystkich innych algorytmów przeszukiwania przestrzeni stanów gry i modyfikując ją można iść ku dalszej poprawie efektywności. Jednocześnie piszę tę notkę dla takich osób jak ja, które niegdyś szukały prostych algorytmów sztucznej inteligencji, ale niestety nie mogły znaleźć odpowiednich materiałów, albo – co jeszcze lepiej brzmi – nie wiedziały czego szukać. Dlatego zapraszam do opisu Alfa-Bety. Co prawda, teoretycznego, ale myślę, że zainspiruję początkowych adeptów informatyki do próby przełożenia teorii na praktykę.&lt;/p&gt;  &lt;p&gt;Na początku jednak wypada opowiedzieć na jakiej płaszczyźnie będziemy rozpatrywać naszą techniką i w jakich warunkach będzie on działać. Najłatwiej wyobrazić go sobie na jakiejkolwiek grze planszowej, w której dwóch graczy naprzemiennie wykonuje ruchy. Jednego zawodnika nazwiemy Maxem, a drugiego – Minem. Załóżmy również, że sytuacja na planszy jest oceniana za pomocą jakieś funkcji (zwaną heurystyczną) i pierwszy z graczy dąży do jej zmaksymalizowania, a drugi – zminimalizowania. Wynika zatem z tego, że Max, mając do wyboru kilka ruchów, wybierze ten, który zapewni sytuację zasługującą na jak największą wartość funkcji heurystycznej.&lt;/p&gt;  &lt;p&gt;Co rozumiemy poprzez graf przestrzeni stanów gry? Jest to (jak sama nazwa wskazuje) graf (jak sama nazwa ponownie wskazuje) przestrzeni stanów jakiejś (jak sama nazwa wskazuje) gry. A czymże jest stan? Jest to omawiana już sytuacja na planszy wraz z informacją o wartości funkcji heurystycznej oraz dodatkowymi danymi (który gracz wykonuje ruch, głębokość przeszukiwania, itd.). &lt;/p&gt;  &lt;p&gt;Jak nietrudno się domyślić, skoro mówimy o grafie, to faktycznie można narysować sobie graf. Pozwolę pokazać to sobie na grafice znajdującej się &lt;a href="http://liza.umcs.lublin.pl/~mhac/nqueens/grafika/konwersja_szach_graf.jpg" target="_blank"&gt;tutaj&lt;/a&gt; (mam nadzieję, że nie naruszę żadnych praw autorskich). &lt;/p&gt;  &lt;p&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" height="110" src="http://liza.umcs.lublin.pl/~mhac/nqueens/grafika/konwersja_szach_graf.jpg" width="325" /&gt; &lt;/p&gt;  &lt;p&gt;Pierwszy gracz ma kilka możliwości ruchu (w przykładzie dwa), po których drugi gracz ma również kilka możliwości ruchu. Oczywiście, są to naprzemienne ruchy graczy Max i Min, przy czym oboje będą wybierali następniki najlepsze dla siebie z dostępnych. Kolejną oczywistością (dużo będzie tych oczywistości tutaj) jest to, że im większe takie drzewko zrobimy, tym nasza sztuczna inteligencja będzie “mądrzejsza” (i będzie nas denerwowała swoimi wygranymi), ale – co obecnie jest dużo ważniejsze – algorytm będzie się dłużej wykonywał. W praktyce w większości gier planszowych tych następników nie ma 2-3, tylko można je liczyć w setkach, tysiącach. Takie &lt;a href="http://pl.wikipedia.org/wiki/Go" target="_blank"&gt;Go&lt;/a&gt; ma liczbę stanów sięgającą 10&lt;sup&gt;720&lt;/sup&gt;, co na razie jest nie do przeskoczenia dla maszyn liczących. Można tutaj użyć ładnego określenia “eksplozji kombinatorycznej”, które opisuje właśnie problem z algorytmami przeszukiwania przestrzeni stanów – liczba wierzchołków do przejrzenia rośnie wykładniczo i właśnie to jest odpowiedzialne za kolejne herbaty, które robimy sobie podczas obliczeń komputera, który się niemiłosiernie męczy (biedaczek).&lt;/p&gt;  &lt;p&gt;Świetnie, mamy problem (cudownie, eureka, tysiąc słoni). Jak mawia profesor na Politechnice Poznańskiej – “najważniejsze to dostrzec problem” (pozdrawiam przy okazji całą kadrę naukową Instytutu Informatyki na PP). Po chwilowej fascynacji kłopotem wypadałoby jednak zastanowić się nad drugą fazą – rozwiązaniem. Oczywiście (kolejna oczywista rzecz, ale “mądra” notka, nic nie tłumaczy, tylko wszystko stwierdza), drogą ku lepszej efektywności jest zmniejszenie ilości przeszukiwanych wierzchołków, ale należy zrobić to tak, aby nie zepsuć wyniku, który powstałby po przejrzeniu całej przestrzeni stanów. Jaki z tego wniosek? Należy ograniczać te gałęzie, które nie są w stanie zmienić naszego wyniku. Właśnie na tym polega nasza Alfa-Beta. Aby nasze rozważania miały sens, należy jeszcze założyć jedno – obaj gracze grają na maksimum swoich możliwości i wybierają ruchy w danej chwili dla nich najlepsze.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S4ByNDbug_I/AAAAAAAAAZg/xnz4alMGXls/s1600-h/alfa1%5B9%5D.png"&gt;&lt;img title="alfa1" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 5px 0px 0px; border-left: 0px; border-bottom: 0px" height="174" alt="alfa1" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S4ByN-inHtI/AAAAAAAAAZk/z6bQ7yNKshc/alfa1_thumb%5B5%5D.png?imgmax=800" width="173" align="left" border="0" /&gt;&lt;/a&gt; Przypatrzmy się teraz sytuacjom, które mogą wystąpić w naszej przestrzeni stanów (teraz nastąpi orgia rysunków z Painta, zatem strzeżcie się – estetycznie nie będzie). Pierwszą mamy po lewej – ruch ma gracz Max, który ma dwa dostępne ruchy, podobnie zresztą jak i Min. Min, zgodnie z tym, co wcześniej powiedzieliśmy, będzie starał się minimalizować swój wynik, zatem z dostępnej trójki i czwórki wybierze 3. Oznacza to, że Min w tym ruchu nie jest w stanie osiągnąć wyniku wyższego niż 3, a jest w stanie go nawet poprawić (czyli pomniejszyć) – oczywiście, jeśli graf rozciągałby się dalej. Trójka jest przepropagowywana w górę grafu i Max dostaje informację, że po wybraniu lewej gałęzi może liczyć na sytuację zasługującą na ocenę 3, a podczas dalszego przeszukiwania może to tylko poprawić. Rozochocony wędruje zatem do prawej odnogi, gdzie znowu Min ma ruch. Widzi on dwójkę, więc sobie ją przepisuje, jednak tym razem Max kontroluje sytuację. Widzi, że 2 jest mniejsze od 3, a zatem, ponieważ gracz Min na pewno wybierze dwójkę (albo i coś mniejszego), gracz Max stwierdza, iż nie opłaca się dalej przeglądać tego fragmentu grafu, gdyż nic wartościowego tutaj nie znajdzie, a 3 ma już zagwarantowane z lewej odnogi. Co zatem robimy? Przed ósemką widzimy taką czerwoną kreskę – oznacza to, że zrobiliśmy tutaj odcięcie alfa i dalszych elementów tego fragmentu grafu nie będziemy przeglądać, gdyż nie ma po prostu sensu. W przykładzie “pozbyliśmy” się zatem jednego wierzchołka, ale pamiętajcie, że w normalnej przestrzeni stanów zysk może być znacznie większy.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S4ByOBuihKI/AAAAAAAAAZo/9iaSU495Z0c/s1600-h/beta1%5B4%5D.png"&gt;&lt;img title="beta1" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 0px 0px 5px; border-left: 0px; border-bottom: 0px" height="170" alt="beta1" src="http://lh3.ggpht.com/_R2ix0MLn8lM/S4ByO4KbdrI/AAAAAAAAAZs/5cVNRonq-_c/beta1_thumb%5B2%5D.png?imgmax=800" width="169" align="right" border="0" /&gt;&lt;/a&gt; Wiemy już, czym jest odcięcie alfa, a więc dalsza konkluzja jest zapewne taka, iż istnieje odcięcie beta, prawda? Przeczucie Was nie myli – istotnie, teraz pokażemy sobie, na czym owo odcięcie polega. Po prawej widzimy podobną sytuację do powyższej, ale tym razem gracz Min ma ruch. Ochoczo wędruje on do lewej odnogi, gdzie Max rozgląda się po dostępnych wierzchołkach niczym Casanova za kobietami – widzi 3 oraz 6 i oczywiście, wybierze tę drugą wartość. Szóstka jest przepropagowywana ku górze i Min myśli sobie “mam już zagwarantowane sześć – idę dalej szukać, może uda się jeszcze ten wynik poprawić”. Wędruje zatem do prawej odnogi, gdzie znowu czai się nasz niewyżyty gracz Max. Istną ekstazę sprawia mu odnalezienie dziewiątki w lewym podrzewie, którą sobie przywłaszcza. Gracz Min widzi jednak co się dzieje – Max na pewno w tym fragmencie grafu nie zejdzie poniżej wartości 9, zatem nie opłaca się go dalej przeglądać, gdyż szóstki i tak nie poprawimy. W tym miejscu następuje zatem odcięcie beta. Ponownie, w przykładzie zysk nie jest zbyt duży, ale w większej przestrzeni stanów może być znaczący.&lt;/p&gt;  &lt;p&gt;Co wynika z powyższych opisów odcięć? Kolejność przeglądanych liści drzewa ma znaczenie – jeżeli np. na drugim rysunku zamienilibyśmy dziewiątkę i czwórkę, to cały graf zostałby przejrzany i nie mielibyśmy żadnego zysku. Wniosek z tego taki, iż warto również zadbać o generację następników, aby uzyskać jak największe odcięcia. Ewentualnie zdać się na losowość i czekać na cuda.&lt;/p&gt;  &lt;p&gt;Jak się pewnie domyślacie, nie jest to jedyna forma optymalizacji przeszukiwania, ale za to najbardziej podstawowa. Generalnie, są trzy drogi dalszej optymalizacji.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Pogłębiamy iteracyjnie głębokość przeszukiwania – tak naprawdę, nie ma tutaj znaczącej poprawy szybkości działania, ale za to zwiększamy inteligencję komputera stosunkowo małym kosztem. W metodach opartych na iteracyjnym pogłębianiu możemy manipulować maksymalną głębokością przeszukiwania, jednak musimy liczyć się z tym, że będziemy odwiedzać niektóre stany parę razy. Chyba, że zastosujemy inne usprawnienia.&lt;/li&gt;    &lt;li&gt;Porządkujemy następniki – o tym już wspomniałem, ale mamy tutaj naprawdę wiele dróg – możemy stosować tzw. tablice transpozycji, tablice historii ruchów, tablice ruchów-zabójców. Widzimy zatem, że aby usprawnić nasze obliczenia, możemy zapisywać już odwiedzone stany i pobierać o nich informacje z pamięci, dzieki czemu znamy już określony fragment przestrzeni stanów.&lt;/li&gt;    &lt;li&gt;Zmieniamy (w locie) głębokość przeszukiwania – zapobiegamy zjawisku zwanego efektem horyzontu, które polega na tym, iż dochodzimy do jakiegoś interesującego nas stanu (dobrego dla danego gracza), jednak nie wiemy, iż prowadzi on dalej do naszej przegranej (lub mniej drastycznych zjawisk, na przykład spalenia komputera), gdyż skończyła nam się głębokość przeszukiwania. Dlatego stosuje się często zmienną głębokość przeszukiwania, wydłużając te ścieżki, które mogą być interesujące dla danego gracza. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Nie da się jednak ukryć, iż najczęściej stosuje się rozwiązania hybrydowe, korzystając zarówno z manipulacji głębokością przeszukiwania, tablicy transpozycji (tablicy, w której zapisujemy odwiedzone już stany i nie musimy na nowo obliczać pewnych wartości dla nich) jak i innych technik. Jest tego naprawdę cała masa i tak naprawdę większość metod ma różną efektywność zależną bezpośrednio od rodzaju naszej gry. &lt;/p&gt;  &lt;p&gt;Niestety, nie będę opisywał już tych bardziej zaawansowanych metod – moim celem było tylko przedstawienie podstawowego algorytmu Alfa-Beta. Jestem świadomy tego, że większość osób zna tę metodę, jednak notkę pisałem z myślą o mniej doświadczonych programistach. Jeżeli ktoś zamierza poszerzać swoją wiedzę w zakresie przeszukiwania przestrzeni stanów, polecam:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://pl.wikipedia.org/wiki/Algorytm_alfa-beta" target="_blank"&gt;Wikipedię&lt;/a&gt;&amp;#160;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.cs.put.poznan.pl/amichalski/search/si2006.rgb4pp.pdf" target="_blank"&gt;Wykład dr inż. Artura Michalskiego (pozdrawiam)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.google.com" target="_blank"&gt;Google&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic11/" target="_blank"&gt;Wykład Schools of Computer Science&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.mimuw.edu.pl/~paterek/sid2006.html" target="_blank"&gt;Informacje na stronie Wydziału Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jeżeli choć jedna osoba po przeczytaniu powyższej notki czuje się bardziej doinformowana i rozwiała swoje wątpliwości – jest mi bardzo miło. Zapraszam oczywiście do komentowania, oceniania, doradzania i krytykowania.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-3099502273277720205?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/3099502273277720205/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=3099502273277720205' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3099502273277720205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3099502273277720205'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/02/z-cyklu-proste-algorytmy-sztucznej.html' title='Z cyklu “Proste Algorytmy Sztucznej Inteligencji, Czyli SceNtriC Się Obudził”'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_R2ix0MLn8lM/S4ByN-inHtI/AAAAAAAAAZk/z6bQ7yNKshc/s72-c/alfa1_thumb%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2919321395725931706</id><published>2010-02-13T21:40:00.002+01:00</published><updated>2010-02-13T21:41:04.051+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Grafy dysjunkcyjne, metaheurystyki – czyli znowu o szeregowaniu</title><content type='html'>&lt;p&gt;Jakiś czas temu &lt;a href="http://pseudodev.blogspot.com/2009/11/niedziaajacy-algorytm-ale-cos-w-sobie.html" target="_blank"&gt;wspominałem o problemie Job Shop&lt;/a&gt;, na który dane nam było napisać trzy algorytmy dający rozwiązania w rozsądnym czasie i dobre jakościowo. Jest to oczywiście trudne, gdyż można podejrzewać, że jedno wyklucza drugie – jeżeli chcemy uzyskać rozwiązanie dokładne (czyli najkrótszy czas uszeregowania zadań), to najprostszym sposobem byłoby przeglądnięcie wszystkich rozwiązań, jednak wtedy podejrzewam, że w oczekiwaniu na wynik można by były zrobić niejedną herbatę, ale cały dzbanek, wiaderko, zapasy dla całego osiedla i jeszcze przeszłoby się całego Baldur’s Gate’a II z wszystkimi zadaniami dodatkowymi. Dwa razy. Na końcu okazałoby się, że atomy podtrzymujące materię komputera wzięłyby urlop.&lt;/p&gt;&lt;p&gt;Można też oczywiście pogodzić się z ograniczoną dokładnością rozwiązania i zaprojektować algorytm, który będzie działał tak, że nawet tej jednej torebki herbaty nie zdążymy wyjąć z pudełka. Inspirować można się tutaj &lt;a href="http://pl.wikipedia.org/wiki/Algorytm_szeregowania" target="_blank"&gt;algorytmami szeregowania procesów w systemie operacyjnym&lt;/a&gt; i jednym z rozwiązań, jakie napisaliśmy z koleżanką na zaliczenie przedmiotu Optymalizacji Kombinatorycznej (pozdrawiam koleżankę) była właśnie mutacja algorytmu SJF. Niestety, profesor (którego również pozdrawiam) dosyć szybko sprowadził nas na ziemię, iż metoda jest tak naprawdę pseudowielomianowa (zależy nie tylko od rozmiaru instancji [konkretnego przykładu problemu] lecz także od największej danej wejściowej), ale przynajmniej przy “niezłośliwych” wartościach działa szybko.&lt;/p&gt;&lt;p&gt;Wspominałem, iż Job Shopa rozgryzaliśmy w ramach przedmiotu Optymalizacja Kombinatoryczna, który dostarczał nam wiedzy, jak (a jakże) optymalizować algorytmy ten sposób, aby działały szybko i dawały jak najlepsze wyniki. W tym momencie należy wspomnieć o czymś, co nazywamy &lt;a href="http://pl.wikipedia.org/wiki/Metaheurystyka" target="_blank"&gt;metaheurystykami&lt;/a&gt;. Można je &lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S3cOO9gxyeI/AAAAAAAAAZI/AwtarrTTKyQ/s1600-h/01%5B3%5D.png"&gt;&lt;img title="01" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; MARGIN: 0px 5px 0px 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="132" alt="01" src="http://lh4.ggpht.com/_R2ix0MLn8lM/S3cOPVzHruI/AAAAAAAAAZM/TrC8GZV_AbU/01_thumb%5B1%5D.png?imgmax=800" width="113" align="left" border="0" /&gt;&lt;/a&gt; najprościej opisać, jako pomysły na rozwiązywanie różnych problemów optymalizacyjnych niezależnie od tego, jakie one naprawdę są. Wszystkie opierają się na odpowiednim poruszaniu się po zbiorze możliwych rozwiązań i szukaniu tego najlepszego (schematycznie zostało to przedstawione na rysunku obok – kropki to dopuszczalne rozwiązania). Na zajęciach poznaliśmy cztery techniki, które postaram się skrótowo opisać poniżej.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://pl.wikipedia.org/wiki/Symulowane_wy%C5%BCarzanie" target="_blank"&gt;Simulated Annealing (Symulowane Wyżarzanie)&lt;/a&gt; – technika pochodząca od metalurgii, oparta na zmianie temperatury, w zależności od której akceptujemy bądź odrzucamy nowopowstałe rozwiązania.&lt;/li&gt;&lt;li&gt;&lt;a href="http://pl.wikipedia.org/wiki/Przeszukiwanie_tabu" target="_blank"&gt;Tabu Search (Przeszukiwanie Tabu)&lt;/a&gt; – technika podobna do powyższej, ale nie ma tutaj temperatury, za to jest lista zabronionych ruchów (lista tabu) oraz różne dziwne rozwiązania.&lt;/li&gt;&lt;li&gt;&lt;a href="http://pl.wikipedia.org/wiki/Algorytm_genetyczny" target="_blank"&gt;Genetic Algoritm (Algorytm Genetyczny)&lt;/a&gt; – jeden z algorytmów inspirowanych naturą, polegający na utworzeniu populacji generalnej oraz krzyżowaniu (i “mutowaniu”) osobników w celu uzyskania lepszych.&lt;/li&gt;&lt;li&gt;GRASP (Greedy Randomized Adaptive Search Procedures) – właściwie to nie jest metaheurystyka, tylko wygenerowanie początkowego rozwiązania, a następnie ulepszaniu go za pomocą &lt;a href="http://pl.wikipedia.org/wiki/Algorytm_zach%C5%82anny" target="_blank"&gt;algorytmu zachłannego&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Chyba nawet bardzo skrótowo wyszło. Parę informacji i linki możecie znaleźć też &lt;a href="http://www.mimuw.edu.pl/~grygiel/archive/metaheurystyki.html" target="_blank"&gt;tutaj&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Ważne jest to, że wszystkie pozwalają uzyskać wielomianowy czas obliczeń, są ciekawe, można regulować ich parametry i warunek zakończenia (na przykład ilość przeprowadzonych iteracji) i są interesujące. Tak samo jak ciekawe. Co oznacza, że są interesujące, chociażby dlatego, że trzeba troszkę nad nimi posiedzieć i pomyśleć, ale są to zwykle miłe posiedzenia i rozmyślania. Gdyż są to ciekawe zagadnienia. &lt;/p&gt;&lt;p&gt;Dla odmiany, w następnym akapicie ani razy nie padnie słowo “interesujący/a/e” ani “ciekawy/a/e”. &lt;/p&gt;&lt;p&gt;W tym momencie wróćmy do naszego problemu Job Shop. Jak pamiętamy, mamy w nim n zadań, każde o określonej ilości etapów oraz m maszyn. Etapy zadania wymagają kolejnej obsługi na określonych maszynach przez określony czas. Naszym celem jest uszeregować wszystkie zadania w taki sposób, aby wszystko wykonało się jak najszybciej. Zadania się niepodzielne i niewywłaszczalne. Mamy chociażby taką instancję:&lt;/p&gt;&lt;p&gt;3 3&lt;/p&gt;&lt;p&gt;1 2 2 1 3 1&lt;/p&gt;&lt;p&gt;3 2 1 1 2 2&lt;/p&gt;&lt;p&gt;1 1 3 2 2 3&lt;/p&gt;&lt;p&gt;Rozszyfrujmy ten zapis – mamy 3 zadania i 3 maszyny. Pierwsze zadanie najpierw wędruje na pierwszą maszynę i spędza tam dwie jednostki czasu, następnie na drugiej maszynie musi być obsługiwane przez jeden kwant czasu, a na koniec spotyka się z trzecią maszyną i piją herbatę przez jedną jednostkę. Podobnie inne zadania – każdy wiersz to osobny proces (zadanie – będę używał zamiennie tych pojęć).&lt;/p&gt;&lt;p&gt;Docelowo rozwiązanie chcielibyśmy przedstawić np. za pomocą &lt;a href="http://pl.wikipedia.org/wiki/Diagram_Gantta" target="_blank"&gt;diagramu Gantta&lt;/a&gt;, aby było od razu widać, kiedy i gdzie dane etapy procesów są wykonywane. Dla metaheurystyk warto jednak przygotować inną formę. O taką:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_R2ix0MLn8lM/S3cOP4yla-I/AAAAAAAAAZQ/gdNo7_QH4Hc/s1600-h/03%5B11%5D.png"&gt;&lt;img title="03" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-LEFT: 0px; MARGIN-RIGHT: auto; BORDER-BOTTOM: 0px" height="258" alt="03" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S3cOQpSMrvI/AAAAAAAAAZU/lDtIIz0yev4/03_thumb%5B7%5D.png?imgmax=800" width="400" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Co to jest? Po bliższym zapoznaniu się z materiałem dochodzimy do wniosku, iż jest to graf skierowany acykliczny (tzw. DAG), którego wierzchołkami są etapy zadań. Jeśli jednak przetrzemy oczy, dopatrzymy się również niebieskich krawędzi (nieskierowanych łuków) między niektórymi wierzchołkami, na przykład między 1a oraz 2b. Co one oznaczają? Przyjrzyjcie się powyżej podanej instancji i porównajcie z grafem – łuki wskazują kolejne etapy danego zadania (s to początek szeregowania, a t – jego koniec), a niebieskie krawędzie łączą etapy, które wykorzystują tę samą maszynę, a co za tym idzie – wierzchołki konfliktowe. Co taki graf dysjunkcyjny (bo tak się to zwierzątko wabi) nam daje? To, że cały problem sprowadza się teraz do nadania takiego zwrotu niebieskim krąwędziom, aby graf nadal nie miał cykli. A to, jak ułożymy to zwroty, determinuje jakość rozwiązania danej instancji. Przykładowe rozwiązanie na przykład może być takie – dodałem również czasy trwania poszczególnych zadań.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/S3cORM3P3RI/AAAAAAAAAZY/rN_i981funA/s1600-h/04%5B5%5D.png"&gt;&lt;img title="04" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; BORDER-LEFT: 0px; MARGIN-RIGHT: auto; BORDER-BOTTOM: 0px" height="247" alt="04" src="http://lh6.ggpht.com/_R2ix0MLn8lM/S3cOR-1PZaI/AAAAAAAAAZc/Hmnj2X_mMro/04_thumb%5B3%5D.png?imgmax=800" width="383" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Jeżeli się nie pomyliłem, to nie ma żadnego cyklu i dane rozwiązanie jest dopuszczalne. Trzeba mieć jednak jakieś pomocnicze algorytmy, aby bawić się takim grafem dysjunkcyjnym. &lt;/p&gt;&lt;p&gt;Aby stwierdzić (nie)obecność cyklu, wystarczy skorzystać z &lt;a href="http://pl.wikipedia.org/wiki/Depth_First_Search" target="_blank"&gt;przeszukiwania w głąb&lt;/a&gt; (czyli popularnego DFS-a). Jeżeli wykryjemy cykl – trzeba coś pozmieniać w grafie, a jeżeli nie – uzyskujemy przy okazji kolejność &lt;a href="http://pl.wikipedia.org/wiki/Sortowanie_topologiczne" target="_blank"&gt;sortowania topologicznego&lt;/a&gt;. (Przy okazji – przepraszam, że rzucam fachowymi nazwami i nie za bardzo staram się tłumaczyć dane zagadnienia – wtedy ta notka (która planowo miała być bardzo krótka) rozrosłaby się do monstrualnych rozmiarów. Dlatego staram się podawać wszędzie linki do Wikipedii bądź innych serwisów – zachęcam również do korzystania z Google’a oraz książek.) To sortowanie topologiczne jest nam potrzebne do określenia czasu uszeregowania, który de facto jest najdłuższą ścieżką w grafie i tak będziemy to rozpatrywać. Algorytm, który został zaimplementowany w projekcie zaliczeniowym to metoda przypominająca z grubsza &lt;a href="http://pl.wikipedia.org/wiki/Algorytm_Dijkstry" target="_blank"&gt;algorytm Dijkstry&lt;/a&gt; (opisana w &lt;a href="http://www.lideria.pl/img_big/36823.jpg" target="_blank"&gt;Cormenie&lt;/a&gt; w rozdziale 24. oraz w tym &lt;a href="http://www.cs.princeton.edu/courses/archive/fall06/cos226/lectures/shortest-path.pdf" target="_blank"&gt;PDF-ie z Princetonu&lt;/a&gt;). Zmianą jest oczywiście to, że nie szukamy najkrótszej ścieżki, ale najdłuższej (podchodzimy pesymistycznie do naszego czasu uszeregowania). W związku z tym, należy zamienić wartości początkowe na minus nieskończoność (w praktyce – 0) oraz znak “&amp;gt;” na “&amp;lt;”. Podobnie możemy szukać czasów rozpoczęcia poszczególnych etapów.&lt;/p&gt;&lt;p&gt;Jeżeli chodzi o generowanie nowych rozwiązań – jest to tak naprawdę zmiana zwrotu jednego z “łuków dysjunkcyjnych” (tak, tych niebieskich) i testowaniu, co to zmienia w naszym rozwiązaniu – czy jest lepsze, gorsze, nijakie, podpija nam herbatę lub inne. W projekcie użyliśmy metaheurystyki Simulated Annealing na podstawie &lt;a href="http://www.fs.utm.my/matematika/images/stories/matematika/200420101.pdf" target="_blank"&gt;tej pracy naukowej&lt;/a&gt; autorstwa malezyjskich naukowców. Jeśli przeraża Was już sam tytuł albo charakter/język dokumentu – przejdzcie od razu na stronę 12 i dalszą, gdzie pokazany jest prosty przykład, jak to ma wyglądać. Jeżeli zajdzie taka potrzeba (ktoś wyrazi chęć), postaram się dokładniej tę metaheurystykę opisać w osobnej notce. Na razie chciałem Was zainteresować tematem i ewentualnie zachęcić do własnych rozważań.&lt;/p&gt;&lt;p&gt;Czy opisywany problem ma jakiekolwiek zastosowanie w grach komputerowych? Ciężko powiedzieć – na pierwszy rzut oka nie, na drugi też nie, na trzeci ucieka z pola widzenia, ale jak zmusimy się do myślenia, to może się okazać, że da się jakoś zaoptymalizować czas wytwarzania jednostek w kilku budynkach w grze strategicznej. Nie sądzę jednak, aby ktoś robił produkcję z wykorzystaniem metaheurystyki przy tak prozaicznej rzeczy jak wytwarzanie jednostek. Choć może…&lt;/p&gt;&lt;p&gt;Oczywiście, czekam na wszelkie uwagi, komentarze, wątpliwości i takie tam różne. Troszeczkę rozluźniła mi się sesja (ale nie do końca), więc może uda mi się częściej popisać na blogu. Nawet mam pomysł na kolejną notkę, która z grami będzie miała trochę więcej wspólnego, ale nadal będą to reminiscencje (o, nowe słowo) z minionego semestru na uczelni.&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2919321395725931706?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2919321395725931706/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2919321395725931706' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2919321395725931706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2919321395725931706'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/02/grafy-dysjunkcyjne-metaheurystyki-czyli.html' title='Grafy dysjunkcyjne, metaheurystyki – czyli znowu o szeregowaniu'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_R2ix0MLn8lM/S3cOPVzHruI/AAAAAAAAAZM/TrC8GZV_AbU/s72-c/01_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-6801804057845500790</id><published>2010-01-25T19:23:00.003+01:00</published><updated>2010-01-26T10:40:22.013+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Proste gry i casuale'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Inne projekty'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Statki z javowym nadzieniem</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_R2ix0MLn8lM/S13hf_NJCcI/AAAAAAAAAZA/GvElRu64p0w/s1600-h/Statki%5B3%5D.png"&gt;&lt;img title="Statki" style="border: 0px none ; margin: 0px 5px 0px 0px; display: inline;" alt="Statki" src="http://lh5.ggpht.com/_R2ix0MLn8lM/S13hiFsXM4I/AAAAAAAAAZE/P_lbCVHixSM/Statki_thumb%5B1%5D.png?imgmax=800" width="244" align="left" border="0" height="147" /&gt;&lt;/a&gt; Jakiś czas temu pisałem o różnych projektach, które mnie czekają na uczelni. W większości udało się je ukończyć – jeszcze z jednym się męczę podczas gdy kolokwia i egzaminy atakują z każdej możliwej strony. Wtedy, kiedy pisałem o tym wszystkim (czyli “jakiś czas temu” – zaskakujące, prawda?), wspomniałem również, iż postaram się chociaż część projektów przemycić do internetu i pokazać światu – w końcu czasami trzeba pobawić się w kabaret.&lt;/p&gt;&lt;p&gt;Problem jest jednak taki, że regulamin studiów nie pozwala na przyznawanie sobie praw autorskich do prac poczynionych w ramach zajęć na uczelni, a co za tym idzie – publikowania ich w całości. Na szczęście, większość prowadzących jest na tyle wyrozumiała, że nie ma nic przeciwko temu, aby studenci czasami pokazali coś z zajęć na swoich stronach domowych czy devblogach – stąd też dziękuję doktorowi od programowania obiektowego (pozdrawiam) i umieszczam Statki, które były do wykonania w ramach nauki języka Java. Robię to nie tylko dlatego, aby coś się ruszało na tej stronie, ale także dlatego, żeby ktoś mógł podpatrzeć jakieś rozwiązania, jeśli coś mu nie będzie wychodziło. Prosiłbym jednak, aby ktoś, kto będzie miał podobny projekt do napisania nie brał całego kodu jako swojego. Wzorowanie się, podpatrywanie – nie ma sprawy. Chodzi mi po prostu o to, aby ktoś nie ma miał problemów i nie nakryto go – brzydko i obscenicznie (a fuj) mówiąc - “zrzynaniu” (tak, nie "zżynaniu", gdyż to znaczy co innego). &lt;/p&gt;&lt;p&gt;Pod &lt;a href="http://chomikuj.pl/SceNtriC/Programy/Statki.zip" target="_blank"&gt;tym linkiem&lt;/a&gt; możecie znaleźć plik .jar z grą, grafiki (wszystkie mojego autorstwa – co zresztą widać, aż ocieka kombinacją Paint + GIMP), skróconą dokumentacją w Javadocu oraz same źródła.&lt;/p&gt;&lt;p&gt;Idei kodu nie będę za bardzo tłumaczył – jest tam troszkę bałaganu, ale nie aż takiego, aby nie można było dotrzeć do wszystkiego czego się chce, gdyż używam dość sporej ilości komentarzy. Całośc była kompilowana i testowana pod NetBeansem 6.7.1 i polecam ten program wszystkim chcącym programować w Javie – naprawdę prosto i przyjemnie się to robi. &lt;/p&gt;&lt;p&gt;Jeśli chodzi o samą grę, to nie ma tutaj fajerwerków graficznych – nie o to chodziło. Jest możliwość ustawienia różnych rozmiarów planszy (nie tylko kwadratowej 10x10) oraz wybrania ilości i rodzajów statków. Plansze są generowane losowo, co nie jest takie głupie – gra wymaga nieco wyczucia probabilistyki (tak to tłumaczę oficjalnie – tak naprawdę nie za bardzo chciało mi się i nie miałem czasu na rozstawianie samodzielne. Prawda jakie proste?). W wymaganiach projektowych było zaimplementowanie prostej sztucznej inteligencji komputerowego przeciwnika, który jednak od czasu do czasu wykazuje pociąg (tu-tut) do twórczego działania i strzela w miejsca okoliczne do tych, w które trafił. W programie musiały znaleźć się trzy komponenty, trzy wątki (tutaj są to: odświeżanie obrazu, sprawdzanie stanu zakończenia rozgrywki oraz ruch komputera). Słowem – nic specjalnego, można sobie pograć z kolegą jak dopada nas nuda (na przykład poczas sesji – tak, to była ironia). &lt;/p&gt;&lt;p&gt;Zapraszam do ściągania i komentowania, ale muszę powiedzieć jedno – o ile Java jest całkiem sympatyczna w trakcie programowania (pisze się szybko i estetycznie), tak jest na tyle wolna w działaniu, że moim skromnym zdaniem nie nadaje się specjalnie do gier. Jeśli nawet w przypadku takiej prostej gry miałem do czynienia z opóźnieniami na linii grafika-klikanie, to nie chcę wiedzieć, co się dzieje przy większych produkcjach. Oczywiście, nie przeczę, że są na to sposoby – tak czy siak, zostanę przy C++.&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-6801804057845500790?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/6801804057845500790/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=6801804057845500790' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/6801804057845500790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/6801804057845500790'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/01/statki-z-javowym-nadzieniem.html' title='Statki z javowym nadzieniem'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_R2ix0MLn8lM/S13hiFsXM4I/AAAAAAAAAZE/P_lbCVHixSM/s72-c/Statki_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-5445878500390512746</id><published>2010-01-17T13:25:00.002+01:00</published><updated>2010-01-17T13:26:03.841+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wielki Mistrz'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Jakby co, blog nie upadł</title><content type='html'>&lt;p&gt;To taka informacja dla tych, którzy myślą, że wyjątkowo długi czas, jaki opłynął od ostatniej notki, świadczy o moim niezainteresowaniu dalszym blogowaniem. Jeżeli ktoś się już cieszył, że nie będzie nowych notek – bardzo przepraszam.&lt;/p&gt;&lt;p&gt;Jak nietrudno się domyślić, brak nowych wpisów związany jest z tym, co czyha na studentow na uczelniach – okres zaliczeniowy i sesja. W związku z tym, że w Święta Bożego Narodzenia troszeczkę się rozleniwiłem, muszę teraz nadganiać wszelkie projekty. Dobra wiadomość jest jednak taka, że znalazłem sobie nową dyscyplinę sportową, którą śledzę. Teraz już nie tylko będę czasami spędzał noce na oglądaniu NBA, ale również NFL, czyli ligę futbolu amerykańskiego – przynajmniej na jakiś czas. Jeśli jednak ktoś przy mojej posturze wygoni mnie na boisko w kasku i każe biec z piłką wśród linebackerów przeciwnika – niech mnie nie naraża, bo faktycznie blog upadnie.&lt;/p&gt;&lt;p&gt;To, co chciałem zawrzeć w notce, to dwa artykuły dotyczące Wielkiego Mistrza, jakie niedawno się pojawiły na serwisie &lt;a href="http://polter.pl/" target="_blank"&gt;Poltergeist&lt;/a&gt;. Oto one:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://gry.polter.pl/Gamedev-czesc-druga-c21002" target="_blank"&gt;Ciągła Integracja autorstwa Toxica&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gry.polter.pl/Wielki-Mistrz-wywiad-z-tworcami-gry-c21064" target="_blank"&gt;Wywiad z twórcami gry Wielki Mistrz&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Oczywiście, zachęcam do przeczytania – mam nadzieję, że artykuł się spodoba, a z wywiadu dowiecie się kilku ciekawych rzeczy. I nie, nie mam tam żartów o gumowych kurczakach.&lt;/p&gt;&lt;p&gt;W przygotowaniu będzie też (bo jeszcze go nie ma) artykuł odnośnie problemu JSP (Job Shop Scheduling), o którym kiedyś tam pisałem (o, &lt;a href="http://pseudodev.blogspot.com/2009/11/niedziaajacy-algorytm-ale-cos-w-sobie.html" target="_blank"&gt;tutaj&lt;/a&gt;). Jeżeli wszystko pójdzie dobrze, to po sesji postaram się coś naskrobać odnośnie metaheurystyki simulated annealing (tak, “annealing”, tam jest jeszcze jeszcze “e” – po angielsku “wyżarzanie”). Mam nadzieję, że uda mi się to zrobić w miarę sprawnie.&lt;/p&gt;&lt;p&gt;Cóż, to wszystko na dzisiaj, mam nadzieję, że zaraz po sesji uda mi się coś wrzucić na tę stronę.&lt;/p&gt;&lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-5445878500390512746?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/5445878500390512746/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=5445878500390512746' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5445878500390512746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/5445878500390512746'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2010/01/jakby-co-blog-nie-upad.html' title='Jakby co, blog nie upadł'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-3441903962405096923</id><published>2009-12-19T13:31:00.002+01:00</published><updated>2009-12-19T17:56:38.591+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wielki Mistrz'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>To już koniec Wielkiego Mistrza</title><content type='html'>&lt;p&gt;&lt;a href="http://amatorskagra.wikispaces.com/file/view/fa82e267490636ee9a195fcb896c31b4.jpg/109695373/fa82e267490636ee9a195fcb896c31b4.jpg" target="_blank"&gt;&lt;img style="margin: 0px 5px 0px 0px; display: inline;" src="http://amatorskagra.wikispaces.com/file/view/fa82e267490636ee9a195fcb896c31b4.jpg/109695373/fa82e267490636ee9a195fcb896c31b4.jpg" width="176" align="left" height="99" /&gt;&lt;/a&gt; Można śmiało powiedzieć, iż zakończyliśmy prace nad Wielkim Mistrzem. Jeżeli już cokolwiek się zmieni, to jedynie jakieś grafiki – sam kod pozostaje już bez zmian. W tym krótkim okresie czasu, od &lt;a href="http://pseudodev.blogspot.com/2009/11/wielki-mistrz-nadszed.html" target="_blank"&gt;ostatniego release’u&lt;/a&gt; zmienił się głównie sposób informowania gracza o postępach w procesie ubijania stworów – zmiana polega na tym, że ten system informacji teraz istnieje. Ale o tym za chwilę.&lt;/p&gt;  &lt;p&gt;Najpierw linki:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://students.mimuw.edu.pl/%7Eps209499/mistrz/releases/grimmar/win32?from=blog_scentrica" target="_blank"&gt;Wersja dla Windows, archiwum&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://students.mimuw.edu.pl/%7Eps209499/mistrz/releases/grimmar/setup?from=blog_scentrica" target="_blank"&gt;Wersja dla Windows, instalator&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://students.mimuw.edu.pl/%7Eps209499/mistrz/releases/grimmar/linux?from=blog_scentrica" target="_blank"&gt;Wersja dla Linux&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://amatorskagra.wikispaces.com/Patche" target="_blank"&gt;Patche (w tym dodający shadery)&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://forum.gamedev.pl/index.php/topic,9753.msg177368.html#msg177368" target="_blank"&gt;Wątek na forum Warsztatu&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Jak pewnie zauważycie po uruchomieniu gry, wielu zmian nie ma. Najbardziej widoczne są: pasek życia potworów (tak!) i kamień zmieniający kolor w zależności od tego, ile zostało życia potworów (o tak!). Możecie się zastanawiać, dlaczego istnieją dwa sposoby informowania gracza o stanie przeciwnika. Wytłumaczenie jest proste, choć dosyć dziwne – nie mogliśmy się zdecydować i uznaliśmy, że obie formy mogą ze sobą współistnieć i nawet nieźle to wygląda. &lt;/p&gt;  &lt;p&gt;Oczywiście, ogromną zmianę jest z pewnością patch, który umożliwia stosowanie shaderów i mapowania wypukłości w grze. Ten “ficzerek” nie został wdrożony do gry odgórnie ze względu na problemy techniczne na niektórych konfiguracjach (dobrze – większości konfiguracji). Jako, że nie udało nam się załatać tego błędu, postanowiliśmy całą grę wypuścić bez bump mappingu, ale umożliwić ciekawskim włączenie efektów. Mam nadzieję, że uda się Wam to odpalić i zadziała bez najmniejszych problemów.&lt;/p&gt;  &lt;p&gt;Czy to oznacza, że przy WM już nie będzie się działo? Nie do końca – może zostanie zmienionych parę assetów (plików graficznych, dźwiękowych, modeli, itd.), choć to już raczej w formie “zwykłej” (obrazki do ściągnięcia i wstawienia w określone miejsce). Bardzo możliwe też, iż będziemy działać w celu promocji gry – jeżeli nam się uda, bądźcie pewni, że o tym napiszę.&lt;/p&gt;  &lt;p&gt;Chciałem podziękować całemu zespołowi SystemSzok i wszystkim, którzy choć trochę byli zaangażowani w tworzenie gry – Toxic, Krajek, Voytech, Kamma, Thyros, Jarko, Freeqstyler, Dyv, Bercik i wszystkim innych, których niestety nie umiem teraz przywołać. Dziękuję nie tylko za wspólną pracę i efekt, jaki osiągnęliśmy, ale także za możliwość tworzenia tak rozbudowanej gry, zapoznanie się z trybem pracy nad taką produkcją, nauczenie wielu rzeczy związanych z procesem powstawania gry, inspirację do napisania tylu notek na tym devblogu i za dobrą zabawę – mówcie co chcecie, ale pomijając to, iż tworzenie gry to ciężki kawałek chleba, jest przy tym dużo radości. Zwłaszcza, jak się widzi końcowy kształt i słyszy komentarze ludzi, mówiących “To wam wyszło”.&lt;/p&gt;  &lt;p&gt;Wyszło troszkę oficjalnie, ale raz na jakiś czas można sobie na to pozwolić. Dla całego zespołu – &lt;a href="http://znam.to/userfiles/R/039/R039-a0a6300.jpg" target="_blank"&gt;wafelki&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Teraz przychodzi smutna rzeczywistość – projekty na uczelnię. Muszę jednak przyznać, że laboranci z Politechniki się starają – aż trzy z czterech projektów na Święta to gry (&lt;a href="http://pl.wikipedia.org/wiki/Statki" target="_blank"&gt;Statki&lt;/a&gt; w Javie, &lt;a href="http://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi/25271?do=show;id=666" target="_blank"&gt;Oxelbergen&lt;/a&gt; [zwróćcie uwagę na id gry na tym serwisie – musiało mi się trafić], &lt;a href="http://pl.wikipedia.org/wiki/Guitar_Hero" target="_blank"&gt;Guitar Hero&lt;/a&gt; (bez dźwięku, za to ze świecącymi diodami) na płytce &lt;a href="http://rawski.zpt.tele.pw.edu.pl/pl/files/altera_DE2-70.png" target="_blank"&gt;FPGA&lt;/a&gt; – jedynie Job-shop, o którym już pisałem, nie jest projektem rozrywkowym). Jeżeli będę miał coś działającego – postaram się to ujawnić w kolejnych notkach. &lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję - SceNtriC&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-3441903962405096923?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/3441903962405096923/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=3441903962405096923' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3441903962405096923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/3441903962405096923'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2009/12/to-juz-koniec-wielkiego-mistrza.html' title='To już koniec Wielkiego Mistrza'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2636207826222691879</id><published>2009-12-05T16:45:00.003+01:00</published><updated>2009-12-05T16:48:11.525+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Magic: the Gathering'/><category scheme='http://www.blogger.com/atom/ns#' term='Inne projekty'/><category scheme='http://www.blogger.com/atom/ns#' term='Framework 3D'/><title type='text'>RepackGenerator</title><content type='html'>&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_R2ix0MLn8lM/SxqACHyaoCI/AAAAAAAAAYs/lSrWizDGCrI/s1600-h/scr%5B3%5D.png"&gt;&lt;img title="scr" style="border: 0px none ; margin: 0px 0px 0px 5px; display: inline;" alt="scr" src="http://lh4.ggpht.com/_R2ix0MLn8lM/SxqACiHvpmI/AAAAAAAAAYw/5J4fjPx1rAg/scr_thumb%5B1%5D.png?imgmax=800" width="244" align="right" border="0" height="125" /&gt;&lt;/a&gt; Poprzednio wspominałem o prostym projekciku generującym repacki z podanej puli kart Magic: the Gathering. Jest to pewne ułatwienie w przypadku organizacji jakiegoś common draftu bądź innych wydarzeń. Nie sądzę jednak, żeby to dalej rozwijać lub komuś to wciskać – ważniejsza tutaj jest chyba wartość programistyczna.&lt;/p&gt;  &lt;p&gt;Naszym niedawnym projektem na przedmiot Programowanie Obiektowe było przygotowanie programu, którzy zarządzałby obiektami w strukturze klas podobnej do drzewa. Oczywiście, chodziło o zaznajomienie studenta z dziedziczeniem, polimorfizmem i innych aspektami OOP-u, ale samo zadanie było dosyć ciekawe. Ponieważ nie napisałem go (jako projekt oddałem framework – Yestę), postanowiłem nadrobić zaległości w wykorzystywaniu obiektowości i powstał RepackGenerator.&lt;/p&gt;  &lt;p&gt;Idea kodu jest oczywista (jak się na niego spojrzy) – jeden obiekt zarządzający wszystkim, co się dzieje w programie, a interfejs ogranicza się do konsoli ze znakiem zachęty. Bardzo mi się podoba ta idea – może dlatego, że Bash to jest jedna z kilku rzeczy, jakie mi się podobają w systemach uniksowych. &lt;/p&gt;  &lt;p&gt;Ten projekt był też okazją, aby zapoznać się z systemem dokumentowania &lt;a href="http://www.stack.nl/%7Edimitri/doxygen/" target="_blank"&gt;Doxygen&lt;/a&gt;. Wyszło całkiem sympatycznie – wygląda estetycznie i politycznie poprawnie. Jedyną wadą tego rozwiązania jest niewygodny sposób komentowania kodu, ale z drugiej strony nie widzę innego sposobu na mechanizm dokumentowania źródeł. Cóż – i tak muszę się z tym zaprzyjaźnić w kontekście uczelni. A poza tym – wypadałoby. &lt;/p&gt;  &lt;p&gt;Jak widać, na screenie, nie wpisałem ambitnych kart do testowania. Właściwie, to w ogóle kart nie wpisałem – przyznaję, iż nie chciało mi się wtłaczać mojej bazy tzw. “crapów” (niewiele wartych kart, które można wykorzystać do takich zabaw). Ważniejszy na chwilę obecną był jednak aspekt informatyczny i edukacyjny programu.&lt;/p&gt;  &lt;p&gt;Linki, pod którymi możecie znaleźć program wraz z źródłami i dokumentacją:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://chomikuj.pl/SceNtriC/Programy/RepackGenerator.zip" target="_blank"&gt;Chomik&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.speedyshare.com/files/19632954/RepackGenerator.zip"&gt;&lt;span style="text-decoration: underline;"&gt;S&lt;/span&gt;&lt;/a&gt;&lt;a href="http://www.speedyshare.com/files/19632954/RepackGenerator.zip" target="_blank"&gt;peedyshare&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Czekam na komentarze i uwagi. Mam również pewną przykrą informację – na razie zarzucam framework i prawdopodobnie nie będę już w nim implementował generowania terenu. Dobra wiadomość jest jednak taka, że jak znajdę trochę czasu, rozpocznę w końcu prace nad silnikiem – wiem, że powtarzam to jak mantrę od paru miesięcy, ale właśnie ten teren (oprócz studiów) najbardziej mnie hamował pod tym względem. Pozostaje jeszcze przezwyciężyć lenistwo.&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2636207826222691879?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2636207826222691879/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2636207826222691879' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2636207826222691879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2636207826222691879'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2009/12/repackgenerator.html' title='RepackGenerator'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_R2ix0MLn8lM/SxqACiHvpmI/AAAAAAAAAYw/5J4fjPx1rAg/s72-c/scr_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-2241568399563238440</id><published>2009-12-05T15:29:00.003+01:00</published><updated>2009-12-05T19:13:10.685+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Magic: the Gathering'/><category scheme='http://www.blogger.com/atom/ns#' term='Wielki Mistrz'/><category scheme='http://www.blogger.com/atom/ns#' term='Technikalia'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><title type='text'>Ajajaj – aż trzy tygodnie</title><content type='html'>&lt;p&gt;&lt;img style="margin: 0px 5px 0px 0px; display: inline;" src="http://www.gamedev.pl/screens/e31bc367b82d6f64e9015f579f3a8829.jpg" width="172" align="left" height="97" /&gt; Znowu przerwa… Dobra informacja jest jednak taka, że powoli kończy się “gorący okres” (zwany też “puść ziemniaka”) na Politechnice. Oddanie systemu eksperckiego, kolokwium z Programowania Obiektowego (o ekstremalnym poziomie trudności), wejściówki wszelakie (a raczej groźba ich wystąpienia) – to tematy, którymi zajmowałem się ostatnio. Na szczęście, w najbliższym czasie czeka mnie tylko oddanie pierwszego rozwiązania na Optymalizację Kombinatoryczną (z zagadnienia, które &lt;a href="http://pseudodev.blogspot.com/2009/11/niedziaajacy-algorytm-ale-cos-w-sobie.html" target="_blank"&gt;niedawno opisywałem&lt;/a&gt; – &lt;a href="http://en.wikipedia.org/wiki/Job_Shop_Scheduling" target="_blank"&gt;Job Shop&lt;/a&gt;). A na co przychodzi pora, jak na uczelni nieco się rozluźnia? Na denerwowanie wszystkich opowieściami o Wielkim Mistrzu.&lt;/p&gt;  &lt;p&gt;Nie odkryję Ameryki (Wschodnio-Południowej), gdy rzeknę, iż w &lt;img style="margin: 0px 0px 0px 5px; display: inline;" src="http://www.gamedev.pl/screens/fa82e267490636ee9a195fcb896c31b4.jpg" width="247" align="right" height="139" /&gt; chwili obecnej trwa dostrajanie pewnych rzeczy i myślenie o małej promocji gry. Jesteśmy też zajęci szukaniem niektórych grafik. Ale najważniejszą zmianą jest bez wątpienia to, co pewnie tutaj widać na screenach (jeżeli jeszcze sobie nie poszły na obiad) – mapowanie wypukłości. Bump mapping, relief mapping, jak-miło mapping – sporo osób chciało, żeby to zaimplementować. Na razie są jeszcze jednak małe problemy na niektórych konfiguracjach i niestety, jeżeli nic się pod tym względem nie zmieni, to trzeba będzie z tego zrezygnować w finalnej wersji. Tym niemniej, na pozostałych konfiguracjach działa i widać, jak to wygląda – wreszcie czuć klimat lochów. Chwała naszym programistom (Toxic, Krajek, Voytech i bodajże Dab się włączył – pozdrawiam). Wracając jeszcze do screenów - na tej stronie mogą być zbyt małe, natomiast &lt;a href="http://www.gamedev.pl/user.php?x=view&amp;amp;id=2329"&gt;tutaj&lt;/a&gt; znajdziecie normalne wersje.&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="margin: 0px 5px 0px 0px; display: inline;" src="http://www.gamedev.pl/screens/413c27a434500d34650b8a67a7b336cf.jpg" width="256" align="left" height="160" /&gt; Niedawno (właściwie to przed godziną) skończyłem mój kilkugodzinny projekcik, który miał dwojakie znaczenie. Po pierwsze, ułatwiałby tworzenie “repacków” z puli kart Magic: the Gathering – są to 15-kartowe paczki o zawartości takiej samej jak boostery, ale tworzone z kart, które zostały już “otwarte”. W praktyce można to wykorzystać do bardzo tanich (ok. 6-10 zł zamiast 30-40) booster draftów, gdzie co prawda nie ma szans trafić mocarnych kart, ale jest sporo zabawy i doskonalenia strategii przy grze. Drugi powód napisania programu był typowo informatyczny – chęć doskonalenia swoich umiejętności w zakresie “czystego” programowania obiektowego (z uwzględnieniem wszystkich [no dobrze, może części (niewielkiej)] zasad OOP-u) oraz dziewicze wykorzystanie narzędzia &lt;a href="http://www.stack.nl/%7Edimitri/doxygen/" target="_blank"&gt;Doxygen&lt;/a&gt; do generowania dokumentacji. Przyznaję, że oba eksperymenty wyszły po mojej myśli, a Doxygen okazał się bardzo przyjemnym narzędziem (choć zaburzył moją estetykę kodu – chlip). Jakie są efekty tego projekciku – dowiecie się pewnie już wkrótce. Oczywiście, udostępnie cały kod wraz z projektem w VC++ oraz dokumentacją w formacie HTML (coś ala &lt;a href="http://www.ogre3d.org/docs/api/html/" target="_blank"&gt;dokumentacja Ogre’a&lt;/a&gt; 3D, ale dużo mniejsza).&lt;/p&gt;  &lt;p&gt;Pozdrawiam i dziękuję – SceNtriC.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6324716039497767765-2241568399563238440?l=pseudodev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://pseudodev.blogspot.com/feeds/2241568399563238440/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6324716039497767765&amp;postID=2241568399563238440' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2241568399563238440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6324716039497767765/posts/default/2241568399563238440'/><link rel='alternate' type='text/html' href='http://pseudodev.blogspot.com/2009/12/ajajaj-az-trzy-tygodnie.html' title='Ajajaj – aż trzy tygodnie'/><author><name>SceNtriC</name><uri>http://www.blogger.com/profile/17028361887111275719</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6324716039497767765.post-6547768184850391930</id><published>2009-11-13T20:25:00.002+01:00</published><updated>2009-11-13T20:28:21.457+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktura kodu'/><category scheme='http://www.blogger.com/atom/ns#' term='Studia'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorytmy'/><title type='text'>Niedziałający algorytm – ale coś w sobie ma</title><content type='html'>&lt;p&gt;W trzecim semestrze mamy przedmiot o znamiennej nazwie Optymalizacja Kombinatoryczna. Jak nietrudno się domyślić, jest to dalsza część tematu powiązanego z problemami i algorytmami je rozwiązującymi, jednak tym razem całość krąży wokół szukania rozwiązań optymalnych dla problemów NP-trudnych i silnie NP-trudnych (należących do tzw. NP-zupy). Strasznie zagmatwana dziedzina i do tego bardzo teoretyczna – potrafi być miażdżąca dla umysłu, ale jak się w to wgłębić, to jest dosyć ciekawa (pod warunkiem, że nie trzeba pisać z tego kolokwium). Tym bardziej, że u nas jest bardzo przystępnie tłumaczona (pozdrawiam wykładowcę).&lt;/p&gt;  &lt;p&gt;Zadaniem części studentów na laboratoriach jest napisanie rozwiązań do tzw. problemu &lt;a href="http://en.wikipedia.org/wiki/Job-shop_problem" target="_blank"&gt;Job Shop&lt;/a&gt;. Polega on w skrócie (i intuicyjnie) na tym, iż mamy M maszyn oraz N zadań do wykonania, dla których określone są dwójki (m&lt;sub&gt;0&lt;/sub&gt; t&lt;sub&gt;0&lt;/sub&gt;) (m&lt;sub&gt;1&lt;/sub&gt; t&lt;sub&gt;1&lt;/sub&gt;) … (m&lt;sub&gt;n&lt;/sub&gt; t&lt;sub&gt;n&lt;/sub&gt;), gdzie m&lt;sub&gt;i&lt;/sub&gt; to indeks maszyny, którą potrzebuje dane zadanie, a t&lt;sub&gt;i&lt;/sub&gt; to ilość kwantów czasu, które musi spędzić zadanie na maszynie m&lt;sub&gt;i&lt;/sub&gt;. Etap “produkcji” danego zadania (czyli taka dwójka) musi być wykonany kolejno – najpierw musi przejść pierwszą wymienioną maszynę, potem drugą, trzecią itd. Nie można zmieniać kolejności. Jest też jedna ważna sprawa, przez którą poniższy algorytm działa niepoprawnie (choć będzie poprawny dla innych form tego problemu) – jeżeli dane zadanie dostanie maszynę do dyspozycji, to spędza na niej tyle czasu, ile potrzebuje – nie oddaje jej przed końcem danego procesu (trzyma się kurczowo nóżkami). &lt;/p&gt;  &lt;p&gt;Jest to zatem jedna z odmian problemu szeregowania. Jakby tego było mało, jest to jeden z rodzajów bardzo znanego &lt;a href="http://pl.wikipedia.org/wiki/Problem_komiwoja%C5%BCera" target="_blank"&gt;problemu komiwojażera&lt;/a&gt;, w którym miasta do odwiedzenia to zadania (a ich liczba N), a maszyna jest jedna i jest to nasz podróżnik. &lt;/p&gt;  &lt;p&gt;Jak już wcześniej wspomniałem, jeżeli zadanie dostanie maszynę, to nie może się od niej oderwać przed ukończeniem danego etapu produkcji. Jest to zatem przykład niewywłaszczalności. Poniższy pomysł na algorytm zakłada jednak, że jeżeli nastąpią pewne okoliczności, jedno zadanie może przerwać swój etap i dopuścić maszynę do drugiego zadania. Jest to zatem system wywłaszczalny i w dodatku taki, w którym najwyższy priorytet mają zadania o najmniejszym indeksie.&lt;/p&gt;  &lt;p&gt;Cóż, troszkę formalizmu, a teraz konkrety. Muszę z góry przyznać, iż algorytm jest dosyć kiepski – nie działa zbyt optymalnie. Ma jednak taką właściwość, iż jest bardzo prosty i nawet ja umiałem go zaimplementować. A poza tym, przedstawiam ten pomysł jako inspirację dla kogoś, kto być może wymyśli (albo chociaż zna) działający i optymalny algorytm dla Job Shopa. W garści mam też pomysł oparty na algorytmie &lt;a href="http://pl.wikipedia.org/wiki/Algorytm_szeregowania#Mniej_powszechne" target="_blank"&gt;SJF&lt;/a&gt;, ale wolałbym implementować “mądrzejsze” rozwiązania (algorytmy genetyczne, inne metaheurystyki, B&amp;amp;B, itd.)&lt;/p&gt;  &lt;p&gt;Może mały przykład. Mamy trzy maszyny do dyspozycji (o indeksach od 0 do 2) oraz trzy zadania (0-2), które zostały zdefiniowane następująco:&lt;/p&gt;  &lt;p&gt;T0: (0 2) (1 3) (2 1)&lt;/p&gt;  &lt;p&gt;T1: (1 1) (2 2) (0 1)&lt;/p&gt;  &lt;p&gt;T2: (1 3) (0 2) (2 3)&lt;/p&gt;  &lt;p&gt;Opiszę może słownie jedno z zadań, żeby wszystko było całkowicie jasne – zadanie nr 2 najpierw musi spędzić trzy kwanty czasu na maszynie nr 1, potem przez dwa kwanty czasu jest wykonywane na maszynie nr 0, a na końcu odwiedza maszynę nr 2 i zostaje tam na trzy kwanty. &lt;/p&gt;  &lt;p&gt;Uszeregowanie, jakie proponuje opisywany algorytm, wygląda tak:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_R2ix0MLn8lM/Sv2ysNwJJTI/AAAAAAAAAYk/GH3l3Sr41jM/s1600-h/jsp14.png"&gt;&lt;img title="jsp1" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="jsp1" src="http://lh4.ggpht.com/_R2ix0MLn8lM/Sv2ysuxEajI/AAAAAAAAAYo/3sKwKCcBJ6I/jsp1_thumb2.png?imgmax=800" width="375" border="0" height="155" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Oczywiście, widać, iż nie jest to zbyt optymalne rozwiązanie – zwłaszcza dla zadania drugiego, które smutne i zmechacone powolutku człapie od jednej maszyny do drugiej, w międzyczasie ustępując miejsca zadaniu zerowemu, które ma niższy indeks. W efekcie długość uszeregowania wszystkich zadań wynosi 12 kwantów czasu. Czasami naprawdę się zastanawiam, po co opisuję niedziałające algorytmy. Może dlatego, że są tak proste, że łatwo się o nich pisze notki.&lt;/p&gt;  &lt;p&gt;Pierwszą rzeczą, jaką należy wykonać, jest wykorzystanie kolejek FIFO do trzymania informacji o zadaniach, ale w specyficzny sposób. Mając zadanie, które opisane jest jako:&lt;/p&gt;  &lt;p&gt;(1 2) (0 1) (2 3)&lt;/p&gt;  &lt;p&gt;musimy utworzyć kolejkę o wartościach:&lt;/p&gt;  &lt;p&gt;1 1 0 2 2 2&lt;/p&gt;  &lt;p&gt;Widać, że na maszynie nr 1 musimy spędzić dwa kwanty czasu (są dwie jedynki), na zerowej jeden, a na drugiej – 3 kwanty. Tak przygotowane kolejki następnie wykorzystujemy w algorytmie i stopniowo zdejmujemy z nich wartości. Ale może najpierw schemat, a nie, że ja tutaj tak szybko myk-myk.&lt;/p&gt;  &lt;p&gt;1. Wszystko dzieje się w pętli, która odlicza kolejne kwanty czasu. Jej zakończenie jest uwarunkowane przez stan zmiennej logicznej typu bool.&lt;/p&gt;  &lt;p&gt;2. Tworzymy sobie tablicę tf o typie int i rozmiarze N i zapełniamy ją zerami.&lt;/p&gt;  &lt;p&gt;3. Robimy sobie herbatę.&lt;/p&gt;  &lt;p&gt;4. Tworzymy pętlę dla każdej maszyny. &lt;/p&gt;  &lt;p&gt;5. W każdej iteracji tej pętli tworzymy następną pętlę (z licznikiem t), w której sprawdzamy wszystkie zadania, począwszy od zerowego. Jeżeli jakieś zadanie t nie zostało w tym kwancie “wykorzystane” (tf[t] == 0), jego kolejka nie jest pusta, a pierwszy element to indeks aktualnie przetwarzanej maszyny – tf[t] = 1, zapamiętujemy t, zdejmujemy wartość z kolejki zadania t oraz wychodzimy z pętli.&lt;/p&gt;  &lt;p&gt;6. Zapisujemy do wektora aktualnie przetwarzanej maszyny wartość t. Jeżeli jednak żadne zadanie nie potrzebuje maszyny w danym kwancie czasu, wpisujemy –1 (jakieś oznaczenie musimy przyjąć). &lt;/p&gt;  &lt;p&gt;7. Sprawdzamy (już poza pętlą z punktu 4.), czy kolejka któregokolwiek zadania nie jest pusta. Jeżeli któreś zadanie ma jeszcze jakieś wartości w kolejce – przechodzimy do następnej iteracji pętli zliczającej kwanty czasu. W przeciwnym razie – kończymy algorytm.&lt;/p&gt;  &lt;p&gt;W ten sposób, naszym rozwiązaniem będą wektory kolejnych indeksów zadań, które są wykonywane na danej maszynie w określonym kwancie czasu (lub –1, jeżeli maszyna nie jest wykorzystywana). Polecam też wykonywać punkt 3. jedynie raz – potem Wam się namnożą herbaty.&lt;/p&gt;  &lt;p&gt;Algorytm jest bardzo prosty, choć nie daje zadowalającego wyniku dla szeregowania z wywłaszczaniem. Nie działa też jakoś nienaturalnie wolno, choć złożoność mówi co innego – O(N*M*i), gdzie i to ilość kwantów czasu, jaka jest potrzebna na nasze uszeregowanie. A że i przy dużych instancjach dąży do nieskończoności…&lt;/p&gt;  &lt;p&gt;Na koniec pełny kod naszego rozwiązania (QUANTITY to N, a MAC_QUANTITY to M).&lt;/p&gt;  &lt;div   style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;   &lt;div   style="border-style: none; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;     &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; #include &amp;lt;cstdio&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; #include &amp;lt;cstdlib&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; #include &amp;lt;vector&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; #include &amp;lt;queue&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt; #include &amp;lt;ctime&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; #include &amp;lt;cctype&amp;gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; QUANTITY 3&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt; &lt;span style="color: rgb(204, 102, 51);"&gt;#define&lt;/span&gt; MAC_QUANTITY 3&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; main (&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt; argc, &lt;span style="color: rgb(0, 0, 255);"&gt;char&lt;/span&gt;* argv[])&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// wrzucenie zadań do kolejek&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// jeżeli jakieś zadanie ma być wykonywane:&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// na 1-szej maszynie 2 kwanty czasu, a potem&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// na 2-giej maszynie 3 kwanty czasu, to&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// obraz kolejki:&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// 1 1 2 2 2&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;     std::queue&amp;lt;unsigned&amp;gt; task[QUANTITY];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;     std::vector&amp;lt;&lt;span style="color: rgb(0, 0, 255);"&gt;int&lt;/span&gt;&amp;gt; machine[MAC_QUANTITY];&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;// zadanie 0&lt;/span&gt;&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;     task[0].push(0);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;     task[0].push(0);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;     task[0].push(1);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;     task[0].push(1);&lt;/pre&gt;    &lt;pre   style="border-style: none; margin: 0em; padding: 0px; overflow: visible; width: 100%; color: black; line-height: 12pt; background-color: rgb(244, 244, 244);font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;     task[0].push(1);&lt;/pre&gt;    &lt;pre   st
