Nastoletni Programiści Tue, 29 Jan 2019 15:53:06 +0000 pl-PL hourly 1 https://wordpress.org/?v=5.0.3 115968029 EarthX 0.0.73 – co to za gra i jakie są plany na jej przyszłość? /earthx-0-0-73-co-to-za-gra-i-jakie-sa-plany-na-jej-przyszlosc/ /earthx-0-0-73-co-to-za-gra-i-jakie-sa-plany-na-jej-przyszlosc/#respond Tue, 29 Jan 2019 15:53:06 +0000 /?p=1842 EarthX to nie tak stara gra, jakby się mogło zdawać. Robię ją zaledwie od około miesiąca, a pomysł na taką grę powstał dopiero w wakacje ubiegłego roku. Co to w ogóle jest EarthX i dlaczego warto się tą grą zainteresować? Tego dowiedzie się w tym wpisie.

Włączasz grę, robisz nowy save i nazywasz swoją firmę. Potem możesz opracować technologię silników i zbiorników paliwa, a następnie zaprojektować i nazwać własną rakietę. Oczywiście nie wystartujesz rakiety, jeśli jej nie masz, dlatego musisz też ją najpierw zbudować. Ta cała „ciężka” praca opłaci się, gdy będziesz miał możliwość kliknięcia magicznego przycisku, który wyniesie Twoją rakietę prosto w przestrzeń kosmiczną, a jeśli zainwestowałeś w podwozie, to rakieta będzie mogła również wrócić i spektakularnie wylądować na barce.

Brzmi dobrze? O tym właśnie jest EarthX. Gra pozwoli Ci na rozwijanie najróżniejszych technologii rakietowych i ogólnym zarządzaniem firmą (a w przyszłości również planetą!).

Funkcje, które są na ten moment dostępne w grze:

  • możliwość zaprojektowania, zbudowania i wystrzelenia rakiety na orbitę.
    • jeśli rakieta ma podwozie w formie nóg, będzie ona mogła wylądować z powrotem na ziemi.
  • możliwość odblokowania i rozwijania nowych technologii.
  • możliwość zarabiania oraz tracenia funduszy.
  • możliwość zdobycia punktów doświadczenia.
  • możliwość budowania siedzib firmy w USA oraz zatrudniania pracowników.
  • możliwość zapisu i odczytu gry.
  • minimalistyczna oprawa wizualna, audiowizualna oraz prosty w obsłudze interfejs.
  • możliwość otrzymywania powiadomień w grze.
  • możliwość przeglądu statystyk i informacji o swojej firmie.

Plany na przyszłość gry:

Moim zdaniem gra jest trochę za prosta, dlatego do gry zostaną wprowadzone nowe systemy projektowania, budowania oraz wysyłania rakiety w kosmos. Celem jest podniesienie trudności gry poprzez dodanie większej ilości nowych funkcji oraz nowej zawartości do odblokowania. Dodatkowo ciekawym urozmaiceniem gry będzie dodanie efektów pogodowych (rakieta nie będzie mogła startować przy silnym wietrze), dodanie konkurencji i zleceniodawców oraz oczywiście dodanie różnych zdarzeń w grze (np. rakieta może wybuchnąć).

EarthX to nie jest symulator rakiet. To nie jest nawet podobne do jakiegokolwiek symulatora. EarthX to bardziej taki strategiczno-ekonomiczny sandbox, w którym będziemy mogli rozwijać nie tylko rakiety, ale także różne systemy transportowe na ziemi (Tesla i Boring Company, wait for it ( ͡° ͜ʖ ͡°)).

Kup grę:

Gra jest teraz w bardzo wczesnej fazie rozwoju (Early Access), więc nie posiada jeszcze ona wielu funkcji. Jednakże kupując moją grę za 3$ wspomożesz jej rozwój w przyszłości. Zebrane środki przeznaczę na przyszłe wydanie gry na Steamie oraz opłacenie grafika, który wykona różne ikonki modułów do gry.

Kup grę tutaj: kliknij, aby przejść na itch.io

Oficjalne Gameplaye z gry:

]]>
/earthx-0-0-73-co-to-za-gra-i-jakie-sa-plany-na-jej-przyszlosc/feed/ 0 1842
Obiektowość w Lua /obiektowosc-w-lua/ /obiektowosc-w-lua/#respond Tue, 13 Nov 2018 20:28:58 +0000 /?p=1817 Podejście obiektowe w programowaniu na zawsze zmieniło podejście do kreowania kodu w wielu językach. Możliwość podziału programu na obiekty komunikujące się między sobą w celu rozwiązania problemu ma wiele zalet, co potwierdza popularność tego paradygmatu wśród programistów. Co jednak zrobić w sytuacji, w której język nie jest językiem zorientowanym obiektowo, a jednak chcielibyśmy skorzystać z tego paradygmatu? W tym artykule pochylę się nad językiem Lua. Zapraszam do lektury. 🙂

Język Lua nie udostępnia wprost możliwości działania na obiektach. Jest za to jedna z możliwości, jak taki sposób uzyskać. Z pomocą przychodzą nam metatablice . Jako, iż wikipedia nie jest zbyt wymowna na ich temat, pozwolę sobie skonstruować prostą do zrozumienia definicję na potrzebę ów artykułu. 🙂

Metatablice są to tablice zawierające określony zestaw zachowań, na które jest w stanie zareagować wartość. Każda wartość ma swoją metatablicę, która reguluje to, w jaki sposób np. liczba 5 zareaguje na próbę wykonania na niej operacji dodawania.

Znając teraz uproszczoną definicję metatablicy, możemy przejść przez kawałek teorii związanej z tym zagadnieniem. W Lua mamy do czynienia z prostą dwuwymiarową tablicą, która jest wywoływana przez interpreter w każdym przypadku, gdy coś wyda mu się nie do końca poprawne. Weźmy sobie za przykład wartość nieliczbową, np. tablicę jednowymiarową. Co się stanie, gdy nasza tablica zostanie operandem dodawania? Interpreter zwróci uwagę na to, że chcemy dodać do czegoś wartość nieliczbową i zwróci się do metatablicy podając zdarzenie add . Metatablica zwróci za to metametodę (wartość pod kluczem __add ) odpowiadającą temu zdarzeniu, co pozwoli nam (lub nie, w zależności od tego czy metametoda istnieje) wykonać operację dodawania na tej wartości. Zrzucając szatę możliwego niezrozumienia pojęć pozwolę sobie wytłumaczyć użyte przeze mnie dwa nowe pojęcia. Zdarzenie to po prostu klucz tablicy, a metametoda to funkcja, która zostanie wykonana w przypadku wywołania danego zdarzenia. Brzmi znajomo? Już za moment wszystko powinno stać się zrozumiałe.

Szukając porówniania do innych języków, przykładem dla nas mogą okazać się przeciążenia operatorów w języku C#. Idea działania jest praktycznie taka sama.

Jeżeli teraz połączymy te informację z inną, która mówi nam, że te metatablice można, tak jak w językach typu C#, przeciążać, to dojdziemy do wniosku, że z dużą dozą prawdopodobieństwa uda nam się napisać bardzo dobrze działający „kod zorientowany obiektowo”. Możemy teraz przejść do praktycznej części.

Rozpocznijmy naszą praktykę od utworzenia metatablicy oraz nadpisania jej zdarzenia.

Utworzyliśmy teraz metatablicę Account , której wartość zdarzenia index ustawiliśmy na nią samą. Dzięki czemu obiekty będą mogły korzystać z metod zdefiniowanych w tej tablicy. Na tym jednak nie poprzestajemy.

Tym razem zdefiniowaliśmy metodę create , która pozwoli nam na utworzenie „obiektu” naszej tablicy. Nasz trik polega na utworzeniu pustej tablicy, której wstrzykniemy naszą spreparowaną metatablicę. Następna linijka odpowiada za „konstruktor” naszego obiektu, czyli zapisanie właściwości balance przekazanej z wywołaniem metody create . Na sam koniec zwracamy nowo utworzony „obiekt”. Nie mielibyśmy jednak obiektu, gdyby nie chociaż jedna metoda poza konstruktorem. Utwórzmy więc takową.

Prosta metoda umożliwiająca podanie w argumencie liczby o którą uszczuplimy właściwość balance naszego obiektu. Skorzystaliśmy sobie w niej z parametru self, który umożliwia nam ominięcie odniesienia do globalnej wartości Account . Jest to dobra praktyka, która warto sobie przyswoić.

Jeżeli jesteś osobą, która lepiej czuje się z użyciem parametru this niż self , istnieje możliwość zmiany tego parametru. W tym celu, przy tworzeniu definicji metody, zamiast : korzystamy z operatora . . Wówczas w pierwszym argumencie możemy wpisać this lub cokolwiek innego, dzięki czemu zmienna ta stanie się reprezentacją naszego obiektu w tej definicji.

Do testów starczy nam to w zupełności. Utwórzmy teraz jeden obiekt i skorzystajmy z metody.

Prześledźmy teraz działanie tych dwóch linijek kodu, aby lepiej zrozumieć co się stanie. Pierwsza linijka to po prostu utworzenie obiektu na bazie klasy Account . Działanie tej metody wytłumaczyliśmy sobie parę akapitów wyżej. Druga linijka natomiast nie jest tak oczywista jak mogłoby się wydawać. Odwołanie do metody tablicy acc zwróci błąd, ponieważ nic takiego nie istnieje. Interpreter wie natomiast, że acc to tablica, tak więc podejmie próbę wyszukania indeksu tej tablicy. I tutaj wkracza do akcji przygotowana przez nas metatablica, która umożliwia nam dostanie się do zasobów tablicy Account . I tym sposobem utworzyliśmy nasz pierwszy pełnoprawny obiekt w języku Lua!

Czy istnieje jednak prostsze podejście do obiektowości w Lua? Okazuje się, że tak. Co więcej, być może uda nam się nawet użyć dziedziczenia! To jednak materiał na kolejny artykuł.


Artykuł bazujący na zawartości strony: http://lua-users.org/wiki/SimpleLuaClasses

]]>
/obiektowosc-w-lua/feed/ 0 1817
Wstęp do Machine Learning /wstep-do-machine-learning/ /wstep-do-machine-learning/#respond Sun, 20 May 2018 16:35:14 +0000 /?p=1766 Wstęp do Machine Learning

Machine Learning (pol. uczenie maszynowe, samouczenie się maszyn, systemy uczące się) jest jedną z aktualnie najlepiej prosperujących dziedzin w świecie IT.

W 1959 Alan Turing i Arthur Samuel amerykańscy pionierzy w dziedzinie gier komputerowych i sztucznej inteligencji ukształtowali współczesny termin machine learning .

The field of study that gives computers the ability to learn without being explicitly programmed.

~ Arthur Samuel

Oznacza to możliwość nauki programu komputerowego na podstawie wcześniej przygotowanych danych w celu rozwiązania konkretnego problemu bez znania sposobu na osiągnięcie go, czyli wcześniejszej listy kroków którą ma wykonać program. Oparte jest to o zestaw gotowych algorytmów z podanych dziedzin matematyki:

  • algebra liniowa
  • rachunek prawdopodobieństwa
  • statystyka

Sieć neuronowa

Machine Learning działa w oparciu o sieci neuronowe wzorowane na ludzkich. Powyższy schemat sieci neuronowej pokazuje jej uproszczony sposób działania. Składa się ona z neuronów . Każdy neuron jest wprowadzany przez dendryty od innych neuronów przenosząc sygnały otrzymywane z innych neuronów przez synapsy . Na grafice powyżej czerwone neurony stanowią warstwę wejściową, niebieskie – warstwę ukrytą, a zielone – warstwę wyjściową. Ilość ukrytych warstw jest zależna od tzw. głębokości , im głębsza tym bardziej skomplikowane są połączenia między nimi.

Podczas trenowania własnej sieci neuronowej dane są przekazywane od neuronu do neuronu, każdy kolejny może zapamiętywać (Recurrent Neural Network) wynik poprzedniego i przekazywać coraz to lepsze dane. Im więcej razy będziemy trenować taką sieć tym mniej błędów i lepszy wynik.

