poniedziałek, 31 października 2016

Kończymy klasę pole

Witam

Dzisiaj dalej zajmiemy się klasom pole. Od razu otwórzmy plik pole.cpp i wpiszmy poniższy kod

#include "pole.h"

using namespace sf;

Pole::Pole(int w,int h, int mX, int mY, bool sp,bool st,bool i)
{
//przypisanie podstawowych zmiennych
    width=w;
    height=h;
    marginX=mX;
    marginY=mY;
    ship=sp;
    shot=st;
    IA=i;

//rysowanie pustego pola
    shape.setSize(Vector2f(size_,size_));
    shape.setFillColor(Color(0,128,255));
    shape.setOutlineThickness(1);
    shape.setOutlineColor(Color::Black);
    shape.setPosition(marginX+width*(size_+1),marginY+height*(size_+1));
}

Pole::~Pole()
{
}
void Pole::setPosition(int x,int y,int mx,int my)
{
    //Zmiana pozycji pola
    width=x;
    height=y;
    marginX=mx;
    marginY=my;
    shape.setPosition(marginX+width*(size_+1),marginY+height*(size_+1));
}

bool Pole::getShip()
{
//zwracanie wartości ship
    return ship;
}

bool Pole::getShot()
{
//zwracanie wartości shoy
    return shot;
}

void Pole::update()
{
     if(shot&&ship) //sprawdzenie czy nie zestrzelono statku i wywołanie funkcji wyświetlających graficzny odpowiednik
       {
        drawShip();
        drawHit();
       }

    else if(ship==true&&IA==false) //sprawdzenie czy gracz nie zaznaczył na danym polu swojego statku i wyświetlenie odpowiedniej informacji
        drawShip();

    else if(shot==true) //sprawdzenie czy gracz nie spudłował naciskając dane pole i wyświetlenie informacji
        drawShot();
}

void Pole::draw(sf::RenderTarget &target, sf::RenderStates states)const //funkcja umożliwiająca rysowanie i transformowanie obiektu
{
    states.transform *getTransform();
//narysowanie wszystkich obiektów które chcemy narysować rysując obiekt naszej klasy
    target.draw(shape);
    target.draw(circle);
    target.draw(cross[0]);
    target.draw(cross[1]);
}

void Pole::drawShip() //funkcja odpowiada za narysowanie naszego statku
{

    circle.setRadius(size_/4);
    circle.setOrigin(size_/4,size_/4);
    circle.setPosition(marginX+size_/2+width*(size_+1),marginY+size_/2+height*(size_+1));
    circle.setOutlineThickness(size_/8);
    circle.setOutlineColor(Color::Red);
    circle.setFillColor(Color(0,128,255));

}

void Pole::drawShot() //funkcja odpowiada za narysowanie niecelnego strzału
{
    for(int i=0;i<2;i++)
    {
        cross[i].setSize(Vector2f(5,size_));
        cross[i].setOrigin(3,size_/2);
        cross[i].setFillColor(Color::Red);
        cross[i].setPosition(marginX+size_/2+width*(size_+1),marginY+size_/2+height*(size_+1));
    }
    cross[0].setRotation(45);
    cross[1].setRotation(135);
}

void Pole::drawHit() //funkcja odpowiada za narysowanie naszego trafienia
{
    circle.setFillColor(Color::Red);
}

void Pole::setShot(bool s) //funkcja ustawia wartość shot
{
    shot=s;
}

void Pole::setShip(bool s//funkcja ustawia wartość shot
{
    ship=s;
}

bool Pole::getBounds(Vector2f &m) //funkcja zwraca prawdę jeżeli mysz znajduje się w obrębie pola
{
    return shape.getGlobalBounds().contains(m);
}
void Pole::setIA(bool i//funkcja ustawia wartość IA
{
     IA=i;
}

Teraz w funkcji main stworzymy zwykłe okno z podstawową mechaniką

#include"pole.h"

int main()
{
    Pole p(0,0,20,20); //tworzymy obiekt klasy Pole
    p.setShip(1);
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); //tworzymy okno aplikacji
    while (window.isOpen())
    {
        p.update(); //aktualizujemy informacje na temat naszego obiektu
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed) //naciśnięcie przycisku zamknij
                window.close();
        }

        window.clear(sf::Color::White)
        window.draw(p); //narysowanie naszego obiektu
        window.display();
    }

        return 1;
}

