<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <atom:link href="https://jacek.zlydach.pl/blog/tags/cpp-feed.xml" rel="self" type="application/rss+xml"/>
    <title>Posts tagged: C++ - Jacek Złydach - blog</title>
    <link>https://jacek.zlydach.pl/blog/tags/cpp.html</link>
    <lastBuildDate>Tue, 25 Jan 2022 12:54:25 +0100</lastBuildDate>
    <description>Blog of Jacek Złydach - a programmer and science enthusiast.</description>
    <generator>Regenerate2</generator>
    <managingEditor>temporal.pl@gmail.com (Jacek Złydach)</managingEditor>
    <webMaster>temporal.pl@gmail.com (Jacek Złydach)</webMaster>
    <ttl>1440</ttl>
    <copyright>© 2017, 2018, 2019, 2020, 2021, 2022, Jacek Złydach</copyright>
    <item>
      <title>Lista z wartownikiem</title>
      <link>https://jacek.zlydach.pl/blog/2010-12-02-lista-z-wartownikiem.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2010-12-02-lista-z-wartownikiem.html</guid>
      <pubDate>Thu, 02 Dec 2010 00:34:48 +0100</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/algorytmy.html">algorytmy</category>
      <description><![CDATA[Jest pewna bardzo ciekawa sztuczka programistyczna używana czasem przy implementowaniu operacji na listach, a która mi jakoś zupełnie &quot;uciekła&quot; - odkryłem ją dopiero niedawno, powtarzając algorytmy przed egzaminem inżynierskim. Chodzi o tzw. <strong>listę z wartownikiem</strong>.

Wyobraźmy sobie typową listę łączoną pojedynczo, napisaną w C++. Przykładowa funkcja sprawdzająca, czy szukany element występuje w liście mogłaby wyglądać tak:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">bool</span> element_in_list_p<span class="paren1">(<span class="no-paren-fx">node* startFrom, <span class="symbol">const</span> element&amp; what</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	node* iter = startFrom<span class="paren2">(<span class="no-paren-fx"></span>)</span>;
	<span class="symbol">while</span><span class="paren2">(<span class="no-paren-fx">iter != NULL</span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		<span class="symbol">if</span><span class="paren3">(<span class="no-paren-fx">iter-&gt;value == what</span>)</span>
		<span class="paren3">{<span class="no-paren-fx">
			<span class="symbol">return</span> true;
		</span>}</span>
		iter = iter-&gt;next;
	</span>}</span>
	<span class="symbol">return</span> false;
</span>}</span></span></code></pre>
W każdym obiegu pętli mamy dwa porównania - jedno pilnuje, byśmy nie wyszli poza listę, a drugie sprawdza, czy znaleźliśmy szukany element. <strong>Liczba porównań dla n-elementowej listy to 2n.</strong>

Gdybyśmy jednak trzymali też wskaźnik na koniec listy, algorytm wyszukujący moglibyśmy przepisać następująco:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">bool</span> element_in_list_p<span class="paren1">(<span class="no-paren-fx">node* startFrom, node* end, <span class="symbol">const</span> element&amp; what</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	end-&gt;next = new_list_node<span class="paren2">(<span class="no-paren-fx">what</span>)</span>;

	node* iter = startFrom<span class="paren2">(<span class="no-paren-fx"></span>)</span>;
	<span class="symbol">while</span><span class="paren2">(<span class="no-paren-fx">iter-&gt;value != what</span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		iter = iter-&gt;next;
	</span>}</span>
	
	<span class="symbol">if</span><span class="paren2">(<span class="no-paren-fx">iter == end</span>)</span> <span class="comment">//doszlismy do konca listy - elementu nie bylo
</span>	<span class="paren2">{<span class="no-paren-fx">
		delete_list_node<span class="paren3">(<span class="no-paren-fx">end-&gt;next</span>)</span>;
		end-&gt;next = NULL;
		<span class="symbol">return</span> false;
	</span>}</span>
	<span class="comment">//element znaleziony
</span>	delete_list_node<span class="paren2">(<span class="no-paren-fx">end-&gt;next</span>)</span>;
	end-&gt;next = NULL;
	<span class="symbol">return</span> true;
</span>}</span></span></code></pre>
Idea jest bardzo prosta - <strong>wstawiamy szukaną wartość na koniec listy</strong> - w ten sposób wiemy, że szukana wartość na pewno pojawi się przynajmniej raz, dokładnie na końcu. <strong>Możemy więc wyrzucić jedno sprawdzenie w pętli</strong>, to odpowiedzialne za pilnowanie, czy nie wyszliśmy poza listę. W ten sposób zmniejszyliśmy liczbę sprawdzeń dla n-elementowej listy z 2n do n+1. Oszczędzamy co prawda tylko na stałej, ale przy bardzo dużych listach może to mieć znaczenie. Żeby ta sztuczka miała sens, musimy oczywiście dysponować wskaźnikiem na koniec listy.
]]></description>
    </item>    <item>
      <title>Funktory - traktowanie obiektów jak funkcje w Common Lisp</title>
      <link>https://jacek.zlydach.pl/blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html</guid>
      <pubDate>Mon, 14 Jun 2010 03:34:15 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/matematyka.html">Matematyka</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/lisp.html">Lisp</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/common-lisp.html">Common Lisp</category>
      <description><![CDATA[<a href="http://en.wikipedia.org/wiki/Function_object">Funktorem</a> nazywamy obiekt, który może być wywoływany jak funkcja. Często chcemy też, by wywołanie takiego funktora przypominało składnią wywołanie normalnej funkcji w danym języku programowania.

W niektórych językach (<a href="blog/2010-05-01-lisp-domkniecia-i-pokemony.html">np. w C++, o czym niedawno pisałem</a>) funktorów używa się do naprawienia braku naturalnego wsparcia dla <a href="http://en.wikipedia.org/wiki/First-class_function"><em>funkcji first-class</em></a>. Jednak Common Lisp takie wsparcie ma, więc zasadnicze pytanie brzmi: po co nam funktory w języku, w którym funkcja jest takim samym typem danych jak każdy inny?

Zadajmy sobie inne pytanie - co robimy z funktorami?
<ol>
	<li>Przekazujemy je do <a href="http://pl.wikipedia.org/wiki/Funkcja_wy%C5%BCszego_rz%C4%99du">funkcji wyższego rzędu</a>, takich jak <code lang="Lisp" inline="true"><span class="no-paren-fx">map</span></code> czy <code lang="Lisp" inline="true"><span class="no-paren-fx">reduce</span></code>.</li>
	<li>Ponieważ są to obiekty, możemy trzymać w nich dodatkowe informacje lub umożliwiać wykonywanie na nich dodatkowych operacji.</li>
</ol>

Wyobraźmy sobie, że piszemy bibliotekę do obliczania minimum zadanej funkcji matematycznej<a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_REF_1" name="POST_CL_FUNCTOR_MT_1">*</a>. Niektóre metody potrzebują jedynie znać wartości naszej funkcji w kilku punktach. Inne potrzebują także pochodnych lub <a href="http://pl.wikipedia.org/wiki/Gradient_%28matematyka%29">gradientu</a>. Chcielibyśmy takie informacje trzymać &quot;razem&quot; z naszą funkcją, móc uzyskać do nich dostęp w razie potrzeby (na tym etapie nie zastanawiamy się nad sposobem ich wyliczenia czy przechowywania). Nasza matematyczna funkcja powinna więc być obiektem. Z drugiej strony, chcemy mieć możliwość użycia jej jak normalnej funkcji w języku programowania - choćby po to, by nie mnożyć dziwnej składni tylko dlatego, że chcemy &quot;na boku&quot; przechowywać dodatkowe informacje. W C++ przeładowalibyśmy <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">operator</span><span class="paren1">(<span class="no-paren-fx"></span>)</span></span></code> - spełniając w ten sposób wymagania 1) i 2) naszego funktora.

Deklaracja i użycie wyglądałyby na przykład tak:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">class</span> MathFunction
<span class="paren1">{<span class="no-paren-fx">
<span class="comment">//...
</span>public:
	MathFunction FirstDerivative<span class="paren2">(<span class="no-paren-fx"></span>)</span>; <span class="comment">//funkcja zwracajaca nam pierwsza pochodna
</span>	<span class="symbol">double</span> <span class="symbol">operator</span><span class="paren2">(<span class="no-paren-fx"></span>)</span> <span class="paren2">(<span class="no-paren-fx"><span class="symbol">double</span> x</span>)</span>; <span class="comment">//funkcja zwracajaca nam wartosc w punkcie
</span></span>}</span>;

<span class="comment">//uzycie
</span>MathFunction funkcja;
<span class="symbol">double</span> wynik = funkcja<span class="paren1">(<span class="no-paren-fx">100.0</span>)</span>;
std::for_each<span class="paren1">(<span class="no-paren-fx">dane.begin<span class="paren2">(<span class="no-paren-fx"></span>)</span>, dane.end<span class="paren2">(<span class="no-paren-fx"></span>)</span>, funkcja</span>)</span>;</span></code></pre>

Powiedzmy raz jeszcze, co chcemy uzyskać w Lispie - chcielibyśmy mieć obiekt <code lang="Lisp" inline="true"><span class="no-paren-fx">funkcja</span></code>, który dałoby się wywołać jak funkcję, pisząc: <code lang="Lisp" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">funcall funkcja 100</span>)</span></span></code><a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_REF_2" name="POST_CL_FUNCTOR_MT_2">**</a>, oraz przekazać do funkcji wyższego rzędu, np.: <code lang="Lisp" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">map 'list funkcja dane</span>)</span></span></code>, ale równocześnie chcemy uzyskiwać z niego pewne informacje, np. <code lang="Lisp" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">first-derivative funkcja</span>)</span></span></code>.

Rozwiązaniem jest użycie <a href="http://en.wikipedia.org/wiki/Metaobject_protocol">Metaobject Protocol</a> do zmiany typu klasy z <code lang="Lisp" inline="true"><span class="no-paren-fx">standard-class</span></code> na <code lang="Lisp" inline="true"><span class="no-paren-fx">funcallable-standard-class</span></code>. Przykładowo (w Clozure Common Lisp<a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_REF_3" name="POST_CL_FUNCTOR_MT_3">***</a>):
<pre><code lang="Lisp"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx"><i><span class="symbol">defclass</span></i> math-function <span class="paren2">(<span class="no-paren-fx"></span>)</span>
  <span class="paren2">(<span class="no-paren-fx"></span>)</span> <span class="comment">; tutaj mozemy umieszczac sloty, czyli zmienne skladowe
</span>  <span class="paren2">(<span class="no-paren-fx"><span class="keyword">:metaclass</span> ccl:funcallable-standard-class</span>)</span></span>)</span></span></code></pre>

Definiujemy również metodę zwracającą pierwszą pochodną:
<pre><code lang="Lisp"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx"><i><span class="symbol">defgeneric</span></i> first-derivative <span class="paren2">(<span class="no-paren-fx"></span>)</span>
  <span class="paren2">(<span class="no-paren-fx"><span class="keyword">:documentation</span> <span class="string">&quot;Returns analytical first derivative of a function.&quot;</span></span>)</span></span>)</span>

<span class="paren1">(<span class="no-paren-fx"><i><span class="symbol">defmethod</span></i> first-derivative <span class="paren2">(<span class="no-paren-fx"><span class="paren3">(<span class="no-paren-fx">f math-function</span>)</span></span>)</span>
  <span class="paren2">(<span class="no-paren-fx">...</span>)</span></span>)</span> <span class="comment">; kod metody pomijam</span></span></code></pre>

Od teraz obiekty klasy <code lang="Lisp" inline="true"><span class="no-paren-fx">math-object</span></code> są &quot;funcallable&quot; - mogą być przekazane do <code lang="Lisp" inline="true"><span class="no-paren-fx">funcall</span></code>, co oznacza, że mogą być argumentami funkcji wyższego rzędu. Spełniamy tym samym wymagania 1) i 2) naszego funktora.

Pozostaje tylko pytanie, jaki kod wykona &quot;wywołanie&quot; naszego obiektu? Kod ten możemy ustawić za pomocą <code lang="Lisp" inline="true"><span class="no-paren-fx">set-funcallable-instance-function</span></code>. Wygodnie jest zrobić to w konstruktorze. W Lispie, konstruktor klasy tworzymy dodając metodę <em>after</em> o nazwie <code lang="Lisp" inline="true"><span class="no-paren-fx">initialize-instance</span></code>.

<pre><code lang="Lisp"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx"><i><span class="symbol">defmethod</span></i> initialize-instance <span class="keyword">:after</span> <span class="paren2">(<span class="no-paren-fx"><span class="paren3">(<span class="no-paren-fx">f math-function</span>)</span> &amp;key code</span>)</span>
  <span class="paren2">(<span class="no-paren-fx">set-funcallable-instance-function f code</span>)</span></span>)</span></span></code></pre>