Rodzaje sieci neuronowych w jednym zdaniu

Feedforward Neural Network

Ta sieć bardzo dobrze klasyfikuje proste rzeczy, ale nie pamięta o poprzednich czynnościach/zmianach oraz ma nieskończone warianty wyników.

Recurrent Neural Network

W tym przypadku sieć pamięta poprzednie zmiany i ma skończony wariant wyników.

Sposoby uczenia

Uczenie nadzorowane (supervised learning)

Ten sposób uczenia polega na stworzeniu modelu danych, wejściowych czyli próbek (samples) wraz z modelem wyjściowym na przykład etykiet. Gdy wytrenujemy naszą sieć będziemy mogli prawidłowo przypisać wyjście dla obiektu którego dotychczas nie było na wejściu. Nasza sieć uczy się w oparciu o nasz model tzw. dataset .

Uczenie nienadzorowane (unsupervised learning)

Tym razem sieć nie otrzymuje danych wyjściowych (etykiet), więc sama musi znaleźć odpowiedni sposób, aby uzyskać dane wejściowe.

Uczenie przez wzmacnianie (reinforcement learning)

W uczenie przez wzmacnianie sieć działa bez określonych danych wejściowych i wyjściowych. Jedyne informacje jakie otrzymuje to tzw sygnał wzmocnienia, który może być pozytywny (nagroda) w przypadku podejmowania trafnych decyzji lub negatywny w przypadku mylenia się (kara). Jest to całkiem niezły sposób na naukę naszej AI grania w proste gry bez pomocy człowieka czy nawet zostania mistrzem świata w Go i tworzenia własnych skomplikowanych strategii. Jest to niestety najbardziej wymagający czasu jak i mocy obliczeniowej sposób nauki.

Rodzaje problemów

Dwa najpopularniejsze rodzaje problemów to klasyfikacja oraz regresja.

Klasyfikacja (classification)

Nasze wejściowe dane łączone są w model na podstawie którego jest określane czy spełnione są odpowiednie warunki czy też nie. Wynik z największym prawdopodobieństwem zostanie nam zwrócony. Na przykład rozpoznawanie ręcznie narysowanych cyfr, w tym przypadku mamy dataset w którym są próbki z zdjęciami narysowanych cyfr oraz etykiety dla każdego z nich. Podajemy nasze dane (zdjęcie) oraz trenujemy sieć używając naszego datasetu i otrzymujemy wynik.

Regresja (regression)

Działa to tak jak wyżej, lecz z jedną różnicą, a mianowicie tutaj otrzymujemy ciąg wyników/tablice z wynikami, a nie tylko jeden wynik. Przykładem problemu regresji może być przewidywanie ceny bitcoina w zależności od jego aktualnego kursu oraz w oparciu o dane z poprzednich miesięcy.

Podsumowując, Machine Learning ma wielki potencjał niemal w każdej dziedzinie, myślę, że ten wstęp powinien przybliżyć Ci jak mniej więcej to działa.

Źródła:

  • https://en.wikipedia.org/wiki/Artificial_neural_network
  • http://scikit-learn.org/
  • http://itcraftsman.pl/wstep-do-machine-learning/
]]>
/wstep-do-machine-learning/feed/ 0 1766
DevTycoon – Tech Demo /devtycoon-tech-demo/ /devtycoon-tech-demo/#respond Sun, 25 Mar 2018 12:42:06 +0000 /?p=1738 Witam! Po prawie dwóch miesiącach normalnej pracy i dwóch tygodni ciężkiej harówy jesteśmy gotowi, aby zaprezentować Wam pierwszą wersję naszej, małej jak na razie, gierki, która jest poświęcona tematowi, który tutaj wszyscy lubimy i kochamy, a mianowicie o byciu Deweloperem . Demo Technologiczne nie posiada zbyt dużo detali i zawartości. Wydaliśmy tę wersję gry, aby już mieć jakiś cel, i ogólnie, żeby już wystartować z grą. W tej wersji, dużą uwagę zwróciliśmy na samej wygląd gry . Staraliśmy się osiągnąć ładnie wyglądającą grafikę i połączyć to z dobrą optymalizacją , co nam się po części udało (GTX 960 wyciąga około 80-100fps na ultra ). Oprócz ładnie wyglądającej oprawy graficznej, przygotowaliśmy także fundament pod różne funkcje, które dojdą w przyszłych aktualizacjach. W Demie Technologicznym możliwe jest bardzo uproszczone programowanie, sklep oraz powiadomienia. Nie zabrakło opcji wyłączenia gry, co zresztą dodaliśmy 2 dni przed jej wydaniem..

Teraz może coś o naszym małym zespole, o którym raczej też należy wspomnieć. Głównym pomysłodawcą i programistą gry jestem ja, Denis. Pomysł na DevTycoon miałem już na początku 2017 roku, lecz brakowało mi umiejętności kodowania oraz modelowania. Jednym z pierwszych pomagierów został mój najlepszy internetowy przyjaciel, Jakub, który odpowiedzialny jest za całe otoczenie w świecie gry oraz trochę za działanie gry. Jako że to on najwięcej czasu poświęcił w granie gry na jego youtubowym kanale, został on moim prywatnym doradcą w sprawie responsywności interfejsu oraz ogólnie całego gameplay’u. Z tego miejsca mogę też wspomnieć o dwóch innych osobach, mianowicie o Staśku oraz o Wiktorze . Stasiek bardzo dużo pomaga przy zaawansowanych modelach , to dzięki niemu Auta mają wnętrze, a komputery to nie klocki, niczym z Minecraft’a. Wiktor przygotował dla Was stronę , którą będzie z czasem rozbudowywał pod Betę oraz Alphę. I teraz najważniejsza grupa, czyli Testerzy przedpremierowi. Bardzo chciałbym podziękować Root’owi oraz iLiquid’owi za udział w testach, które pomogły nam wyłapać głupie, aczkolwiek ciężko wykrywalne błędy. Ogólnie, gdyby nie te wszystkie osoby, gra by najprawdopodobniej nie powstała, bo by mnie to autentycznie przerosło.

Teraz chyba odpowiedź na pytanie, na którą wszyscy czekają. Czym DevTycoon będzie różniło się od innych tego typu gierek? W sumie, to niczym, oprócz tego, że chcemy zapożyczyć wszystkie udane pomysły, dodać do nich troszkę oryginalności i wszystkie włożyć pod jedną maskę. Np. w Simsach da się wchodzić w zaawansowaną interakcję z simem, u nas będzie podobnie, lecz trochę mniej zaawansowanie i bardziej pod temat programowania. Teraz zostają wszystkie inne gierki: Mad Games Tycoon, Game Dev Tycoon, StartUp Company oraz Software Inc. Każda z tych gier jest poświęcona innemu tematowi w dziedzinie programowania. W jednych możesz programować gry, w drugich antywirusy, a w jeszcze innych możesz robić nawet strony internetowe. Co by się stało, gdyby to wszystko połączyć w jedną całość? Podjęliśmy się zadania, aby to sprawdzić.

Co dalej z grą? Nie wiemy. Jeśli Demo Technologiczne wyjdzie znakomicie , a opinie będą w miarę dobre, to będziemy starać się rozwijać grę jak najlepiej, a w przyszłości wydać ją nawet na steamie. O fundingu na razie nie myślimy. Być może założymy Patronite, aby najbardziej zainteresowane osoby mogły nas wspierać finansowo, ale bardzo staramy się robić wszystko samemu .

// Krótki gameplay z gry zostanie dodany, kiedy będzie on gotowy.

Link do pobrania znajduje się na stronie: https://devtycoon.com/

Podsumowując: Wszelkie pomysły i uwagi na temat gry prosimy kierować na nasz adres Email: [email protected] , na wszystkie postaramy się odpowiedzieć.

Trochę screenów:

]]>
/devtycoon-tech-demo/feed/ 0 1738
Qt – Deployment aplikacji na Windowsa [dynamicznie] /qt-deployment-aplikacji-na-windowsa-dynamicznie/ /qt-deployment-aplikacji-na-windowsa-dynamicznie/#respond Wed, 22 Nov 2017 09:00:26 +0000 /?p=788 Czego unikać?

Bardzo popularnym, często powielanym błędem podczas deploymentu na Windowsa jest czekanie na błędy i wrzucanie bibliotek „na pałę” do folderu z binarką aplikacji, jest to pracochłonne, i działa tylko w niektórych przypadkach:

  • Aplikacja konsolowa Qt
  • Prosta aplikacja Qt Widgets (nie mylić z Qt Quick)

Trochę lepszym sposobem jest używanie dependency walker który, skanuje plik exe w poszukiwaniu zależności, i wyświetla brakujące biblioteki.

Prawidłowy i szybki deployment

Zacznę od aplikacji nieużywających komponentów Qt Quick , do tego celu użyjemy narzędzia windeployqt , znajduje się ono w katalogu Qt, podkatalogu wersji, podkatalogu mingw , i wreszcie w folderze bin w moim przypadku jest to C:/Qt/5.9/mingw53_32/bin .

Najczęściej popełnianym błędem, który i ja popełniłem jest użycie złej wersji narzędzia windeployqt , dlatego wcześniej warto się upewnić jakiej wersji Qt użyliśmy do budowy aplikacji.

Teraz czas uruchomić cmd i wywołać windeployqt wraz z odpowiednimi argumentami, w przypadku prostej aplikacji będzie to

Narzędzie automatycznie wykryje potrzebne biblioteki, znajdzie je i dorzuci do katalogu z naszym plikiem exe.

W przypadku aplikacji Qt Quick, należy dodatkowo załączyć adres projektu, wynika to z tego, że aplikacja wymaga dynamicznie zaczepionych plików qml od komponentów które zostały użyte, w tym celu używamy windeployqt zgodnie ze składnią:

Tu warto wspomnieć, że częstym błędem jest mylenie folderu projektu, z folderem qml który znajduje się obok folderu bin .

Przykładowe użycie:

Po więcej argumentów w razie potrzeby należy wywołać:

Polecam też zajrzeć na http://doc.qt.io/qt-5/windows-deployment.html .

]]>
/qt-deployment-aplikacji-na-windowsa-dynamicznie/feed/ 0 788
Wyniki ankiety, czyli jak wygląda (nie)przeciętny nastoletni programista. Część 1. /wyniki-ankiety-czyli-jak-wyglada-nieprzecietny-nastoletni-programista-czesc-1/ /wyniki-ankiety-czyli-jak-wyglada-nieprzecietny-nastoletni-programista-czesc-1/#comments Wed, 10 May 2017 18:16:00 +0000 /?p=1506 Mała retrospektywa: pamiętacie co zostało opublikowane na facebookowej grupie NP 11 marca? Prawdopodobnie nie. Skąd to wiem? Z wyników ankiety, którą wtedy opublikował jeden z administratorów. A mój post postara się ją wam nieco przybliżyć. Zapraszam!

Nazywam się Adam Jachowicz , jestem z Nastoletnimi od ich początków (dołączyłem do grupy 3 maja 2015, mogę się już chyba nazywać weteranem?). Większość z Was kojarzy mnie (jeżeli w ogóle, bo apogeum aktywności osiągnąłem bardzo dawno ) z bycia głównym redaktorem bloga http://programistycznepieklo.pl . No i jak możecie się domyślać – to mnie przypadło podsumowanie wyników ankiety. Sama przyjemność!

Przeciętny członek NP jest mężczyzną (cóż za zdziwienie) , ma 15-17 lat. Jego głównym obszarem zainteresowań jest desktop , zwykle ma też jakieś doświadczenie z webdevelopmentem . Zna też C++ , oprócz tego zwykle PHP i JS , rzadziej Javę , SQL i C# . Nigdy nie pracował ani nie wykonywał żadnego zlecenia. Ocenia swoją satysfakcję z programowania na 8.5 w skali od 1 do 10. Jeżeli przyszedłeś tylko po to co obiecywał tytuł – to tyle, możesz już zamknąć tę stronę.

Jeżeli jednak chcesz zobaczyć coś więcej…

Analiza danych pochodzących od respondentów – czyli coś dla chcących WIĘCEJ