I wtedy naszym oczom ukarze się widok naszego pola

Możemy również pobawić się funkcjami setShip(), setShot() aby uzyskać takie efekty:
nasz statek

zbity statek

pudło
(dodatkowo zmieniłem rozmiar pola żeby było lepiej widać) 

Podsumowanie

Dziś wreszcie skończyliśmy klasę pole i zobaczyliśmy efekt naszej pracy jednak do ukończenia projektu jeszcze długa droga. Kod całej aplikacji możecie znaleźć na moim profilu github. Jak zwykle zachęcam do zadawania pytań i zgłaszania propozycji w komentarzach.

niedziela, 30 października 2016

Zaczynamy tworzyć aplikacje okienkową

Witam

Dzisiaj zaczniemy tworzyć nową grę. Jednak tym razem będzie to aplikacja okienkowa. Ponownie stworzymy  grę w statki jednak tym razem będzie ona wyglądać w ten sposób

Aplikacje pisałem przy użyciu biblioteki SFML 2.0, ale powinna ona działać również z późniejszymi wersjami dej biblioteki, ponieważ zachowuje ona kompatybilność wsteczną. Jeśli pierwszy raz słyszysz o tej bibliotece koniecznie odwiedź oficjalną stronę i zapoznaj się ze znajdującym tam tutorialem lub jeśli nie znasz angielskiego odwiedź blog Szymona Siarkiewicza. Oprócz znajomości tej biblioteki musisz również umieć korzystać z obiektowego C++, możesz się go nauczyć z kursu Mirosława Zelenta

W naszym projekcie stworzymy trzy klasy, teraz pokrótce opisze do czego służy każda klasa

pole.h-ta klasa będzie odpowiadać za narysowanie każdego pola i wyświetlenie czy statek na tym polu został trafiony czy nie czy gracz porostu spudłował.

engine.h-ta klasa odpowiada za główna mechanikę gry, będzie sprawdzać czy gracz nie wybrał któregoś pola i będzie wywoływać odpowiednie funkcje klasy pole.

game.h-jest to główna klasa całej aplikacji odpowiada ona za renderowanie okna i początkowe menu.

Teraz stworzymy klasę pole, dzisiaj zajmiemy się tylko plikiem nagłówkowym. 


#include <SFML/Graphics.hpp>
#pragma once

class Pole: public sf::Drawable,
sf::Transformable
{

    bool ship//wartość prawda jeżeli na polu znajduje się statek
    bool shot//wartość prawda jeżeli ple było zaznaczone
    int height, width, marginX, marginY, size_=48;//?
    bool IA//wartość prawda jeżeli pole jest komputera, jest ona potrzebna ponieważ będziemy używać tej samej klasy do rysowania naszych pul i pul przeciwnika

    public:

    Pole(int=0,int=0,int=1,int=1,bool=0,bool=0,bool=0)
    ~Pole();
//konstruktor i destruktor



    void setPosition(int,int,int,int)//ustawia pozycje pola

    bool getShip();//zwraca prawdę jeśli na polu jest statek
    bool getShot();//zwraca prawdę jeśli było trafienie
    bool getBounds(sf::Vector2f &m)//zwraca prawdę jeśli myszka najedzie na obiekt

    void setShot(bool)//zmienia wartość zmiennej shot
    void setShip(bool)//zmienia wartość zmiennej ship
    void setIA(bool)//zmienia wartość zmiennej IA

    void update(); //aktualizuje informacje o polu
    void drawShot(); //rysuje strzał który był nietrafiony
    void drawShip(); //rysuje statek
    void drawHit(); //rysuje celny strzał

    sf::RectangleShape shape//puste pole
    sf::CircleShape circle; //statek
    sf::RectangleShape cross[2]//krzyżyk symbolizujący pudło


    virtual void draw(sf::RenderTarget &target,sf::RenderStates states) const; //funkcja umożliwiająca transformowanie obiektów klasy pole
};

Chciałbym teraz dokładniej opisać linijkę którą oznaczyłem "//?":

 width i height-oznaczają współrzędne danego pola względem całej planszy gracza licząc od lewego górnego rogu.

marginX i marginY-oznaczają jaką odległość ma mieć lewy górny róg planszy od lewego górnego narożnika okna aplikacji.

