sobota, 19 grudnia 2009

To już koniec Wielkiego Mistrza

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 ostatniego release’u 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ę.

Najpierw linki:

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.

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.

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ę.

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”.

Wyszło troszkę oficjalnie, ale raz na jakiś czas można sobie na to pozwolić. Dla całego zespołu – wafelki.

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 (Statki w Javie, Oxelbergen [zwróćcie uwagę na id gry na tym serwisie – musiało mi się trafić], Guitar Hero (bez dźwięku, za to ze świecącymi diodami) na płytce FPGA – 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.

Pozdrawiam i dziękuję - SceNtriC

sobota, 5 grudnia 2009

RepackGenerator

scr 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.

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.

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.

Ten projekt był też okazją, aby zapoznać się z systemem dokumentowania Doxygen. 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.

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.

Linki, pod którymi możecie znaleźć program wraz z źródłami i dokumentacją:

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.

Pozdrawiam i dziękuję – SceNtriC.

Ajajaj – aż trzy tygodnie

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 niedawno opisywałemJob Shop). A na co przychodzi pora, jak na uczelni nieco się rozluźnia? Na denerwowanie wszystkich opowieściami o Wielkim Mistrzu.

Nie odkryję Ameryki (Wschodnio-Południowej), gdy rzeknę, iż w 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 tutaj znajdziecie normalne wersje.

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 Doxygen 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 dokumentacja Ogre’a 3D, ale dużo mniejsza).

Pozdrawiam i dziękuję – SceNtriC.

piątek, 13 listopada 2009

Niedziałający algorytm – ale coś w sobie ma

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ę).

Zadaniem części studentów na laboratoriach jest napisanie rozwiązań do tzw. problemu Job Shop. 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 (m0 t0) (m1 t1) … (mn tn), gdzie mi to indeks maszyny, którą potrzebuje dane zadanie, a ti to ilość kwantów czasu, które musi spędzić zadanie na maszynie mi. 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).

Jest to zatem jedna z odmian problemu szeregowania. Jakby tego było mało, jest to jeden z rodzajów bardzo znanego problemu komiwojażera, w którym miasta do odwiedzenia to zadania (a ich liczba N), a maszyna jest jedna i jest to nasz podróżnik.

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.

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 SJF, ale wolałbym implementować “mądrzejsze” rozwiązania (algorytmy genetyczne, inne metaheurystyki, B&B, itd.)

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:

T0: (0 2) (1 3) (2 1)

T1: (1 1) (2 2) (0 1)

T2: (1 3) (0 2) (2 3)

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.

Uszeregowanie, jakie proponuje opisywany algorytm, wygląda tak:

jsp1

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.

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:

(1 2) (0 1) (2 3)

musimy utworzyć kolejkę o wartościach:

1 1 0 2 2 2

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.

1. Wszystko dzieje się w pętli, która odlicza kolejne kwanty czasu. Jej zakończenie jest uwarunkowane przez stan zmiennej logicznej typu bool.

2. Tworzymy sobie tablicę tf o typie int i rozmiarze N i zapełniamy ją zerami.

3. Robimy sobie herbatę.

4. Tworzymy pętlę dla każdej maszyny.

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.

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ąć).

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.

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.

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…

