Odwracanie macierzy 4×4

2008-01-04 20:54

Do napisania czegokolwiek z dziedziny programowania gier lub grafiki potrzebna jest zawsze chociaż skromna biblioteka, zawierają podstawowe obiekty matematyczne. Jej częścią na pewno muszą być wektory, a nie od rzeczy są także macierze, kwaterniony, obiekty reprezentujące linie i płaszczyzny, i tak dalej. Taką bibliotekę zwykle albo pisze się raz, albo wykorzystuje jedną z już istniejących. Jakikolwiek byłby nasz wybór, mogłoby się wydawać, że sprawę z nią można załatwić raz na zawsze.
Cóż, nic bardziej błędnego :) Możemy być oczywiście bardzo przywiązani do narzędzi, którymi się posługujemy – języka programowania, platformy, itd. – ale kiedyś na pewno przyjdzie nam zmierzyć się z zupełnie innym językiem i innym środowiskiem. A wtedy trzeba jakoś ten problem matematycznej biblioteki rozwiązać choćby na szybko.

Ostatnio przytrafiło mi się właśnie coś takiego. Nie jest to naturalnie nic pasjonującego, bowiem implementowania dodawania, odejmowania czy mnożenia wektorów jest zajęciem raczej nużącym. Jednak okazało się, że istnieje przynajmniej jedna potrzebna, a niezbyt oczywista matematyczna operacja, którą należy koniecznie uwzględnić. To odwracanie macierzy.
Chcąc tego dokonać programowo, możemy wykorzystać na przykład któryś z tych trzech sposobów:

  • Metoda bezpośrednia. Jest to prostu zaimplementowanie ręcznego sposobu odwracania macierzy, wykorzystywanego zazwyczaj w połączeniu z kartką i długopisem :) Dla tych, co przysypiali na wykładach z algebry (lub nie mieli jeszcze szczęścia na nie uczęszczać ;)) przypominam, że polega to na wykonaniu określonych operacji (mnożenia przez liczbę oraz dodawania) na wierszach naszej macierzy oraz jednocześnie na wierszach macierzy jednostkowej. W ich wyniku nasza macierz sama ma zmienić się w jednostkową, zaś ta druga będzie wtedy szukaną odwrotnością. Wiadomo skądinąd, że złożoność tego algorytmu to O(n3), gdzie n to wymiar macierzy.

    Ręczne odwracanie macierzy

  • Rozwiązanie układów równań. Ta metoda wymaga posiadania procedury rozwiązującej układy równań, jak na przykład eliminacji Gaussa lub znajdowania rozkładu LU. Posługując się nią, możemy obliczyć kolejne wiersze macierzy odwrotnej i też zajmie nam to czas O(n3). Oczywiście trzeba jeszcze mieć (tj. napisać) rzeczoną procedurę, co już takie proste nie jest :)
  • Dopełnienie algebraiczne. Ten sposób charakteryzuje się głównie tym, że wymaga obliczenia sporej liczby wyznaczników – nie tylko tej macierzy, którą odwracamy, ale i każdej z jej podmacierzy. Wiadomo zaś, ze wyliczanie wyznaczników nie należy do operacji tanich. W istocie złożoność tej metody odwracania leży gdzieś w okolicach wykładniczej.

Trzeba jednak zauważyć pewną rzecz. Otóż do celów graficznych potrzebujemy jedynie macierzy o stałym rozmiarze, i to niewielkim – zwykle 4×4. Przy tak małym rozmiarze danych złożoność algorytmu (która niejawnie zakłada, że rozmiar ten jest bardzo duży) nie jest miarodajna. Liczy się bowiem dokładna ilość faktycznie wykonywanych operacji. A przy takim podejściu spotyka nas niespodzianka, jako że najwyraźniej najlepsza okazuje się metoda ostatnia. Jest ona używana na przykład w funkcji D3DXMatrixInverse, zatem posiada całkiem dobrą rekomendację :)
I ma chyba tylko jedną wadę. Po rozpisaniu występującej w niej pętli (co jest możliwe, jeśli znamy z góry rozmiar macierzy) zamienia się ona w dość odstraszającą szpaltę kodu z kilkunastoma długimi, niemal identycznie wyglądającymi wierszami, które różnią się tylko permutacją cyferek oraz plusów i minusów. Ale przecież tak wygląda kod w zasadzie każdego działania na macierzach i właśnie dlatego tak lubimy je implementować ;-)