Czas odpowiedzieć na pierwsze pytanie jakie może nasuwać się uważnemu czytelnikowi – skąd wiem, że większość osób będących członkami NP nie wiedziało o ankiecie? Albo konkretniej, że większość osób jej nie wypełniła ?

Ankietę (na dzień 01.04.2017) wypełniło 388 osób (ale pod uwagę wziąłem tylko 372, dalej okaże się czemu) – to mało jak na 5754 członków… Tak na dobrą sprawę to bardzo mało – dokładnie 6.47% grupy. Można by dyskutować, czy taka próbka nadaje się do analizy, ale to jedyne do czego mam dostęp, więc… ¯\_(ツ)_/¯

Płeć

Myślę że nie będzie tu niespodzianki, więc nie ma się co rozpisywać:

Wyk. 1: rozkład płci.

W sumie może i jest co napisać na ten temat… Oczywiście no offence i te sprawy, ale… kobiety wyglądają trochę jak błąd statystyczny ( ͡° ͜ʖ ͡°)

Wiek

Wyk. 2: Rozkład wieku

Tu już na szczęście robi się trochę ciekawiej . Znaczy, no, kobiety nadal wyglądają jak błąd statystyczny ( ͡° ͜ʖ ͡°) ale widać tu już jakieś ciekawsze powiązania. Przykładowo, kształt wykresu powinien być dla niektórych znajomy… Tak, to bardzo ładna krzywa normalna. Co prawda przesunięta nieco w stronę młodszych, ale nadal normalna.

Przykład dystrybucji normalnej zmiennych losowych.

Krzywa normalna (dzwonowata) – jedna z ważniejszych krzywych w statystyce ze względu na jej częste występowanie w naturze (m. in. krzywa wykresu obrazującego rozkład wartości IQ czy wzrostu lub nawet błędu pomiarowego). Posiada pewne ciekawe właściwości, ale ich tłumaczenie nie wchodzi jednak w zakres tego artykułu.

Jest jeszcze jedna rzecz która powinna się rzucić w oczy po analizie etykiet słupków… Jeżeli to zauważyłeś – moje osobiste gratulacje . Jeżeli nadal tego nie widzisz – istnieje słupek 20 jak i „>20”, ale pary „13” i „<13” już nie widać . Jak to się stało? No, nie chcę przywoływać nazwisk i imion, ale pewien z administratorów którego imię zaczyna się na A i kończy na lbert zapomniał dodać takiej opcji w ankiecie ( ͡° ͜ʖ ͡°) No nic, na potrzeby tego artykułu musimy założyć że każde „<13” jest tak naprawdę odpowiednikiem „<14”.

Technologia

W ankiecie trzeba było wybrać technologię na dwa sposoby – podać swoją główną oraz wszystkie znane technologie. Najpierw zajmiemy się tą główną:

Wyk. 3: Rozkład głównej technologii

Wartości procentowe odnoszą się do ogółu respondentów.

Co tu widzimy? Połowa członków NP jako target swoich programów wybiera głównie desktop, a 1/3 pisze stronki. Także nic zaskakującego, w końcu C++ i JS jest jednym z najbardziej ooops, jeszcze tu nie dotarliśmy Pod Innymi kryją się odpowiedzi takie jak:

konsolka,
Inne, (???)
asm, ale reverse engineering różnych technologii,
Teamspeak.

Skoro mamy dane dotyczące wieku jak i dane dotyczące technologii, możemy je skorelować – to dwa z ciekawszych wykresów:

Jak widać – wraz z wiekem więcej osób dryfuje z desktopa do innych technologii. Czemu tak się dzieje? Ano dlatego, że im młodszy jesteś, tym większe prawdopodobieństwo że dopiero się uczysz. A od czego zwykle zaczynają młodzi adepci programowania? Od C++. Potem dopiero zaczyna się odkrywanie technologii która jest ci bliska – najpierw zawsze jest ten proces nauki. Nie dziwi też to że nie przechodzą do webdevu – tak właściwie to następuje tu rotacja w obie strony, ponieważ drugim zestawem języków od którego często zaczynamy przygodę z programowaniem jest HTML, CSS i JS. A czemu wzrósł udział mobilek i mikrokontrolerów, i to akurat względem desktopa? Proste – programując na desktop, łatwiej jest się potem przerzucić na którąś z tych technologii niż na webdev.

Ten trend łatwiej będzie zauważyć na tym wykresie:

Wyk. 5: Porównanie procenta grup wiekowych wybierających Desktop/Web jako ich główną technologię.

Wartości procentowe obu słupków przy wieku nie sumują się do 100%, ponieważ są to wartości żywcem wyciągnięte z takiego jak powyżej wykresu kołowego – ważne są tu różnice w wysokości słupków, które wraz z wzrastającym wiekiem utrzymują w miarę stały trend malejący. Błędy, małe skoki w górę czy wielki skok nie pasujący do tezy przy grupie 20 czy >20 jest spowodowany wielkością próbki – tak jak mówiłem, jest trochę za mała by wyciągać z niej dokładne wnioski bezpośrednio, jednak pewnych rzeczy jako człowiek z doświadczeniem w takich rzeczach mogę się domyślić na podstawie nawet i takich danych

Wyniki drugiego związanego z technologią pytania nie powinny być zaskoczeniem po przeczytaniu wcześniejszego tekstu:

Wyk. 6: Procent wybierających dane technolgie.

Tutaj wartości nadal nie sumują się do 100%, ale tu powód jest prostszy – pytanie było pytaniem wielokrotnego wyboru i dotyczyło wszystkich znanych technologii. Ogólnie to nic ciekawego, ale mogę przywołać to co tym razem znalazło się pod pojęciem Inne :

Skryptowanie gier,
LUA (Multi Theft Auto: San Andreas),
dużo, (???)
Serwery, bazy danych,
Games,
Teamspeak,
STM32.

Po technologii czas na to co dla mnie osobiście jest najciekawszym zbiorem wektorów danych…

Języki

Zanim pokażę pierwszy wykres związany z tym działem muszę was ostrzec – praktycznie każdy wykres tutaj może dla was wyglądać tak samo. Muszę was jednak zapewnić że nie są takie same – wrażenie takie może się wziąć z tego, że próbują one pokazać jak najwięcej danych w jak najmniejszej/najefektywniejszej/najczytelniejszej postaci. No i kolorki są podobne.

Nie przedłużając, pierwszy kolos:

Wyk. 7: rozkład poziomu znajomości dla każdego z języków w ankiecie

Może na początku wytłumaczę co dokładnie ten wykres tak właściwie przedstawia. Po lewej mamy języki. Na dole jest liczbowa reprezentacja zaawansowania – wygodniej było się z tym obchodzić w kodzie, myślę że jest też bardziej przejrzyście na wykresach. Cyfry oznaczają:

  • 0 – Nie znam,
  • 1 – Nowicjusz,
  • 2 – Amator,
  • 3 – Średnio zaawansowany,
  • 4 – Zaawansowany,
  • 5 – Ekspert.

W ten sposób mogę traktować zaawansowanie w języku jako ciągłe, liniowe pasmo a nie jako zbiór 6 stopni – wygodniej

Wykres na górze przedstawia procent wszystkich respondentów mających dane zaawansowanie w danym języku. Przykładowo: 83 procent wszystkich respondentów nie zna Assemblera, 11 procent w jakiś sposób się z nim zetknęło ale tylko około 6 procent może się pochwalić pełniejszą wiedzą.

Możecie zauważyć, że na wykresie procenty dla Assemblera sumują się nie do 100, a do 101 procent – powodem są błędy zaokrągleń, niestety :/

Oprócz tego wykres posortowany jest tak, że język z największym średnim poziomem znania jest na górze, a ten z najmniejszym – na dole. Dzięki temu bardzo łatwo jest zobaczyć jakie języki są najpopularniejsze wśród członków naszej grupy – są to C++ , PHP , JS , SQL , C# , Java , Python i C . Trzeba jednak nadmienić że C++ ma nad nimi znaczącą przewagę, jak zresztą widać na wykresie. Można powiedzieć że języki od Perla w dół są językami nieznanymi na NP.

Osobiście mi trochę smutno że języki nowatorskie czy niestandardowe (Haskell, Go, Clojure, Scala, Groovy) lub specjalistyczne (Prolog, R) są pomijane przez członków NP – wiadomo, rzadko przyjdzie pisać większy projekt z ich udziałem ale ich znajomość może wiele rzeczy wyjaśnić, pokazać inne podejście do programowania. Ale cóż, co ja mogę ¯\_(ツ)_/¯

Co ciekawe, mamy raczej skromnych programistów, mało osób zaznaczało w ankiecie ekspercki poziom znania języka. Nawet w przypadku C++ było to tylko 3 % ankietowanych. Kochani, więcej pewności siebie ^^

Następny wykres (Wyk. 8) może być ciekawszy ze względu na to, że pokazuje on średnią znajomość danego języka wyrażoną w procentach w danej grupie wiekowej – oczywiste jest że wartości nie mogą się tu sumować do 100 %.

Wyk. 8: Średnia znajomość danego języka wśród danej grupy wiekowej (%)

Na tym wykresie bardzo ciekawie widać jedną rzecz – to, że z wiekiem umiemy coraz więcej. Niby taki banał, a tak ładnie zwizualizowany

Ciekawym ewenementem są członkowie w wieku 20 i >20 lat – zacznijmy może od dwudziestek.

Z danych jednoznacznie wynika… że są głupsi. Tak naprawdę to jedyny rocznik który nie podąża za trendem wzrostu wiedzy wraz z wiekiem. Czym może być to spowodowane? Właściwie to nie mam bladego pojęcia. W następnym wykresie ten spadek będzie widoczny jeszcze bardziej.

Chociaż właściwie to jest jedna rzecz w której trzymają się trendu – w językach, które zwykle są ignorowane przez programistów ;-; Ciekawe, prawda? Popularność języków wśród danych grup wiekowych także będzie przedmiotem jednego z następnych wykresów, więc będzie można ładnie zobaczyć tę zależność.

Osoby posiadające ponad 20 lat na karku są za to z niektórymi językami aż za bardzo do przodu (Pascal, Swift). Pierwszy z nich łatwo wytumaczyć – starsze roczniki często w szkołach uczyły się Pascala czy Delphi więc konsekwencją tej nauki musi być wyższy poziom poznania języka. Swift za to nie jest już taki banalny do wytłumaczenia – co tu się stało?

Na wynik wpłynęło to, że >20 to większa zasięgowo grupa niż na przykład takie 14 . Wśród osób zaznaczających tą odpowiedź mogły znajdować się zarówno dwudziestojedno jak i dwudziestopięciolatkowie. A jeżeli zakładamy że z wiekiem wiedza rośnie, to w wynikach grupy >20 nie ma nic dziwnego.

Czternastolatków przywołałem tu nie bez przyczyny – z jakiegoś dziwnego powodu są za bardzo zaawansowani w C# jak na swój wiek… Ma ktoś jakiś pomysł jak to wyjaśnić? Komentarze są wasze .

Co ciekawego jeszcze widzimy? Dziewiętnastolatkowie wychodzą poza szereg jeżeli chodzi o języki inne niż C++. To z kolei może oznaczać dwie rzeczy:

  • Nastolatkowie po skończeniu liceum nabywają dużo wiedzy programistycznej, albo…
  • …po prostu nie wyłapałem wszystkich trolli.

Pamiętacie co pisałem na początku? Z 388 odpowiedzi wziąłem pod uwagę tylko 372. Dlaczego? Właśnie z tego powodu – dane od trolli bardzo zakrzywiały różne korelacje/wyniki.

Myślę że można już przejść do kolejnego, obiecanego wykresu:

Wyk. 9: Średnie zaawansowanie w programowaniu w zależności od wieku

Cyferki mało tutaj znaczą – ten procent to średnia z kolumn z poprzedniego (Wyk. 8) wykresu. Ważne są zależności i trendy, które tutaj widać bardzo wyraźnie.

Pierwsze co się rzuca w oczy – wyraźny ubytek przy słupku opisanym 20 . Wcześniej już o tym pisałem – na tym wykresie można to zauważyć dokładniej. Jakieś pomysły? Znaczy, to zawsze może być błąd statystyczny, bo przy grupie badanych równej 13 osobom… No ale o małej wielkości próbki już pisałem…

