{"id":405,"date":"2018-11-16T08:20:35","date_gmt":"2018-11-16T07:20:35","guid":{"rendered":"https:\/\/www.kompikownia.pl\/?p=405"},"modified":"2018-11-22T20:53:19","modified_gmt":"2018-11-22T19:53:19","slug":"symulator-pozaru-lasu-zalozenia-i-pierwsze-kroki","status":"publish","type":"post","link":"https:\/\/www.kompikownia.pl\/index.php\/2018\/11\/16\/symulator-pozaru-lasu-zalozenia-i-pierwsze-kroki\/","title":{"rendered":"Symulator po\u017caru lasu &#8211; za\u0142o\u017cenia i pierwsze kroki"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span><p>Na studiach spotkasz si\u0119 z wieloma typami zaj\u0119\u0107. S\u0105 laboratoria, s\u0105 \u0107wiczenia i wiele innych. Spo\u015br\u00f3d wszystkich najbardziej lubi\u0119 projekty. Mam wyznaczone zadanie, kt\u00f3re musz\u0119 wykona\u0107 do okre\u015blonego dnia. I\u00a0nikt mnie nie zmusza do tego aby u\u017cy\u0107 konkretnego sposobu rozwi\u0105zania problemu. K\u0142opotem nie jest tak\u017ce czas. Co prawda istniej\u0105 odg\u00f3rnie wyznaczone terminy m\u00f3wi\u0105ce o tym, do kiedy nale\u017cy wykona\u0107 projekt (np.: za miesi\u0105c). Lecz to jak roz\u0142o\u017c\u0119 sobie prac\u0119 na poszczeg\u00f3lne dni zale\u017cy ca\u0142kowicie ode mnie. Uwielbiam wolno\u015b\u0107 tkwi\u0105c\u0105 w tego typu zaj\u0119ciach.<\/p>\n<p>W tym semestrze mam jeden projekt natury stricte programistycznej. Przedmiot nazywa si\u0119 \u201eProgramowanie w j\u0119zyku C2\u201d (czyli C++). Zadanie jest nast\u0119puj\u0105ce: stworzy\u0107 program, kt\u00f3ry zasymuluje po\u017car (lasu). Symulacja ma zosta\u0107 przeprowadzona przy pomocy algorytmu automatu kom\u00f3rkowego.<\/p>\n<h2 class=\"western\">Za\u0142o\u017cenia projektowe<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-409\" src=\"https:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/11\/lean-startup-2230822_1920.jpg\" alt=\"zalozenia_projektowe\" width=\"800\" height=\"600\" \/><\/p>\n<p>Temat jest postawiony do\u015b\u0107 og\u00f3lnie. W moim projekcie b\u0119d\u0119 chcia\u0142 zasymulowa\u0107 po\u017car lasu. Zanim zabra\u0142em si\u0119 za prac\u0119, musia\u0142em ustali\u0107, z jakich bibliotek b\u0119d\u0119 korzysta\u0142.<\/p>\n<p>W kwestii biblioteki graficznej istnieje wiele opcji do wyboru. Jest Allegro, SFML, SDL2 i wiele, naprawd\u0119 wiele innych. Allegro odrzuci\u0142em na starcie, gdy\u017c nieco zrazi\u0142em si\u0119 do dziwnych rozwi\u0105za\u0144 zastosowanych w tej bibliotece. Na placu boju pozosta\u0142y SFML i SDL2. SFML bardziej nadaje si\u0119 pod C++, gdy\u017c jest obiektowy. Jednak\u017ce wyb\u00f3r pad\u0142 na SDL, gdy\u017c osoba, z kt\u00f3r\u0105 pracuj\u0119 nad projektem (zespo\u0142y s\u0105 dwuosobowe) zna w\u0142a\u015bnie SDL.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-408\" src=\"https:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/11\/Sdl-logo.png\" alt=\"logo sdl\" width=\"414\" height=\"240\" \/><\/p>\n<p>Jestem mi\u0142o\u015bnikiem Linuksa. Sam u\u017cywam go na co dzie\u0144, Windowsa odpalaj\u0105c tylko do jednej gry (Gwint, Wied\u017ami\u0144ska Gra Karciana). Z tego te\u017c powodu chc\u0119, aby aplikacja by\u0142a wieloplatformowa, czyli aby dzia\u0142a\u0142a bez problemu zar\u00f3wno pod Linuksem jak i pod Windowsem. SDL za\u0142atwia ten problem z punktu widzenia kodu aplikacji.<\/p>\n<p>Chcia\u0142bym, aby aplikacja posiada\u0142a okienkowy interfejs u\u017cytkownika (GUI). S\u0142u\u017cy\u0142by by on do konfigurowania wielu r\u00f3\u017cnych parametr\u00f3w symulacji. Interfejs okienkowy b\u0119dzie pozwala\u0142 na:<\/p>\n<ul>\n<li>Wyb\u00f3r konkretnego narz\u0119dzia i rodzaju \u201eobiektu\u201d, kt\u00f3re b\u0119dzie rysowa\u0142. (Narz\u0119dzia: Spray\/o\u0142\u00f3wek\/gumka. Dost\u0119pne rodzaje obiekt\u00f3w: drzewo\/po\u017car\/spalone drzewo).<\/li>\n<li>uruchomienie i zatrzymanie symulacji w dowolnym momencie.<\/li>\n<li>wp\u0142ywanie na szybko\u015b\u0107 symulacji (suwak).<\/li>\n<li>zmian\u0119 obszaru symulacji, zar\u00f3wno fizycznego (zmiana rozmiaru okna) jak i\u00a0logicznego (mniejsze\/wi\u0119ksze piksele).<\/li>\n<li>(Opcjonalne) odczyt\/zapis stanu symulacji do pliku<\/li>\n<\/ul>\n<p>Interfejs okienkowy b\u0119dzie wykonany w WxWidgets. W pierwszym etapie GUI b\u0119dzie oddzieln\u0105 aplikacj\u0105. W\u00a0kolejnym kroku zostanie ono zintegrowane w jedn\u0105 aplikacj\u0119 z programem g\u0142\u00f3wnym napisanym w SDL-u.<\/p>\n<p>Dlaczego nie zrobi\u0119 GUI od razu w SDL? Powod\u00f3w jest wiele. Po pierwsze, bardziej zaawansowane kontrolki, takie jak slidery, b\u0119dzie ci\u0119\u017cko oprogramowa\u0107 w bibliotece SDL. Po drugie, dzi\u0119ki WxWidgets aplikacja b\u0119dzie dostosowana do motywu systemu, gdy\u017c ten framework korzysta z natywnych kontrolek systemowych.<\/p>\n<h2 class=\"western\"><\/h2>\n<h2 class=\"western\">Projekt szablonu klas<\/h2>\n<p>Pora przej\u015b\u0107 do nast\u0119pnego etapu. Za\u0142o\u017cenia zosta\u0142y ju\u017c ustanowione. Teraz wsp\u00f3lnie z tob\u0105, czytelniku zajmiemy si\u0119 ich analiz\u0105 i realizacj\u0105. Zastanowimy si\u0119 nad wst\u0119pnym szablonem klas. Postaramy si\u0119 tak je zaplanowa\u0107, aby maksymalnie u\u0142atwi\u0142y nam zaimplementowanie finalnego algorytmu automatu kom\u00f3rkowego. Ponadto, dodatkowym celem jest ukrycie \u201ewstr\u0119tnego SDL-owego C\u201d\u00a0za przyjemn\u0105 dla oka sk\u0142adni\u0105 C++.<\/p>\n<h3 class=\"western\">Drzewo<\/h3>\n<p>Co b\u0119dzie najbardziej podstawowym, najmniejszym obiektem w naszej symulacji? Oczywi\u015bcie drzewo. Mo\u017cna tak\u017ce powiedzie\u0107 og\u00f3lniej \u2013 obiekt, kt\u00f3ry mo\u017ce si\u0119 pali\u0107. Jakie w\u0142a\u015bciwo\u015bci b\u0119d\u0105 z\u00a0nim powi\u0105zane? Przede wszystkim &#8211; stan. Istniej\u0105 trzy mo\u017cliwo\u015bci:<\/p>\n<ul>\n<li>Obiekt po prostu istnieje. Lasek sobie ro\u015bnie w z\u0142otych promieniach S\u0142o\u0144ca i nic specjalnego si\u0119 nie dzieje.\u00a0 (<strong>EXIST).<\/strong><\/li>\n<li>Po\u017car trawi drzewo.<strong>(FIRE)<\/strong><\/li>\n<li>\u017bywio\u0142 pokona\u0142 obiekt. <strong>(BURN)<\/strong><\/li>\n<\/ul>\n<p>Stan b\u0119dzie zapisany w formie enuma. Jego definicja znajduje si\u0119 poni\u017cej.<\/p>\n<pre lang=\"cpp\" line=\"12\">enum PType {\r\n    EXIST,\r\n    FIRE,\r\n    BURN\r\n};\r\n<\/pre>\n<p>Natomiast definicja drzewa wygl\u0105da tak:<\/p>\n<pre lang=\"cpp\" line=\"34\">class Tree {\r\n    public:\r\n    Tree() {\r\n        type = EXIST;\r\n    }\r\n    Tree(PType status) {\r\n        this->type = status;\r\n    }\r\n    PType getType() {return this->type;}\r\n    Tree operator++(int) {\r\n        Tree temp = *this;\r\n        switch(this->type) {\r\n            case EXIST:\r\n                this->type = FIRE;\r\n            break;\r\n            case FIRE:\r\n                this->type = BURN;\r\n            break;\r\n            case BURN:\r\n            break;\r\n        }\r\n        return temp;\r\n    }\r\n    private:\r\n    PType type;\r\n};\r\n<\/pre>\n<p>Skoro w drzewie przechowujemy tylko typ, to sk\u0105d b\u0119dzie wiadomo na jakich wsp\u00f3\u0142rz\u0119dnych si\u0119 ono znajduje? To jest dobry temat do dalszych rozwa\u017ca\u0144. Jak rozwi\u0105\u017cemy ten problem?<\/p>\n<p>Pozycj\u0105 obiekt\u00f3w na mapie b\u0119dzie zajmowa\u0142a si\u0119 specjalna klasa \u2013 <strong>ForestMap<\/strong>. Wsp\u00f3\u0142rz\u0119dne mogliby\u015bmy przechowywa\u0107 w tablicy dwuwymiarowej. To podej\u015bcie niesie ze sob\u0105 pewne wady. Po pierwsze \u2013 musieliby\u015bmy po\u015bwi\u0119ci\u0107 du\u017co czasu na zabaw\u0119 z alokowaniem pami\u0119ci dla dwuwymiarowej tablicy. Po drugie \u2013 spor\u0105 cz\u0119\u015b\u0107 akcji musieliby\u015bmy przeci\u0105\u017ca\u0107 sami. Istnieje prostsze rozwi\u0105zanie tego problemu \u2013 kontener domy\u015blnie obecny w C++ &#8211; <strong>std::map<\/strong>.<\/p>\n<p>Ale zaraz zaraz, nie b\u0119dzie nam pasowa\u0142a jedna rzecz. Kontener std::map przechowuje pary klucz\u2011warto\u015b\u0107. W naszym wypadku kluczem b\u0119d\u0105 wsp\u00f3\u0142rz\u0119dne, a tych jest dwie: x i y. Nie mo\u017cemy stworzy\u0107 mapy, kt\u00f3ra b\u0119dzie mia\u0142a dwa klucze. Jakie sobie z tym poradzi\u0107? Stworzymy kolejn\u0105 klas\u0119 &#8211; <strong>Coordinates<\/strong>.<\/p>\n<h3 class=\"western\">Coordinates<\/h3>\n<pre lang=\"cpp\" line=\"17\">class Coordinates {\r\n    public:\r\n    Coordinates(unsigned int x,unsigned int y) {\r\n        this->x = x;\r\n        this->y = y;\r\n    }\r\n    Coordinates(unsigned int x) {\r\n        this->x = x;\r\n        this->y = 0;\r\n    }\r\n    unsigned int x;\r\n    unsigned int y;\r\n    bool operator< (const Coordinates&#038; rhs) const {\r\n    return (this->x<rhs.x) || ((this->x==rhs.x) && (this->y < rhs.y));\r\n    }\r\n};\r\n<\/pre>\n<p>Powy\u017cej znajduje si\u0119 definicja klasy Coordinates. Nie ma w niej nic niezwyk\u0142ego. Mamy dwa konstruktory. Jeden, kt\u00f3ry przyjmuje warto\u015bci x i y, oraz drugi, kt\u00f3ry przyjmuje jedynie x\u2019a. O ile obecno\u015b\u0107 pierwszego z nich jest oczywista, o tyle mo\u017ce nas zastanawia\u0107 potrzeba stosowania drugiego konstruktora. Po co nam to? Nied\u0142ugo si\u0119 dowiesz. W tej chwili mog\u0119 uchyli\u0107 r\u0105bek tajemnicy m\u00f3wi\u0105cy o tym, \u017ce ma to zwi\u0105zek z przeci\u0105\u017caniem operatora [].<\/p>\n<p>Intryguj\u0105ca jest tak\u017ce obecno\u015b\u0107 przeci\u0105\u017cenia operatora mniejszo\u015bci. Nie b\u0119dziemy u\u017cywali tego jawnie. Musieli\u015bmy stworzy\u0107 takie przeci\u0105\u017cenie, gdy\u017c tego wymaga\u0142 kontener std::map. Elementy w kontenerze s\u0105 uk\u0142adane tak, aby warto\u015bci by\u0142y posortowane wg kluczy. Aby std::map m\u00f3g\u0142 wykona\u0107 t\u0119 operacj\u0119, musi wiedzie\u0107 jak wykona\u0107 algorytm sortowania, kt\u00f3ry element jest mniejszy, a kt\u00f3ry wi\u0119kszy. Dla prostych typ\u00f3w, takich jak int jest to oczywiste. Dla samodzielnie stworzonej klasy taki operator musimy przeci\u0105\u017cy\u0107 samodzielnie.<\/p>\n<h3 class=\"western\">ForestMap<\/h3>\n<p>Klasa ForestMap b\u0119dzie jedn\u0105 z najbardziej skomplikowanych klas na tym etapie projektu. B\u0119dzie zawiera\u0142a najwi\u0119cej metod. Podstawowym zadaniem b\u0119dzie oczywi\u015bcie przechowywanie wsp\u00f3\u0142rz\u0119dnych wszystkich obiekt\u00f3w. Ale nie tylko. Klasa musi udost\u0119pni\u0107 metod\u0119 <strong>drawAll<\/strong>, dzi\u0119ki kt\u00f3rej SDL b\u0119dzie m\u00f3g\u0142 narysowa\u0107 wszystkie punkty. Musimy udost\u0119pni\u0107 metody <strong>add<\/strong> i <strong>del<\/strong>, kt\u00f3re b\u0119d\u0105 s\u0142u\u017cy\u0142y do dodawania i usuwania punkt\u00f3w. No i najwa\u017cniejsze \u2013 wykonamy <strong>przeci\u0105\u017cenie operatora [][]<\/strong>. Po co nam to potrzebne? Aby\u015bmy mogli \u0142atwo sprawdzi\u0107 stan punktu np.: w ten spos\u00f3b:<\/p>\n<pre lang=\"cpp\">Tree* drzewo = map[4][3]; \/\/ pobierze obiekt drzewa znajduj\u0105cy si\u0119 na wsp\u00f3\u0142rz\u0119dnych (4,3)\r\n<\/pre>\n<p>Sp\u00f3jrz na kod \u017ar\u00f3d\u0142owy klasy ForestMap w obecnej postaci.<\/p>\n<pre lang=\"cpp\" line=\"75\">\r\nclass ForestMap {\r\n    public:\r\n    ForestMap() {\r\n        fullMap = make_shared<map<Coordinates,Tree>>();\r\n    }\r\n    SingleCell operator[](int x) {\r\n        return SingleCell(x,fullMap);\r\n    }\r\n    void add(int x,int y,PType status) {\r\n        Tree new_tree(status);\r\n        (*fullMap)[Coordinates(x,y)] = new_tree;\r\n    }\r\n    void drawAll(function<void(int,int,PType)> func) {\r\n        map<Coordinates,Tree>& mp = *fullMap.get();\r\n        map<Coordinates,Tree>::iterator it;\r\n        for(it = mp.begin();it!=mp.end();it++) {\r\n            func(it->first.x,it->first.y,it->second.getType());\r\n        }\r\n    }\r\n    private:\r\n    shared_ptr<map<Coordinates,Tree>> fullMap;\r\n};\r\n<\/pre>\n<p>Zaczniemy nieco od ko\u0144ca. W linijce 95 deklarujemy kontener map, w kt\u00f3rym b\u0119dziemy przechowywa\u0107 obiekty Tree wg klucza Coordinates. Powstaje pytanie, dlaczego jest to wska\u017anik typu <a href=\"https:\/\/www.kompikownia.pl\/index.php\/2018\/09\/25\/shared_ptr-inteligetne-wskazniki\/\">shared_ptr<\/a>, a nie zwyk\u0142a w\u0142a\u015bciwo\u015b\u0107 klasy? Zrobili\u015bmy tak, poniewa\u017c mapa b\u0119dzie cz\u0119sto przekazywana do innych funkcji\/metod, kt\u00f3re b\u0119d\u0105 wyci\u0105ga\u0142y z niej pewne warto\u015bci. Przekazywanie mapy zawieraj\u0105cej kilka tysi\u0119cy punkt\u00f3w przez warto\u015b\u0107 b\u0119dzie mocno nieefektywne. Nie chcemy bawi\u0107 si\u0119 staromodnymi \u201eraw pointerami\u201d z C. Jedynym rozwi\u0105zaniem pozostaje u\u017cycie inteligentnych wska\u017anik\u00f3w.<\/p>\n<p>Om\u00f3wmy teraz metod\u0119 <strong>drawAll<\/strong>, kt\u00f3rej definicja zaczyna si\u0119 w linijce 87. Wydaje si\u0119 ona dosy\u0107 skomplikowana, gdy\u017c przekazujemy jej wska\u017anik na funkcj\u0119. Pe\u0142na definicja funkcji, kt\u00f3rej wska\u017anik przekazujemy mog\u0142aby wygl\u0105da\u0107 tak:<\/p>\n<pre lang=\"cpp\">void draw(int x,int y,Ptype d)<\/pre>\n<p>W tej chwili wystarczy aby\u015bmy wiedzieli, \u017ce draw rysuje punkt o danym typie na ekranie. Zadanie drawAll w takim wypadku sprowadza si\u0119 do wywo\u0142ania funkcji draw dla ka\u017cdego punktu znajduj\u0105cego si\u0119 w mapie.<\/p>\n<p>Sp\u00f3jrzmy na metod\u0119 <strong>add<\/strong>. Jako argumenty przyjmuje ona wsp\u00f3\u0142rz\u0119dne oraz status drzewa. A jak dzia\u0142a? Bardzo prosto. W linijce 84 tworzymy zwyk\u0142\u0105 zmienn\u0105 Tree. Natomiast w kolejnej dodajemy j\u0105 do mapy.<\/p>\n<h4><span style=\"font-family: Liberation Sans, sans-serif;\"><span style=\"font-size: large;\">SingleCell<\/span><\/span><\/h4>\n<p>Zajmijmy si\u0119 przeci\u0105\u017ceniem operatora []. Jak pami\u0119tamy, operator[] ForestMap zwraca obiekt SingleCell, a jako argument przyjmuje jedynie jedn\u0105 wsp\u00f3\u0142rz\u0119dn\u0105 \u2013 x. SingleCell jest \u201enadmiarow\u0105\u201d klas\u0105, kt\u00f3ra umo\u017cliwi nam przeci\u0105\u017cenie operatora tablicy dwuwymiarowej [][] dla ca\u0142ego ForestMap. SingleCell b\u0119dzie zwraca\u0142 obiekt konkretnego drzewa. Aby to zrobi\u0107, musi otrzyma\u0107 wska\u017anik na ca\u0142\u0105 map\u0119. Przeanalizujmy to.<\/p>\n<p>Klasa pomocnicza SingleCell wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<pre lang=\"cpp\" line=\"60\">\r\nclass SingleCell {\r\n    public:\r\n    SingleCell(int x,shared_ptr<map<Coordinates,Tree>> mp) {\r\n        fullmap = mp;\r\n        this->x = x;\r\n    }\r\n    Tree* operator[](int y) {\r\n        if((*fullmap).find(Coordinates(x,y))==(*fullmap).end()) return nullptr;\r\n        Tree* toReturn = &(*fullmap)[Coordinates(x,y)];\r\n        return toReturn;\r\n    }\r\n    private:\r\n    int x;\r\n    shared_ptr<map<Coordinates,Tree>> fullmap;\r\n};\r\n<\/pre>\n<p>Konstruktor om\u00f3wili\u015bmy wcze\u015bniej. W kolejnych linijkach zauwa\u017camy przeci\u0105\u017cenie operatora []. Zwraca ono obiekt kt\u00f3ry chcieli\u015bmy uzyska\u0107. Je\u015bli na danych wsp\u00f3\u0142rz\u0119dnych nie istnieje drzewo ani po\u017car ani spalone drzewo, to zwracamy nullptr. W przeciwnym razie zwracamy wska\u017anik na Tree.<\/p>\n<p>&nbsp;<\/p>\n<h1 class=\"western\">To wszystko<\/h1>\n<p>Ujawni\u0142em wszystko, co planowa\u0142em w dzisiejszym wpisie. Nie mamy jeszcze programu, kt\u00f3ry by si\u0119 uruchamia\u0142. Posiadamy natomiast zacz\u0105tek \u2013 co\u015b, co mo\u017ce wyewoluowa\u0107 w\u00a0pe\u0142noprawn\u0105 aplikacj\u0119. Ten kod mo\u017ce si\u0119 oczywi\u015bcie zmienia\u0107, gdy\u017c wpisy tworz\u0119 r\u00f3wnolegle do prac nad projektem.<\/p>\n<p>Co by\u015b zmieni\u0142? Mo\u017ce masz lepszy pomys\u0142 na rozwi\u0105zanie problem\u00f3w z kt\u00f3rymi si\u0119 boryka\u0142em? Je\u015bli tak, podziel si\u0119 nim w komentarzu.<\/p>\n<p>Kod \u017ar\u00f3d\u0142owy projektu znajduje si\u0119 <a href=\"https:\/\/github.com\/karol221-10\/forest_fire\/tree\/article-1\">w tym miejscu<\/a>. (GitHub).<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span> Na studiach spotkasz si\u0119 z wieloma typami zaj\u0119\u0107. S\u0105 laboratoria, s\u0105 \u0107wiczenia i wiele innych. Spo\u015br\u00f3d wszystkich najbardziej lubi\u0119 projekty. Mam wyznaczone zadanie, kt\u00f3re musz\u0119 wykona\u0107 do okre\u015blonego dnia. I\u00a0nikt &#8230;<\/p>\n","protected":false},"author":1,"featured_media":462,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31,34],"tags":[],"_links":{"self":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/405"}],"collection":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/comments?post=405"}],"version-history":[{"count":33,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/405\/revisions"}],"predecessor-version":[{"id":441,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/405\/revisions\/441"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media\/462"}],"wp:attachment":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media?parent=405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/categories?post=405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/tags?post=405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}