Tags:
Author: Xion, posted under Programming » 3 comments

A.I. – wariacja na temat

2008-01-04 0:36

Zawsze byłem sceptycznie nastawiony do tak zwanej 'sztucznej inteligencji'. Nie chodzi tu bynajmniej o stosunkowo proste algorytmy klasyfikowane dość swobodnie i niezbyt formalnie jako AI, a wykorzystywane chociażby w programowaniu gier: wyszukiwanie najkrótszej drogi, zachowanie się postaci typu NPC, itp. Mam raczej na myśli takie konstrukcje (zarówno programy, jak i urządzenia, a najczęściej połączenie jednych i drugich), które starają się być znacznie bardziej uniwersalne i sprawiać wrażenie inteligentnych w jakimkolwiek z spośród licznych i niezbyt jasnych znaczeń tego słowa.
Mój "problem" polegał mniej więcej na tym, że jakoś ciężko było mi uwierzyć w to, że kiedyś - nawet niekoniecznie w przewidywalnej przyszłości - maszyny będą rzeczywiście myślały. Można to uznać za swego rodzaju zawodowe zboczenie. Wiedząc, że komputery działają zawsze w oparciu o określony, niezmienny i ściśle zdefiniowany algorytm, trudno jest uwierzyć, że wystarczy tylko odpowiedni wzrost mocy obliczeniowej, by nagle zyskały one jakieś nieprzewidziane zdolności. W takim podejściu tkwi jednak pewne dość wątpliwe, a kluczowe założenie, o istnieniu którego zdałem sobie sprawę dopiero niedawno...

Robot Kismet
Kismet - robot "z uczuciami"
© Jared C. Benedict, MIT

Zasadniczo z maszynami, które mają być w jakimś aspekcie podobne do ludzi lub innych istot żywych, wiążą się dwa zasadnicze problemy. Pierwszym jest różnica między właściwościami, jakie faktycznie posiadają, a tymi, które tylko wydają się posiadać. Nietrudno na przykład zauważyć, że spsiały robot Aibo całkiem dobrze naśladuje zachowanie prawdziwego zwierzęcia. Równie szybko można jednak zdać sobie sprawę, że tak naprawdę nie zrobi on niczego, do czego nie został wcześniej zaprogramowany. Nawet jeśli ktokolwiek przypisuje mu więc jakiekolwiek psie cechy, nie czyni go to jeszcze sztucznym psem.
Drugim i znacznie poważniejszym problemem jest to, że konstruując tego rodzaju maszyny, ludzie starają się naśladować coś, o czym tak naprawdę wiedzą niewiele. Wciąż nie mamy dobrych (czyli weryfikowalnych) definicji na takie pojęcia jak 'życie', 'inteligencja' czy 'świadomość'. Zwłaszcza ten ostatni termin jest kłopotliwy, gdyż stuprocentowo pewną odpowiedź pozytywną na pytanie "Czy coś jest świadome?" możemy udzielić tylko wtedy, gdy chodzi o... nas samych.

I chociaż filozofia jak zwykle nie dostarcza żadnych konkretnych odpowiedzi, nie przeszkadza to badaczom dociekać, jak świadomość może powstawać - ze szczególnym uwzględnieniem ludzkiej, która musiała przecież wykształcić się w toku ewolucji. Do niedawna najlepszym "wyjaśnieniem", o jakim słyszałem, była emergencja, czyli powstawanie złożonych zjawisk na kanwie prostych "klocków". Innymi słowy jest to twierdzenie, że całość jest czymś więcej niż tylko sumą części. W odniesieniu do świadomości oznacza to, że w dostatecznie dużym zbiorze neuronów (albo odpowiednio zaawansowanym komputerze czy też sieci tychże) wyłoni się ona samoistnie. Raczej mało przekonujące, nieprawdaż?
Znacznie ciekawszym przypuszczeniem jest hipoteza, że ludzie są samoświadomi, gdyż używają w stosunku do swojej osoby pewnych modeli, które są wykorzystywane przez mózg w odniesieniu do innych ludzi. Zakładamy na przykład, że inni ludzie też myślą, mają uczucia i że w swoim postępowaniu kierują się jakimiś zasadami. Często takie założenia i oparte na nich modele zachowań bywają trafne, więc przez pokolenia były udoskonalane, bo miały po prostu ewolucyjne uzasadnienie. Ciekawie zaczyna się robić wtedy, kiedy odkrywa się, że z pomocą tzw. neuronów lustrzanych ludzki mózg może budować modele swego posiadacza. Właśnie taki model może być jeśli nie samoświadomością, to przynajmniej jej solidną podstawą.