Skok u dziewiętnastolatków również widać tutaj doskonale, przyczyny również opisałem wcześniej. Ten wykres służy właściwie podsumowaniu danych z tamtej mapy ciepła, nic szczególnego za sobą nie niesie.

W tym momencie podczas pisania tego artykułu się zadumałem. Czy ktokolwiek dojdzie do tego momentu? – myślałem. Licznik słów przekręcił się na magiczną liczbę 1720. Była we mnie nutka zwątpienia, ale także i ciekawości. Jeb^CChędożyć to! – powiedziałem w myślach. I zacząłem pisać dalej, zostawiając pytania o sens mojej egzystencji gdzieś na później.

Wyk. 10: Rozkład znajomości języków w danych grupach wiekowych.

Kolejny wykres również jest mapą ciepła. Znowu wartości w rzędach nie sumują się do 100%. Czemu więc? Wykres przedstawia procentową znajomość danego języka w danych grupach wiekowych.

W tym wykresie ważne jest, żeby przedstawić założenia na których opierałem się żeby zaliczyć dany język do „znanego” przez respondenta czy też nie. Problem w tego typu wykresach jest taki, że nie da się jednoznacznie, obiektywnie określić czy dany język jest przez kogoś znany. Bo jak określić znajomość?

Teoretycznie mogę nie programować w danym języku, ale mimo to znać go, chociażby tylko z nazwy. Chyba nie będzie sporów, gdy powiem że znam taki język? Niestety w tej ankiecie nie miałem szansy wdrożyć takiego podejścia przez sposób zadania pytania o języki – ewidentnie kładło ono nacisk na poziom poznania języka, a nie na jego znajomość .

Musiałem więc posłużyć się uproszczoną metryką znajomości i założyć, że każdy kto zaznaczył przy danym języku poziom zaawansowania przynajmniej 1 ( Nowicjusz ) zna ten język, a reszta która zaznaczyła 0 tego języka nie zna .

Przechodząc do analizy… Jest taki język który zna każdy. Niezależnie od grupy wiekowej. Małe odchyłki w liczbach właściwie nic nie znaczą, mapa ciepła mówi sama za siebie – pasek przypisany C++ jest w całości gorący .

Nasz poprzedni fenomen, dziewiętnastolatkowie, nadal wyróżniają się w tabeli, głównie za sprawą języków stricte webowych – JS’a i PHP . Co ciekawe – kosztem Javy .

Starsi, grupa >20 jak można było przewidzieć cechuje się najszerszą znajomością języków. Można też zobaczyć że moja hipoteza o Pascalu potwierdza się – na mapie widać, że starsze roczniki umieją go w znacznie większym procencie osób niż inne.

Dwudziestolatkowie mają z kolei problemy z… C#’em . W sumie oni mają ze wszystkim problemy (jak mogliśmy zobaczyć na wcześniejszych wykresach)… Ale to i tak dziwne jak na ogół. Za to znają Assemblera i Haskella na najlepszym poziomie ze wszystkich badanych grup wiekowych – zawsze coś ( ͡° ͜ʖ ͡°)

Wyk. 11: Rozkład znajomości języków w zależności od głównej technologii.

Ostatni już wykres (Wyk. 11) pokazuje rozkład procentowy znajomości danego języka w zależności od wybranej technologii głównej.

Skróty na dole pochodzą od nazw technologii:

  • W – Web ,
  • D – Desktop ,
  • M – Mobile ,
  • A – AVR/ARM.

Widać tu pewne silne trendy – przykładowo, 79% wybierających AVR/ARM zna C. Nie powinno być tu zaskoczenia, tak samo jak przy fakcie posiadania największej procentowej znajomości C++ wśród wszystkich grup technologicznych . Znają też dobrze Pythona , PHP i JS’a . Co do tego PHP i JS’a – podejrzewam że wynika to z błędu statystycznego, mała grupa badanych. Pythona dałoby się wytłumaczyć tym, że to popularny język skryptowy, jednak nadal myślę że nie usprawiedliwia to jego popularności w tym zestawieniu.

Co ciekawe, Webowcy znają Pascala niż inne grupy technologiczne – kto spodziewał się takiego wyniku? Mimo to, uzasadnienie istnieje – w szkołach obok Pascala jako języka stricte desktopowego nauczany jest też HTML razem z elementami CSSa i (czasem bo czasem, ale jednak) JSa. Wiadomo, że jakaś część uczniów wybierze Web jako swoją główną technologię, druga część wybierze Desktop. A jak mogliśmy zobaczyć na wykresach 3, 4.1 i 4.2 istnieje tendencja do wyrównywania się ilości osób mających za swoje główne technologie Web i Desktop wraz z końcem procesu kształcenia szkolnego. Więc zagadka rozwikłana

Wysoka znajomość Javy wśród Mobilnych chyba nie dziwi, tak jak najmniejsza ze wszystkich grup znajomość C++’a . Ciekawi najniższa wśród wszystkich grup znajomość Objective-C . Tak, wiem że teraz wszyscy w Swift’cie piszą, ale jednak – w ankiecie było pytanie o znajomość, a nie o używanie danego języka. W porównaniu do innych grup wygląda to słabiutko… No, ale za to wspomniany już wyżej Swift znają najlepiej ze wszystkich.

Trochę dziwi taka monotematyczność wśród Desktopowców – można to jednak tłumaczyć tym, że wśród desktopowców dużą przewagę mają młodsi, dopiero uczący się adepci programowania. Java czy C# nie są tu znane tak bardzo jak porównywalne języki w innych grupach, za to C++ trzyma się na stałym, wysokim poziomie znajomości wśród reprezentantów grupy Desktopowej.

I na tym niestety muszę zakończyć.

Post zrobił się nieco długi, powstawał też masę czasu – niestety, ale muszę go podzielić na dwie części. W następnej – dalsza część ankiety, czyli satysfakcja badanych kontra różne czynniki oraz praca i jej szczegóły takie jak typ umowy czy średnia płaca za godzinę. Będzie ciekawie! A do czasu pojawienia się następnej części zapraszam serdecznie do komentowania i zadawania pytań – na każde postaram się odpowiedzieć

A – no i w następnej części udostępnię kod generujący wykresy (jest konfigurowalny) oraz dane na których pracuję – stay tuned!

]]>
/wyniki-ankiety-czyli-jak-wyglada-nieprzecietny-nastoletni-programista-czesc-1/feed/ 10 1506
Sztuczna inteligencja w grach #01 – wstęp, zmysł wzroku oraz prosty debug-mode. /sztuczna-inteligencja-w-grach-01-wstep-zmysl-wzroku-oraz-prosty-debug-mode/ /sztuczna-inteligencja-w-grach-01-wstep-zmysl-wzroku-oraz-prosty-debug-mode/#comments Fri, 14 Apr 2017 12:27:34 +0000 /?p=1452 Sztuczna inteligencja w grach jest nieodłącznym elementem od dawien dawna. Jest ona mózgiem każdego wroga i NPC-ta. Kiedy programujemy A.I. mamy ogromne pole do popisu. Rozbudowywanie jej nie jest trudne i daje świetne efekty. Jest to element, który łatwo dostrzec i dzięki temu ludzie doceniają Twoją pracę jeszcze bardziej. W różnych grach można spotkać przeróżny poziom jakości zachowań postaci sterowanych komputerem. To jak dobre A.I. będą mieli wrogowie, często ma największy wpływ na końcową ocenę gry.

Niektóre z tytułów wręcz są popularne ze swojej prymitywnej S.I.:

Policjanci w GTA.

Źródło: http://www.memecenter.com/fun/509528/gta-sa-logic

Wbrew popularnej opinii sztuczna inteligencja policjantów w San Andreas nie jest aż taka prosta, jednak można by było ją trochę doszlifować. W tym artykule rozpoczniemy tworzenie podstawowego zmysłu dla przeciwników – zmysłu wzroku i wprowadzimy sobie prosty interfejs do debuggingu.

Zaczniemy od kodu finalnego z mojego poprzedniego artykułu: Jak programować gry? Najważniejsze elementy w grach 2D. Kod źródłowy z tamtego artykułu znajdziecie tutaj: GitHub

1. Przygotowanie sterowania i postaci pod grę.

Rozpoczniemy od stworzenia klasy gracza oraz klasy przeciwnika, które nazwiemy odpowiednio CPlayer oraz CEnemy . Następnie stworzymy prosty kontroler dla obydwu, a dodatkowo w kontrolerze gracza dodamy możliwość poruszania się.

Podobny schemat realizowałem już w filmie o tworzeniu bombermana, jednak przewiduję, że prawdopodobnie go nie obejrzałeś (bo komu chciałoby się oglądać w całości film o tworzeniu gry trwający 2 godziny). Z tego względu jeszcze raz wytłumaczę, co zrobiliśmy:

I) Utworzyliśmy klasę gracza i jego kontrolera:

  • CPlayer – klasa gracza
  • CPlayerController – klasa kontrolera gracza zawierająca sterowanie

Opisałem kod tak, by było dokładnie widać co krok po kroku trzeba wykonać.

Plik nagłówkowy Player.hpp :

Plik źródłowy Player.cpp :

II) Utworzyliśmy klasę wroga i jego kontrolera. Póki co nasze A.I. zostawimy w spokoju. Zajmiemy się nim w następnej części tego artykułu.

  • CEnemy – klasa wroga
  • CEnemyAIController – klasa kontrolera S.I. wroga

Plik nagłówkowy Enemy.hpp :

Plik źródłowy Enemy.cpp :

III) Wczytaliśmy potrzebne tekstury przy uruchamianiu gry:

IV) Stworzyliśmy gracza i jednego wroga, a następnie dodaliśmy ich do poziomu:

2. Utworzenie zmysłu wzroku.

Sztuczna inteligencja w grach jest oparta o różne zmysły np.: zmysł wzroku, zmysł słuchu czy nawet czasem zmysł węchu. Najprostszym do zaimplementowania jest zmysł wzroku, który jak zapewne łatwo jest się domyślić, będzie odpowiadał za widzenie. Będzie on działał w ten sposób, że będzie sprawdzał, czy jest coś interesującego w zasięgu wzroku oraz w obszarze widoku (kąt widzenia zrobimy łatwy do dostosowania) i jeśli coś wykryje, to zwróci to w wyniku.

Na początku, jako że wszystkie zmysły będą miały kilka wspólnych metod i własności, utworzymy sobie klasę bazową. Nazwałem ją IAISense (w swoich projektach przedrostek „I” dodaje do klas bazowych, dostarczających swego rodzaju interfejs do późniejszego rozbudowywania, jednak takich, które nie mogą być bezpośrednio używane). Do implementacji stworzymy sobie osobne pliki – AISense.hpp i AISense.cpp .

Teraz, zanim przejdziemy do kodu, zastanówmy się, co będzie musiał mieć każdy zmysł. Po chwili rozmyślań doszedłem do wniosku, że:

  • zmysł musi wiedzieć, kto jest jego właścicielem, gdyż każdy z nich musi znać np. pozycje właściciela;
  • zmysł musi posiadać jakąś listę postrzeganych aktorów;
  • zmysł musi dostarczać możliwość uaktualnienia postrzeganych aktorów (np. gdy ktoś wejdzie do pola widzenia albo wyjdzie z niego).

Będąc świadomym tego, do czego dążymy, utworzyłem następującą klasę bazową:

Warto bardzo dokładnie przeanalizować komentarze, szczególnie ten przy metodzie QueryActors, bo jest to kluczowa metoda tej klasy. Teraz do zaimplementowania został nam tak naprawdę tylko konstruktor (zwróć uwagę, że QueryActors jest metodą czysto wirtualną, GetSensedActors jest zdefiniowana jako inline ).

Kod konstruktora jest bardzo prosty:

Pokusiłem się tutaj o referencje na klasę IPawn (lub bazową) właściciela. Takie rozwiązanie wymusza podanie go (gdybyśmy użyli wskaźników, ktoś mógłby podać np. pusty wskaźnik), przez co reszta kodu, która się do niego odnosi, zadziała poprawnie.