size-oznacza porostu wielkość jednego pola.

Podsumowanie

Na dziś już starczy tego pisania. Zachęcam do samodzielnego przeanalizowania kodu znajdującego się na moim profilu github. Jak zawsze zachęcam do komętowania.

sobota, 29 października 2016

Menu gry

Witam

Dzisiaj zajmiemy się ostatnią częścią naszego projektu czyli menu. Bierzmy się zatem do pracy.

int menu()
{
    for(;;) //tworzymy nieskończoną pętle w której będzie działać cała aplikacja
    {

        system("cls"); //czyścimy ekran
        cout<<"1.GRAJ"<<endl;
        cout<<"2.WYJŚCIE"<<endl;
        wyb=getch();
        system("cls");
// wypisujemy dostępne opcje w menu i odczytujemy wybór gracza
        switch(wyb) //switch który wywoła odpowiednie funkcje zależnie od wyboru gracza 
        {
        case '1': //jeśli gracz wybrał opcję graj wywołujemy funkcje zaznacz wylicz i rysuj
        {
            zerowanie();
            wylicz();
            rysuj();
            do
            {
                ruch();
                atak();
                rysuj();
            }
            while(punk<20&&punk_kom<20); //następnie wywołujemy funkcje ruch atak i rysuj dopóki gracz albo komputer zestrzeli wszystkie statki przeciwnika
       }
        break;
        case '2': // jeśli gracz wybrał opcję wyście zwracamy wartość funkcji menu tym samym wychodzimy z funkcji i z samej gry
        {
            return 0;
        }
        break;
       }
       system("pause"); //czekamy aż gracz naciśnie dowolny klawisz żeby mógł zobaczyć wynik swojej gry
    }
}

I możemy podziwiać efekty naszej pracy:
Zauważamy jednak pewien problem jeżeli jeszcze raz wybierzemy graj nasza plansza będzie już wypełniona. Jest to spowodowane tym że nie wyzerowaliśmy koordynatorów naszych statków. Zróbmy więc to używając funkcji zerującej.

void zerowanie()
{
    punk=0;
    punk_kom=0;
    for(int i=0;i<10;i++)
    {
       for(int j=0;j<10;j++)
    {
         statek[j][i]=false;
         strzal[j][i]=false;
         zaznaczenia[j][i]=false;
         strzal_kom[j][i]=false;
    }
    }
}

Jest to bardzo prosta funkcja więc nie będę jej dokładnie opisywał, porostu ustawia wartość wszystkich zmiennych na zero. Pozostaje nam ją już tylko wywołać w void menu() nad funkcją zaznacz(). 

Podsumowanie  

Nasz projekt możemy uznać za skończony. Teraz prawdopodobnie zajmiemy się drugim projektem którym będą okienkowe statki. Kod całej aplikacji jest dostępny na moim profilu github. Jestem otwarty na wszelkie uwagi, pytania itp. oraz zachęcam do komentowania. 


piątek, 28 października 2016

Stworzenie sztucznej inteligencji

Witam 

W dzisiejszym artykule zajmiemy się dwiema funkcjami odpowiedzialnymi za sztuczną inteligencję. Na Początek zajmijmy się funkcją która zaznaczy statki przeciwnika czyli void wylicz();

void wylicz()
{
   int iii,jjj; //tworzymy dwie zmienne które będą wskazywać odpowiednie współrzędne 
   srand(time(NULL)); //pobieramy czas komputera, ta funkcja jest niezbędna do działania liczb losowych
   for(int i=0;i<20;i++) //pętla której zawartość będzie wykonywać się 20 razy ponieważ chcemy żeby komputer zaznaczył 20 statków 
   {
      do
      {
          jjj=rand()%10;
          iii=rand()%10;
          //losujemy współrzędne statku 
      }while(statek[jjj][iii]==true); //sprawdzamy czy statek nie jest już zaznaczony jeśli jest losujemy współrzędne ponownie
   statek[jjj][iii]=true; //przypisujemy współrzędne 
}}

Teraz pora na funkcję odpowiedzialną za zgadywanie pozycji naszych statków przez komputer