Na koniec pełny kod naszego rozwiązania (QUANTITY to N, a MAC_QUANTITY to M).

   1: #include <cstdio>
   2: #include <cstdlib>
   3: #include <vector>
   4: #include <queue>
   5: #include <ctime>
   6: #include <cctype>
   7:  
   8: #define QUANTITY 3
   9: #define MAC_QUANTITY 3
  10:  
  11: int main (int argc, char* argv[])
  12: {
  13:     // wrzucenie zadań do kolejek
  14:     // jeżeli jakieś zadanie ma być wykonywane:
  15:     // na 1-szej maszynie 2 kwanty czasu, a potem
  16:     // na 2-giej maszynie 3 kwanty czasu, to
  17:     // obraz kolejki:
  18:     // 1 1 2 2 2
  19:     std::queue<unsigned> task[QUANTITY];
  20:     std::vector<int> machine[MAC_QUANTITY];
  21:  
  22:     // zadanie 0
  23:     task[0].push(0);
  24:     task[0].push(0);
  25:     task[0].push(1);
  26:     task[0].push(1);
  27:     task[0].push(1);
  28:     task[0].push(2);
  29:  
  30:     // zadanie 1
  31:     task[1].push(1);
  32:     task[1].push(2);
  33:     task[1].push(2);
  34:     task[1].push(0);
  35:  
  36:     // zadanie 2
  37:     task[2].push(1);
  38:     task[2].push(1);
  39:     task[2].push(1);
  40:     task[2].push(0);
  41:     task[2].push(0);
  42:     task[2].push(2);
  43:     task[2].push(2);
  44:     task[2].push(2);
  45:  
  46:     // odliczamy kolejne kwanty czasu
  47:     bool end = false;
  48:     int i;
  49:  
  50:     for (i = 0; !end; ++i)
  51:     {
  52:         int tf[QUANTITY] = { 0 }; // jeżeli danego zadania jeszcze nie było w określonym kwancie czasu
  53:  
  54:         // dla każdej maszyny bierzemy pierwsze zadanie, które ją wymaga
  55:         for (int j = 0; j < MAC_QUANTITY; ++j)
  56:         {
  57:             int t; // zachowujemy numer zadania
  58:  
  59:             for (t = 0; t < QUANTITY; ++t)
  60:             {
  61:                 // jeśli coś jeszcze zostało do zrobienia w danym zadaniu (kolejka nie jest pusta)
  62:                 // oraz zadanie nie zostało już gdzieś "włożone" w danym kwancie czasu
  63:                 if (!task[t].empty() && tf[t] == 0)
  64:                 {
  65:                     // jeśli pierwszy element to indeks danej maszyny
  66:                     if (task[t].front() == j)
  67:                     {
  68:                         tf[t] = 1;
  69:                         task[t].pop();
  70:                         break; // kończymy pętlę
  71:                     }
  72:                 }
  73:             }
  74:  
  75:             // jeżeli t zmieściło się w pętli, to zapisujemy indeks
  76:             // zadania do wektora danej maszyny - w przeciwnym razie
  77:             // zapisujemy -1
  78:             if (t < QUANTITY)
  79:             {
  80:                 machine[j].push_back(t);
  81:             }
  82:             else
  83:             {
  84:                 machine[j].push_back(-1);
  85:             }       
  86:         } // for (int j = 0; j < MAC_QUANTITY; ++j)
  87:  
  88:         bool e = true;
  89:  
  90:         // jeżeli kolejka któregokolwiek zadania nie jest pusta,
  91:         // to jeszcze nie kończymy algorytmu
  92:         for (int t = 0; t < QUANTITY; ++t)
  93:         {
  94:             if (!task[t].empty())
  95:             {
  96:                 e = false;
  97:                 break;
  98:             }
  99:         }
 100:  
 101:         end = e;
 102:     } // for (i = 0; !end; ++i) 
 103:  
 104:     for (unsigned i = 0; i < MAC_QUANTITY; ++i)
 105:     {
 106:         printf("Maszyna %d: ", i);
 107:  
 108:         std::vector<int>::iterator it;
 109:  
 110:         for (it = machine[i].begin(); it != machine[i].end(); ++it)
 111:         {
 112:             printf("%d ", *it);
 113:         }
 114:         printf("\n");
 115:     }
 116:  
 117:     printf("\n");
 118:  
 119:     printf("Łączny czas uszeregowania procesów: %d\n", i);
 120:    
 121:     getchar();
 122:     return 0;
 123: }

Pozdrawiam i dziękuję - SceNtriC

środa, 11 listopada 2009

Małe aktualności ze świata gier i oczywiście Wielki Mistrz

Ostatnio niewiele tu pisałem na tematy niezwiązane bezpośrednio z Wielkim Mistrzem. Ta notka też nie będzie całkowicie pozbawiona informacji o naszym cRPG-u – wczoraj pojawiła się mała aktualizacja, która poprawia parę niedoróbek fabularnych i przede wszystkim oferuje większy plecak. Zamiast przywoływać linki, pozwolę sobie przywołać post z forum Warsztatu, w którym znajdują się odnośniki do poszczególnych wersji – znajdziecie pod nimi aktualną wersję:

A oto te linki

Należałoby jednak wspomnieć o dwóch wydarzeniach. Pierwszym – bardzo ważnym w środowisku gier komputerowych i drugim nieco mniej istotnym, ale ciekawym.

Pierwsza sprawa to oczywiście decyzja Epic Games o wypuszczeniu na wolność Unreal Engine 3. Może za bardzo Was zachęciłem, więc uściślę – gracze otrzymali Unreal Development Kit, który może być używany przez firmy do tworzenia komercyjnych gier. Jest oczywiście pewien haczyk – dochód do 5000$ nie wymaga posiadania licencji od Epica, natomiast każdy zysk ponad ten próg wymaga zapłacenia 25% od nadmiarowego dobra. Muszę przyznać, że nie próbowałem się tym zajmować i prawdopodobnie w najbliższej przyszłości nie będę miał czasu i chęci. Nie jest to też silnik w pełnym tego słowa znaczeniu – nie otrzymujemy źródeł, ale narzędzia (edytory), które pozwalają nam na stworzenie gry w oparciu o możliwości Unreal Engine 3 – między innymi skrypty do dyspozycji mamy język skryptowy UnrealScript. Jak to napisał Regedit na swoim blogu – jest to taki Game Maker, tylko bardziej zaawansowany. Ciekawa inicjatywa – wygląda na to, że firmy szukają najwytrwalszych jednostek wśród społeczeństwa programistów, którzy w przyszłości mogliby zasilić ich szeregi. A jeżeli ktoś chce się pobawić, to również ma doskonałą okazję, żeby zrobić coś ciekawego. Jeżeli ktoś chce poczytać wątek na forum Warsztatu, to nie musicie już go szukać.

Druga sprawa to nowa inicjatywa Google. Jak wiadomo, ta firma szybko wkracza w nowe dziedziny życia informatycznego – zaczęło się od wyszukiwarki, potem przyszła pora na pocztę elektroniczną, arkusze, mapy, przeglądarki, wkrótce dostaniemy system operacyjny, a teraz możemy pobawić się językiem programowania Go. Tylko czekam, aż u rzeźnika zobaczę kiełbasy sygnowane logiem Google – żartuję, inicjatywa bardzo mi się podoba (choć GoogleMeat bym nie zjadł). Nie przeglądałem za bardzo projektu, ale muszę przyznać, że nie podoba mi się troszkę składnia nowego języka. Zresztą sami popatrzcie:

05    package main
07 import (

08 "./file";
09 "fmt";
10 "os";
11 )
13 func main() {
14 hello := []byte{'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n'};
15 file.Stdout.Write(hello);
16 file, err := file.Open("/does/not/exist", 0, 0);
17 if file == nil {
18 fmt.Printf("can't open file; err=%s\n", err.String());
19 os.Exit(1);
20 }
21 }

Być może jestem za bardzo przyzwyczajony do składni C-podobnej, ale pisanie pascalowego “:=” przy przypisywaniu wartości uważam za zbyteczne. Choć to może tylko takie pobieżne spojrzenie – na pewno język został przemyślany i możemy się spodziewać kilku ciekawych rozwiązań (tak, zawsze tak mówią).

Z tego, co udało mi się przeczytać na wyżej podlinkowanej stronie, Google nie ukrywa, iż Go jest eksperymentem, a nie próbą zawładnięcia “rynkiem” języków programowania. Cechuje się podobno szybką kompilacją, garbage collectorem, brakiem konieczności dołączania wielu plików nagłówkowych, wsparciem wielu rdzeni i nie tak ścisłym typowaniem. Powiem uczciwie – więcej mi się nie chciało czytać. Jeżeli ktoś jest ciekawy, to polecam jeszcze raz zajrzeć pod link, który podałem wcześniej – są tam tutoriale, dokumentacja i sposób instalacji. A tutaj wątek na forum Warsztatu.

Cóż, dzisiejsza notka może mało wylewna, ale w sumie nie ma o czym pisać. Postaram się coś naskrobać w najbliższym czasie.

Pozdrawiam i dziękuję – SceNtriC.