Uff, to było wyczerpująca dygresja ;-) A jakie są praktyczne wnioski dla sztucznej inteligencji? Otóż jeśli świadomość rzeczywiście tak "działa", to można nią obdarzyć dowolny byt w relatywnie łatwy sposób. Wystarczy, że będzie on posiadał jakiś mechanizm, umożliwiający mu rozpoznawanie innych bytów, a następnie zastosuje go w stosunku do siebie.
Proponuję teraz zejść wreszcie z tych niebotycznych wyżyn abstrakcji - i to od razu na sam dół: do kodu. Napiszmy po prostu klasę obiektów, które będą świadome w powyższym sensie:

class ConciousObject:
    def perceive(self, obj):
        if (obj != self):
            print "`" + str(obj) + "` is a(n) " + str(obj.__class__)
        else:
            print "I am a(n) " + str(self.__class__)

    def introspect(self):
        self.perceive(self)

Tak, to już jest to. To chyba najbardziej prymitywny sposób realizacji całego pomysłu, ale zawiera wszystkie niezbędne elementy. Mamy tutaj metodę perceive, za pomocą której nasz obiekt może "postrzegać" jakiś inny obiekt - co tutaj oznacza po prostu wypisanie jego tekstowej reprezentacji wraz z nazwą jego klasy. Przejawem samoświadomości jest z kolei metoda introspect, która to pozwala obiektowi "postrzegać" w ten sposób siebie. Robi to podobnie jak we wszystkich pozostałych przypadkach, acz nieco inaczej, gdyż wie (tak jak ludzie), że teraz "patrzy" do swojego wnętrza. Mechanizm jest jednak podobny.
A przykładowe wyniki są następujące:

`42` is a(n) <type 'int'>
`Ala ma kota` is a(n) <type 'str'>
`<Foo instance at 0x014BDA08>` is a(n) Foo
I am a(n) ConciousObject

To oczywiście tylko żart, ale jeśli wspomniana teoria samoświadomości zdobędzie solidne dowody, to kto wie - może na analogicznej zasadzie będą w przyszłości konstruowane maszyny, które nie tylko myślą, ale też wiedzą, że myślą. Jeżeli bowiem świadomość jest tylko złudzeniem, to być może da się ten artefakt funkcjonowania mózgu zaimplementować także u maszyn.
W każdym razie mam nieodparte wrażenie, że zanim prawdziwego rozpędu nabierze rozwój sztucznej inteligencji, ja zdołam wyprodukować jeszcze sporą ilość podobnych "naturalnych głupot" ;-)

Tags:
Author: Xion, posted under Computer Science & IT, Thoughts » 7 comments

Niemal standardowe nazwy klas

2008-01-02 13:48
Model-View-Controller
Model-View-Controller (MVC),
bardzo modny ostatnio 'wzorzec'

Wzorce projektowe (design patterns) to w założeniu ogólne modele związków pomiędzy klasami (i samych klas), jakie mogą pojawiać się w projektach. Każdy taki wzorzec jest przeznaczony do dość ściśle określonych okoliczności, dokładnie opisany i, przede wszystkim, nazwany. Na pewno każdy średnio zaawansowany programista miał okazję spotkać się z takimi terminami jak Iterator, Fabryka czy Singleton. Są one już na tyle długo używane, że w większości przypadków nie ma problemów ze zrozumieniem tego, co w danej sytuacji oznaczają.