Dodaliśmy parametr kluczowy <code lang="Lisp" inline="true"><span class="no-paren-fx">code</span></code>, który pozwala nam tworzyć obiekty w następujący sposób:
<pre><code lang="Lisp"><span class="no-paren-fx"><span class="comment">; stworzony obiekt zapisujemy do zmiennej square
</span><span class="paren1">(<span class="no-paren-fx"><i><span class="symbol">setq</span></i> square <span class="paren2">(<span class="no-paren-fx">make-instance 'math-function <span class="keyword">:code</span> <span class="paren3">(<span class="no-paren-fx"><i><span class="symbol">lambda</span></i> <span class="paren4">(<span class="no-paren-fx">x</span>)</span> <span class="paren4">(<span class="no-paren-fx">* x x</span>)</span></span>)</span></span>)</span></span>)</span>

<span class="comment">; uzycie:
</span><span class="paren1">(<span class="no-paren-fx">funcall square 3</span>)</span>
<span class="comment">;wynik: 9</span></span></code></pre>

Jeżeli chcemy, aby nasz funktor był widziany jak funkcja globalna i używany ze składnią normalnego wywołania funkcji, możemy napisać:
<pre><code lang="Lisp"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">setf <span class="paren2">(<span class="no-paren-fx">fdefinition 'square</span>)</span> square</span>)</span>

<span class="comment">; ponizszy kod teraz bedzie dzialal:
</span><span class="paren1">(<span class="no-paren-fx">square 3</span>)</span>
<span class="comment">; wynik: 9</span></span></code></pre>

Wydaje się, że konieczność zaprzęgania Metaobject Protocol sprawia, iż stworzenie funktora jest czymś skomplikowanym w stosunku do np. C++. Należy jednak pamiętać, funktory w Lispie zwykle nie są potrzebne - same funkcje są <em>first-class</em> i można je przekazywać oraz zwracać jak każdy inny typ. Konieczność łączenia z funkcjami dodatkowych danych i operacji jest - wydaje mi się - czymś rzadkim. I nawet nie jestem pewien, czy nie znalazłaby się lepsza abstrakcja dla tego problemu.

<strong>Przypisy</strong>
<a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_MT_1" name="POST_CL_FUNCTOR_REF_1">*</a> - problem nie jest wcale taki błahy ani wzięty z powietrza - w tym semestrze miałem na studiach cały przedmiot poświęcony znajdywaniu minimum funkcji na różne, niekiedy <a href="http://www.kmg.ps.pl/opt/wyklad/bezgrad/rosen.html">dość dziwne</a> sposoby.
<a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_MT_2" name="POST_CL_FUNCTOR_REF_2">**</a> - składnia <code lang="Lisp" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">funcall funkcja argumenty</span>)</span></span></code> jest naturalnym sposobem wywoływania funkcji przekazanej w zmiennej w Common Lisp. Język ten, w przeciwieństwie do Scheme, pozwala funkcjom i zmiennym nosić te same nazwy - dlatego nie możemy napisać po prostu <code lang="Lisp" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">przekazana-funkcja argumenty</span>)</span></span></code> (tak jak zrobilibyśmy w Scheme), gdyż Lisp będzie szukał symbolu <code lang="Lisp" inline="true"><span class="no-paren-fx">przekazana-funkcja</span></code> w przestrzeni nazw funkcji.
<a href="blog/2010-06-14-funktory-traktowanie-obiektow-jak-funkcje-w-common-lisp.html#POST_CL_FUNCTOR_MT_3" name="POST_CL_FUNCTOR_REF_3">***</a> - jest trochę zamieszania z Metaobject Protocol w różnych implementacjach Common Lispu. Sam symbol <code lang="Lisp" inline="true"><span class="no-paren-fx">funcallable-standard-class</span></code> znajduje się w pakiecie specyficznym dla danej implementacji. Dla Clozure Common Lisp jest to pakiet CCL (tak jak w przykładzie), w SBCL prawdopodobnie SB-MOP. Powstał projekt <a href="http://common-lisp.net/project/closer/index.html">Closer</a> mający na celu ujednolicenie Metaobject Protocol pomiędzy różnymi implementacjami Common Lispu, ale nie miałem okazji jeszcze z niego korzystać.
]]></description>
    </item>    <item>
      <title>QED - UNIX API w wersji trochę bardziej przyjaznej</title>
      <link>https://jacek.zlydach.pl/blog/2010-02-25-qed-unix-api-w-wersji-troche-bardziej-przyjaznej.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2010-02-25-qed-unix-api-w-wersji-troche-bardziej-przyjaznej.html</guid>
      <pubDate>Thu, 25 Feb 2010 20:25:56 +0100</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/narzedzia.html">narzędzia</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/linux.html">Linux</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/unix.html">Unix</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/qed.html">QED</category>
      <description><![CDATA[<a href="projects.html#qed">Chciałbym opublikować kawałek kodu</a>, który napisałem pod wpływem emocji w ramach nauki na końcowe kolokwium z systemów operacyjnych. Zadania, które dostawaliśmy tam były niemożliwe do zrobienia bez dobrej znajomości API UNIXa dotyczącego <a href="http://pl.wikipedia.org/wiki/Komunikacja_mi%C4%99dzyprocesowa">komunikacji międzyprocesowej</a> i przygotowania sobie jakiegoś kodu wcześniej. Teoretycznie można było korzystać z Internetu i dowolnych własnych zasobów, ale bez wstępnego przygotowania nie było szans ;). Większość znajomych przygotowywała więc sobie rozwiązania dotychczasowych zadań z laboratorium w nadziei, że będą się dały zaadaptować do kolokwium.

QED, bo tak nazywa się biblioteka, powstała jako wynik frustracji po słabym zaliczeniu pierwszego terminu. Opakowuje ona całe to przykre i bolesne w użyciu API <a href="http://pl.wikipedia.org/wiki/Komunikacja_mi%C4%99dzyprocesowa">IPC</a> UNIX'a do postaci prostych klas i funkcji C++. Większość zadań da się zrobić bez ani jednej linii kodu w czystym UNIXowym API :).

<a href="projects.html#qed"><strong>Biblioteka QED oraz przykładowe zadania z laboratoriów / kolokwium.</strong></a>

Biblioteczka ta zawiera:
<ul>
	<li>Uproszczony <a href="http://www.boost.org/doc/libs/1_42_0/libs/conversion/lexical_cast.htm"><code lang="C++" inline="true"><span class="no-paren-fx">lexical_cast</span></code></a></li>
	<li>Obiekty do łatwego synchronizowania operacji na <code lang="C++" inline="true"><span class="no-paren-fx">std::ostream</span></code>(tak, na <code lang="C++" inline="true"><span class="no-paren-fx">std::cout</span></code> też!) w programach wielowątkowych</li>
	<li>Funkcję do pobierania czasu z milisekundową rozdzielczością</li>
	<li>Pomocnicze makra zastępujące powtarzający się w kółko kod</li>
	<li>Pomocnicze funkcje do <strong>wygodnego</strong> <code lang="C++" inline="true"><span class="no-paren-fx">fork<span class="paren1">(<span class="no-paren-fx"></span>)</span></span></code> (łącznie z przepinaniem STDIN i STDOUT dziecka); <a href="http://en.wikipedia.org/wiki/Fork-exec">fork-exec idiom</a> trzeba sobie zrobić samemu, ale co to za problem wywołać sobie funkcję <code lang="C++" inline="true"><span class="no-paren-fx">exec<span class="paren1">(<span class="no-paren-fx"></span>)</span></span></code> :P.</li>
	<li>Klasy izolujące <a href="http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html#pipes">nienazwane</a> i nazwane <a href="http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html#fifos">pipe'y (FIFO)</a>, <a href="http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html#semaphores">semafory</a>, <a href="http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html#shm">pamięć współdzieloną</a> i <a href="http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html#mq">kolejki komunikatów</a></li>
	<li>Inne pomocnicze funkcje</li>
</ul>

Mam szczerą nadzieję, że kod ten przyda się przynajmniej tym z Czytelników, którzy już za rok (albo i wcześniej) zmierzą się z Systemami Operacyjnymi na IS :).

Dlaczego taka nazwa? QED oznacza <a href="http://pl.wikipedia.org/wiki/Elektrodynamika_kwantowa">elektrodynamikę kwantową</a> - bardzo pokręconą dziedzinę fizyki, o której czytałem sobie &quot;do obiadu&quot; w okresie prac nad powyższą biblioteką. <a href="http://pl.wikipedia.org/wiki/Q.e.d.">Q.E.D.</a> to też łaciński skrót oznaczający <em>Quod erat demonstrandum</em> (&quot;Co było do udowodnienia&quot;) - co dobrze współgrało z moją frustracją po pierwszym terminie (na zasadzie: &quot;no, na drugim pokażę!&quot;).

Dla niewystarczająco przekonanych, przykład kodu:
<pre><code lang="C++"><span class="no-paren-fx"><span class="comment">//================================================================
</span><span class="comment">//Beta section
</span><span class="comment">//================================================================
</span><span class="symbol">int</span> process_beta<span class="paren1">(<span class="no-paren-fx"><span class="symbol">void</span>* data</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	betaQueue.attach<span class="paren2">(<span class="no-paren-fx"></span>)</span>;
	alphaSharedQueue.attach<span class="paren2">(<span class="no-paren-fx"></span>)</span>;

	<span class="symbol">char</span> buffer<span class="paren2">[<span class="no-paren-fx">1024</span>]</span>;

	<span class="symbol">while</span><span class="paren2">(<span class="no-paren-fx"><span class="symbol">true</span></span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		std::memset<span class="paren3">(<span class="no-paren-fx">buffer, 0, 1024*<span class="symbol">sizeof</span><span class="paren4">(<span class="no-paren-fx"><span class="symbol">char</span></span>)</span></span>)</span>;
		
		<span class="comment">//get data from msg queue
</span>		betaQueue.receive_message<span class="paren3">(<span class="no-paren-fx">buffer</span>)</span>;

		<span class="comment">//cut out last two letters
</span>		buffer<span class="paren3">[<span class="no-paren-fx">std::max<span class="paren4">(<span class="no-paren-fx"><span class="symbol">static_cast</span>&lt;<span class="symbol">int</span>&gt;<span class="paren5">(<span class="no-paren-fx">std::strlen<span class="paren6">(<span class="no-paren-fx">buffer</span>)</span></span>)</span> - 2, 0</span>)</span></span>]</span> = <span class="character">'\0'</span>;

		<span class="comment">//send data via message queue to P1
</span>		alphaSharedQueue.send_message<span class="paren3">(<span class="no-paren-fx">buffer</span>)</span>;
	</span>}</span>

	<span class="symbol">return</span> 0;
</span>}</span></span></code></pre>
Oto kod procesu, który odbiera informacje z kolejki komunikatów, obcina im dwa ostatnie znaki i wysyła je inną kolejką komunikatów.
Teraz, wyobraź sobie, że piszesz w czystym UNIX API :P.
]]></description>
    </item>    <item>
      <title>Stulecie Robotów w Krakowie - Reportaż, część 3</title>
      <link>https://jacek.zlydach.pl/blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html</guid>
      <pubDate>Mon, 15 Jun 2009 19:24:22 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/roboty.html">roboty</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/stulecie-robotow.html">Stulecie Robotów</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/qfix.html">qfix</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/graupner-robotics.html">Graupner Robotics</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/galeria-krakowska.html">Galeria Krakowska</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/atmega128.html">ATmega128</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/reportaze.html">reportaże</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/soccerboard.html">SoccerBoard</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/fsm.html">FSM</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/maszyna-stanow-skonczonych.html">maszyna stanów skończonych</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/sztuczna-inteligencja.html">sztuczna inteligencja</category>
      <description><![CDATA[<em><a href="blog/2009-06-06-stulecie-robotow-w-krakowie-reportaz-czesc-1.html">(kontynuacja tematu o Festiwalu Robotów w Krakowie)</a>
<em><a href="galleries/stulecie-robotow-w-krakowie/index.html">(Stulecie Robotów - Galeria)</a></em>
(<a href="blog/2009-06-07-stulecie-robotow-w-krakowie-reportaz-czesc-2.html">&lt;&lt; poprzednia część</a>)</em>
<p><img src="old-blog/download/roboty_krakow/stulecie_vsmall.jpg" alt="Stulecie Robotów - logo" width="100" style="float: left; margin-right: 15px;"></p>
Wrzuciłem <a href="galleries/stulecie-robotow-w-krakowie/index.html">troszkę nowych zdjęć do galerii</a>. Pojawiły się też pierwsze filmiki, ale o tym później :). W tej części reportażu opisuję osobiste zmagania z robotem Graupnera, które okazały się wielkim sukcesem (<a href="http://www.youtube.com/watch?v=Y6ljFaKRTrI">&quot;I'm making a note here: HUGE SUCCESS&quot;</a>) i doprowadziły do sytuacji, w której robot z zamontowanym aparatem cyfrowym rozbijał się po sklepach w Galerii Krakowskiej :).

<center><strong>Starcie Trzecie - Sobota, 06.06.2009</strong></center>
Tym razem spędziłem w Galerii praktycznie cały dzień, intensywnie pracując nad uruchomionym już robotem Graupnera. Zaczęło się od prostych programików testowych, które pozwoliły mi ocenić funkcjonowanie silników i przycisków na płytce oraz ogólną mechanikę pracy z robotem. Mając już tę podstawową wiedzę zabrałem się za kolejny etap zabawy...

<strong>Kalibracja czujników odległości</strong>
Przede mną znajdowały się czujniki odległości. Z instrukcji po niemiecku dowiedziałem się tylko tyle, że działają na podczerwień i mierzą odległość w granicach 4-30cm. Jego obłsuga, podobnie jak każdego innego analogowego czujnika na tej płytce sprowadzała się do wywołania funkcji, która zwracała wartość od 0 do 255. Nigdzie w dokumentacji nie podano, jak mają się te wskazania (0..255) do odległości wyrażonej w metrach (nie była podana tzw. <em>charakterystyki czujnika</em>). Zmierzyłem ją więc eksperymentalnie. Po stwierdzeniu, że większe wartości występują, gdy wykryty obiekt znajduje się bliżej czujnika posłużyłem się linijką i poniższym kodem:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">while</span><span class="paren1">(<span class="no-paren-fx">1</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	<span class="symbol">if</span><span class="paren2">(<span class="no-paren-fx">board.GetMainBoard<span class="paren3">(<span class="no-paren-fx"></span>)</span>.analog<span class="paren3">(<span class="no-paren-fx">7</span>)</span> &gt; FORWARD_THRESHOLD</span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		board.GetMainBoard<span class="paren3">(<span class="no-paren-fx"></span>)</span>.motor<span class="paren3">(<span class="no-paren-fx">0, 255</span>)</span>;
	</span>}</span>
	<span class="symbol">else</span>
	<span class="paren2">{<span class="no-paren-fx">
		board.GetMainBoard<span class="paren3">(<span class="no-paren-fx"></span>)</span>.motorsOff<span class="paren3">(<span class="no-paren-fx"></span>)</span>;
	</span>}</span>
</span>}</span></span></code></pre>
Jak nie trudno zauważyć, regulując parametr <em>FORWARD_THRESHOLD</em> zmieniałem moment, w którym uruchamiały się silniczki. Po rozciągnięciu składanej kilkumetrowej linijki mierzyłem więc czujnik ręką, badając w którym momencie zaczyna on wskazywać zadaną w <em>FORWARD_THRESHOLD</em> wartość. W ten sposób uzyskałem 10 punktów, układających się w mniej-więcej w eksponentę ;).
<center><a href="old-blog/download/roboty_krakow/charakterystyka.png" target="_blank"><img src="old-blog/download/roboty_krakow/charakterystyka_small.png" alt="Doświadczalnie zmierzona charakterystyka czujnika odległości."></a></center>
Mając te próbki mogłem już wyznaczyć przybliżoną odległość dla dowolnego wskazania czujników w mierzonym zakresie oraz spodziewane wskazanie czujników dla dowolnej podanej odległości - wszystko to oczywiście za pomocą magicznej sztuczki zwanej <em>liniową interpolacją</em><a name="POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_MT_1" href="blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html#POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_REF_1">*</a>, o mniej więcej w ten sposób:
<pre><code lang="C++"><span class="no-paren-fx"><span class="comment">//(...)
</span><span class="comment">//gdzies tam w konstruktorze:
</span><span class="comment">//set up ir sensor data
</span>irSensorSettings<span class="paren1">[<span class="no-paren-fx">0</span>]</span> = 0; 	irSensorRanges<span class="paren1">[<span class="no-paren-fx">0</span>]</span> = 1.3f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">1</span>]</span> = 12;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">1</span>]</span> = 0.65f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">2</span>]</span> = 15;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">2</span>]</span> = 0.34f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">3</span>]</span> = 25;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">3</span>]</span> = 0.30f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">4</span>]</span> = 30;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">4</span>]</span> = 0.24f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">5</span>]</span> = 40;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">5</span>]</span> = 0.16f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">6</span>]</span> = 50;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">6</span>]</span> = 0.13f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">7</span>]</span> = 75;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">7</span>]</span> = 0.08f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">8</span>]</span> = 100;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">8</span>]</span> = 0.06f;
irSensorSettings<span class="paren1">[<span class="no-paren-fx">9</span>]</span> = 150;	irSensorRanges<span class="paren1">[<span class="no-paren-fx">9</span>]</span> = 0.025f;
<span class="comment">//(...)
</span><span class="comment">//magiczna funkcja:
</span><span class="symbol">int</span> GetIRThresholdForDistance<span class="paren1">(<span class="no-paren-fx"><span class="symbol">float</span> distance</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	<span class="symbol">for</span><span class="paren2">(<span class="no-paren-fx"><span class="symbol">int</span> i = 1 ; i &lt; IR_SENSOR_SAMPLES ; ++i</span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		<span class="symbol">if</span><span class="paren3">(<span class="no-paren-fx">distance &gt; irSensorRanges<span class="paren4">[<span class="no-paren-fx">i</span>]</span></span>)</span>
		<span class="paren3">{<span class="no-paren-fx">
			<span class="symbol">float</span> scale = <span class="paren4">(<span class="no-paren-fx">distance - irSensorRanges<span class="paren5">[<span class="no-paren-fx">i</span>]</span></span>)</span>/<span class="paren4">(<span class="no-paren-fx">irSensorRanges<span class="paren5">[<span class="no-paren-fx">i-1</span>]</span> - irSensorRanges<span class="paren5">[<span class="no-paren-fx">i</span>]</span></span>)</span>;
			<span class="symbol">return</span> <span class="symbol">static_cast</span>&lt;<span class="symbol">int</span>&gt;<span class="paren4">(<span class="no-paren-fx">irSensorSettings<span class="paren5">[<span class="no-paren-fx">i</span>]</span>*<span class="paren5">(<span class="no-paren-fx">scale</span>)</span> + irSensorSettings<span class="paren5">[<span class="no-paren-fx">i-1</span>]</span>*<span class="paren5">(<span class="no-paren-fx">1.0f-scale</span>)</span></span>)</span>;
		</span>}</span>
	</span>}</span>
	<span class="symbol">return</span> 0;
</span>}</span></span></code></pre>
Pomiary nie były szczególnie dokładne, ale biorąc pod uwagę, że przedział od 2 centymetrów do ponad 1.5 metra mieści się w zakresie od 0 do 150 stwierdzam, że przybliżenie jest wystarczające :). Wartości powyżej 150 nie mierzyłem częściowo z braku potrzeby, a częściowo z tego, że różnice między kolejnymi wartościami wynosiłyby teoretycznie ułamki centymetra. Uzyskane pomiary błyskawicznie zweryfikowałem w praktyce i okazały się one wystarczająco dobre, by robot mógł się poruszać w terenie. Postanowiłem więc napisać...