Następnym etapem będzie stworzenie zmysłu wzroku. Aby mieć jakiś wgląd w sposób jego działania, spójrz na poniższy obraz:

Zatem mamy do stworzenia kolejną klasę, która będzie zawierała kąt i zasięg widzenia oraz implementacje metody QueryActors , która sprawdzi, czy aktorzy są polu widzenia. Zdecydowałem, że umieszczę tę klasę również w plikach AISense.hpp i AISense.cpp by nasz projekt nie miał za chwile 40 plików.

Tak oto wygląda ta klasa:

Tym razem do zaimplementowania mamy konstruktor oraz trzy metody. Może zajmijmy się najpierw konstruktorem:

Nie wrzuciłem ustawienia m_sightDistance i m_sightAngle do listy inicjalizacyjnej, ze względu na to, że mamy od tego odpowiednie funkcje, które zapobiegają wprowadzeniu nieodpowiednich danych.

Teraz spójrzmy dalej do metod SetSightDistance i SetSightAngle . Odpowiednie środki bezpieczeństwa są tutaj wymagane. Nie chcemy przecież mieć ujemnego zasięgu lub kąta widzenia > 180 stopni. Warto również zauważyć, że podane funkcje zwracają true , jeśli poprawnie ustawiono wartość a false , jeśli wartość była niepoprawna. Nie będziemy póki co z tego korzystać, ale warto mieć coś takiego zaimplementowanego – może niedługo się przyda

Przyszedł czas na kluczowy moment. Teraz zajmiemy się całą logiką zmysłu. Pomyślmy, co powinien on krok po kroku zrobić:

  • pobrać listę wszystkich aktorów ze sceny;
  • każdy aktor powinien być sprawdzony pod niżej wypisanymi kryteriami. Jeśli wszystkie z nich zostaną spełnione, dodajemy go do wynikowej listy aktorów;
    • aktor nie jest właścicielem tego zmysłu;
    • aktor znajduje się w odległości mniejszej niż zasięg wzroku;
    • kąt, pod którym znajduje się aktor względem właściciela, jest mniejszy niż kąt widzenia;
    • funkcja filtrująca pozwoliła aktorowi na dodanie do wyników.
  • zwrócić końcową listę aktorów.

Problemem jednak jest to, że w poprzednim artykule nie stworzyliśmy sobie metody, dzięki której zyskamy dostęp do listy aktorów ze sceny. Dlatego właśnie potrzebna jest nam poniższa funkcja, którą dodałem do klasy CLevel :

Na tych założeniach zbudowałem taką funkcję. Polecam przeanalizować po kolei każdy etap jej działania, gdyż właśnie jesteśmy w punkcie kulminacyjnym tego artykułu.

Uff… już najtrudniejsze za nami. Teraz możemy dodać już zmysł wzroku do wroga.
CSightSense m_sightSense; // Zmysl wzroku wroga
Należy również pamiętać o prawidłowym wywołaniu konstruktora zmysłu z poziomu listy inicjalizacyjnej. Następnie, aby nasz zmysł „działał” musimy go ciągle uaktualniać. Do tego posłuży nam metoda IActor::Update , którą sobie przeładujemy. Musimy jednak pamiętać, że metoda ta również ma swoją implementację w klasie bazowej IPawn , więc musimy umieścić też odwołanie do implementacji bazowej:

Co nam jednak z tego, że tak się narobiliśmy, a wciąż nie widzimy efektów? Właśnie dlatego teraz zaimplementujemy…

3. Widok informacji dla debuggingu

Wyszukiwanie błędów w grach jest bardzo uciążliwe, jeśli przed sobą mamy same cyferki i nic konkretnego. Dlatego właśnie wiele gier dodaje sobie prosty panel debugowania „in-game”. Tym właśnie się teraz zajmiemy.

Debugowanie w Gothic 2 NK

Na samym początku już wiemy, że potrzebna będzie nam funkcja generująca kształt wycinka koła. Jako że SFML sam jej nie dostarcza, postanowiłem napisać ją sam. Stworzyłem więc plik z deklaracją SFMLShapes.hpp oraz plik źródłowy SFMLShapes.cpp . Możliwe, że w przyszłości potrzebne będzie nam więcej własnych kształtów i wtedy umieścimy ich generowanie również w tych plikach.

Nazwałem ten kształt Pie (odnosi się do angielskiej nazwy ciasta, ponieważ nasz kształt to jakby wycinek ciasta ).

Powyższa funkcja nie jest w pełni funkcjonalna, jednak wystarcza do podstawowych zastosowań. Jej mankamentem jest to, że używa sf::ConvexShape (convex – wypukły). Może to spowodować niechciany efekt przy wyświetlaniu wycinka o kącie > 90 stopni. Jeśli ktoś ma na tyle ochoty, żeby się z tym bawić, to polecam do tego użyć sf::VertexArray .

Teraz już możemy wykorzystać ten generator. Pamiętamy jeszcze klasę IAISense ? Każdy zmysł będzie mógł się popisać jakimś fajnym symbolem przy debuggingu, dlatego też utworzymy metodę dla tej klasy, która będzie rysowała takie symbole na ekranie.

Metoda ta, nie jest metodą czysto wirtualną, bo zmysł ma mieć możliwość wyświetlenia debug info, ale nie jest do tego zmuszany.

Teraz czym do diabła jest to static bool DebugMode; ?

Dobrym pomysłem jest posiadanie jakiegoś przełącznika, którym będziemy sterowali, by albo włączyć tryb testowy, albo go wyłączyć. Statyczna zmienna DebugMode jest właśnie takim przełącznikiem. Oczywiście pamiętamy o tym, że taką zmienną statyczną trzeba też zainicjalizować. Najprościej będzie zrobić to na początku pliku źródłowego:

bool IAISense::DebugMode = true;

Mamy już bazę, to teraz trzeba zaimplementować wyświetlanie informacji trybu testowego dla zmysłu wzroku. Zrobiłem to tak:

Weźmy głęboki oddech… w tym miejscu artykuł ten możemy zakończyć jedną linijką, którą dodamy, by nasz debug info mógł się w ogóle wyświetlić. Jak zapewne się już domyśliłeś, umieścimy ją w metodzie wyświetlającej wroga na ekranie.

m_sightSense.DrawDebug();

4. Podsumowanie

W tym artykule zbudowaliśmy sobie podstawę pod dalsze rozwijanie modułu sztucznej inteligencji. Dodaliśmy również możliwość wyświetlania podstawowych informacji debuggingu. Kod z tego artykułu znajdziesz tutaj: GitHub . Teksturki można pobrać tutaj: Mega .

]]>
/sztuczna-inteligencja-w-grach-01-wstep-zmysl-wzroku-oraz-prosty-debug-mode/feed/ 2 1452
Zabezpieczenie antypirackie – aktywacja online z algorytmem RSA i BCrypt /zabezpieczenie-antypirackie-aktywacja-online-z-algorytmem-rsa-i-bcrypt/ /zabezpieczenie-antypirackie-aktywacja-online-z-algorytmem-rsa-i-bcrypt/#comments Mon, 27 Feb 2017 18:19:32 +0000 /?p=1307 Tworzycie aplikacje, które chcecie potem sprzedać? Za pewne chociaż przez chwilę pomyślałeś: „a co z piratami?”. W tym artykule chciałbym pokazać przykład zabezpieczenia aplikacji z aktywacją online, a także pokazać, jak szyfruje się algorytmem RSA i hashuje BCrypt’em.

Uwaga, aby artykuł nie miał setek stron, pominąłem dogłębne tłumaczenie kodu Javy/PHP/SQL. Co nie znaczy, że jeśli jesteś zaciekawionym tematem to nic nie zrozumiesz. Postarał się w miarę możliwości dobrze okomentować kod. W każdym razie czujcie się ostrzeżeni!

Z nielegalnym oprogramowaniem spotykamy się na co dzień – w Polsce jest ono dosyć popularne . Tworząc aplikację, którą chcemy sprzedać komuś, chcielibyśmy zadbać o to, żeby inni nie mieli do niej dostępu. Dlatego programiści starają się wymyślać coraz to nowsze zabezpieczenia przeciw piratom. Chciałbym pokazać jedną z prostych metod zabezpieczenia aplikacji.

Typowe zabezpieczenia:

  1. Aktywacja offline – tzn. wpisujemy klucz i wszystko działa
    • Zalety:
      • Brak konieczności połączenia z internetem
      • Najmniejszy problem dla użytkownika
    • Wady:
      • Najgorsze zabezpieczenie, możliwość wpisania tego samego klucza na wielu urządzeniach
  2. Aktywacja online z kontem – wpisujemy klucz i zostaje on przypisany do konta
    • Zalety:
      • Klucz nie jest przypisany do urządzenia, lecz do konta (możliwość przeniesienia licencji na inne urządzenia)
      • Po pierwszej aktywacji, można korzystać z programu offline
    • Wady:
      • Konieczność jednorazowego połączenia z internetem
      • Każdy użytkownik musi zrobić konto
      • Serwer aktywacji musi stale być dostępny, lecz tylko na czas aktywacji
  3. Aktywacja urządzenia online – wpisujemy klucz i urządzenie jest zapisywane do bazy danych
    • Zalety:
      • Brak możliwości skopiowania pliku weryfikującego licencję
      • Po pierwszej aktywacji, można korzystać z programu offline
    • Wady:
      • Konieczność jednorazowego połączenia z internetem
      • Serwer aktywacji musi stale być dostępny, lecz tylko na czas aktywacji
      • Brak możliwości aktywacji na kolejnym urządzeniu (co jeśli komputer się zepsuje?)
  4. Stały wymóg online
    • Zalety:
      • Najlepsze zabezpieczenie, bez zmian w kodzie programu trudne do obejścia
      • Możliwość instalacji programu na różnych urządzeniach (z tym że jednocześnie można włączyć tylko jeden)
    • Wady:
      • Konieczność stałego połączenia z internetem.
      • Serwer aktywacji musi stale być dostępny! Inaczej użytkownik nie włączy programu.

Do każdego z tych punktów można dopisać jeszcze jedną wadę:

Żadne zabezpieczenie nie jest całkiem bezpieczne

Żadne z tych zabezpieczeń nie odeprze jednego: zmiany kodu programu. Dlatego warto jest korzystać z różnych zabezpieczeń, które modyfikują nam nazwy zmiennych/funkcji w kodzie, aby potem kod był trudny do rozczytania po dekompilacji.

Aktywacja systemu Windows

Przed zastosowaniem zabezpieczenia warto przemyśleć, które warto wybrać. Jak każdy wie, stały wymóg połączenia internetowego może być denerwujący dla użytkownika. Jeżeli nie robicie aplikacji, która operuje na połączeniu internetowym, to nie zawsze warto wybierać to zabezpieczenie. Na dzień dzisiejszy najlepszym sposobem wydawać się może jednorazowa aktywacja – ma ją np. Windows, Steam. W tym artykule chciałbym zaprezentować mój sposób na system aktywacji, który przedstawiłem jako nr. 3 w liście wyżej; czyli – aktywacja urządzenia online.

Dlaczego akurat to wybrałem? Gdy myślałem o zastosowaniu mojej aplikacji, stwierdziłem, że zależy mi, aby nie była ona wykorzystywana przez jedną osobę na kilku urządzeniach. Dlatego aktywacja urządzenia wydaje się być rozsądnym wyborem.

Jak to wygląda?

Identyfikator sprzętowy

Przy aktywacji urządzenia pierwszą rzeczą, jaka jest nam potrzebna, to pobranie jakiegoś identyfikatora urządzenia. I to jest drobny problem – co można wziąć? W większości przypadków znajdziecie na internecie wykorzystanie adresu MAC karty sieciowej, ale to rozwiązanie jest dosyć słabe – ponieważ w przypadku laptopów jest możliwość, iż aplikacja była instalowana gdy interfejs sieciowy WLAN był włączony, a potem wyłączony. Adres MAC w aplikacji zostanie zwrócony inny i aplikacja przestanie działać . Dlatego polecam np. wykorzystać identyfikator BIOS’u. W Windowsie pobiera się go wpisując komendę w konsoli: wmic bios get serialnumber , w przypadku Linuxa sprawa jest nieco trudniejsza, ale i tak są pewne rozwiązania.