Wzorce nie są oczywiście doskonałe. Ze względu na względnie dużą ścisłość nie mogą opisywać wszystkich rozwiązań, jakie mogą być konieczne, jeśli myślimy o zaprojektowaniu dowolnego programu. Nie jest więc tak, że każda klasa, jaka przyjdzie nam głowy, może być od razu wpasowana w jakiś gotowy szablon.
Przeglądając gotowe kody i różnego rodzaju dokumentacje stwierdziłem jednak, że często powtarzają się w nich różnego rodzaju "pseudowzorce". Objawiają się one głównie używaniem pewnych słów w nazwach klas, dzięki którym można mniej więcej domyślić się, jaka jest rola poszczególnych typów, do czego służą, jak - z grubsza - działają oraz jakie wykazują zależności z innymi klasami. Naturalnie mogą występować spore różnice pomiędzy poszczególnymi bibliotekami i językami, ale przynajmniej dla dwóch największych zbiorów klas, jakie są obecnie w powszechnym użyciu (czyli .NET Framework i JDK), rozbieżności nie są zbyt duże. Co więcej, ponieważ wielu programistów używa któregoś z tych dwóch narzędzi, często przejmują oni te wzorce nazewnictwa (świadomie lub nie) i stosują je we własnych kodach. Kto wie, może dzięki temu przeciętna czytelność kodu produkowanego przez statystycznego programistę (jeśli w ogóle istnieje ktoś taki :]) ma szansę choć odrobinę wzrosnąć?...

Jakie są więc te nieformalne "wzorce"? Otóż znalazłem kilka następujących:

  • Manager to egzemplarz występujący bardzo często i niestety chyba najmniej jednoznaczny z nich wszystkich. W dosłownym tłumaczeniu jest to 'zarządca' czegoś i właściwie niewiele więcej można o nim powiedzieć. Nazywanie wszystkiego 'menedżerem' jest popularne zwłaszcza wśród programistów gier: mamy więc menedżery zasobów, tekstur, stanów, czcionek - i tak dalej. Zastanawiam się tylko, skąd to upodobanie to tego akurat terminu. Czyżby programiści z sentymentem wspominali w ten sposób Menedżera Programów, czyli sławetną "powłokę" systemu Windows w archaicznych wersjach 3.x? :)
  • Handler (ew. listener) jest już znacznie precyzyjniejszym pojęciem. Zazwyczaj jest to bowiem obiekt, który ma wykonywać jakieś działanie w reakcji na określenie zdarzenie - czyli ma je 'obsługiwać'. Najczęściej oznacza to, że typ handlera jest tylko abstrakcyjną klasą bazową lub interfejsem, po którym powinniśmy dziedziczyć, a następnie zaimplementować jego metody i wreszcie "podpiąć" powstały obiekt pod mechanizm obsługi zdarzeń. Typowym zastosowaniem takiego rozwiązania jest reakcja na zdarzenia interfejsu użytkownika (klikanie w przyciski, wciśnięcia klawiszy, itd.) albo powiadamianie o przebiegu operacji asynchronicznych (np. komunikacji sieciowej).
  • Provider jest z kolei obiektem, który ma 'dostarczać'(lub 'zapewniać') jakąś funkcjonalność. Od strony technicznej często działa on tak samo jak handler (czyli w oparciu o polimorfizm metod wirtualnych), tyle że jego przeznaczenie i sposób użycia są nieco inne. Takiego providera podajemy w funkcji lub w obiekcie, dzięki czemu może ona wykonać przy jego pomocy jakieś czynności. Prostym przykładem jest chociażby sortowanie, któremu podajemy obiekt komparatora, odpowiedzialny za dokonywanie porównań. Tak naprawdę jest to więc po prostu wzorzec Strategia (Polityka - policy), któremu ktoś z niewiadomych powodów nadał bardziej "profesjonalną" nazwę.
  • Context oznacza najczęściej taki obiekt, który definiuje jakieś 'środowisko', w którym działają inne obiekty. Są one zależne od obiektu reprezentującego kontekst, ale nie można powiedzieć, aby ten się z nich składał (może on nawet "nie wiedzieć", że jest przez nie wykorzystywany). Po prostu dzięki niemu obiekty "potomne" mogą wykonywać swoje czynności.