<strong>Proste AI robota</strong>
Rzeczywiście, chociaż w konstrukcji jest ono stosunkowo proste, to w praktyce przerosło (pozytywnie) moje oczekiwania. Inteligencję robota zapewniała prosta maszyna stanów<a name="POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_MT_2" href="blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html#POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_REF_2">**</a>. Konstrukcję robota i skończoną maszynę stanów ilustruje poniższy schemat:
<center><a href="old-blog/download/roboty_krakow/robot_schemat.png" target="_blank"><img src="old-blog/download/roboty_krakow/robot_schemat_small.png" alt="Schemat konstrukcji robota oraz jego oprogramowania."></a></center>
Stan <strong>Wandering Around</strong> <em>(ang. wędrówka po okolicy)</em> to po prostu spacer w kółko - robot najpierw porusza się dwie sekundy przed siebie, by następnie skręcić w losowym kierunku przez pół sekundy. W międzyczasie czujniki odległości odpytywane są 10 razy na sekundę i w sytuacji, w której odległość od najbliższego obiektu spadnie poniżej ustalonej wartości następuje natychmiastowe przełączenie stanu na <strong>Evade</strong> <em>(ang. unikaj)</em>. Stan ten obsługuje omijanie obiektów, które znalazły się zbyt blisko. Zależnie od tego, na którym czujniku wykryto obiekt wybrany zostaje odpowiedni kierunek unikania. Robot następnie wykonuje manewr. Pojedyncza iteracja tego stanu trwa około 100ms - mniej więcej tak często robot sprawdza czujniki. Jeżeli potencjalna przeszkoda znalazła się wystarczająco daleko, robot wraca do stanu <strong>Wandering Around</strong>. Jeśli natomiast czujnik wykrył jakiś obiekt ekstremalnie blisko robota, włączony zostaje stan <strong>Run Like Hell</strong> - awaryjna ucieczka. W tym stanie robot z piskiem (dosłownie - <a href="http://en.wikipedia.org/wiki/Buzzer">beeper</a>) ucieka w kierunku przeciwnym do tego, z którego wykryto zagrożenie. Pojedyncza iteracja stanu trwa pół sekundy - przez ten czas robot nie sprawdza okolicy, co w ekstremalnych przypadkach może skończyć się uderzeniem w inną przeszkodę przy wycofywaniu się. Gdy zagrożenie minie, robot przełącza się w stan <strong>Wandering Around</strong>.

<center><a href="old-blog/download/roboty_krakow/TRCSoccerBot.jpg" target="_blank"><img src="old-blog/download/roboty_krakow/TRCSoccerBot_small.jpg" alt="Robot, którego programowałem."><br>
<em>Robot, którego programowałem</em></a></center>

Ten prosty system okazał się niewiarygodnie skuteczny w terenie. Pierwsze testy na arenie pokazały, że ściany i ręce małych dzieci są dla robota praktycznie niegroźne (jedyny problem sprawiały duże roboty, które miały korpus powyżej linii czujników). Niezłym wyzwaniem była nawet próba złapania robota na tej arenie, by go wyłączyć :). Jednak na prawdę ciekawie zrobiło się gdy robot, uzbrojony w aparat cyfrowy, wyruszył na spacer po Galerii. Samodzielnie poruszał się między ludźmi (ku wielkiej uciesze kilkulatków), zwiedził też kilka sklepów. Poniżej dwa filmiki - jeden z areny, drugi z jazdy po Galerii:
<center><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/SJhNz0cEPxo&amp;hl=pl&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/SJhNz0cEPxo&amp;hl=pl&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></center>
<center><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bZHYdd_jiOQ&amp;hl=pl&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/bZHYdd_jiOQ&amp;hl=pl&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></center>
Na koniec jeszcze uwaga o stronie implementacyjnej - całą maszynę stanów oparłem (głównie dla szybkości pisania) o wskaźnik do funkcji :) . Nie jest to może szczególnie elastyczne, ale działa świetnie :) .
Zbierając do kupy różne fragmenty kodu stworzyłem w końcu pierwszą próbę rozszerzenia API dla robotów SoccerBoard. Omawiany wyżej program, wraz z TRC SoccerBoard API 1.0 można ściągnąć z poniższego linka:
<a href="old-blog/download/roboty_krakow/roboty_src1.zip">(źródła)</a>

Gdzieś pomiędzy tym wszystkim obsługa zaczęła mi podsuwać informacje, że ponoć te roboty mogą być zdalnie sterowane. Pytali się mnie, czy nie byłbym im w stanie tego uruchomić...

<em>Ciąg dalszy nastąpi...</em>

<strong>Przypisy:</strong>
<a name="POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_REF_1" href="blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html#POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_MT_1">*</a> - Przeraża mnie fakt, który zaobserwowałem, że sporo osób zetknęło się z pojęciem interpolacji w szkole lub na studiach i kojarzą ją jedynie z 'dziwnymi wzorami' Lagrange'a i Newtona, podczas gdy nie umieją w żaden sposób wyobrazić jej sobie w praktyce. Wspomnę coś na ten temat niedługo, stay tuned :).

<a name="POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_REF_2" href="blog/2009-06-15-stulecie-robotow-w-krakowie-reportaz-czesc-3.html#POST_STULECIE_ROBOTOW_W_KRAKOWIE_REP3_MT_2">**</a> - Niektórzy Czytelnicy mogą nie być zaznajomieni z koncepcją maszyny stanów skończonych <em>(ang. Finite State Machine)</em>. Żeby nie sypać skomplikowanymi definicjami z Wikipedii, powiem krótko - prostym (i typowym) przykładem FSM jest... <strong>żarówka w pokoju</strong>. Jako obiekt ma dwa <strong>stany wewnętrzne</strong> - może być zapalona lub zgaszona. Zależnie od stanu inaczej się zachowuje (zapalona - świeci i grzeje się, zgaszona - nie świeci i stygnie). Ustalone są też <strong>przejścia między stanami</strong> - używając włącznika możemy przełączyć żarówkę ze stanu <em>świeci się</em> na stan <em>nie świeci się</em> i odwrotnie. Projektując FSM rysuje się często grafy podobne do tego, który znalazł się też w tym poście.
]]></description>
    </item>    <item>
      <title>Stulecie Robotów w Krakowie - Reportaż, część 2</title>
      <link>https://jacek.zlydach.pl/blog/2009-06-07-stulecie-robotow-w-krakowie-reportaz-czesc-2.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2009-06-07-stulecie-robotow-w-krakowie-reportaz-czesc-2.html</guid>
      <pubDate>Sun, 07 Jun 2009 18:58:39 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/roboty.html">roboty</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/stulecie-robotow.html">Stulecie Robotów</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/lego-mindstorms.html">Lego Mindstorms</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/qfix.html">qfix</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/graupner-robotics.html">Graupner Robotics</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/galeria-krakowska.html">Galeria Krakowska</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/atmega128.html">ATmega128</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/reportaze.html">reportaże</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/soccerboard.html">SoccerBoard</category>
      <description><![CDATA[<em><a href="blog/2009-06-06-stulecie-robotow-w-krakowie-reportaz-czesc-1.html">(kontynuacja tematu o Festiwalu Robotów w Krakowie)</a>
<em><a href="galleries/stulecie-robotow-w-krakowie/index.html">(Stulecie Robotów - Galeria)</a></em>
(<a href="blog/2009-06-06-stulecie-robotow-w-krakowie-reportaz-czesc-1.html">&lt;&lt; poprzednia część</a>)</em>

Oto kolejna część reportażu z imprezy Stulecie Robotów. W ramach testu <a href="http://alexrabe.boelinger.com/wordpress-plugins/nextgen-gallery/">plugina NextGEN Gallery</a> wrzuciłem kilka pierwszych zdjęć z tego wydarzenia. Niedługo pojawią się filmiki, stay tuned... :)

<center><strong>Starcie Drugie - Czwartek, 04.06.2009</strong></center>
Niedługo później, bo w czwartek (04.06.2009) wróciłem do Galerii by zająć się budową robotów. Przyszedłem dość późno, gdyż miałem tego dnia egzamin zerowy z Podstaw Sterowania ;). Na miejscu spotkałem jednego z chłopaków od Lego Mindstorms. Poprosiliśmy o wspomniane zestawy programowalne w C++. Okazało się, że są to <a href="http://www.graupner-robotics.de/en/robot/rc-soccerbot.html">roboty niemieckiej firmy Graupner Robotics</a> służące do zawodów w piłkę nożną. Obsługa powiedziała mi, że w Niemczech takie roboty dawane są szkołom na okres kilku miesięcy, by uczniowie mieli czas przygotować oprogramowanie, a następnie roboty biorą udział w jakiegoś rodzaju konkursie. Po konkursie roboty są zwykle zostawiane szkołom.

Roboty dostaliśmy w dość rozsypanej postaci - przez pierwsze pół godziny grzebaliśmy w pudełkach szukając zasilania i programatora do szkieletu, który zdawał się być najprostszą w pełni działającą konstrukcją. Po uruchomieniu mechaniki przyszedł czas na programowanie; odnalezienie się zajęło jakieś kolejne pół godziny. Niestety, robot po wgraniu programu wyprawiał nieopisane cuda z silniczkami. Próba rozwiązania tego problemu zajęła mi praktycznie cały czas do 19:00. Pomagał w tym <a href="http://wawszczak.pr0.pl">Stanisław</a>, który pojawił się w międzyczasie w Galerii. Robot jednak nie zaczął działać poprawnie; musieliśmy go w końcu zostawić i opuścić galerię.