Schemat aktywacji

Okej – mamy już identyfikator sprzętowy – teraz przydałoby się go jakoś wysłać do serwera i odebrać plik weryfikacyjny. Tak to będzie wyglądać:

  1. Urządzenie klienta wysyła do serwera informację z identyfikatorem urządzenia + kluczem produktu do serwera.
  2. Serwer sprawdza czy klucz jest w bazie danych, jeśli jest to zwiększa jego licznik użycia i dodaje identyfikator urządzenia do tabeli.
  3. Następnie szyfruje algorytmem RSA przy użyciu klucza prywatnego sam identyfikator, wpisuje go do bazy danych i
  4. odsyła klientowi.
  5. Gdy klient odbierze plik, odszyfrowuje go za pomocą klucza publicznego i sprawdza czy jest to ten sam identyfikator sprzętowy.
  6. Następnie zapisuje zaszyfrowaną wiadomość w pliku *.key, który znajduje się w lokalizacji instalacji programu.

Ogólny schemat pierwszej aktywacji prezentuje się tak:

Schemat będzie się nieco różnić w przypadku, gdy klient aktywuje drugi raz aplikację na tym samym urządzeniu. Wtedy gdy serwer wykryje że klucz jest już użyty (czyli used_num>=1 ) to będzie sprawdzać tabelę activations i będzie próbował znaleźć hardware_id taki, jaki wysłał klient. Jeśli znajdzie takowy w tabeli, to oznacza, że klucz jest poprawny i odsyła klientowi klucz weryfikacyjny z kolumny response_key .

Przejdźmy do implementacji. Potrzebny nam serwer + baza danych na tym serwerze. Ja wybrałem bazę danych MySQL. Stworzyłem bazę danych o nazwie Activation , a w środku dwie tabele:

  • activation_keys – w tej tabeli zawarte są wszystkie zaszyfrowane klucze programu i ich liczba użyć
    CREATE TABLE activation_keys (id int PRIMARY KEY NOT NULL AUTO_INCREMENT, activation_key varchar(72) NOT NULL, used_num int);
  • activations – w tej tabeli zwarte są wszystkie aktywacje, identyfikator sprzętowy i identyfikator klucza z tabeli activation_keys
    CREATE TABLE activations (id int PRIMARY KEY NOT NULL AUTO_INCREMENT, id_key int NOT NULL, hardware_id varchar(64), response_key TEXT);

Identyfikator urządzenia będziemy pobierać, korzystając z wyżej wymienionego kodu + hashowania SHA-256.

Klucze będziemy szyfrować algorytmem BCrypt , który generuje maksymalnie 72-znakowy kod. Na obrazku obok jest pokazany schemat BCrypt. Jest to bardzo zalecane , gdyż mając atak hakerów na bazę danych, będą oni w stanie sprawdzić wszystkie dostępne klucze . Ogólnie, BCrypt zamienia klucz do formy zhashowanej. Ten proces trudno odwrócić, tzn.posiadając hash, trudno odnaleźć taki klucz, który po zhashowaniu będzie mieć taką samą formę jak zhashowany. BCrypt często wykorzystuje się do zapisywania haseł użytkowników na wielu stronach internetowych. Klient wysyła do serwera hasło w formie zahashowanej , a następnie jest sprawdzana jego poprawność. W przypadku ataku na bazę danych z hasłami, haker będzie mieć tylko tabelę z hasłami zahashowanymi oraz będzie mieć problem z odwróceniem procesu hashowania. Biblioteki BCrypt znajdziecie w Google.

Uwaga! Np. SHA-1, SHA-256 przestał być bezpiecznym algorytmem i dziś z dobrym komputerem nie ma większych problemów z inwersją. Jeżeli zależy wam na zabezpieczeniu przeciw dobrym hakerom, to polecam poszukać w Google nowych, skuteczniejszych zabezpieczeń. Jednak jeśli chcecie się obronić przed „Script kiddie”, to wystarczy nawet MD5. (nie warto też wrzucać tysięcy kluczy do tabeli, lecz dodawać nowe przy zakupie przez daną osobę)

Do tworzenia kluczy polecam stworzyć program. Ja uznałem że moje klucze będą 16 znakowe. Tak prezentuje się kod w Javie do wygenerowania losowego klucza i zhashowania go. Potrzebna jest też biblioteka BCrypt dla Javy: link .

BCrypt.gensalt(10) – decyduje o złożoności hasła. Czym większa liczba w argumencie, tym trudniej będzie odszyfrować. Ale też sprawdzanie za pomocą serwera będzie dłuższe. BCrypt.gensalt() generuje optymalną wartość, wybraną przez twórcę biblioteki. Warto zauważyć, że duża wartość może być też problemem dla serwera przy sprawdzaniu poprawności klucza.

String AB – w tym łańcuchu znaków znajdują się wszystkie znaki, które będą mogły znaleźć się w kluczu niezaszyfrowanym.

funkcja randomString – zwraca losowy łańcuch znaków o długości len , z wykorzystaniem znaków z łańcucha znaków String AB .

Test generacji klucza

Dodajmy od razu testowy klucz 1234567890123456. Aby taki zrobić wystarczy w kodzie zamiast String key = randomString(16); dać String key = "1234567890123456"; Klucze w takiej formie będą przechowywane w tabeli do której nikt nie ma prawa mieć dostępu. Możecie zrobić bazę danych albo po prostu wklejać je do arkusza kalkulacyjnego. Otrzymujemy zaszyfrowany klucz – $2a$10$SjT/4zh1LwNrsiKCvhUlzec4bAilAsvhw3xb2vpJkRK6eTacCTJFy. Teraz wpisujemy go do tabeli na serwerze korzystając z komendy SQL INSERT INTO .

INSERT INTO `activation_keys`(`activation_key`,`used_num`) VALUES (" $2a$10$SjT/4zh1LwNrsiKCvhUlzec4bAilAsvhw3xb2vpJkRK6eTacCTJFy ",0);

Czyli zhashowane klucze dodajemy do tabeli SQL, a klucz niezhashowany wysyłamy klientowi. Aplikacja będzie hashować klucz wpisany przez klienta, następnie wysyła go do serwera, który będzie porównywać wszystkie zhashowane klucze.

Okej, więc mamy bazę danych z kluczami gotową. Przejdźmy teraz do pliku weryfikującego licencję. Aby program zadziałał, w swojej lokalizacji musi mieć plik activation.key , który po odszyfrowaniu kluczem publicznym RSA wskaże SHA-256 identyfikatora sprzętowego urządzenia, na którym jest odpalany właśnie ten program. Ten plik activation.key będzie tworzony podczas pierwszej aktywacji (serwer wyśle odpowiedni kod dla klienta, który następnie zostanie zapisany w owym pliku). Trudno stworzyć taki klucz, żeby po odszyfrowaniu kluczem publicznych, dał SHA-256 identyfikatora, dlatego to zabezpieczenie jest w miarę bezpieczne. Serwer, posiadając klucz prywatny RSA może z łatwością stworzyć klucz weryfikacyjny. Rysunek pomoże dobrze zinterpretować to co napisałem:

Tworzenie klucza RSA

Dla przypomnienia – schemat szyfrowania RSA . Wszystko pokazane na obrazku wyżej: kluczem publicznym szyfrujemy wiadomość; zaszyfrowanej wiadomości nie można rozszyfrować kluczem publicznym , potrzebny jest do tego klucz prywatny . Szyfrowanie to może też działać w drugą stronę – można szyfrować kluczem prywatnym, a odszyfrowywać publicznym, co dziś wykorzystamy. W naszym przypadku klucz weryfikacyjny będzie szyfrowany kluczem prywatnym na serwerze , a potem klucz będzie odszyfrowywany w aplikacji kluczem publicznym.

Jak stworzyć klucz RSA ? Do jego stworzenia wykorzystam narzędzie OpenSSL , które można pobrać tu dla Windowsa: http://gnuwins32.sourceforge.net/packages/openssl.htm
Program ten odpala się w trybie konsolowym. Potrzebne nam będzie parę komend:

  • openssl genrsa -out private_key.pem 2048 – tworzy 2048-bitowy klucz prywatny, o rozszerzeniu *.pem, które dobrze odczyta PHP. Jeśli chcecie lepszy poziom zabezpieczeń, to możecie użyć 3072 bitów.
  • openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt – tworzy plik private_key.der w formacie PKCS#8, który lepiej jest odczytywany w Javie (bez kombinowania)
  • openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der – tworzy plik public_key.der, który łatwiej odczytać w Javie (bez tworzenia przeróżnych funkcji które zmieniają format klucza)

Są klucze, więc przyszła część na PHP, do którego będzie się zwracał klient. PHP będzie wypisywać proste komunikaty typu „ERROR”, „OK”, „WRONGKEY”, które następnie program wczyta i wskaże odpowiedni komunikat.

Klucz i identyfikator urządzenia będą wysyłane metodą POST. Wynik będzie wypisany funkcją echo, a oto lista możliwych wyników:

  • OK;klucz_weryfikacyjny; – aktywacja przebiegła pomyślnie, pomiędzy średnikami znajduje się klucz weryfikacyjny (zaszyfrowany kluczem prywatnym)
  • OK_USED;klucz_weryfikacyjny; – aktywacja przebiegła pomyślnie, nie jest to pierwsza aktywacja na tym urządzeniu
  • WRONGKEY – klucz nie znajduje się w bazie
  • WRONGHARDWARE – identyfikator urządzenia jest pusty
  • USED – klucz jest już aktywowany dla innego urządzenia
  • ERROR – Błąd przy łączeniu z bazą lub inny

Po co te średniki w odpowiedziach? Są one po to aby wydzielić granice klucza weryfikacyjnego. Głębsze wyjaśnienie tego znajdziecie w dalszej części artykułu.

Program desktopowy będzie sprawdzać, jaki kod został otrzymany i wyświetli odpowiedni komunikat.

Część serwerowa – plik PHP

Na początku stworzyłem sobie dwie funkcje, które kończą wykonywanie pliku PHP i zwracają błąd:

Jeśli jakimś cudem nie ma parametrów HTTP POST lub identyfikator sprzętowy jest pusty to należy zakończyć działanie programu:

Klucz prywatny (private_key.pem) wrzucamy do poprzedniego katalogu niż jest plik PHP. Upewnijmy się, że prawa do pliku są tylko dla serwera i że nie można tego pliku otworzyć bezpośrednio z innego urządzenia.

Teraz należy pobrać klucz prywatny RSA z poprzedniego katalogu, który nie jest dostępny dla nikogo:

Połączenie się z bazą danych i ewentualne zwrócenie błędu:

Pobieramy rekordy z tabeli activation_keys i sprawdzamy, czy klucz jest dobry.

password_verify() – sprawdza czy klucz w formie niezaszyfrowanej, jest odpowiednikiem zaszyfrowanego podanego w drugim argumencie (BCrypt)

trim() – usuwa spacje na początku i końcu klucza. (zabezpieczenie, jeśli do bazy danych daliśmy zaszyfrowany klucz z niepotrzebną spacją – mi się to zdarzyło)

Jeżeli klucz nie został jeszcze użyty – czyli $used jest równe 0, to przygotujemy klucz weryfikacyjny dla klienta metodą openssl_private_encrypt($informacja_do_zaszyfrowania, $zmienna_gdzie_zapisze_sie_zaszyfrowany_tekst, $klucz_prywatny_RSA); Następnie należy powiększyć licznik użycia klucza i dodać identyfikator sprzętowy do tabeli activations . Na sam koniec wystarczy zwrócić klientowi klucz weryfikacyjny funkcją echo , który następnie klient zapisze do pliku.

Użyte jest to proste zabezpieczenie przed SQL Injection, więcej o tym możecie poczytać w innym artykule na tej stronie: Zabezpieczenia baz danych

Jeżeli klucz jest użyty to należy sprawdzić, czy urządzenie o identyfikatorze wysłanym w HTTP POST występuje w tabeli activations . Jeśli występuje to należy klucz weryfikujący wysłać klientowi.