Prawdopodobnie dałoby się wyróżnić jeszcze kilka pozycji (chociaż część byłaby dokładnym odpowiednikiem klasycznych wzorców projektowych), ale, jak widać, w sumie chyba nie jest ich zbyt dużo. To w gruncie rzeczy całkiem dobra wiadomość, gdyż nietrudno zauważyć, że wszystkie te nazwy są raczej "magiczne" i na pierwszy rzut nie przywołują jakichś natychmiastowych skojarzeń - zwłaszcza, jeśli nie jesteśmy do nich przyzwyczajeni. Ale taki już urok projektowania zorientowanego obiektowo, polegającego na tworzeniu dziwnych bytów i jeszcze dziwniejszych zależności między nimi :)

Tags: ,
Author: Xion, posted under Programming » 4 comments

Sprawa kalendarzowa

2007-12-31 11:40

Dzisiejszy dzień nie jest zwyczajny - ale tylko dlatego, że kiedyś tak postanowiono. Z bliżej nieokreślonych przyczyn Nowy Rok świętujemy wtedy, gdy za oknami jest szaro, buro i ponuro (względnie biało i zimno). Oczywiście wszystko zależy od punktu widzenia, a ten od punktu siedzenia - lub raczej zamieszkania tudzież klimatu - ale można sobie wyobrazić lepiej dobrany termin...
W ogóle należy stwierdzić, że używany przez nas kalendarz jest wybitne nielogiczny :) Wprawdzie na pewne występujące w nim liczby (zwłaszcza 365 jako najczęstsza liczbę dni w roku) nie da się nic poradzić, ale inne - jak 12, 24, 60, itp. - nie mają specjalnego uzasadnienia ani też żadnej logiki w sobie. Może więc dałoby się jakoś ten system usprawnić? Proponuję "subtelne" przerobienie go na modłę koderską, aby kluczową rolę odgrywały w nim... potęgi dwójki :) Kalendarz ten mógłby wyglądać następująco:

  • Zaczynamy od sekundy, którą aczkolwiek zostawimy w spokoju, jako że jest bardzo dobrze zdefiniowana sposób fizyczny. U nas miałaby więc tę samą długość.
  • Minuta powinna mieć naturalnie 64 (26) sekundy.
  • Analogicznie, godzinę ustalimy jako trwającą 64 minuty.
  • Z długością dnia jest pewien problem, jako że 24 znajduje się dokładnie między dwoma potęgami dwójki (16 i 32). Dwa powody przemawiają jednak za tym, aby ustalić tę długość na 32 godziny. Po pierwsze dlatego, iż pozwoli nam to później dobrać dogodniejszą długość roku. A po drugie: dla kodera obecna 24-godzinna doba jest zwykle za krótka, więc dobrze by było ją wydłużyć :-)
  • Tydzień miałby oczywiście 8 dni. Zauważmy, że jeśli weekend dalej byłby dwudniowy, to w tym systemie miałby on 64 godziny - czyli o 50% więcej!
  • Z miesiącem też nie ma kłopotu: okrągłe 4 tygodnie dałyby łącznie 32 dni w każdym miesiącu. Równa długość miesięcy jest zresztą bardzo praktyczna, bowiem wtedy każda data miałaby jednoznacznie przypisany dzień tygodnia.
  • Jeśli zaś chodzi o liczbę miesięcy w roku, to powinna ona wynosić 8. Wtedy nasz koderski rok będzie miał bardzo przyjemną liczbę 256 dni :)