<strong>Roboty Graupnera</strong>
<p><a href="old-blog/download/roboty_krakow/soccerboard_big.png" target="_blank"><img src="old-blog/download/roboty_krakow/soccerboard_small.png" alt="Układ SoccerBoard firmy qfix" style="float: right; margin-left: 15px;"></a></p>
Platforma Graupnera różni się zasadniczo od Lego Mindstorms i Fischertechnika - w przypadku dwóch ostatnich konstrukcja robota to plastikowe klocki, natomiast ten pierwszy to pełnoprawny metalowy robot zrobiony z przykręcanych / mocowanych części. Sercem układu sterującego, <a href="old-blog/download/roboty_krakow/soccerboard_big.png" target="_blank">nazwanego SoccerBoard</a>, jest procesor ATmega128. SoccerBoard pozwala na podłączenie aż sześciu różnych silników (trzy z nich typowa konstrukcja wykorzystuje do poruszania się), 8-miu wejść cyfrowych oraz 8-miu wejść analogowych. Dodatkowo pierwsze cztery wejścia analogowe i cyfrowe mogą służyć za wyjścia mocy, którymi można np. zasilać żaróweczki. Przydatnym do debugowania programów mogłaby się okazać możliwość podłączenia małego wyświetlacza LCD - gdyby ktoś na festiwalu taki wyświetlacz miał.

Roboty Graupnera oparte są o platformę <a href="http://www.qfix.de">niemieckiej firmy qfix</a>. Całość programuje się w C++ przy użyciu specjalnie przygotowanego prostego API. Razem z oprogramowaniem robota instalowany jest Programmer's Notepad, w którym proces kompilacji i programowania układu został uproszczony do naciskania klawiszy F5 i F6.


<center><strong>Starcie Trzecie - Piątek, 05.06.2009</strong></center>
<p><a href="old-blog/download/roboty_krakow/pnotepad.png" target="_blank"><img src="old-blog/download/roboty_krakow/pnotepad_small.png" alt="Jak zostałem największym idiotą Galaktyki" width="128" style="float: left; margin-right: 15px;"></a></p> Korzystając z chwili wolnego (nie mieliśmy tego dnia zajęć) udałem się do Galerii by kontynuować próby poprawnego zaprogramowania SoccerBoard'a. Analizowałem dokładnie API qfix'a i studiowałem pojedyncze bity na portach, które ustawiały funkcje mające wpływ na silniczki. Wreszcie doszło do tego, że znalazłem w Internecie SDK i zainstalowałem je na swoim laptopie. I wtedy przypadkiem odkryłem prawdziwą przyczynę błędnej pracy układu - niewielka lista rozwijana, która - jak mi się zdawało - służyła tylko do wyboru języka, dla którego kolorowana będzie składnia kontrolowała także model programowalnego chipa. Narzędzia kompilacji i nagrywania programu, dostępne pod klawiszami F5 i F6, były zależne od wyboru dokonanego na tej liście. Tak zostałem największym idiotą Galaktyki ;).

Dzięki powyższemu odkryciu udało mi się w końcu w pełni poprawnie zaprogramować robota (wszystkie hacki, które zainstalowałem w API qfix'a okazały się w tym momencie niepotrzebne ;) ). Niestety, musiałem w tym momencie opuścić Galerię ale przynajmniej było pewne, że robot Graupnera może być łatwo i przyjemnie zaprogramowany. Postanowiłem powrócić... :)

<em>Ciąg dalszy nastąpi...</em>
]]></description>
    </item>    <item>
      <title>Stulecie Robotów w Krakowie - Reportaż, część 1</title>
      <link>https://jacek.zlydach.pl/blog/2009-06-06-stulecie-robotow-w-krakowie-reportaz-czesc-1.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2009-06-06-stulecie-robotow-w-krakowie-reportaz-czesc-1.html</guid>
      <pubDate>Sat, 06 Jun 2009 11:06:08 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/roboty.html">roboty</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/stulecie-robotow.html">Stulecie Robotów</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/fischertechnik.html">Fischertechnik</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/lego-mindstorms.html">Lego Mindstorms</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/qfix.html">qfix</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/graupner-robotics.html">Graupner Robotics</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/galeria-krakowska.html">Galeria Krakowska</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/atmega128.html">ATmega128</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/reportaze.html">reportaże</category>
      <description><![CDATA[W Galerii Krakowskiej odbywa się obecnie festiwal o nazwie &quot;Stulecie Robotów&quot;. Trwać będzie on (według moich informacji) <strong>do końca przyszłego tygodnia, tj. do niedzieli 14.06.2009</strong>. Galeria pełna jest gablot z małymi i dużymi robotami, jednak najciekawszym miejscem jest czynny codziennie w godzinach 09:00 - 19:00 (czasem 10:00 - 20:00) punkt, w którym przygotowano zestawy <a href="http://en.wikipedia.org/wiki/LEGO_Mindstorms">Lego Mindstorms</a>, <a href="http://en.wikipedia.org/wiki/Fischertechnik">Fischertechnik</a> i <a href="http://fjernstyret.dk/graupner-r1001-rc-soccerbot-p-121.html">Graupner Robotics (Soccerbot)</a> i do samodzielnego złożenia i zaprogramowania. Zwłaszcza ten ostatni &quot;zestaw&quot; jest ciekawy, gdyż wewnętrznie jest to układ ATmega128 programowany w C++.

Ponieważ jestem studentem i właśnie mam sesję, postanowiłem się pouczyć i tak zawędrowałem na wspomniany festiwal :). W najbliższych kilku postach postaram się zrelacjonować to wydarzenie. Pojawi się trochę zdjęć i filmów, których jeszcze nie zrobiłem bo byłem zbyt zajęty psuciem robotów ;)


<center><strong>Starcie Pierwsze - Wtorek, 02.06.2009</strong></center>
Po krótkim spacerze między gablotami trafiłem do 'części konstrukcyjnej', gdzie zostałem zaproszony do skorzystania z zestawów Fischertechnik. Lego Mindstorms zajęte były przez młodych chłopaków, którzy tworzyli dość ambitne konstrukcje kroczące, by następnie udać się na pobliską arenę dla robotów i przetestować je w walce. Wspomniana 'arena' to specjalna plansza, na której można testować zbudowane przez siebie roboty oraz sterować trzema robotami-zabawkami &quot;na pilota&quot;. <del datetime="2009-06-06T19:22:42+00:00">Dwa z nich przypominają transformersy :) i poruszają się na dwóch nogach,</del><ins datetime="2009-06-06T19:22:42+00:00">Jeden z nich porusza się na dwóch nogach, drugi na owadzich kończynach a</ins> trzeci to model węża. Zdjęcia i filmiki wkrótce :).

Posadzony przed klockami Fischertechnik znalazłem jakąś instrukcję i zacząłem konstrukcję podstawowego modułu jeżdżącego. Nie było to takie proste zadanie, pierwszy raz widziałem takie klocki na oczy ;). Otrzymałem procesor sterujący, baterię oraz dostęp do kabli i oprzyrządowania. Gdy robot był już gotowy, miły człowiek z obsługi festiwalu posadził mnie przy komputerze i poinstruował jak korzystać z oprogramowania. Po podpięciu procesora robota do PC przez kabel USB zaczęła się zabawa :).

<center><a href="old-blog/download/roboty_krakow/fischertechnik_1.jpg" style="padding-right: 30px;" target="_blank"><img src="old-blog/download/roboty_krakow/fischertechnik_1_small.jpg" alt="Robot Fischertechnik, widok z boku"></a><a href="old-blog/download/roboty_krakow/fischertechnik_2.jpg" style="padding-left: 30px;" target="_blank"><img src="old-blog/download/roboty_krakow/fischertechnik_2_small.jpg" alt="Robot Fischertechnik, widok z góry"></a>
<em>Robot mojej konstrukcji</em></center>

<strong>Narzędzia Fischertechnik</strong>
Narzędzia Fischertechnik - podobnie jak Lego Mindstorms - pozwalają na tworzenie aplikacji przez wyklikiwanie schematów blokowych w dedykowanej aplikacji. Program, z którego korzystałem pozwalał pracować na pięciu poziomach zaawansowania - z każdym kolejnym dostawało się do dyspozycji więcej opcji. Poziom podstawowy to bardzo prosty interfejs, w którym można wyklikać prosty program. Dostępne opcje to m.in. zaczekanie na przycisk (dokładniej: wejście cyfrowe), sterowanie pracą silnika (dokładniej: wyjścia sterującego :)). Za pomocą niektórych bloczków program mógł się rozgałęzić lub zapętlić. Kolejnym poziomem zaawansowania był poziom 'podprogramów' - w tym trybie pojawiały się dodatkowe, bardziej złożone bloczki oraz można było wyklikiwać własne funkcje (w postaci podobnych schematów blokowych), które następnie stawały się bloczkami i można było z nich korzystać w programie. Kolejne trzy poziomy to dodatkowe bloczki (m.in. operacje na zmiennych, dość zaawansowane konstrukcje logiczne) i lekkie skomplikowanie interfejsu. Niezastąpione okazało się okienko podglądu aktualnego stanu robota, dzięki któremu można było mieć zarówno podgląd wszystkich wejść analogowych i cyfrowych w czasie rzeczywistym (tak długo, jak robot był podpięty do komputera), jak i można było sterować każdym z wyjść sterujących bez konieczności wgrywania nowego programu. W całym tym procesie jedna tylko rzecz mi bardzo przeszkadzała - komputery pracowały na systemie w niemieckiej wersji językowej; nie był to wielki problem, ale za to denerwujący.

<strong>Robot</strong>
Ostatecznie wyposażyłem swojego robota w dwa przyciski, które służyły za czujniki zderzenia z przeszkodą. Następnie stworzyłem program, dzięki któremu robot 'patrolował' teren poruszając się z niewielką szybkością do przodu, a w przypadku naciśnięcia któregokolwiek z przycisków błyskawicznie odskakiwał i omijał punkt zderzenia (dokładniej cofał się, skręcał w odpowiednią stronę, reorientował i podjeżdżał - zakreślając coś na kształt dużego U). Ten prosty kod okazał się być wystarczająco dobry, by robot mógł zostać pozostawiony na arenie, gdzie toczyły się walki - potrafił poruszać się bardzo długo bez pomocy człowieka i nie blokował się (głównie dlatego, że jedno z kółek było krzywe i robot nie jechał zwykle idealnie po prostej).

Kilka słów o elementach elektronicznych w zestawach Fischertechnik, przynajmniej tych dostępnych na festiwalu. Jedynym wejściem dla robota okazał się być wspomniany przycisk. Służy on za wejście cyfrowe - ma dwa stany. Ponadto za wejście możnaby uznać pewne bliżej niezidentyfikowane urządzenie przypominające fototranzystor; nie udało mi się go jednak uruchomić. Z elementów wyjściowych dołączone były silniki oraz żarówkowe światełka. Oba te rodzaje urządzeń korzystają z tych samych wyjść. Sama płytka sterująca posiada wejścia analogowe mierzące napięcie (jedno mierzy rezystancję) i pozwala podłączyć jedynie cztery urządzenia wyjściowe (to i tak o jedno więcej niż Lego Mindstorms).

Wybiła godzina 19:00 i trzeba było się zbierać. Od obsługi dostałem informację, że mają też trzeci rodzaj robotów, programowalny w C++ i że mogą go udostępnić następnym razem, jeśli będę chciał. Ponadto z rozpędu zgubiłem na wystawie rolkę <a href="http://en.wikipedia.org/wiki/Duct_tape">Duct Tape</a> (na szczęście na wykończeniu).