Jeśli po zakończeniu pętli nie odnaleziono klucza, to należy zwrócić błąd – zły klucz.

Cały plik prezentuje się tak:

Możecie stworzyć też prosty plik HTML i porobić parę testów:

Aplikacja desktopowa

W tym fragmencie artykułu będę opisywał stworzenie aplikacji desktopowej Javie, co nie zmienia faktu, że tak samo da się zrobić w innych językach programowania.

Zacznijmy od stworzenia projektu i dodania biblioteki BCrypt. Link do biblioteki: http://www.mindrot.org/projects/jBCrypt/

Stwórzmy najpierw klasę pomocniczą Activation.java . Będzie ona pomagać w tworzeniu klucza identyfikatora urządzenia i do odszyfrowania klucza weryfikacyjnego:

Jak pewnie zauważyliście, do pobrania identyfikatora sprzętowego potrzebna jest magiczna klasa WindowsID. Wyżej napisałem, jak w przypadku systemu Windows pobierać identyfikator. Oto ta klasa:

W przypadku innych systemów też znajdziecie różne rozwiązania na pobranie identyfikatora sprzętowego.

Przejdźmy teraz do GUI aplikacji. Na początku można zrobić prosty layout w JavaFX (Java Scene Builder):

A tutaj przegląd obiektów, dla których przypisałem jakieś id. Jest to potrzebne po to, aby już w kodzie Javy móc pobrać te obiekty:

Do katalogu resources (jeśli nie wiecie jak dodawać to zapraszam tutaj: link ) wrzucamy plik public_key.der . Startowy plik Javy wygląda tak:

OnActivationListener zawiera funkcję, która zostanie aktywowana, jeśli aktywacja się powiedzie oraz funkcję pobrania klucza publicznego.

Teraz część kontrolera Aktywacji. W JavaFX, korzystając z kontrolera scen, można łatwo pobierać obiekty GUI dla których przypisaliśmy jakiś identyfikator. Wystarczy podać adnotację @FXML a następnie klasę obiektu i jego identyfikator. Bardzo ułatwia to pracę.

Po kliknięciu przycisku submitButton jest on wyłączany (na czas próby połączenia z serwerem) i są wykonywane czynności łączenia. Do funkcji connectToServer dodałem 3 argumenty:

  • keyInput.getText() – klucz produktu
  • id – identyfikator urządzenia
  • interfejs ActivationListener – informuje o rezultacie połączenia / zwraca wynik wykonania PHP

Interfejs ActivationListener wygląda tak:

W odpowiedzi serwera musimy sprawdzić wszystkie przypadki, które wymieniłem wcześniej, czyli: OK , OK_USED , WRONGKEY , WRONGHARDWARE , USED , ERROR i jeszcze przypadek, jak coś innego zostało zwrócone (nieznany błąd). Gdy wystąpi błąd połączenia z serwerm (brak internetu lub serwer jest wyłączony) to zostanie wywołana funkcja z interfejsu ActivationListener void error(); Błąd połączania wyskoczy jako wyjątek IOException , który łatwo wyłapać.

A tak wygląda sama funkcja łączenia z serwerem:

Warto zaznaczyć, że koniecznie trzeba tu użyć wątków. Bez nich aplikacja zacięłaby się na czas łączenia z serwerem. Tak nie może być! Dlatego też skorzystałem z prostego wątku Thread.

Wracamy do interfejsu ActivationListener . Co jeśli jest błąd połączenia? Należy wyświetlić odpowiedni komunikat i ponownie włączyć przycisk submitButton (bo użytkownik ma prawo ponowić próbę).

Warto zauważyć, iż aktualizując elementy interfejsu z innego wątku, należy skorzystać z funkcji Platform.runLater , która aktualizuje GUI z wątku interfejsu graficznego. Bez tego nie da się aktualizować interfejsu.

Przejdźmy teraz do drugiej funkcji interfejsu ActivationListener. Serwer zwraca pewien ciąg bajtów, które można zamienić na łańcuch znaków: String responseString = new String (response); Problem polega na tym, że PHP zwraca niepotrzebne spacje i nowe linie na końcu pliku, dlatego też użyłem średników do wyznaczania początku i końca klucza weryfikacyjnego. Do tego klucz weryfikacyjny jest zapisany w formie bitów i zawiera różne znaki, które po przekształceniu do String’a, zmienią swój format. Dlatego, w przypadku zwróconego klucza weryfikacyjnego przez serwer, trzeba na nim operować jako na tablicy bajtów . Funkcja trimKey obcina tablicę bajtów do pierwszej znalezionej liczby podanej w argumencie 2 oraz obcina tablicę od końca to ostatniej znalezionej liczby podanej w argumencie 2. Średnik to w kodzie ASCII numer 59, dlatego też taki wpisałem do funkcji trimKey . Dobry klucz jest pobierany do zmiennej goodKey , a do zmiennej keyFromServerDecrypted przypisywany jest odszyfrowany klucz weryfikacyjny. Jeśli oba te zmienne mają takie same wartości ( contentEquals ), to należy zapisać klucz zaszyfrowany w pliku activation.key . Starałem się okomentować kod, aby był w miarę możliwości zrozumiały:

A funkcja trimKey prezentuje się tak:

Na sam koniec wystarczy jeszcze dopieszczyć plik startowy, aby program nie wyświetlał okna z aktywacją przy każdym uruchomieniu. Klucz będzie sprawdzany tak samo jak w przypadku aktywacji, więc nie tłumaczę już kodu. Poniżej fragment kodu z funkcji startowej JavaFX:

Wygląd okienka aktywacyjnego

Nareszcie koniec ! Cieszę się, jeśli dotrwaliście do tego momentu. Od teraz możecie powiedzieć, że algorytm RSA nie taki straszny, a nasza aplikacja stała się w miarę bezpieczna! Jakbyście czegoś nie rozumieli to zapraszam do komentowania !

Podsumowanie

Tworząc aplikacje, które dotrą do wielkiej liczby użytkowników, nie jesteśmy w stanie całkiem przeciwdziałać ich niecnym zamiarom okradania nas. Jednakże systemy antypirackie takie jak aktywacja online pozwalają pozbyć się tego problemu nawet w większości przypadków. Warto łączyć różne systemy aktywacji, tworzyć własne, aby były trudniejsze do ogarnięcia .

W tym artykule przekazałem także informacje na temat szyfrowania – jest ono używane wszędzie: na stronach banku , sklepach, mediach społecznościowych. Dlatego kryptografia (utajnianie wiadomości) jest taka ważna. Korzystamy z niej na co dzień! Tworząc stronę internetową warto zadbać o to, aby hasła użytkowników nie były narażone na proste ataki hakerów. Zabezpieczenie haseł nie jest trudnym zajęciem, jednakże nadal sporo osób omija to szerokim łukiem lub używa przestarzałych algorytmów.

]]>
/zabezpieczenie-antypirackie-aktywacja-online-z-algorytmem-rsa-i-bcrypt/feed/ 3 1307
Kontenery w C++ – std::array, czyli ładniejsza tablica. /kontenery-w-c-stdarray-czyli-ladniejsza-tablica/ /kontenery-w-c-stdarray-czyli-ladniejsza-tablica/#comments Sun, 19 Feb 2017 13:33:02 +0000 http://nastoletni.pl/?p=1280 W standardowych i popularnych kursach języka C++ zazwyczaj nikt nie rusza tematów poświęconych szczegółom takim jak kontenery, czy też inne pierdoły z referencji języka – mogą one się wydać rozpraszające lub po prostu trudne dla początkującego, lub komuś po prostu się nie chce. Dlatego postanowiłem napisać serię poradników poświęconych właśnie takim szczegółom, które potrafią bardzo ułatwić życie a o których rzadko kiedy się pisze. Zakładam oczywiście, że czytelnik posiada podstawową wiedzę na temat C++’a, bo bez tego może być mu ciężko ugryźć ten poradnik.

Zacznę od podstawowego kontenera, jakim jest std::array .

Zakładam, że wiesz co to tablica, prawda? Ot, zbiór elementów jednego typu poukładanych w pamięci jeden za drugim. Nic strasznego, nic trudnego. Jest to bardzo prosta rzecz, można by rzec nawet, że aż za prosta – standardowy C-style array nie posiada w sobie nic ciekawego, żadnych iteratorów, żadnych fajnych metod dostępu do niego, wszystko trzeba robić „ręcznie”.

I tutaj na scenie pojawia się std::array z biblioteki array , dodany w standardzie C++11

Ważne – (zazwyczaj) domyślnie każdy kompilator korzysta ze standardu C++03. Żeby skorzystać z nowszych, należy to sprecyzować przy użyciu flagi -std=c++11/14/17 (zależnie od standardu), albo w opcjach kompilatora – ale to zostawiam już do samodzielnego ogarnięcia).

Jest to bardzo przyjemna alternatywa, posiadająca dużą wartość użytkową – po prostu ułatwia programiście życie. No dobra, ale co w tym takiego fajnego? Dlaczego miałbym się przestawić nagle na std::array , zamiast używać starego dobrego c-style arraya?

But… why?

Używanie std::array jest prawie takie samo jak używanie zwykłego c-style arraya – losowy dostęp do elementów umożliwia standardowy operator [] , ale oprócz tego ten kontener posiada kilka bajerów:

Po pierwsze – std::array posiada tak zwany iterator . Iterator to obiekt wskazujący na jakiś element z zakresu elementów, który potrafi iterować (czyli, potocznie mówiąc, „przeskakiwać” ) między elementami przy pomocy na przykład operatorów inkrementacji czy dekrementacji (ale częściej iteratorów używa się ich w range-based for’ach na przykład, o czym za chwilę). Jest to duże ułatwienie w sytuacjach gdzie musimy na przykład przelecieć całą tablicę od początku do końca (lub też od końca do początku, bo std::array posiada także reverse iterator!)

Po drugie – posiada przeładowane operatory porównania == , != , < , <= , > , >= . Czyli możemy w łatwy sposób porównywać dwa std::array’e. Dodatkowo, ma przeładowania dla std::swap i std::get , gdybyśmy potrzebowali w fikuśny sposób dostać się do danego elementu tablicy lub zamienić jej zawartość z zawartością innej.

Po trzecie – posiada kilka użytkowych metod, takich jak fill (wypełnienie tablicy pewną wartością), front / back (dostęp do pierwszego/ostatniego elementu), empty (sprawdzenie czy tablica jest pusta), size / max_size (sprawdzenie aktualnej i maksymalnej ilości elementów). Jest to też typ agregowalny, czyli przykładowo można go inicjalizować poprzez klamry {} , tak jak zwykłą tablicę.

Podsumowując – std::array jest prawie taki sam w użytkowaniu jak zwykły c-style array, tylko fajniejszy oraz często wygodniejszy.

No fajnie, tylko jak tego użyć?

Jak już wcześniej mówiłem, można używać std::array tak samo jak zwykłej tablicy. Inaczej wygląda deklaracja, ponieważ jest to zwyczajna struktura z szablonowymi typami w konstruktorze:

template<class T, std::size_t N> struct array;

Gdzie T to typ danych przechowywanych w naszym kontenerze, a N to jego początkowa wielkość. std::size_t to ogólnie mówiąc typ danych dla liczb całkowitych bez znaku.

Warto o tym pamiętać, polecam przy odnoszeniu się do wielkości kontenerów używać std::size_t zamiast int’a czy jakiegokolwiek innego typu danych, oszczędzi nam to ostrzeżeń kompilatora mówiących o porównywaniu typów ze znakiem i bez niego.

Przykładowe deklaracje takich kontenerów wyglądają następująco

No i fajnie, mamy jakieśtam tablice. Co teraz z nimi zrobić? Wykorzystajmy dla przykładu iteratory.

Ten kod chyba wymaga tłumaczenia, szczególnie jeśli ktoś wcześniej nie miał kontaktu z nowszymi standardami C++.