Nietrudno zauważyć, że możliwe są jeszcze trzy inne warianty tego kalendarza, zależne od liczby godzin w dobie i miesięcy w roku (które to w normalnym kalendarzu są niefortunnie 'pośrodku'). Dwa skrajne produkowałyby jednak rok bardzo różniący długością od obecnego. Trzeci - z 16-godzinnym dniem i 512-dniowym rokiem - miałby z kolei zbyt dużo dni w roku: liczbie 365 (lub 366) jest bowiem nieco bliżej do 256.
Najciekawsze jest to, że w kalendarzu opisanym powyżej rok byłby tylko o 6,33% dłuższy od obecnego. Jeśli więc wystartowalibyśmy koderski rok dzisiaj o północy, to jego koniec przypadłby nad ranem 23 stycznia 2009 roku. Myślę jednak, że istnieją o wiele lepsze punkty startowe, wśród których od razu nasuwa się początek epoki uniksowej, czyli północ 1 stycznia 1970 roku w UTC.

Oczywiście ta wielce pożądana reforma kalendarza napotyka pewne problemy praktyczne. Inna długość doby zapewne byłaby jednym z nich, chociaż oznaczałaby jedynie, że nowa data pojawia się na zmianę albo w środku nocy, albo w środku dnia. Niestety nawet ta prawidłowość dość szybko przestałaby obowiązywać, a w dalszej perspektywie te 6,33% różnicy w długości roku też zaczęłoby być widoczne. I w ten sposób ten genialny w swej prostocie (czy raczej głupocie ;]) pomysł należałoby niestety odrzucić. Po prostu astronomia nie chce z nami współpracować ;P
Ale jest i pewna dobra strona. Otóż napisanie prostego zegarka, wyświetlającego czas w tym systemie "koderiańskim" to zajęcie nieskomplikowane i mało pracochłonne - idealne jako odpoczynek po sylwestrze :)


Author: Xion, posted under Programming » 7 comments

Przyszłoroczne gry

2007-12-29 18:01

Nowy rok powinien być oczywiście mlekiem i kodem płynący, ale poza programowaniem gier wypadałoby czasami w rzeczone gry również grać :) Dlatego warto przyjrzeć się produkcjom, które mają szansę pojawić na rynku w przyszłym roku. Wśród nich moja osobista i zupełnie subiektywna lista najciekawszych (w której kolejność pozycji jest jak najbardziej istotna) przedstawia się następująco:

  • SporeLogo gry Spore. To bardzo ciekawie zapowiadająca się produkcja, która nawiązuje do SimEarth (tej samej firmy, swoją drogą) oraz znanej skądinąd serii Civilization. Mamy w niej pokierować rozwojem życia na planecie - od prostych aminokwasów przez ewolucję organizmów aż do podboju kosmosu przez powstałą w ten sposób cywilizację. Rozgrywka ma przebiegać na wiele różnych sposobów (innych dla każdego stadium rozwoju), a sama gra ma zawierać też wiele innych innowacji - jak na przykład intensywnie wykorzystanie proceduralnie generowanej treści. Jeżeli to wszystko zostanie umiejętnie połączone ze sobą, to rezultaty mogą być niezwykle interesujące.
  • Starcraft IILogo Starcraft II. Tej gry przedstawiać raczej nie trzeba :) Chociaż pierwsza część ma już 11 lat, wciąż (a może właśnie dlatego) grają w nią miliony i jest jedną z obowiązkowych "konkurencji" każdego turnieju pro-gaming. Blizzard najwyraźniej dokłada wszelkich starań, aby to, co jest prawie doskonałe, jeszcze bardziej ulepszyć, a jednocześnie nie doprowadzić do przerostu formy nad treścią. Możliwe jednak, że w 2008 roku nie zobaczymy jeszcze rezultatów tych wysiłków, chociaż należy być dobrej myśli :]
  • World of Warcraft: Wrath of the Lich KingPudełko World of Warcraft: Wrath of the Lich King. Drugi dodatek do najpopularniejszego MMORPGa nie będzie zapewne żadną rewolucją. Trudno przecież dokonywać ryzykownych zmian, gdy na ręce patrzy 9 milionów graczy, którzy co miesiąc zasilają nasz budżet pokaźną sumką. Będzie zatem po prostu "więcej i lepiej", co nie znaczy, że nie warto będzie przyjrzeć się temu dodatkowi. A zwłaszcza dalszym pomysłom na kontynuowanie (czy raczej 'ciągnięcie') rozgrywki po tym, gdy główny oponent w WoW - czyli tytułowy Król Lisz - zostanie w końcu przez graczy pokonany ;P
  • Braid. W tym niewielkim zestawieniu nie mogło zabraknąć równie niewielkiej, co pomysłowej gry. Przeznaczona docelowo na PC oraz Xbox 360, ta platformówka wyróżnia się ogromnie pomysłowym gameplayem, w którym do osiągnięcia sukcesu potrzebne jest kreatywne sterowanie... czasem - jego przyspieszaniem, zwalnianiem, a nawet cofaniem. Może nie jest to pierwsza gra, która wykorzystuje manipulacje czwartym wymiarem (weźmy np. jedną z części serii Prince of Persia), ale akurat tutaj jest to wyjątkowo efektowne.
  • Grand Theft Auto IVOkładka Grand Theft Auto IV. Cóż można powiedzieć o tej grze? Zapewne to, że będzie ona poważnym pretekstem do tego, aby zacząć myśleć nad rozpoczęciem zastanawiania się nad rozważaniem kupna konsoli :-) Tej gigantycznej, graficznie (i nie tylko graficznie) doskonałej produkcji na pewno szybko nie ujrzymy w wersji na PC-ty - a bardzo prawdopodobne, że nie ujrzymy jej nigdy. Do tego, że pewne gatunki gier są wydawane wyłącznie na konsole, trzeba pewnie będzie się powoli przyzwyczajać. Na szczęście do premiery tego cudeńka pozostało jeszcze trochę czasu ;)