void atak()
{
    int iii,jjj;
    srand(time(NULL));
    do
    {
        do
        {
            jjj=rand()%10;
            iii=rand()%10;
        }
        while(strzal_kom[jjj][iii]==true);
        strzal_kom[jjj][iii]=true;
//powyższa część kodu jest niemal identyczna jak we wcześniejszej funkcji dlatego nie będę jej opisywał
        if(zaznaczenia[jjj][iii]==&&strzal_kom[jjj][iii]==true&&punk_kom<20&&punk<20) //sprawdzamy czy komputer trafił w nasz statek i jeśli trafiliśmy aktualizujemy dane odnośnie zestrzeleń naszych statków
        {
            rysuj();
            system("cls");
            if(punk_kom==20)
            {
                system("cls");
            }
        }
    }while(zaznaczenia[jjj][iii]==true&&strzal_kom[jjj][iii]==true&&punk<20&&punk_kom<20);
//jeśli komputer trafił zgaduje jeszcze raz 
}

Sztuczną inteligencję już mamy, pozostaje nam ją jeszcze wywołać w int main() w ten sposób.

int main()
{
    zaznacz();
    wylicz();
    while(true)
    {
        rysuj();
        ruch();
        atak();
    }
}

I możemy już podziwiać efekty naszej pracy:
Zauważamy jednak jeden problem, pomimo że wszystkie statki zostały zestrzelone gra się nie skończyła i możemy dalej zaznaczać nasze statki. Tym problemem zajmiemy się jednak dopiero tworząc menu w następnej części kursu.



Podsumowanie

Myślę że tyle kodu do napisania wystarczy na dziś. Oczywiście kod źródłowy całej aplikacji dostępny jest na moim profilu github. Zachęcam do samodzielnego przeanalizowania kodu.
Jestem otwarty na wszelkie uwagi, pytania, itp. Zapraszam do komentowania.

niedziela, 23 października 2016

Odgadywanie statków przeciwnika

Witam

Dzisiejszy post będzie krótki ponieważ nie mam za dużo czasu, a kod który napiszemy nie jest długi.
Dziś zajmiemy się funkcją która pozwala nam odgadywać statki przeciwnika. Więc zaczynajmy.


//?
void ruch()
{
  char ii,jj;
  int jjj,iii;
  do
  {
   do
  {
      jj=getch();
      jjj=jj-48;
      ii=getch();
      iii=ii-48;

     if(strzal[jjj][iii]==true)
     {
     system("cls");
     rysuj();
     cout<<"to pole już zaznaczyłeś wybierz inne"<<endl;
    }
     if(jjj>=10||iii>=10||jjj<0||iii<0)
     {
     system("cls");
     rysuj();
     cout<<"pole z poza zakresem"<<endl;
     }
  }while(strzal[jjj][iii]==true||jjj>=10||iii>=10||jjj<0||iii<0);


  strzal[jjj][iii]=true;
  system("cls");
//?
  if(statek[jjj][iii]==true&&strzal[jjj][iii]==true&&punk<20&&punk_kom<20)
     {
      rysuj(); //ta funkcja musi tu być ponieważ wcześniej wyczyściliśmy ekran i gdybyśmy trafili statek przeciwnika zobaczylibyśmy pusty ekran
        if(punk==20) //tutaj jeszcze raz sprawdzamy czy nie zestrzeliliśmy wszystkich statków przeciwnika ponieważ ta informacja jest aktualizowana dopiero przy rysowaniu
           {
               system("cls");
           }
     }
  }while(statek[jjj][iii]==true&&strzal[jjj][iii]==true&&punk<20&&punk_kom<20);

}

Kodu znajdującego się pomiędzy "//?" nie będziemy analizować ponieważ jest on niemal identyczny jak zaznaczenie naszych statków które opisałem w poprzedniej części kursu.
Natomiast druga pętla while odpowiada za dodatkowy strzał jeśli trafimy w statek przeciwnika. Będzie się ona wykonywać dopóki będziemy trafiać lub zestrzelimy wszystkie statki.
Teraz możesz wywołać wywołać tą funkcję w funkcji main()
int main()
{
    zaznacz();
while(true)
    {
    rysuj();
    ruch();

    }
}

I możemy podziwiać efekty naszej pracy.

Co prawda nie zestrzelimy żadnego statku przeciwnika ponieważ nie wprowadziliśmy jeszcze sztucznej inteligencji, ale tym zajmiemy się w następnej części kursu.