Więc tak – pierwszy przykład wyświetla nam zawartość std::array przy użyciu range-based for’a. const auto &v to stała referencja do kolejnych wartości kontenera, iterator automatycznie inkrementuje się co iterację pętli. Dlaczego odnoszę się do elementów w ten sposób? Mógłbym to zrobić klasycznie, poprzez int v , ale w ten sposób każdy z elementów byłby kopiowany do tymczasowej zmiennej v , co w przypadku większych kontenerów stwarzało by duży problem wydajnościowy. Odniesienie się poprzez referencję pozwala na kopiowanie jedynie adresu do elementu, unikając kopiowania jego samego, a const uniemożliwia zmianę danego elementu (bo nie chcemy go przecież zmieniać). W tym wypadku jest to na tyle mała skala że w praktyce nie zauważymy żadnych wzrostów wydajności, ale warto wyrobić sobie praktykę używania referencji. Jeśli chodzi o auto , to jest to tylko kwestia wygody – ten keyword i tak zostanie zamieniony przez kompilator na odpowiedni typ danych.

W następnym kawałku kodu wypełniamy sobie tablicę bezpośrednio odnosząc się do iteratorów – b.begin() wskazuje na początek, b.end() na koniec naszego kontenera (analogicznie, b.rbegin() wskazuje na koniec, a b.rend() na początek). Jak wcześniej mówiłem, iteratory mają przeładowane operatory – inkrementacja, dekrementacja i tego typu rzeczy, które są bardzo wygodne.

Dalej, modyfikacja elementów przy użyciu range-based for’a, tutaj używam referencji bez const ponieważ modyfikuję elementy (i w tym wypadku nie mogę odnieść się bez referencji, ponieważ bez niej operował bym na kopiach elementów tablicy)

I na koniec smaczek, przelatuję sobie tablicę od końca co drugi element.

Ale jak by to wyglądało na normalnej tablicy?

Oczywiście to tylko kilka przykładowych porównań, ale widzimy, że std::array jest o wiele bardziej czytelniejszy niż standardowa tablica.

Podsumowanie – plusy i minusy

Przyszedł czas na krótkie podsumowanie naszego kontenera

  • + Czytelny – posiada wiele funkcji które pozwalają na pisanie czytelnego kodu z wykorzystaniem naszego arraya
  • + Wygodny – Iteratory, przeładowania operatorów, metody pozwalające na sprawdzenie wielkości i dostęp do krańcowych elementów oraz wiele więcej metod i bajerów ułatwiających życie
  • + Kompatybilny – Można go używać w ten sam sposób, jak normalnej tablicy. Ale nie trzeba.
  • – Stała wielkość – Jeśli potrzebujemy kontenera o zmiennej wielkości, należy użyć na przykład std::vector

I w sumie tyle. Jeśli masz jakieś wątpliwości, nadal czegoś nie rozumiesz, zapomniałem o czymś, masz jakąś sugestię czy cokolwiek – pisz śmiało w komentarzu.

A po pełną referencję i więcej przykładów dla tego kontenera zapraszam tutaj: http://en.cppreference.com/w/cpp/container/array .

Następny rozdział będzie poświęcony kontenerowi std::vector.

]]>
/kontenery-w-c-stdarray-czyli-ladniejsza-tablica/feed/ 5 1280
Zarabianie na zleceniach /zarabianie-na-zleceniach/ /zarabianie-na-zleceniach/#comments Sun, 12 Feb 2017 21:50:37 +0000 http://nastoletni.pl/?p=1166 Umiecie programować i chcielibyście zdobyć więcej kieszonkowego? A może nie macie motywacji by cokolwiek robić samemu, co wydawać się może niepotrzebne? Z pomocą przychodzą wam płatne zlecenia, dzięki którym doszlifujecie umiejętności w programowaniu i możecie coś zarobić!


Jako nastoletni programiści nieraz mamy taki moment, że nie wiemy co mamy robić. Kolejna strona/program? Brak pomysłów ! Więc czemu by nie sprawdzić siebie w zleceniach? W tym artykule chciałbym omówić tę kwestię.

Zlecenia to dobry sposób na nabycie doświadczenia.

W Polsce najpopularniejszym serwisem od zleceń dla programistów z pewnością jest Oferia.pl . Na tej stronie znajdziecie pełno zleceń – od budownictwa, grafik, transportu, aż po właśnie programowanie. Aktualnie jest 1300+ zleceń, które możemy wykonywać. Myślę, że każdy może tu znaleźć coś dla siebie – najwięcej zleceń jest z PHP, C++, C#, HTML i Javy.

Przykładowe oferty – jak widać jest duża różnorodność

Rejestracja

– jest dwuetapowa. Najpierw należy zrobić konto, podając adres email i hasło, a następnie po aktywacji przystąpić do konfiguracji konta. Co ważne – nie musicie mieć 18 lat ! W całym regulaminie Oferii nie ma wzmianki o wieku. Co więcej, nie musicie go nawet podawać! Z rejestracją jest tylko jeden mały problem – nasze dane osobowe będą widoczne w Google . Niektórym będzie to przeszkadzać, ale cóż, z tym nie da się nic zrobić. Podczas rejestracji należy podać imię, nazwisko, telefon i adres zamieszkania.

Legalność / oszustwa

Jak to z legalnością? – tutaj w większości zależy od zleceniodawcy. Zdecydowana większość zleceniodawców woli nie mieć żadnych umów . Większość tutaj kontaktuje się przez waszego maila, całkowicie omijając potem serwis Oferia – co najwyżej potem mogą wystawić wam ocenę, jeśli poprosicie. Zrobiłem już parę zleceń i ani razu nie miałem dalszego kontaktu przez ten serwis, nawet ocen nie dostałem.

„Wielu spotkałem takich ludzi, którzy chcieliby oszukiwać, ale takiego, który by chciał być oszukiwany, nie spotkałem.” – Aureliusz Augustyn z Hippony

Skoro bez umowy, to łatwo nas okraść? – tak, to niestety jest prawda . Oczywiście, możesz wymagać takowej umowy, ale szczerze mówiąc nie trafiłem jeszcze na kogoś, kto by mnie oszukał. A nawet jakby ktoś oszukał, to chciałoby wam się „gonić” za tą osobą? Oczywiście to zależy od ceny zlecenia, lecz na sam początek proponuję nie brać tych droższych – lepiej oswoić się z zleceniami, robiąc coś prostego.

Trafiają się też osoby, które najpierw wymagały mniej, a potem okazało się, że chcą jeszcze „to i tamto”. Wtedy musicie zadecydować – albo robicie w tej cenie, albo cena wzrośnie.

Wracając trochę do wstępu – jak nie macie co robić i robicie w miarę tanie zlecenia, to nawet jeśli dalibyście się zrobić w konia (dość rzadko się to zdarza), to zawsze macie kolejny projekt do portfolio ! Nie każdy ma motywację, żeby robić sobie samemu takie projekty do portfolio, a dzięki takim zleceniom macie ciekawe pomysły + uczycie się nowych technologii! Jest wiele prostych aplikacji, których nie chciałoby wam się robić, bo wydają się wam niepotrzebne, a jest wiele osób, które potrzebują takie aplikacje. Np. studenci często potrzebują prostych zadań – wyświetlanie figur 3D, prosty odtwarzacz muzyki, liczenie kredytów – to dobra okazja, aby nauczyć się jakiegoś API!

Pewnie teraz zapytacie – czyli jak składam ofertę, to muszę umieć perfekcyjnie to, co jest w zleceniu ? – odpowiedź brzmi: nie ! Jeżeli w ofercie jest wymagane używanie jakiegoś frameworka, to przejrzyj go z grubsza, oceń czy dasz radę i po prostu napisz ofertę. Zleceń nie trzeba wykonywać w 1 dzień – nieraz firmy robią dłużej projekty niż osoby prywatne. Skoro się jednocześnie uczysz i robisz zlecenia, to możesz dodać konkurencyjną cenę!

Przykład, że mimo pakietu MAX, ogłoszenia są mało atrakcyjne.

Portfolio i opis zgłoszenia

– to jest najważniejsze. Po przeczytaniu waszej oferty zleceniodawcy często patrzą na portfolio. Na Oferii
macie możliwość tworzenia portfolio, jednakże ja polecam własną stronę – bo to po prostu ładniej wygląda. Kolejne projekty będziecie tam wrzucać i będzie to wszystko ładnie rosło. Ja jeszcze nie mam, ale musicie uwierzyć mi na słowo.

Bez portfolio trudno dostać dobrą ofertę. Wyobraźcie siebie na miejscu zleceniodawcy – chcecie mieć dobry program/stronkę, a nie wykonaną przez gimnazjalistę w Scratchu. W opisie oferty zawsze odpowiadaj dokładnie na to, co prosi zleceniodawca – tzn. jeśli chce konkretną kwotę, to musisz ją podać! Uwzględnij swoje kompetencje, np. jeśli robiłeś coś podobnego w przeszłości, to wspomnij o tym. Możesz powiedzieć coś o sobie, przytoczyć inne projekty (portfolio). Dodaj, że bardzo chętnie podejmiesz się tego zlecenia i na sam koniec koniecznie podaj adres e-mail – bo, jak mówiłem, większość zleceniodawców woli kontakt przez e-mail niż przez prywatne wiadomości serwisu Oferia. Ogólnie jest dużo osób, które nawet nie czytają zlecenia, kopiują swoją ofertę i wklejają do wielu ofert (z ceną „do negocjacji”) – Ty już jesteś od nich lepszy !

Jak pewnie zauważysz, niektóre oferty są podświetlone – jest to pakiet MAX na Oferii. To już do was należy przemyśleć, czy chcecie taki kupić – z doświadczenia powiem, że bez tego z pewnością znajdziecie zlecenia. Opis i tak jest ważniejszy!

Bez niesamowitych pakietów można stworzyć lepszą ofertę!

Konkurencja

Gdy już znajdziesz odpowiednie zlecenie, to często inni wykonawcy będą podbijać i edytować swoje oferty. Możesz tutaj troszkę oszukać system i napisać coś więcej – ale wtedy licz się z tym, że zleceniodawca będzie wymagał od Ciebie profesjonalizmu. Pamiętaj też, że najniższa cena niczego nie gwarantuje. Jeśli nie masz portfolio, a ofertę masz kiepską, to najniższa cena nic nie pomoże.

Wysyłajcie wiele ofert – z doświadczenia wiem, że niektórzy zleceniodawcy rezygnują z projektu i do nikogo nie piszą. Jeśli jest jakiekolwiek nowe zlecenie, które Ci się podoba – pisz od razu . Jeśli nawet trafi Ci się potem tak, że napisze do Ciebie paru gości na maila, to po prostu powiesz im, że aktualnie nie dasz rady tego wykonać.

Podczas wykonywania zleceń możecie trafić na osobę, która w przyszłości będzie wam dostarczać zlecenia. Wasze dane osobowe są teraz publiczne, więc może się zdarzyć, że zleceniodawcy do was zadzwonią: ja na przykład otrzymałem ofertę stworzenia systemu dla biblioteki (spis książek, aplikacja webowa i Androidowa). Co więcej – nawet dzwoniła do mnie firma, która szuka programistę Java. Niestety jako iż jeszcze się uczę, a praca miała być na cały etat, to musiałem odmówić.

Inne strony

Inne strony ( żeby nie było, że to reklama Oferii ) – Z innych stron korzystałem też z freelancer.com . Tam jest baaaardzo dużo ofert (w końcu nie tylko polskie), jednak jakoś nie miałem tam powodzenia. Jest tam też dużo większy wybór pakietów (i dużo droższych) + większy limit ofert na miesiąc. Ale spróbować na pewno warto .

Podsumowanie

Przywołując słowa Alberta Einsteina:

„Każda pra­ca jest dob­ra, o ile jest dob­rze wykonywana.”

starajmy się, aby każde nasze zlecenie było dobrze wykonywane. Czym więcej zadowolonych klientów, to tym więcej doświadczenia i szansa na zauważenie takiej osoby przez znane firmy. Wykonując dobrą robotę, dostaniecie dobrą pracę, więc jeśli jeszcze nie wykonywałeś żadnej aplikacji na zlecenie – spróbuj !

]]>
/zarabianie-na-zleceniach/feed/ 2 1166