Do tej listy chciałoby się dopisać jeszcze jedną pozycję: chociaż jedną przyzwoitą, ukończoną grę własnego autorstwa. Może taka chęć to jeszcze za mało na oficjalne noworoczne postanowienie, ale zawsze to dobry początek. Zwłaszcza, że - jak widać powyżej - potencjalne wzorce są coraz bardziej imponujące :)

Tags: , , ,
Author: Xion, posted under Games » 5 comments

Wyliczenia na sterydach

2007-12-28 21:57

Co można powiedzieć o typach wyliczeniowych (enums)? Choćby to, że przydają się tam, gdzie mamy do czynienia ze stanami lub atrybutami, które należą do jakiegoś skończonego zbiory. Z technicznego punktu widzenia to kilka(naście/dziesiąt/set) liczb nazwanych stałymi identyfikatorami. I zazwyczaj języki programowania nie oferują wiele ponad to.
Lecz Java musiała się tu wyróżnić :) Z wierzchu jej enumy wyglądają niby zwyczajnie:

public enum Answer { YES, NO, DONT_KNOW, DONT_CARE }

ale w środku kryją bardzo szerokie i pewnie trochę udziwnione możliwości...

Zacznijmy od tego, że takie stałe wyliczeniowe są bezpieczne pod względem typowania - nie można więc jawnie rzutować ich na zwykłe liczby typu int. Słowo kluczowe enum tworzy też - podobnie jak w C# - przestrzeń nazw, więc do stałych odwołujemy się nazwami kwalifikowanymi (Answer.YES) i nie trzeba stosować żadnych przedrostków.
Ale to są wręcz oczywistości. Kolejnym punktem programu jest możliwość dostępu do zbioru zadeklarowanych stałych oraz ich wypisywania w postaci tekstowych nazw:

System.out.println ("[Poll] Are enums in Java too exaggerated?");
for (Answer answer : Answer.values())
   System.out.printf ("( ) %s\n", answer);

Takie nazwy mogą być jednak brzydkie. Żaden problem, bowiem w Javie z każdą stałą może być związany dowolny zestaw danych:

public enum Answer
{
   YES("Yes"), NO("No"), DONT_KNOW("I don't know"), DONT_CARE("I don't care");

   // deklaracja dodatkowych danych w postaci pól
   private final String message;

   // konstruktor (!)
   Answer(String message)   { this.message = message; }

   // metoda dostępowa
   public String getMessage()   { return message; }
}

które - jak widać - deklarujemy podobnie jak składniki klas. A poszczególne "stałe" typu wyliczeniowego nie są już na pewno tylko liczbami: to pelnoprawne obiekty:

System.out.println ("[Poll] Is this poll much better?");
for (Answer answer : Answer.values())
   System.out.printf ("( ) %s\n", answer.getMessage());

