Jestem bardzo wdzięczny za reakcje (rzadkie!). Dzięki Wam pojawił się chomik pod Windows i sandbox (link). Pomyślałem, że może odpowiem na pytanie dlaczego właściwie gotreka lepiej jest pisać w chomiku niż np. bezpośrednio w C++. Otóż w gotreku, w pliku chomik/user_defined_types.chomik są zdefiniowane akcje i informacje jak już o tym pisałem. Teraz je rozbudowałem, jeden z testów (odpalcie "make check") sprawdza ile jest akcji a drugi ile jest informacji. Obecnie akcji jest 1086, a informacji 2188. W tym samym pliku są zdefiniowane trzy wartości dla typu tense (past, present, future). Na przykład taki enum:
(X:person) is in (T:tense) in (Y:place)
jest rozwijany do informacji "Gotrek is in past in Krakow", "Gotrek is in future in Warszawa" itd. co w przełożeniu na polski oznacza "Gotrek był w Krakowie", "Gotrek będzie w Warszawie". To rozwijanie w C++ nie istnieje, trzeba by na piechotę dopisać kawałek kodu, który w chomiku produkuje iloczyn kartezjański możliwych zbiorów (person x tense x place).
W pliku chomik/persons_decisions_generate.chomik dla każdej osoby (person) jest generowane pięć możliwych decyzji. Każda z akcji wybrana jako decyzja nr.x należy do jakiejś klasy akcji. Chomik przywraca właściwe znaczenia wielu słowom. Np. słowo klasa akcji oznacza po prostu zbiór akcji, jest do tego specjalny enum:
type action_class={ actions that do not depend on anything,
actions that depend on a place,
actions that depend on a person proposals,
actions that depend on a person answers,
actions that depend on a person others};
Te enumy są tylko enumami, nie mają nic wspólnego z pojęciem klasy z OOP. Są one używane do generowania możliwych decyzji - najpierw generuje się losowo klasę, załóżmy że jest to - "actions that depend on place", Wówczas wybiera się tylko miejsca do których jest połączenie z miejsca, w którym znajduje się dana osoba, np. dla Krakowa będzie to Warszawa i Wrocław. No i możliwa decyzja może być "idź do Warszawy"/"idź do Wrocławia". Z kolei akcje zależne od osób mają trzy klasy - bo są trzy możliwe fazy gry:
game_phase_type={asking phase, answering phase, moving phase}
W fazie "asking phase" wybierane są tylko takie akcje, które należą do subklasy (subklasa do oddzielny enum), załóżmy, że wylosowaliśmy jako osobę Pregora - sprawdzamy czy dana osoba jest obecna tam gdzie postać, dla której generujemy możliwe decyzje. Ostatecznie możemy wpaść na pomysł, żeby wybrać akcję z rodziny:
ask (X:person) what is in (T:tense) (Y:person) function
Na przykład "ask Pregor what is in past Gerrudir function" - czyli "spytaj Pregora jaki urząd pełnił Gerrudir". Zauważcie, że taki chomikowy enum to zwykły ciąg identyfikatorów, na przykład "actions that do not depend on anything", i jako taki może nam posłużyć do wyboru kodu z rodziny o którą nam chodzi. Czyli zamiast ifa w pseudokodzie:
if (selected_class == "actions that do not depend on anything")
{
<generate possible decisions for the current person and action class actions that do not depend on anything>;
}
else
if (selected_class == "actions that depend on a place")
{
<generate possible decisions for the current person and action class actions that depend on a place>;
}
else
...
... możemy napisać po prostu:
<generate possible decisions for the current person and action class <selected_class>>;
Możecie sprawdzić, że tego rodzaju wybór kodu jest dokonywany w pliku chomik/persons_decisions_generate.chomik (linia 160):
<generate possible decisions for the current person and action class <current action class>>;
Za każdym razem jak wszystkie postaci wykonają ruch jest ustawiana kolejna faza, przy czym po "moving phase" następuje znowu "asking phase". W "asking phase" można zadawać pytania, lub składać propozycje. W drugiej fazie - answering phase - można reagować na złożone propozycje, odpowiadać na pytania. W trzeciej fazie można się przemieszczać do innych miast.
Następnie w pliku chomik/make_decisions.chomik decyzje są podejmowane - każdy NPC wybiera decyzję losowo (losując numer 1 do 5 - one nie są w ogóle inteligentne), tylko dla Gotreka nadpisuje się decyzję zgodnie z tym co wybrał gracz - w górnym okienku. To się dzieje w pliku chomik/decisions_make.chomik.
Generalnie ten sposób identyfikacji kodu lub jakichś wartości innych typów jest bardzo silny. Jest w ogóle możliwy dlatego, że w Chomiku nazwą mogą być nie tylko identyfikatory, ale ciągi identyfikatorów, poprzetykane literałami i placeholderami. W języku takim jak C++ żeby uzyskać tą samą funkcjonalność trzeba pisać ify, switche lub redefiniować wirtualne metody. I i tak jest słabszy. Chomik nadal jest tylko zabawką (nie ma w nim nawet mnożenia, czy otwierania plików do czytania), ale wydaje się, że ma bardzo duży potencjał. Wiążę duże nadzieje zwłaszcza z tymi rekurencyjnymi enumeracjami - np. gdy Gotrek powie Gerrudirowi, że Pregor był w Krakowie, to później może komuś innemu (Gwaigilionowi) powiedzieć o tym i sprawić, że Gwaigilion będzie myślał, że Gotrek powiedział Gerrudirowi, że ... Jest tu jawna rekurencja. Oczywiście Chomik nie dopuszcza nieskończonej rekurencji. Ale i tak jest fajny, Dawaliśmy się, że tak powiem, zbyt długo wodzić za nos matematykom, którzy mają mało fantazji. Mam na myśli kopiowanie zapisu matematycznego do programowania. Chomik zrobi z tym porządek ;)))
Jeszcze taka refleksja - wydawało mi się pierwotnie, że typy "range" czyli np. 1..10 są niepotrzebnie związane z tą samą składnią co zwykłe enumy. Ale już tak nie myślę. W istocie mają z enumami wiele wspólnego - tyle, że jest zadany z góry algorytm jak generować kolejne nazwy w takich enumeracjach. Bo w gruncie rzeczy literał 10 jest nazwą, nazwą liczby 10 w systemie dziesiątkowym, a jednocześnie nazwą liczby 2 w systemie dwójkowym itd. Jest nazwą i niczym więcej.