<em>Ciąg dalszy nastąpi...</em>
]]></description>
    </item>    <item>
      <title>Projekty zaliczeniowe - rzut pierwszy :)</title>
      <link>https://jacek.zlydach.pl/blog/2009-02-22-projekty-zaliczeniowe-rzut-pierwszy.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2009-02-22-projekty-zaliczeniowe-rzut-pierwszy.html</guid>
      <pubDate>Sun, 22 Feb 2009 22:10:32 +0100</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/agh.html">AGH</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/matematyka.html">Matematyka</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/delphi.html">Delphi</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/anything.html">Anything</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/analiza-glownych-skladowych.html">analiza głównych składowych</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/gra-w-zycie.html">gra w życie</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/alfabet-morsa.html">alfabet Morsa</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/prezentacje-multimedialne.html">prezentacje multimedialne</category>
      <description><![CDATA[Jedną z najlepszych stron kierunku Informatyka Stosowana na AGH są pojawiające się od czasu do czasu projekty zaliczeniowe. Poniżej publikuję pierwszą serię 'drobnicy' - projekty zaliczeniowe z I roku. Nie są może one zbyt ambitne (sprawy osobiste wymagały bardzo dużo uwagi), ale potrzebne zaliczenia dały ;).

<strong>Podstawy Użytkowania Komputerów (I semestr)</strong>
<a href="old-blog/download/is07/zaliczeniowki/PUK.zip">Pobierz prezentacje</a>
Zaliczeniem z <a href="blog/2007-12-13-swieze-buleczki-jak-pisac-specyfikacje.html">najlepszego jak dotąd przedmiotu</a> z najlepszym jak dotąd prowadzącym :) była prezentacja multimedialna oraz specyfikacja projektu technicznego. Ta druga zaginęła gdzieś w czeluściach Internetu (była robiona grupowo na jakiejś Wiki u <a href="http://wizualno-werbalny.blogspot.com/">Asmodeusza</a> na serwerze). Na temat prezentacji multimedialnej wybrałem wstęp do programowania gier. Nie dane było mi jej jednak przedstawić publicznie :(.

<strong>Podstawy Informatyki (I semestr)</strong>
<a href="old-blog/download/is07/zaliczeniowki/PI.zip">Pobierz paczkę</a>
W ramach zaliczenia przedmiotu oddałem trzy programy. Pierwsze dwa - konwerter kodu Morse'a i baza danych na drzewie binarnym - nie są warte uwagi (może za wyjątkiem sztuczki zastosowanej w bazie, by ułatwić sobie kasowanie elementów z drzewa :D ). Trzecim programem jest wyjątkowo dopieszczony symulator <a href="http://pl.wikipedia.org/wiki/Gra_w_%C5%BCycie">gry w życie</a>. Opisy w Readme.

<strong>Analiza Danych i Probabilistyka (II semestr)</strong>
<a href="old-blog/download/is07/zaliczeniowki/skladowe.zip">Pobierz <abbr title="Principal Component Analysis">PCA</abbr></a>
Program ten ilustruje <a href="http://pl.wikipedia.org/wiki/Analiza_g%C5%82%C3%B3wnych_sk%C5%82adowych">problematykę analizy i redukcji głównych składowych</a>. Oddany w terminie zdobyłby lekką ręką 6.0, jednak z powodu spóźnienia ocena była niższa :(. Opis w Readme.

Na pierwszym roku stworzyłem jeszcze troszkę nie wartej publikacji drobnicy, która dała 6.0 i zwolnienie z języka C. Analogiczną ocenę i zwolnienie z C++'a dał framework Anything-A (retrofit <a href="projects.html#anything">Anything</a>) :).

Trwa drugi rok, do tej pory wrzuciłem już <a href="blog/2009-01-23-softimagexsi-i-kaczka-startujaca-z-tafli-lodu.html">jeden z projektów zaliczeniowych</a> i <a href="blog/2009-01-08-sprawozdanka.html">sporo</a> <a href="blog/2009-01-21-metody-numeryczne-zadania-dodatkowe.html">drobnicy</a>, która powstała w trakcie nauki. Z gotowych projektów może podrzucę za jakiś czas projekt zaliczeniowy z Programowania Obiektowego (gra w Javie). Ponadto, obecny - czwarty już - semestr zdaje się być wyjątkowo nasycony projektami; niewątpliwie nowych prac powstanie więcej :).
]]></description>
    </item>    <item>
      <title>Chronienie funkcji</title>
      <link>https://jacek.zlydach.pl/blog/2008-01-03-chronienie-funkcji.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2008-01-03-chronienie-funkcji.html</guid>
      <pubDate>Thu, 03 Jan 2008 13:17:45 +0100</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <description><![CDATA[Chronienie funkcji to ciekawe zastosowanie metody obsługi sytuacji wyjątkowych, dzięki któremu możemy w chwili wystąpienia błędu uzyskać dokładne informacje o miejscu awarii. Samą technikę podpatrzyłem dawno temu w publicznym kodzie gry <a href="http://en.wikipedia.org/wiki/Unreal_Tournament">Unreal Tournament</a>. Przykładowy komunikat błędu prezentuje poniższy screen:
<p style="text-align: center"><a href="old-blog/download/posts/guarding/guarding_mbox.png"><img src="old-blog/download/posts/guarding/guarding_mbox-200px.png" alt="Komunikat o błędzie pokazujący stos wywołań."></a></p>
Jak widać, komunikat zawiera historię wywołań funkcji, które doprowadziły do miejsca wystąpienia błędu (tak zwany call-stack).

Napiszmy dwa pomocnicze makra oraz przykład użycia
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#define GUARD(functionName) {static const char __GUARDED_FUNCTION_NAME__[] = #functionName; try{
</span><span class="special">#define UNGUARD } catch(...) { Framework-&gt;GetErrorManager()-&gt;AddCallHistory(__GUARDED_FUNCTION_NAME__); throw; } }
</span><span class="comment">//przyklad uzycia
</span><span class="symbol">void</span> funkcja_chroniona<span class="paren1">(<span class="no-paren-fx"></span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	GUARD<span class="paren2">(<span class="no-paren-fx">funkcja_chroniona</span>)</span>;
	<span class="comment">//jakies operacje
</span>	UNGUARD<span class="paren2">(<span class="no-paren-fx">funkcja_chroniona</span>)</span>;
</span>}</span></span></code></pre>
Makra te ujmują kod zawarty między nimi w blok try-catch. Kiedy chcemy zasygnalizować wystąpienie bardzo poważnego błędu, który powinien spowodować przerwanie działania programu, wówczas rzucamy wyjątek. W chwili złapania wyjątku w makrze UNGUARD, nazwa podana do makra GUARD zostaje zapisana w systemie obsługi błędów ( to proszę napisać sobie samemu ;) ), po czym wyjątek zostaje rzucony dalej. Jeśli zabezpieczymy w ten sposób wiele funkcji, to rzucony wyjątek przeleci przez nie wszystkie aż do miejsca, w którym zostanie obsłużony i zatrzymany. Takim miejscem może być np. pętla główna gry. Przykład:
<pre><code lang="C++"><span class="no-paren-fx"><span class="comment">//punkt obslugi, fragment jakiejs funkcji
</span><span class="comment">//...
</span><span class="symbol">try</span>
<span class="paren1">{<span class="no-paren-fx">
	EnterMainLoop<span class="paren2">(<span class="no-paren-fx"></span>)</span>;
</span>}</span>
<span class="symbol">catch</span><span class="paren1">(<span class="no-paren-fx">std::exception&amp; exc</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	errorSystem-&gt;DisplayException<span class="paren2">(<span class="no-paren-fx"><span class="string">&quot;STL exception&quot;</span>, exc.what<span class="paren3">(<span class="no-paren-fx"></span>)</span></span>)</span>;
</span>}</span>
<span class="symbol">catch</span><span class="paren1">(<span class="no-paren-fx">CMyException&amp; exc</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	errorSystem-&gt;DisplayException<span class="paren2">(<span class="no-paren-fx">exc.type<span class="paren3">(<span class="no-paren-fx"></span>)</span>, exc.what<span class="paren3">(<span class="no-paren-fx"></span>)</span></span>)</span>;
</span>}</span>
<span class="symbol">catch</span><span class="paren1">(<span class="no-paren-fx">...</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	errorSystem-&gt;DisplayException<span class="paren2">(<span class="no-paren-fx"><span class="string">&quot;Unknown exception&quot;</span>, <span class="string">&quot;Unknown error&quot;</span></span>)</span>;
</span>}</span>
<span class="comment">//...</span></span></code></pre>
Z metodą tą wiążą się też pewne niedogodności:
<ul>
	<li>Każdą chronioną funkcję / blok kodu trzeba zawierać w makrach GUARD/UNGUARD</li>
	<li>Blok try/catch powoduje zwiększenie czasu wykonania funkcji</li>
	<li>Utrudnione lub wręcz uniemożliwione jest używanie w kodzie wyjątków w celach innych niż obsługa błędów krytycznych, powodujących awaryjne zakończenie pracy programu</li>
</ul>
Równoważone są one jednak przez korzyść wynikającą ze znajomości dokładnej historii wywołań funkcji prowadzącej do miejsca wystąpienia błędu. Oczywiście makr tych nie stosujemy we wszystkich możliwych funkcjach; na przykład nie powinno się ich używać w prostych funkcjach wymagających bardzo dużej wydajności (np. iloczyn wektorowy).

Możliwe usprawnienia podanego przykładu:
<ul>
	<li>Zastosowanie dyrektyw #ifdef / #else / #endif do warunkowej kompilacji makr GUARD/UNGUARD, dzięki czemu można będzie je łatwo wyłączyć</li>
	<li>Stworzenie dodatkowej pary makr GUARD_SLOW i UNGUARD_SLOW, które będą automatycznie wyłączane w wersji wydaniowej (patrz punkt poprzedni), a które stosowane będą w funkcjach wymagających możliwie wysokiej wydajności</li>
	<li>Połączenie chronienia funkcji z własnymi makrami Assert/Verify, dzięki czemu przerywając pracę programu uzyskamy dokładne informacje o miejscu naruszenia asercji i drodze do tego miejsca. Własne makra Assert/Verify opiszę w przyszłości.</li>
	<li>Połączenie makra GUARD z loggerem, dzięki czemu nazwa funkcji będzie automatycznie dopisywana do komunikatu. Jest to duże udogodnienie, jeśli ktoś zapisuje nazwy funkcji do loga.</li>
	<li>Przerobienie makr, by system <a href="blog/2007-10-04-unicode-w-programowaniu-gier-podstawy.html">działał w oparciu o Unicode</a> (w przypadku kodu, który w całości jest oparty o to kodowanie znaków)</li>
</ul>
Osobiście z powodzeniem stosuje koncepcję chronienia funkcji w kodzie od dość długiego czasu. Zintegrowała się ona na stałe z silnikami i frameworkami, których pisania się podejmowałem. Z wymienionych wyżej usprawnień nie udało mi się jedynie połączyć chronienia funkcji z loggerem.
]]></description>
    </item>    <item>
      <title>Ciekawe kody numeryczne</title>
      <link>https://jacek.zlydach.pl/blog/2007-10-26-ciekawe-kody-numeryczne.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-10-26-ciekawe-kody-numeryczne.html</guid>
      <pubDate>Fri, 26 Oct 2007 05:27:20 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <description><![CDATA[Kilkanaście minut temu skończyłem pisanie nowego Settings Manager'a. Ale to temat na inny post ;). W tym wpisie chciałbym wspomnieć o ciekawych wartościach przypisywanych pamięci w systemie Windows w aplikacjach kompilowanych na VC++ w trybie Debug:

Najważniejszy z omawianych kodów, a zarazem posiadający praktyczne znaczenie to <strong>0xCDCDCDCD</strong>. Jeśli jeszcze nie miałeś styczności z tym kodem a programujesz pod Windows to go zapamiętaj. Stary Dobry VC++6.0 przypisywał mu termin <em>&quot;Expression cannot be evaluated&quot;</em> (<em>wyrażenie nie może zostać obliczone</em>). Ten kod jest bardzo charakterystyczny dla niezainicjowanych zmiennych (przypominam, mowa o trybie Debug; w trybie Release kompilator nie bawi się w takie ustawianie) dlatego jeśli w toku pracy programu wyłapiesz taki kod debuggerem to najprawdopodobniej znaczy, że gdzieś w kodzie do obliczeń został użyty niezainicjowany fragment pamięci.

Inne, bardziej wesołe kody, które <a href="http://www.nobugs.org/developer/win32/debug_crt_heap.html">udało mi się odnaleźć</a> to:
<ul>
	<li><strong>0xBAADFOOD</strong> - funkcja <a href="http://msdn2.microsoft.com/en-us/library/aa366597.aspx">HeapAlloc()</a> w taki sposób inicjuje alokowaną pamięć</li>
	<li><strong>0xFEEEFEEE</strong> - funkcja <a href="http://msdn2.microsoft.com/en-us/library/aa366701.aspx">HeapFree()</a> w taki sposób czyści zwolnioną pamięć</li>
	<li><strong>0xFDFDFDFD</strong> - w ten sposób malloc() oznacza cztery bajty przed i cztery bajty po przydzielonym bloku pamięci (służą jako 'strażnicy')</li>
	<li><strong>0xDDDDDDDD</strong> - funkcja free() tak oznacza zwolnioną pamięć</li>
</ul>
Przypominam, że powyższe kody obowiązują w systemie Windows przy kompilowaniu VC++ w trybie Debug ;). A skoro już przy kodach jestem, to warto też przypomnieć <a href="blog/2007-10-04-ujarzmic-access-violation.html">0xC0000005 - Access Violation</a> :).
]]></description>
    </item>    <item>
      <title>Profiler skończony!</title>
      <link>https://jacek.zlydach.pl/blog/2007-10-22-profiler-skonczony.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-10-22-profiler-skonczony.html</guid>
      <pubDate>Mon, 22 Oct 2007 00:16:40 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/profiler.html">profiler</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/anything.html">Anything</category>
      <description><![CDATA[Nareszcie, po ponad tygodniowej przerwie, zabrałem się za kod. Do napisania w planach miałem <a href="http://en.wikipedia.org/wiki/Profiler_%28computer_science%29">profiler</a>. Wczoraj powstał interfejs, dzisiaj implementacja. Jest to pierwszy profiler, jaki w życiu napisałem. Po wstępnych testach wszystko wskazuje na to, że działa całkiem poprawnie, ale - jak to zwykle bywa - wszystkie ewentualne niedoróbki ujawnią się w trakcie używania. Narzędzie, które napisałem zbiera następujące statystyki:
<ul>
	<li>Czas rzeczywisty trwania profilowanego bloku (w milisekundach)</li>
	<li>Ilość wywołań danego bloku w ciągu jednej klatki profilowania (np. w ciągu jednego obiegu pętli głównej)</li>
	<li>Procentowy czas trwania wszystkich wywołań bloku w danej klatce profilowania w stosunku do czasu trwania klatki</li>
</ul>Dla każdej z tych statystyk klient ma dostęp do minimalnej, maksymalnej, średniej i ostatnio zmierzonej wartości.

Profiler (jak każdy podsystem modernizowanego przeze mnie frameworka) składa się z dwóch oddzielonych elementów - interfejsu i implementacji. Implementacja jest stosunkowo prosta i na pewno mogłaby zostać napisana lepiej i wydajniej, niemniej jednak na razie wystarczy mi taka. Wspomniane rozdzielenie jej od interfejsu pozwoli na łatwą wymianę w przyszłości.

Z ciekawych elementów interfejsu profilera można wymienić interfejs iteratora, który służy do przeglądania zapisu historii pomiarów. Iterator ten pozwala klientom przechodzić przez historię nie znając jej wewnętrznej struktury. Zgodnie z opisanymi standardami iterator przechodzi ewentualną strukturę drzewiastą <a href="http://www.i-lo.tarnow.pl/edu/inf/utils/rozinf/images/ol020_06.gif">metodą preorder</a> oraz udostępnia informację o poziomie zagnieżdżenia, co pozwala reprezentować ją graficznie (np. wcięciami w tekście). Obecnie jednak implementacja działa na strukturze płaskiej :).

Co dalej? Zobaczymy :). Wypadałoby do najbliższej niedzieli zakończyć modernizacje framework'a.
]]></description>
    </item>    <item>
      <title>Unicode w programowaniu gier - podstawy</title>
      <link>https://jacek.zlydach.pl/blog/2007-10-04-unicode-w-programowaniu-gier-podstawy.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-10-04-unicode-w-programowaniu-gier-podstawy.html</guid>
      <pubDate>Thu, 04 Oct 2007 22:01:40 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/unicode.html">Unicode</category>
      <description><![CDATA[Właśnie skończyłem ulepszać framework nad którym pracuję do postaci wspierającej wewnętrznie <a href="http://pl.wikipedia.org/wiki/Unicode">Unicode</a>. W tej chwili framework kompiluje się i działa zarówno w trybie Unicode jak i ASCII. Była to momentami ciężka walka i bardzo dziękuję tutaj <a href="http://spax.gamedev.pl/">Spax'owi</a> za pomoc (z resztą to on mnie na Unicode nawrócił w pierwszej kolejności :) ). Dlatego chciałem podzielić się kilkoma doświadczeniami, które mogą przydać się początkującym w tej dziedzinie.

<strong>1. Nie mieszaj w projekcie różnych standardów kodowania.</strong> Ciężko potem nad tym zapanować. Dlatego od razu na początku warto zrobić sobie kilka typedef'ów, na przykład w taki sposób:
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#ifdef _UNICODE
</span><span class="symbol">typedef</span> <span class="symbol">wchar_t</span> achar;
<span class="symbol">typedef</span> std::wstring astring;
<span class="symbol">typedef</span> std::wstringstream astringstream;
<span class="symbol">typedef</span> boost::wformat aformat;
<span class="comment">//(...)
</span><span class="special">#else
</span><span class="symbol">typedef</span> <span class="symbol">char</span> achar;
<span class="symbol">typedef</span> std::string astring;
<span class="symbol">typedef</span> std::stringstream astringstream;
<span class="symbol">typedef</span> boost::format aformat;
<span class="special">#endif</span></span></code></pre>
I potem używać tych typedef'ów w całym kodzie. Ponieważ stałe znakowe / tekstowe w C++ należy poprzedzać literką L żeby oznaczyć, że są to wielobajtowe znaki, dlatego przydają się też makra:
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#ifdef _UNICODE
</span><span class="special">#define ATEXT(x) L##x
</span><span class="special">#else
</span><span class="special">#define ATEXT(x) x
</span><span class="special">#endif</span></span></code></pre>
Każdą pojawiającą się w kodzie stałą tekstową lub znakową zapisujemy z użyciem tego makra, np. ATEXT('a') albo ATEXT(&quot;Hello&quot;). WinAPI zapewnia makro TEXT, które w uproszczeniu wygląda podobnie, ale osobiście stosuję własne makro ATEXT, by oddzielić kod frameworka (w szczególności interfejsy i późniejszą logikę gry) od platformy.

<strong>2. Unikaj konwersji.</strong> Zamiana sposobu kodowania tekstu jest wolna i nierzadko skomplikowana, dlatego należy jak najbardziej jej unikać. Może się zdarzyć, że będziemy musieli korzystać z funkcji bibliotecznych języka C (takich jak printf, strcpy, _strdate). Funkcje te na szczęście mają swoje odpowiedniki dla Unikodu (np. wprintf, wcscpy, _wstrdate). Zamiast jednak używać jednej z tych rodzin i przygotowywać sobie konwerter ASCII/Unicode na nasze wewnętrzne stringi, lepiej jest stworzyć specjalne makrodefinicje, na przykład:
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#ifdef _UNICODE
</span><span class="special">#define astrdate _wstrdate
</span><span class="special">#define astrcpy wcscpy
</span><span class="comment">//(...)
</span><span class="special">#else
</span><span class="special">#define astrdate _strdate
</span><span class="special">#define astrcpy strcpy
</span><span class="comment">//(...)
</span><span class="special">#endif</span></span></code></pre>
Następnie w kodzie można już używać tych makr (astrcpy, astrdate). Zauważmy, że podobnie skonstruowane jest WinAPI, w którym praktycznie każda funkcja przyjmująca parametr tekstowy (np. MessageBox) to tak na prawdę makrodefinicja na funkcje przyjmujące tekst ASCII/Unicode (MessageBoxA, MessageBoxW), zależnie od ustawień kompilacji projektu.

<strong>3. Oddzielaj mocno interfejs od implementacji.</strong> Jest to ogólna rada inżynierii oprogramowania, która także tutaj ma znaczenie. Dobrze napisane elementy framework'a powinny komunikować się z innymi za pośrednictwem wewnętrznych reprezentacji stringów (np. nasze astring) zupełnie nie przejmując się ich typem, a wszelkie konwersje Unicode/ASCII należy ograniczać tylko do strony implementacji. W szczególności kod gry opartej na takim framework'u nie powinien w ogóle mieć do czynienia z konwersjami.

Wsparcie dla Unicode na różnych platformach jest wciąż skomplikowane, więc jeśli programiście zależy na przenośności kodu to musi zadbać, żeby zmian w kodzie związanym z konwersjami było jak najmniej, i żeby te zmiany były jak najbardziej wyizolowane.

<strong>4. Uważaj na pułapki przy wczytywaniu plików.</strong> Może się zdarzyć, że wczytywane pliki (np. konfiguracja gry) okażą się mieć kodowanie niezgodne z kodowaniem gry (np. pliki w ASCII podczas, gdy gra używa Unicode). Należy wtedy rozpoznać używane przez plik kodowanie i dokonać stosownej konwersji. Sprawa troszkę się komplikuje, gdy gra korzysta z formatów binarnych przechowujących w swej strukturze tekst (na przykład w implementacji <abbr title="Virtual File System">VFS</abbr>). Warto zachować szczególną ostrożność w tych miejscach.

<strong>Na zakończenie</strong> chciałbym tylko wskazać osobom korzystającym z VC++ 2005 Express (w nowych IDE Visual C++ powinno być podobnie), w którym miejscu można włączyć/wyłączyć obsługę Unicode w projekcie. Wybieramy menu <strong>Project-&gt;[nazwa projektu] Properties </strong>(albo wciskamy <strong>ALT+F7</strong>). Tam z lewej strony rozwijamy <strong>Configuration Properties</strong> i klikamy na gałęzi <strong>General</strong>. Z prawej strony pod <strong>Project Defaults</strong> znajdujemy opcję <strong>Character Set</strong>. Może ona przyjmować następujące wartości: <strong>Not Set</strong> - projekt korzysta z kodowania ASCII, <strong>Use Unicode Character Set</strong> - projekt korzysta z Unicode, <strong>Use Multi-Byte Character Set</strong> - projekt korzysta z kodowania multibajtowego (to kodowanie to już osobny temat).

Mam nadzieję, że te kilka rad pomoże osobom, które zastanawiają się nad zapewnieniem wsparcia dla Unicode w swoich projektach. Polecam też zapoznać się z <a href="http://wiki.gamedev.pl/%C5%81a%C5%84cuchy_w_CPP">tekstem na Warsztatowym Wiki</a> dotyczącym łańcuchów znakowych w C++, w tym m.in. Unikodowych.
]]></description>
    </item>    <item>
      <title>Ujarzmić Access Violation</title>
      <link>https://jacek.zlydach.pl/blog/2007-10-04-ujarzmic-access-violation.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-10-04-ujarzmic-access-violation.html</guid>
      <pubDate>Thu, 04 Oct 2007 06:23:35 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/windows.html">Windows</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/access-violation.html">Access Violation</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/seh.html">SEH</category>
      <description><![CDATA[<strong>0xC0000005</strong> - ten numer jest zapewne bardzo znany większości osób zajmujących się programowaniem gier, czy tworzeniem pod Windows w ogóle. To oczywiście kod naruszenia dostępu (ang. <em>access violation</em>), występujący gdy odwołujemy się do pamięci, do której nie mamy prawa. Zazwyczaj oznacza to wysypanie aplikacji z znienawidzonym przez użytkowników komunikatem &quot;Program wykonał nieprawidłową operację&quot;. Jest jednak na to metoda.

Mowa oczywiście o <a href="http://en.wikipedia.org/wiki/Exception_handling">Structured Exception Handling</a> (<a href="http://msdn2.microsoft.com/en-us/library/ms680657.aspx">[1]</a>) Microsoftu, czyli próbie wprowadzenia przez firmę z Redmond wyjątków do języka C. SEH pozwala obsługiwać nie tylko wyjątki generowane przez programistów, ale także wyjątki systemu, takie jak wspomniane naruszenie dostępu oraz inne powodujące wysyp aplikacji.

Nie będę dziś wchodził w szczegóły zaawansowanego używania SEH; chciałbym tu podzielić się kawałkiem kodu, który pokazał mi niegdyś <strong>st3tc</strong>, a którego od tego czasu używam w swoich produkcjach. Wklejam go w takiej postaci, w jakiej używałem ostatnio
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#ifdef ANYTHING_USE_SEH
</span>
<span class="special">#pragma comment (lib, &quot;Dbghelp.lib&quot;)
</span>
<span class="special">#include &lt;dbghelp.h&gt;
</span><span class="special">#include &lt;shellapi.h&gt;
</span><span class="special">#include &lt;shlobj.h&gt;
</span>
<span class="special">#endif //ANYTHING_USE_SEH
</span>
<span class="symbol">namespace</span> Anything
<span class="paren1">{<span class="no-paren-fx">
	<span class="symbol">int</span> GameMain<span class="paren2">(<span class="no-paren-fx">HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, <span class="symbol">int</span> nShowCmd</span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
		<span class="paren3">(<span class="no-paren-fx">...</span>)</span>
	</span>}</span>
</span>}</span> <span class="comment">//end of namespace Anything
</span>
<span class="special">#ifdef ANYTHING_USE_SEH
</span>
<span class="comment">//SEH stuff...
</span><span class="comment">//credit to st3tc for showing me this idea
</span><span class="symbol">int</span> GenerateDump<span class="paren1">(<span class="no-paren-fx">EXCEPTION_POINTERS* pExceptionPointers</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	MINIDUMP_EXCEPTION_INFORMATION ExpParam;
	SYSTEMTIME stLocalTime;
	HANDLE hDumpFile;
	<span class="symbol">char</span> szFileName<span class="paren2">[<span class="no-paren-fx">MAX_PATH</span>]</span>;

	GetLocalTime<span class="paren2">(<span class="no-paren-fx"> &amp;stLocalTime </span>)</span>;
	std::sprintf<span class="paren2">(<span class="no-paren-fx"> szFileName, <span class="string">&quot;CrashDump-%04d%02d%02d-%02d%02d%02d.dmp&quot;</span>,
	stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
	stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond </span>)</span>;

	hDumpFile = CreateFile<span class="paren2">(<span class="no-paren-fx"> szFileName, GENERIC_READ|GENERIC_WRITE,
	FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0</span>)</span>;

	ExpParam.ThreadId = GetCurrentThreadId<span class="paren2">(<span class="no-paren-fx"></span>)</span>;
	ExpParam.ExceptionPointers = pExceptionPointers;
	ExpParam.ClientPointers = TRUE;

	MiniDumpWriteDump<span class="paren2">(<span class="no-paren-fx">GetCurrentProcess<span class="paren3">(<span class="no-paren-fx"></span>)</span>, GetCurrentProcessId<span class="paren3">(<span class="no-paren-fx"></span>)</span>, hDumpFile, MiniDumpNormal, &amp;ExpParam, NULL, NULL</span>)</span>;
	<span class="symbol">return</span> EXCEPTION_EXECUTE_HANDLER;
</span>}</span>

<span class="symbol">int</span> WINAPI WinMain<span class="paren1">(<span class="no-paren-fx">HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, <span class="symbol">int</span> nShowCmd</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	__try
	<span class="paren2">{<span class="no-paren-fx">
		<span class="symbol">int</span> retCode = Anything::GameMain<span class="paren3">(<span class="no-paren-fx">hInstance, hPrevInstance, lpCmdLine, nShowCmd</span>)</span>;
		<span class="symbol">return</span> retCode;
	</span>}</span>
	__except<span class="paren2">(<span class="no-paren-fx">GenerateDump<span class="paren3">(<span class="no-paren-fx">GetExceptionInformation<span class="paren4">(<span class="no-paren-fx"></span>)</span></span>)</span></span>)</span>
	<span class="paren2">{<span class="no-paren-fx">
	</span>}</span>
	<span class="symbol">return</span> 0;
</span>}</span>

<span class="special">#else
</span>
<span class="symbol">int</span> WINAPI WinMain<span class="paren1">(<span class="no-paren-fx">HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, <span class="symbol">int</span> nShowCmd</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
	<span class="symbol">return</span> Anything::GameMain<span class="paren2">(<span class="no-paren-fx">hInstance, hPrevInstance, lpCmdLine, nShowCmd</span>)</span>;
</span>}</span>

<span class="special">#endif //ANYTHING_USE_SEH</span></span></code></pre>
<em>(codebox się troszkę popsuł, aby przeczytać niektóre linie niestety trzeba użyć paska przewijania u dołu)</em>
Jest to połączenie użycia SEH z biblioteką <a href="http://www.dll-files.com/dllindex/dll-files.shtml?dbghelp">dbghelp.dll</a>. Ten kod powoduje, że w momencie wystąpienia krytycznego wyjątku systemu, takiego jak <em>Access Violation</em>, program grzecznie się zamyka, generując przy okazji tzw. plik zrzutu (ang. <em>dump file</em>). Ten plik możemy wczytać do debuggera by zobaczyć stan aplikacji (np. rejestry procesora) z chwili wystąpienia wyjątku. Dzięki temu końcowy użytkownik, który napotka tego typu błąd, może wysłać nam ten plik zrzutu (najlepiej razem z logiem z wykonania;) ) a my będziemy mieli dodatkowe ważne informacje pozwalające ustalić jego przyczynę.
Warto w tym kodzie zwrócić uwagę, że ciało funkcji <em>WinMain()</em> zostało przeniesione do wewnątrz funkcji <em>Anything::GameMain()</em>. Jest to spowodowane tym, że SEH jest systemem dołączonym do języka C i nie życzy sobie używania kodu zorientowanego obiektowo bezpośrednio w funkcji, w której użyto bloków<em> __try</em>/<em>__except</em> (konkretnie to problem tworzą destruktory klas w C++, które wymagają tzw. odwikłania stosu).

Oczywiście SEH to dużo potężniejsze narzędzie. Dobrym przykładem jego zastosowania jest <a href="http://www.3ddownloads.com/?file_id=159652">kod gry FreeSpace II</a>, który w przypadku wystąpienia wyjątku systemowego generuje obszernego MessageBox'a z wyświetleniem typu i nazwy błędu oraz rejestru procesora, po czym zapisuje te dane razem ze zrzutem stosu do pliku tekstowego. Te i inne pomysły pozostawiam jako ćwiczenie dla Czytelnika. Polecam też <a href="http://www.howzatt.demon.co.uk/articles/oct04.html">artykuł</a> opisujący jak przy użyciu SEH uzyskać w C++ stos wywołań w chwili błędu.
]]></description>
    </item>    <item>
      <title>Oddam projekt w dobre ręce ;)</title>
      <link>https://jacek.zlydach.pl/blog/2007-09-23-oddam-projekt-w-dobre-rece.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-09-23-oddam-projekt-w-dobre-rece.html</guid>
      <pubDate>Sun, 23 Sep 2007 21:23:42 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/projektowanie.html">projektowanie</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/starcraft.html">StarCraft</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/scgame.html">SCGame</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/holodeck2d.html">Holodeck2D</category>
      <description><![CDATA[Po długim przemyśleniu sprawy postanowiłem porzucić plany realizacji pewnego projektu, w którego rozwój zainwestowałem już sporo czasu i sił. Chodzi mianowicie o grę <strong>StarCraft: A Platform Game</strong>. Pomysł ten kręci się koło mnie już ponad dwa lata. Niektórzy zapewne widzieli starą <a href="http://www.sc-game.prv.pl">stronę tej gry</a>. Od tego czasu do SC:APG podszedłem drugi raz, tym razem z dokładniejszym dokumentem technicznym.

Z pewnych powodów nie zamierzam jednak skończyć tej gry. Dlatego postanawiam opublikować wszystkie związane z nią materiały, głównie w celach edukacyjnych. Jeśli jednak jest ktoś zainteresowany podchwyceniem pomysłu i zrealizowaniem go na własną rękę (nawet jeśli miałby wyglądać zupełnie inaczej niż w moich wyobrażeniach), to ma moje błogosławieństwo i może liczyć na konsultacje :).

Oto materiały:
<a href="old-blog/download/projects/SCGame/SCGame.rar">Kod źródłowy silnika z pierwszego podejścia</a>
(kodu źródłowego z drugiego podejścia szukać w projekcie <a href="projects.html#holodeck-2d-engine">H2D</a>)
<a href="random/varia/dd/SCDesign.pdf">Design Doc gry z 2005 roku</a>
<a href="random/varia/dd/SCTech.pdf">Tech Doc gry z 2006 roku</a>
(oba te dokumenty mam wydrukowane i zbindowane razem ;) )
]]></description>
    </item>    <item>
      <title>std::numeric_limits&lt;T&gt;</title>
      <link>https://jacek.zlydach.pl/blog/2007-07-03-stdnumeric_limitst.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-07-03-stdnumeric_limitst.html</guid>
      <pubDate>Tue, 03 Jul 2007 22:52:39 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/numeric-limits.html">numeric_limits</category>
      <description><![CDATA[Pragnę napisać kilka zdań na temat elementu Biblioteki Standardowej C++, który wydaje się być zapomnianym lub nieznanym przez wielu koderów. Mam oczywiście na myśli nagłówek <code lang="C++" inline="true" escaped="true"><span class="no-paren-fx">&lt;limits&gt;</span></code> zawierający klasy rodziny <code lang="C++" inline="true" escaped="true"><span class="no-paren-fx">std::numeric_limits&lt;&gt;</span></code>. Klasy te służą do reprezentacji różnych informacji typów <a href="http://pl.wikipedia.org/wiki/Wielko%C5%9B%C4%87_skalarna">skalarnych</a>. Uzyskujemy z nich wiedzę na temat ograniczeń i cech różnych typów liczbowych. Przykłady:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">if</span><span class="paren1">(<span class="no-paren-fx"> uZmienna&lt; std::numeric_limits&lt;<span class="symbol">signed</span> <span class="symbol">int</span>&gt;::max<span class="paren2">(<span class="no-paren-fx"></span>)</span> </span>)</span>
<span class="comment">//przekroczono maksymalna wartosc int'a
</span><span class="comment">//uZmienna ma typ unsigned int
</span>
<span class="symbol">if</span><span class="paren1">(<span class="no-paren-fx"> fDistance - fRadius &lt; std::numeric_limits&lt;<span class="symbol">float</span>&gt;::epsilon<span class="paren2">(<span class="no-paren-fx"></span>)</span> </span>)</span>
<span class="comment">//fDistance i fRadius sa typu float
</span><span class="comment">//przykladowy kod mogacy pochodzic z niezbyt zoptymalizowanego
</span><span class="comment">//sprawdzania kolizji sferami otaczajacymi</span></span></code></pre>
Oczywiście <em>numeric_limits</em> dają nam więcej informacji niż maksymalna wartość i tzw. epsilon (różnica między 1.0 i najmniejszą wartością większą od 1.0, którą da się zapisać danym typem zmiennoprzecinkowym). Dowiemy się m.in. jak reprezentowana jest wartość nieskończoności i błędu NaN (Not a Number) (te wartości <a href="http://regedit.gamedev.pl/news_964.html">nie są takie straszne</a>), jakie są błędy zaokrąglania, itd. Nie będę tu omawiał tej biblioteki; zachęcam do zapoznania się z <a href="http://wwwasd.web.cern.ch/wwwasd/lhc++/RW/stdlibcr/num_5679.htm">opisującym ją dokumentem</a>.

Mam więc nadzieję, że następnym razem, gdy Twój kolega zada Ci pytanie &quot;jaka jest największa wartość, jaką można zapisać w zmiennej typu <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">int</span></span></code>&quot;, odpowiesz:
<code lang="C++" escaped="true" inline="true"><span class="no-paren-fx">std::numeric_limits&lt;<span class="symbol">signed</span> <span class="symbol">int</span>&gt;::max<span class="paren1">(<span class="no-paren-fx"></span>)</span>;</span></code>
]]></description>
    </item>    <item>
      <title>Logger - wariacje na temat wyjść</title>
      <link>https://jacek.zlydach.pl/blog/2007-07-03-logger-wariacje-na-temat-wyjsc.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-07-03-logger-wariacje-na-temat-wyjsc.html</guid>
      <pubDate>Tue, 03 Jul 2007 09:22:04 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/windows.html">Windows</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/projektowanie.html">projektowanie</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/logger.html">Logger</category>
      <description><![CDATA[Tekstem tym zaczynam krótką serię rozszerzającą temat loggerów. Temat ten rozwinięty został kiedyś w <a href="http://www.gamedev.pl/articles.php?x=view&amp;id=174">artykule o loggerach</a> na <a href="http://gamedev.pl">Warsztacie</a> i nie chcę powtarzać zamieszczonych tam informacji, dlatego zachęcam Cię, Czytelniku, byś się z nim zapoznał zanim zaczniesz czytać dalej. A w dzisiejszym odcinku porozmawiamy na temat różnych wyjść dla komunikatów loggera.

<strong>Rodzaje wyjść</strong>
Wymieńmy kilka rodzajów wyjść, które możemy chcieć uwzględnić pisząc swój system logowania:
<ul>
	<li><strong>Wyjście tekstowe</strong> - najważniejsze i najczęściej stosowane. Bezpośredni zapis komunikatów do pliku tekstowego, z ewentualnym niewielkim formatowaniem.</li>
	<li><strong>XHTML</strong> - zapis do pliku <a href="http://pl.wikipedia.org/wiki/XHTML">XHTML</a> jest niewiele bardziej skomplikowany od wyjścia tekstowego - musi tylko ujmować komunikaty w odpowiednie tagi formatujące. Ta metoda pozwala nam na wizualne wyróżnianie komunikatów (np. zaznaczenie komunikatów o błędzie na czerwono). W połączeniu z <a href="http://pl.wikipedia.org/wiki/Kaskadowe_arkusze_styl%C3%B3w">arkuszami CSS</a> log w tym formacie może się okazać bardzo przyjazny dla odczytującego, oraz nadawać się do natychmiastowego wrzucenia na stronę internetową.</li>
	<li><strong>XML</strong> - zapis w <a href="http://pl.wikipedia.org/wiki/XML">XML</a>'u jest bardzo podobny do zapisu w XHTML, jednak pozwala programiście na wygodne zapisanie wszystkich informacji o komunikacie w postaci tagów XML. Tak stworzony plik może być zarówno odczytywany, jak i parsowany przez inne programy. Na <a href="http://www.gamedev.net">GameDev.net</a> można znaleźć <a href="http://www.gamedev.net/reference/articles/article2253.asp">wart przeczytania artykuł</a>, który prezentuje możliwości zapisu w XML.</li>
	<li><strong>RTF</strong> - jest to ciekawy format zapisu, zaproponowany i omówiony w <a href="http://www.gamedev.net/reference/articles/article2084.asp">ciekawym artykule</a> na GameDev.net. Oferuje on funkcjonalność podobną do plików XHTML.</li>
	<li><strong>OutputDebugString()</strong> - w systemie Windows mamy do dyspozycji funkcję <a href="http://msdn2.microsoft.com/en-us/library/aa363362.aspx"><em>OutputDebugString()</em></a>, która wypisuje podany jej jako argument tekst do okna <a href="http://pl.wikipedia.org/wiki/Debuger">debuggera</a> (jeśli ten jest włączony). Posiadanie takiego wyjścia warto rozważyć, jeśli korzystamy z debuggera w czasie tworzenia naszej aplikacji. Jako ciekawostkę polecam <a href="http://www.codeproject.com/vcpp/stl/ge_trace.asp">artykuł z CodeProject.com</a>, w którym autor prezentuje klasę strumienia podobną do std::ostream korzystającą z <em>OutputDebugString()</em></li>
	<li><strong>Konsola Windows</strong> - wspomniana już w artykule, do którego przeczytania zachęcałem na początku. To szczególne wyjście pozwala nam śledzić komunikaty o błędach w czasie rzeczywistym. System Windows pozwala też na łatwą <a href="http://msdn2.microsoft.com/en-us/library/ms686047.aspx">zmianę kolorów</a> wypisywanego tekstu, co dobrze współpracuje z komunikatami loggera o różnych priorytetach. Konsola Windows, gdy jest wyświetlana, ma jednak zabójczy wpływ na framerate (jeśli będzie zainteresowanie, to rozszerzę ten temat). Temat używania konsoli jest szerszy i osobiście zachęcam zapoznanie się z artykułem <a href="http://regedit.gamedev.pl">Regedita</a> pod tytułem <a href="http://regedit.gamedev.pl/produkcje/artykuly/AsynchronicznaKonsola.php5"><em>&quot;Asynchroniczna konsola Windows&quot;</em></a>.</li>
	<li><strong>Dziennik zdarzeń Windows</strong> - ten rodzaj wyjścia może być mało przydatny w grach, ale warto wspomnieć o jego istnieniu. Systemy Windows z rodziny NT prowadzą tak zwany dziennik zdarzeń, w którym logują ważne zdarzenia w systemie. <a href="http://support.microsoft.com/kb/308427">Odczytać ten dziennik</a> można przez narzędzie MMC. Temat sposobów zapisu do tego dziennika pozostawię Czytelnikowi do zbadania samodzielnie; podpowiem jedynie funkcję <a href="http://msdn2.microsoft.com/En-US/library/aa363679.aspx"><em>ReportEvent()</em></a> (choć jeśli będzie zainteresowanie, to i o tym mogę tu napisać szerzej).</li>
	<li><strong>Wyjście w sieć</strong> - jeśli &quot;po drugiej stronie&quot; mamy uruchomiony odpowiedni program, to możemy stworzyć połączenie komunikaty loggera wysyłać przez sieć - czy to w obrębie lokalnej maszyny, czy to przez Internet. Zdalne debugowanie aplikacji to kolejny szeroki temat do omówienia; sygnalizuję teraz jedynie jego istnienie.</li>
</ul>
<strong>Ikonki?</strong>
Na ciekawy pomysł wpadł Steel_Eagle, który w swojej <a href="http://forum.gamedev.pl/index.php/topic,1601.msg20822.html#msg20822">wypowiedzi na forum Warsztatu</a> wspomniał o używaniu kolorowych ikonek do oznaczania ważności komunikatów loggera. Ta koncepcja jest godna uwagi przy wyjściach do formatów XHTML i XML, gdyż może znacząco zwiększyć czytelność i uprzyjemnić korzystanie z loga.

<strong>Formatowanie komunikatów</strong>
Zastanawiasz się być może teraz, czy wszystkie te rodzaje wyjść trzeba zapisać w programie? Czy jest sens, żeby program wypluwał z siebie tyle różnych logów o tej samej treści? Powiem szczerze, że... nie. Nie byłoby to nawet rozsądne. Osobiście proponuję przemyśleć sposób, w jaki formatujemy komunikaty wyjściowe dla pliku tekstowego. Odwołując się do wielowyjściowego loggera omówionego w artykule polecanym na początku tego wpisu, polecam taki rodzaj formatu:
<pre><code>[TYP KOMUNIKATU] [CZAS] Klasa::Funkcja() - komunikat</code></pre>
Na przykład:
<pre><code>[S] [10:15:51] CTexture::Load() - loaded texture textures/font.tga - width: 512, height: 512, bpp: 32.</code></pre>
Typem komunikatu może być jedna literka, np. E - błąd, F - błąd fatalny, I - informacja, S - sukces, itd. Poza wartością estetyczną, taki zapis daje nam jedną bardzo dużą korzyść - plik tekstowy loga ma ustalony format. Pozwala nam to napisać prosty programik albo skrypt (na przykład w <a href="http://pl.wikipedia.org/wiki/Perl">Perlu</a>), który przeczyta nasz tekstowy log (zawierający przecież wszystkie informacje o komunikatach) i wygeneruje z niego logi w XHTML, XML, RTF i w czym tam jeszcze nie będziemy chcieli. W ten sposób zachowamy wygodę w czytaniu loga, a jednocześnie uprościmy program oraz życie osób, które logi będą nam wysyłać - wystarczy, że prześlą nam plik tekstowy.

<strong>Zaproszenie do dyskusji</strong>
Tyle na dzisiaj; w następnym odcinku wejdziemy głębiej w temat zapisywania komunikatów w loggerze wewnątrz programu. Na pewno masz, Czytelniku, jakieś przemyślenia dotyczące przedstawionej tu treści. Zachęcam do podzielenia się i podyskutowania na temat wyjść w loggerach.
]]></description>
    </item>    <item>
      <title>Gosie w kodzie</title>
      <link>https://jacek.zlydach.pl/blog/2007-06-28-gosie-w-kodzie.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-06-28-gosie-w-kodzie.html</guid>
      <pubDate>Thu, 28 Jun 2007 23:34:52 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/humor.html">Humor</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/v-lo.html">V-LO</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/gosia-andrzejewicz.html">Gosia Andrzejewicz</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/oi.html">OI</category>
      <description><![CDATA[W ramach humorystycznego akcentu postanowiłem opublikować na devBlog'u swoje produkcje z <a href="http://www.oi.edu.pl">XIV OI</a>.

<strong>Pierwszy etap</strong>
<ul>
	<li><a href="old-blog/download/projects/XIVOI/drz.cpp">Drzewa</a>, alias <a href="http://darus.wrzuta.pl/audio/e9B0Ze9PoZ/05.gosia_andrzejewicz_-_trudny_wybor">&quot;Trudny Wybór&quot;</a></li>
	<li><a href="old-blog/download/projects/XIVOI/osi.cpp">Osie Symetrii</a>, alias <a href="http://dixi20.wrzuta.pl/audio/mawX4kaJSN/niesmialy_chlopak">&quot;Nieśmiały Chłopak 98bpm&quot;</a>, znane popularnie pod nazwą &quot;GOsie&quot;</li>
</ul>
<strong>Drugi etap</strong>
<ul>
	<li><a href="old-blog/download/projects/XIVOI/meg.cpp">Megalopolis</a>, alias <a href="http://mp3.wp.pl/p/strefa/sciagnij/118212.mp3">&quot;Słowa&quot;</a></li>
</ul>
Zaznaczam, że kod był pisany 'w locie', nie podmieniałem nazw już po napisaniu. Zachęcam do <strong>wnikliwej</strong> lektury na poprawę samopoczucia :).
]]></description>
    </item>    <item>
      <title>Naprawianie Microsoft Speech API (SAPI)</title>
      <link>https://jacek.zlydach.pl/blog/2007-06-25-naprawianie-microsoft-speech-api-sapi.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-06-25-naprawianie-microsoft-speech-api-sapi.html</guid>
      <pubDate>Mon, 25 Jun 2007 00:02:41 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/windows.html">Windows</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/sapi.html">SAPI</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/sterowanie-glosem.html">sterowanie głosem</category>
      <description><![CDATA[Z przyczyn... życiowych zaniedbałem ostatnio devblog, ale już to nadrabiam. W dzisiejszym odcinku dowiemy się, jak naprawić Microsoft Speech API pod platformą MSVC++ 2005 Express i PlatformSDK.

Instalacja <abbr title="Speech API">SAPI</abbr> jest prosta i sprowadza się do standardowych kroków: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5E86EC97-40A7-453F-B0EE-6583171B4530&amp;displaylang=en">ściągnij bibliotekę</a>, zainstaluj, ustaw katalogi include i lib w Visualu. Potem można spróbować skompilować jakiś przykład... i tu pojawiają się schody. Speech API w wersji 5.1 było pisane bardzo dawno temu, z ewidentnym brakiem dobrego stylu programowania. Dlatego na nowych Visualach, które są bardzo restrykcyjne, kod się po prostu nie skompiluje z powodu ewidentnych błędów programistycznych w samej bibliotece (które najwyraźniej uchodziły kiedyś jako tzw. skróty myślowe). Ale my się tym nie zrazimy i zaraz Speech API naprawimy ;)

Zacząć należy od dodania podkatalogu <em>atl/</em> w katalogu <em>include/</em> Platform SDK do ścieżek Visuala - plik <em>sphelper.h </em>dołącza nagłówek <em>atlbase.h</em>. A teraz zaczyna się zabawa w hacking SAPI.
Otwieramy plik <em>sphelper.h</em> (główny bohater dzisiejszych zmagań) i <strong>znajdujemy poniższą linię kodu</strong> (u mnie 769):
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">const</span> ulLenVendorPreferred = wcslen<span class="paren1">(<span class="no-paren-fx">pszVendorPreferred</span>)</span>;</span></code></pre><strong>I zamieniamy ją na</strong>
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">const</span> size_t ulLenVendorPreferred = wcslen<span class="paren1">(<span class="no-paren-fx">pszVendorPreferred</span>)</span>;</span></code></pre>Zamiast <em>size_t</em> możemy tez wpisać <em>unsigned long</em> - zależy to od tego, czy bardziej trzymamy się typu zwracanego funkcji <em>wcslen()</em> czy notacji węgierskiej użytej przy nazywaniu zmiennej <em>ulLenVendorPreferred</em> - w praktyce oba typy to i tak to samo.
Kolejny hack to <strong>znalezienie linii o poniższej treści</strong> (u mnie 1418):
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">static</span> CoMemCopyWFEX<span class="paren1">(<span class="no-paren-fx"><span class="symbol">const</span> WAVEFORMATEX * pSrc, WAVEFORMATEX ** ppCoMemWFEX</span>)</span></span></code></pre><strong>i zamiana na</strong>
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">static</span> HRESULT CoMemCopyWFEX<span class="paren1">(<span class="no-paren-fx"><span class="symbol">const</span> WAVEFORMATEX * pSrc, WAVEFORMATEX ** ppCoMemWFEX</span>)</span></span></code></pre>Następnie <strong>odnajdujemy poniższy fragment</strong> (u mnie linia 2372 i 2373):
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">for</span> <span class="paren1">(<span class="no-paren-fx"><span class="symbol">const</span> WCHAR * psz = <span class="paren2">(<span class="no-paren-fx"><span class="symbol">const</span> WCHAR *</span>)</span>lParam; *psz; psz++</span>)</span> <span class="paren1">{<span class="no-paren-fx"></span>}</span>
<span class="symbol">return</span> psz + 1;</span></code></pre>i <strong>przebudowujemy tą pętlę do następującej postaci</strong>:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">const</span> WCHAR * psz = <span class="paren1">(<span class="no-paren-fx"><span class="symbol">const</span> WCHAR *</span>)</span>lParam;
<span class="symbol">for</span> <span class="paren1">(<span class="no-paren-fx">; *psz; psz++</span>)</span> <span class="paren1">{<span class="no-paren-fx"></span>}</span>
<span class="symbol">return</span> psz + 1;</span></code></pre><ins datetime="2007-06-25T08:03:10+00:00">(Dodałem jeszcze jedną linię kodu w obu fragmentach dla uwidocznienia przyczyny błędu)</ins>
Ewidentny przykład tego, jak stare kompilatory Microsoftu obsługiwały zmienne w pętli for niezgodnie ze standardem.
Ale prawdziwa zabawa dopiero się zaczyna; kolejne dwa błędy zmuszają nas do sięgnięcia po narzędzie zwane <em>absolute_cast</em>, o którym możemy <a href="http://regedit.gamedev.pl/produkcje/artykuly/rzutowanie_typow_w_cpp.php5">przeczytać u Regedita</a>. Dlatego na początku nagłówka (zaraz pod include'ami) dodajemy następujący kod:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">template</span> &lt;<span class="symbol">typename</span> destT, <span class="symbol">typename</span> srcT&gt;
destT &amp; absolute_cast<span class="paren1">(<span class="no-paren-fx">srcT &amp;v</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
  <span class="symbol">return</span> <span class="symbol">reinterpret_cast</span>&lt;destT&amp;&gt;<span class="paren2">(<span class="no-paren-fx">v</span>)</span>;
</span>}</span>

<span class="symbol">template</span> &lt;<span class="symbol">typename</span> destT, <span class="symbol">typename</span> srcT&gt;
<span class="symbol">const</span> destT &amp; absolute_cast<span class="paren1">(<span class="no-paren-fx"><span class="symbol">const</span> srcT &amp;v</span>)</span>
<span class="paren1">{<span class="no-paren-fx">
  <span class="symbol">return</span> <span class="symbol">reinterpret_cast</span>&lt;<span class="symbol">const</span> destT&amp;&gt;<span class="paren2">(<span class="no-paren-fx">v</span>)</span>;
</span>}</span></span></code></pre><strong>Odnajdujemy linię</strong> (u mnie 2560 PRZED dodaniem absolute_cast do kodu):
<pre><code lang="C++"><span class="no-paren-fx">SPPHONEID* pphoneId = dsPhoneId;</span></code></pre>i <strong>zamieniamy na</strong>
<pre><code lang="C++"><span class="no-paren-fx">SPPHONEID* pphoneId = absolute_cast&lt;SPPHONEID*&gt;<span class="paren1">(<span class="no-paren-fx">dsPhoneId</span>)</span>;</span></code></pre>Następnie <strong>odnajdujemy linię</strong> (u mnie 2634, jw.):
<pre><code lang="C++"><span class="no-paren-fx">pphoneId += wcslen<span class="paren1">(<span class="no-paren-fx">pphoneId</span>)</span> + 1;</span></code></pre>i <strong>w jej miejsce wstawiamy</strong>:
<pre><code lang="C++"><span class="no-paren-fx">pphoneId += wcslen<span class="paren1">(<span class="no-paren-fx">absolute_cast&lt;<span class="symbol">wchar_t</span> *&gt;<span class="paren2">(<span class="no-paren-fx">pphoneId</span>)</span> </span>)</span> + 1;</span></code></pre>Od tej pory programy SAPI powinny ładnie przechodzić fazę kompilacji. Kto jednak spróbuje zbudować przykładowe programy może się zdziwić, że pojawia się błąd linkowania. Otóż wspomniany na początku opowieści nagłówek <em>atlbase.h</em> zawiera odwołania do biblioteki <em>atlthunk.lib</em>, której typowy użytkownik VC++ 2005 Express nie posiada. Żeby się pozbyć tego błędu, musimy zhack'ować nagłówek <em>atlbase.h</em>. Metoda ta została <a href="http://www.codeproject.com/wtl/WTLExpress.asp">opisana na CodeProject.com</a>. <strong>Odnajdujemy poniższy fragment</strong>
<pre><code lang="C++"><span class="no-paren-fx">PVOID __stdcall __AllocStdCallThunk<span class="paren1">(<span class="no-paren-fx">VOID</span>)</span>;
VOID  __stdcall __FreeStdCallThunk<span class="paren1">(<span class="no-paren-fx">PVOID</span>)</span>;

<span class="special">#define AllocStdCallThunk() __AllocStdCallThunk()
</span><span class="special">#define FreeStdCallThunk(p) __FreeStdCallThunk(p)
</span>
<span class="special">#pragma comment(lib, &quot;atlthunk.lib&quot;)</span></span></code></pre>I <strong>umieszczamy go w komentarzu</strong>. Tuż pod nim <strong>umieszczamy następujący kod</strong>:
<pre><code lang="C++"><span class="no-paren-fx"><span class="special">#define AllocStdCallThunk() HeapAlloc(GetProcessHeap(), 0, sizeof(_stdcallthunk))
</span><span class="special">#define FreeStdCallThunk(p) HeapFree(GetProcessHeap(), 0, p)</span></span></code></pre>W ten sposób pozbyliśmy się odwołań do biblioteki <em>atlthunk.lib</em> zapewniając przy okazji alternatywną definicję dla funkcji z tej biblioteki, których używa nagłówek <em>atlbase.h</em>.

Warto wyciągnąć przy tej okazji naukę - dbajmy o to, jak piszemy kod. Nie stosujmy niezgodnych ze standardem skrótów myślowych, nie pomijajmy typów zwracanych, nie stosujmy w taki sposób niejawnych rzutowań. Moim zdaniem jest to nie lada upokorzenie dla Microsoftu i programistów SAPI, skoro trzeba tą bibliotekę intensywnie hack'ować, żeby w ogóle dała się używać z ich nowymi kompilatorami.

Życzę miłej zabawy z rozpoznawaniem mowy, a ja <del datetime="2007-06-25T01:08:07+00:00">już wkrótce wrzucę</del> <ins datetime="2007-06-25T01:08:07+00:00">w międzyczasie wrzuciłem</ins> <a href="projects.html#voice-control-system">opis obiecanego Voice Control System'u</a>.
]]></description>
    </item>    <item>
      <title>Smart Pointers i nowy adres</title>
      <link>https://jacek.zlydach.pl/blog/2007-05-29-smart-pointers-i-nowy-adres.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2007-05-29-smart-pointers-i-nowy-adres.html</guid>
      <pubDate>Tue, 29 May 2007 14:27:38 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/cpp.html">C++</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/tworzenie-gier.html">Tworzenie gier</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/ksiazki.html">książki</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/pr0-pl.html">pr0.pl</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/smart-pointers.html">smart pointers</category>
      <description><![CDATA[Na forum <a href="http://www.gamedev.pl">Warsztatu</a> pojawiła się ciekawa <a href="http://forum.gamedev.pl/index.php/topic,3616.0.html">dyskusja</a> na temat inteligentnych wskaźników. Jeden z jej uczestników podał link do <a href="old-blog/download/npwcpp-rozdz7.pdf">ciekawego PDF</a>. Jest to fragment książki <a href="http://www.nowoczesne-cplusplus.com/"><em>&quot;Modern C++ Design&quot;</em></a> poświęcony konkretnie tematowi inteligentnych wskaźników. Warto przeczytać ten dokument z wielu powodów. Po pierwsze, przedstawia on teorię stojącą za inteligentnymi wskaźnikami i omawia problemy mogące się pojawić przy ich implementacji. Po drugie, odświeża trochę bardziej zaawansowanych tematów z języka C++ ;). Po trzecie, omawia on także kwestię używania i implementacji smart pointer'ów w aplikacjach wielowątkowych.

Prace &quot;remontowe&quot; środowiska programistycznego już prawie zakończyłem. W międzyczasie dzięki uprzejmości <a href="http://forum.gamedev.pl/index.php?action=profile;u=1">Goliatusa</a> i <a href="http://pr0.pl">Paszczaka</a> ten DevBlog zyskał dodatkowe subdomenki - <a href="http://temporal.gamedev.pl">temporal.gamedev.pl</a> i <a href="http://devblog.temporal.pr0.pl">devblog.temporal.pr0.pl</a>.
]]></description>
    </item>
  </channel>
</rss>