Widzimy, że metody są również dozwolone. Żeby było śmieszniej, mogą być one nawet "wirtualne". Możemy bowiem zapewnić, aby inne ich wersje były wywoływane dla różnych stałych. Robi wrażenie, prawda?...

Cóż, pewnie niekoniecznie - zwłaszcza, że nietrudno osiągnąć podobną funkcjonalność przez instrukcję wyboru. Zgoda, będzie ona bardziej podatna i trudniejsza w konserwacji. Lecz jeśli alternatywą jest przeładowanie języka dziwnymi i nie do końca oczywistymi mechanizmami, to stary dobry switch niekoniecznie musi być rozwiązaniem złym.
Co oczywiście nie zabrania nam być pod wrażeniem pomysłowości twórców języka Java :-)

Tags: ,
Author: Xion, posted under Programming » 12 comments

Obserwując trendy

2007-12-27 15:18

Jako że rok zbliża się ku końcowi, w modzie są wszelkiego rodzaju podsumowania i retrospekcje. Wszędzie możemy więc przeczytać, co w mijającym roku było najważniejsze, najbardziej znaczące, najlepsze, najgorsze, najbardziej przykuwające uwagę, najnudniejsze i - przede wszystkim - najpopularniejsze. Trendy, jak wiadomo, zmieniają się błyskawicznie, lecz okazuje się, że można za nimi podążać przy pomocy... naszej ulubionej wyszukiwarki internetowej.

Logo Google TrendsIstnieje bowiem coś takiego jak Google Trends. Ta mało wyeksponowana część Google pozwala nam na dostęp do historycznych danych na temat częstości występowania różnych zapytań, kierowanych do wyszukiwarki.
Historia ta sięga początku 2004 roku; jest więc dość obszerna i jej przeglądanie daje interesujące i często zaskakujące wyniki. Jest tak zwłaszcza wtedy, gdy wybierzemy kilka wyrażeń i wyświetlimy zmiany ich popularności na jednym wykresie. Oto garść przykładów:

  • Wiadomo że w pojedynku dwóch świąt zdecydowanie wygrywa Gwiazdka... chyba że akurat zbliża się Wielkanoc. Wykres trendów może w tym przypadku swobodnie pełnić rolę kalendarza ;-)
  • Użytkownicy Windows cały czas utrzymują mniej więcej równą przewagę nad zwolennikami systemu spod znaku pingwina. Chociaż ci drudzy pewnie powiedzą, że akurat w tej konkurencji system Windows jest nieświadomie wspierany przez wszystkich, którzy w sieci szukają szklarzy :)
  • Patrząc na trendy możemy też ocenić, jak wiedzie się poszczególnym firmom branży IT - zwłaszcza tym, które od lat ze sobą rywalizują. W przypadku Intel vs AMD czy nVidia vs ATI stawka jest akurat bardzo wyrównana. Ale za to już od dwóch lat nic nie przebije Google - nawet Microsoft (oczywiście przy założeniu, że dane na temat zapytania Google są prawdziwe :])
  • Możemy również obejrzeć, jak wiedzie się dwom wiodącym bibliotekom graficznym. Zobaczywszy wynik szybko jednak stwierdzimy, że już od dawna wiodąca jest tylko jedna :P
  • A na deser możemy przyjrzeć się starciu gigantów, czyli wyborom najpopularniejszego języka programowania. Wyniki są... interesujące ;)

Lecz zanim zechcemy pod ich wpływem zmienić używane przez siebie narzędzia, warto wiedzieć, że pierwsza dziesiątka najczęściej wpisywanych do Google fraz (według Zeitgeist 2007) to:

1. iphone
2. badoo
3. facebook
4. dailymotion
5. webkinz
6. youtube
7. ebuddy
8. second life
9. hi5
10. club penguin

Brakuje chyba tylko Paris Hilton, eh? ;P Widać w każdym razie, że nie powinno się traktować wyszukiwarkowych trendów jako wyroczni w żadnej sprawie :)

Tags:
Author: Xion, posted under Internet » 3 comments
 


© 2012 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.