Podsumowanie.

Myślę że tyle kodu do napisania wystarczy na dziś. Oczywiście kod źródłowy całej aplikacji dostępny jest na moim profilu github. Zachęcam do samodzielnego przeanalizowania kodu.

Jestem otwarty na wszelkie uwagi, pytania, itp. Zapraszam do komentowania.


sobota, 22 października 2016

Zaznaczanie naszych statków

Witam.

Dziś zajmiemy się funkcjami odpowiedzialnymi za nasze statki będą to:
-void zaznacz();
-void zaznaczrysuj();
Ta pierwsza odpowiada bezpośrednio za mechanikę zaznaczania natomiast ta druga rysuje nam planszę.zajmijmy się najpierw rysowaniem planszy.

void zaznaczrysuj()
{


 cout<<"|---|---|---|---|---|---|---|---|---|---|"<<endl;
    for(int j=0;j<=9;j++)
    {

    for(int i=0;i<=9;i++)
    {
    if (zaznaczenia[j][i]==true)
    {
      cout<<"| ";
    cout<<"Y ";
    }

    else
     cout<<"|"<<j<<" "<<i;
    }
    cout<<"|"<<endl<<"|---|---|---|---|---|---|---|---|---|---|"<<endl;
    }
}

Nie będziemy dokładnie opisywać powyższego  kodu ponieważ jest on bardzo podobny do tego rysującego planszę główną z tą różnicą że tu niema planszy bocznej na której są zaznaczone nasze statki ponieważ to jest nasza plansza, a plansza dla komputera jest obecnie zbędna.

Teraz pora na funkcję odpowiedzialną za mechanikę.

void zaznacz()
{
  char ii,jj; //deklarujemy zmienne do poprania znaków
  int iii,jjj; //deklasujemy zmienne do określania koordynatorów

  for(int i=0;i<20;i++)//pętla wywoływana do zaznaczenia 20 statków 
  {

  zaznaczrysuj(); //narysowanie naszej planszy
    do{
      jj=getch(); //pobranie pierwszej współrzędnej
      jjj=jj-48; //przypisanie pierwszej współrzędnej, odejmujemy 48 ponieważ każda cyfra jako znak ASCII ma wartość o 48 większą
      ii=getch();//to samo robimy z drugą współrzędna 
      iii=ii-48;


    if(zaznaczenia[jjj][iii]==true) //sprawdzamy czy nie zaznaczyliśmy wcześniej tego pola
    {
     system("cls");
     zaznaczrysuj();
     cout<<"to pole już zaznaczyłeś wybierz inne"<<endl;
     //jeśli zaznaczyliśmy czyścimy konsole rysujemy plansze i wypisujemy odpowiedni komentarz
     }
     if(jjj>=10||iii>=10||jjj<0||iii<0) //sprawdzamy czy na pewno wpisaliśmy pole z zakresu 
     {
     system("cls");
     zaznaczrysuj();
     cout<<"pole z poza zakresem"<<endl;
     //jeśli zaznaczyliśmy czyścimy konsole rysujemy plansze i wypisujemy odpowiedni komentarz
     }

  }while(zaznaczenia[jjj][iii]==true||jjj>=10||iii>=10||jjj<0||iii<0); //pętla wykonująca się dopóki nie zaznaczymy wolnego pola w zakresie naszej planszy   
  zaznaczenia[jjj][iii]=true; //jeśli powyższe warunki zostały spełnione zaznaczamy statek 
  system("cls");//czyścimy konsole
  }
}

Na zakończenie

Jeszcze jedno zdanie na temat polskich znaków w konsoli wszystko zostało dokładnie wyjaśnione w kursie Mirosława Zelenta
Teraz wystarczy wywołać naszą funkcję 

int main()

{
    zaznacz();

    rysuj();
}
i można podziwiać efekty naszej pracy





Podsumowanie.

Myślę że tyle kodu do napisania wystarczy na dziś. Oczywiście kod źródłowy całej aplikacji dostępny jest na moim profilu github. Zachęcam do samodzielnego przeanalizowania kodu.

Jestem otwarty na wszelkie uwagi, pytania, itp. Zapraszam do komentowania.



piątek, 21 października 2016

Rysujemy główną planszę gry.

Witam.

Dzisiaj będziemy tworzyć główną planszę gry.
 Postaram się w jak najbardziej przystępny sposób wytłumaczyć każdą linię kodu.

Bierzmy się do pracy.

void rysuj()
{

        punk=0;
        punk_kom=0;
//zeruje nasze punkty i punkty przeciwnika ponieważ za każdym razem gdy rysujemy plansze punkty są liczone od nowa
       cout<<"|---|---|---|---|---|---|---|---|---|---|    |-|-|-|-|-|-|-|-|-|-|"<<endl; //rysuje górną ramkę naszej planszy

    for(int j=0;j<=9;j++) //ta pętla odpowiada za narysowanie kolejnych 10 rzędów
    {

    for(int i=0;i<=9;i++) //ta pętla rysuje każde pole z osobna
//ta pętla odpowiada za rysowanie planszy komputera
    {
        if(statek[j][i]==true&&strzal[j][i]==true) //sprawdzamy czy na danym polu jest statek i czy strzelaliśmy w dane pole
        {
            punk++;
            cout<<"| ";
            cout<<"X ";
//jeśli trafiliśmy komputer oznacza to pole  X i dodaje nam jeden punkt 
        }
        else if(strzal[j][i]==true) //sprawdza czy strzelaliśmy w dane pole
        {
          cout<<"| ";
          cout<<"O ";
//jeśli spudłowaliśmy komputer oznacza to pole O
         }
        else
         {
             cout<<"|"<<j<<" "<<i;
//jeśli nie strzelaliśmy w dane pole komputer pokazuje koordynaty pola
          }

     }
    cout<<"|    ";//rysuje boczną ramkę planszy

    for(int i=0;i<=9;i++)//ta pętla rysuje każde pole z osobna
//ta pętla odpowiada za rysowanie planszy komputera
    {
        if(zaznaczenia[j][i]==true&&strzal_kom[j][i]==true)//sprawdza czy na danym polu jest nasz statek i czy komputer strzelał w to pole
        {
           cout<<"|";
           cout<<"X";
           punk_kom++;
//jeśli komputer trafił oznacza to pole X i daje mu punkt
        }
        else if(strzal_kom[j][i]==true) //sprawdza czy na komputer strzelał w dane pole
        {
           cout<<"|";
            cout<<"O";
//jeśli komputer spudłował oznacza to pole O
        }


        else if(zaznaczenia[j][i]==true) //sprawdza czy na danym polu jest nasz statek 
        {
          cout<<"|";
        cout<<"Y";
//jeśli na danym polu jest nasz statek komputer oznacza to pole Y
        }

        else
        cout<<"| ";
//jeśli na danym polu nic niema komputer zostawia je puste
    }

    cout<<"|"<<endl<<"|---|---|---|---|---|---|---|---|---|---|    |-|-|-|-|-|-|-|-|-|-|"<<endl; //rysuje odstępy pomiędzy poszczególnymi rzędami 

    }
    cout<<"TY: "<<punk<<" PRZECIWNIK: "<<punk_kom<<endl;//wypisuje nasze punkty i punkty przeciwnika

//poniższe kilka linijek sprawdza czy przeciwnik nie osiąknął wymaganej liczby punktów (zbił wszystkie statki przeciwnika) i wypisuje stosowny komentarz 
    if(punk==20&&punk_kom==20)
    {
       cout<<"REMIS"<<endl;
    }
    else if(punk_kom==20)
    {
        cout<<"PRZEGRYWASZ"<<endl;
    }
    else if(punk==20)
    {
     cout<<"WYGRYWASZ"<<endl;
    }
}

Na zakończenie 

Dodam jeszcze tylko że narzazie jeśli chcemy wyświetlić naszą plansze wywołujemy ją w funkcji 
main(). Dodatkowo możecie pozmieniać wartości statków i strzałów np.:
statek[2][5]=true;
strzal[2][5]=true;
zaznaczenia[4][6]=true;
strzal_kom[8][3]=true;
da nam to taki efekt:

 Podsumowanie.

Myślę że tyle kodu do napisania wystarczy na dziś. Oczywiście kod źródłowy całej aplikacji dostępny jest na moim profilu github. Zachęcam do samodzielnego przeanalizowania kodu.

Jestem otwarty na wszelkie uwagi, pytania, itp. Zapraszam do komentowania.