{"id":157,"date":"2017-11-14T19:24:56","date_gmt":"2017-11-14T18:24:56","guid":{"rendered":"http:\/\/cwiok.pl\/?p=157"},"modified":"2018-05-23T15:45:33","modified_gmt":"2018-05-23T13:45:33","slug":"nauka-gry-w-flappy-bird-wykorzystujac-ann-i-algorytm-genetyczny","status":"publish","type":"post","link":"https:\/\/cwiok.pl\/index.php\/pl\/2017\/11\/14\/nauka-gry-w-flappy-bird-wykorzystujac-ann-i-algorytm-genetyczny\/","title":{"rendered":"Nauka gry w Flappy Bird wykorzystuj\u0105c ANN i algorytm genetyczny"},"content":{"rendered":"<p>Postanowi\u0142em spr\u00f3bowa\u0107 stworzy\u0107 samo-ucz\u0105cy si\u0119 algorytm radz\u0105cy sobie z prostym problemem. Wiem, \u017ce moje rozwi\u0105zanie jest mocno na wyrost, ale i tak chcia\u0142em poeksperymentowa\u0107 z mo\u017cliwo\u015bciami po\u0142\u0105czenia GA i ANN.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-229\" src=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird.jpg\" alt=\"\" width=\"1200\" height=\"628\" srcset=\"https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird.jpg 1200w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-300x157.jpg 300w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-768x402.jpg 768w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-1024x536.jpg 1024w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><br \/>\n<!--more--><br \/>\nPlan dzia\u0142ania algorytmu jest prosty:<br \/>\n1. Zapisz ekran gry korzystaj\u0105c z OpenCV.<br \/>\n2. Znajd\u017a X i Y ptaka i kolumn. Wska\u017c algorytmowi kiedy gra, a kiedy jest w menu.<br \/>\n3. Podaj ANN dane wsadowe i czekaj na &#8220;decyzj\u0119&#8221;.<br \/>\n4. Oce\u0144 ANN na podstawie czasu gry.<br \/>\n5. Stw\u00f3rz now\u0105 populacj\u0119 ANN korzystaj\u0105c z GA na podstawie najlepszych rodzic\u00f3w.<br \/>\n6. Powt\u00f3rz<\/p>\n<p>Krokiem zerowym by\u0142o znalezienie odpowiedniej wersji gry do u\u017cycia. Wybra\u0142em <a href=\"http:\/\/flappybird.io\">t\u0119 wersj\u0119<\/a> g\u0142\u00f3wnie ze wzgl\u0119du na to, \u017ce mo\u017cna by\u0142o u\u017cywa\u0107 spacji do skakania i mog\u0142em j\u0105 spowolni\u0107 edytuj\u0105 skrypt JS.<\/p>\n<p><strong>Zapisz ekran gry korzystaj\u0105c z OpenCV.<\/strong><\/p>\n<p>Zapisywanie ekranu u\u017cywaj\u0105c biblioteki OpenCV by\u0142o prostym zadaniem. Umie\u015bci\u0142em przegl\u0105dark\u0119 internetow\u0105 po lewej stronie ekranu w taki spos\u00f3b, \u017ceby okno gry mia\u0142o zawsze te same wsp\u00f3\u0142rz\u0119dne (612,162,1090,781) i u\u017cy\u0142em kodu:<\/p>\n<pre>import numpy as np\r\nfrom PIL import ImageGrab\r\nimport cv2\r\n\r\n#To get the right colors\r\ndef process_img(original_image):\r\n    processed_img = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB)\r\n    return processed_img\r\nscreen1 = np.array(ImageGrab.grab(bbox=(612,162,1090, 781)))\r\nnew_screen = process_img(screen1)\r\ncv2.imshow('Flappy bird tracking',new_screen)\r\nif cv2.waitKey(25) &amp; 0xFF == ord('q'):\r\n    cv2.destroyAllWindows()\r\n    break\r\n<\/pre>\n<p>To da\u0142o mi dost\u0119p do ekrany w formacie numpy array. Dzi\u0119ki temu mog\u0142em doda\u0107 warstw\u0119 logiki, kt\u00f3ra pozwoli\u0142a mi znale\u017a\u0107 ptaka, kolumny i sprawdzi\u0107 czy algorytm jest w grze lub menu.<\/p>\n<p><strong>Znajd\u017a X i Y ptaka i kolumn. Wska\u017c algorytmowi kiedy gra, a kiedy jest w menu.<\/strong><\/p>\n<p>Znalezienie kolumny zosta\u0142o wykonane poprzez u\u017cycie metody matchTemplate. Za\u0142adowa\u0142em rysunek kolumny i odczyta\u0142em jej wysoko\u015b\u0107 i szeroko\u015b\u0107.<\/p>\n<pre>template = cv2.imread('column.jpg',0)\r\nw, h = template.shape[::-1]\r\nres = cv2.matchTemplate(cv2.cvtColor(new_screen,cv2.COLOR_BGR2GRAY),template,cv2.TM_CCOEFF_NORMED)\r\nthreshold = 0.8\r\nloc_column = np.where( res &gt;= threshold)\r\nfor pt in zip(*loc_column[::-1]):\r\n    cv2.rectangle(new_screen, pt , (pt[0] + w+55, pt[1] + h), (0,255,255), 2)\r\nif loc_column[::-1][0].any():   \r\n        bird_distance = -bird_dist+loc_column[::-1][0][0]\r\n        column_height = loc_column[::-1][1][0] \r\nelse:\r\n    bird_distance = -bird_dist+300\r\n    column_height = -bird_height+280\r\n<\/pre>\n<p>Znalezienie animowanego i poruszaj\u0105cego ptaka nie by\u0142o mo\u017cliwe przy u\u017cyciu matchTemplate. Postanowi\u0142em znale\u017a\u0107 ptaka poprzez zlokalizowanie kolor\u00f3w, kt\u00f3re wyst\u0119puj\u0105 tylko na ptaku. By\u0142o to spos\u00f3b, kt\u00f3ry wymaga\u0142 kilku pr\u00f3b, ale ostatecznie mia\u0142 100% skuteczno\u015bci.<\/p>\n<pre>lower_red = np.array([30,180,200])\r\nupper_red = np.array([50,200,220])\r\nmask = cv2.inRange(new_screen, lower_red, upper_red)\r\nthreshhold = 1\r\nloc_bird = np.where(mask &gt;= threshhold)\r\nfor pt in zip(*loc_bird[::-1]):\r\n    cv2.rectangle(new_screen, (loc_bird[::-1][0][0]  -20, loc_bird[::-1][1][0] - 5), (loc_bird[::-1][0][0]  +30, loc_bird[::-1][1][0] +30), (0,255,255), 2)\r\nif loc_bird[::-1][0].any():\r\n        #print('Ptak na wysokosci' + str(560-loc_bird[::-1][1][0]))\r\n        bird_height = loc_bird[::-1][1][0]\r\n        bird_dist = loc_bird[::-1][0][0]\r\n        #print(bird_dist)\r\nelse:\r\n    bird_height = 0\r\n    bird_dist = 72\r\n<\/pre>\n<p>W celu sprawdzenia czy algorytm jest w menu, czy nie, postanowi\u0142em sprawdza\u0107 obecno\u015b\u0107 punktacji nad ptakiem. W momencie ich znikni\u0119cia algorytm wie, \u017ce gra si\u0119 ko\u0144czy. Ca\u0142a logika jest dost\u0119pna poni\u017cej:<\/p>\n<pre>    #If there are no white points in the screen upper part:\r\nwhile(i&lt;10):\r\n    if(not([0,0,0] in screen1[100:120,197:267])):\r\n        time.sleep(0.5) \r\n        #Press space to start playing:\r\n        if(state != 'Play'):\r\n            state_update = 'Menu'\r\n            state=state_update\r\n            pyautogui.press('space')\r\n        #The game just ended, score everything:\r\n        else:\r\n            state_update = 'End'\r\n            if(state_update != state):\r\n                state=state_update\r\n                czas_gry = time.time()-last_time\r\n               \r\n                print(str(bird_height_old) + ' ' + str(czas_gry-0.5))\r\n                if((bird_height_old != 600) and (czas_gry-0.5 &gt; 10)):\r\n                    ranking_sieci.append([lista_sieci[i],czas_gry-0.5])\r\n              \r\n                i=i+1\r\n                if(i == 10):\r\n                    if(len(ranking_sieci)&gt;1):\r\n                        mutation_rate = 0.2\r\n                       \r\n                        sieci_ranking = sorted(ranking_sieci,key=lambda x: (x[1]),reverse=True)\r\n                        ranking_sieci=[]\r\n                        print(sieci_ranking)\r\n                        lista_sieci = []\r\n                        sieci_ranking[0][0].save(str(sieci_ranking[0][1]).replace(\".\",\"\"))\r\n                        print('tworze nowa populacje')\r\n                        evolution.create_new_pop(sieci_ranking[0][0],sieci_ranking[1][0],lista_sieci,mutation_rate)\r\n                        i=0\r\n                    else:\r\n                        print(ranking_sieci)\r\n                        print('musze zaorac')\r\n                        mutation_rate = 0.2\r\n                        test = sorted(ranking_sieci,key=lambda x: (x[1]),reverse=True)\r\n                        lista_sieci = [neural_net.NN(2,4,1) for i in range(10) ]\r\n                        i=0\r\n                        ranking_sieci=[]\r\n                        \r\n                        if (len(test)&gt;0): \r\n                          \r\n                            test[0][0].save(str(test[0][1]).replace(\".\",\"\"))\r\n                            lista_sieci[0] = evolution.mutate(test[0][0],0.05)\r\n                            lista_sieci[1] = evolution.mutate(test[0][0],0.1)\r\n                            lista_sieci[2] = evolution.mutate(test[0][0],0.2)\r\n                        \r\n                            \r\n            \r\n                time.sleep(1) \r\n                pyautogui.press('space')\r\n            \r\n    else:\r\n       \r\n        state_update = 'Play'\r\n       \r\n        if(state == 'Menu'):\r\n            last_time= time.time()\r\n            state=state_update\r\n            \r\n            pyautogui.press('space')\r\n            \r\n            \r\n          \r\n        else:\r\n            \r\n            decision = lista_sieci[i].runNN([column_height,bird_height,])\r\n            \r\n            if(column_height == 600):\r\n                time.sleep(1.4)\r\n            \r\n            \r\n            if(decision[0]&gt;0.5):\r\n                pyautogui.press('space')\r\n               \r\n            \r\n            bird_height_old = bird_height   \r\n\r\n<\/pre>\n<p><strong>Podaj ANN dane wsadowe i czekaj na &#8220;decyzj\u0119&#8221;.<\/strong><\/p>\n<p>Ok, na tym etapie mam ju\u017c X i Y obiekt\u00f3w, a algorytm wie kiedy gra. Nast\u0119pnym krokiem jest policzenie odleg\u0142o\u015bci w obu osiach mi\u0119dzy ptakiem, a nadchodz\u0105c\u0105 kolumn\u0105. To b\u0119d\u0105 dane wsadowe do ANN. Tworz\u0119 losowe ANN za pomoc\u0105 <a href=\"http:\/\/code.activestate.com\/recipes\/578241-genetic-algorithm-neural-network-in-python-source-\/\">tego <\/a>i <a href=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/11\/evolution.txt\">tego <\/a> skryptu.<\/p>\n<p>Ta linijka tworzy 10 sieci, kt\u00f3re b\u0119d\u0105 pierwsz\u0105 generacj\u0105. Wyb\u00f3r neuron\u00f3w w warstwie ukrytej jest losowy, bo nie chcia\u0142em sp\u0119dza\u0107 nad tym zbyt du\u017co czasu.<\/p>\n<pre>lista_sieci = [neural_net.NN(2,4,1) for i in range(10) ]\r\n<\/pre>\n<p>Nast\u0119pnie gram w p\u0119tli, gdzie i oznacza iteracj\u0119. W celu uzyskania decyzji o skoku podaj\u0119 dane wsadowe do ANN i na podstawie otrzymanej warto\u015bci podejmuj\u0119 decyzj\u0119:<\/p>\n<pre>decision = lista_sieci[i].runNN([column_height,bird_height,])\r\nif(decision[0]&gt;0.5):\r\n    pyautogui.press('space')\r\n<\/pre>\n<p><strong>Oce\u0144 ANN na podstawie czasu gry<\/strong><\/p>\n<p>Aby oceni\u0107 ANN obliczam czas mi\u0119dzy startem gry, a jej ko\u0144cem. Zegar zaczyna odlicza\u0107 czas w momencie pierwszego klikni\u0119cia spacji w menu. Zatrzymuj\u0119 si\u0119 kiedy ptak ginie. Ranking_sieci jest list\u0105 zawieraj\u0105c\u0105 ANN i ich czasy. Kiedy zostanie posortowana, na pierwszym miejscu znajd\u0105 si\u0119 rodzice wykorzystani do stworzenia kolejnej generacji.<\/p>\n<pre>czas_gry = time.time()-last_time              \r\nprint(str(bird_height_old) + ' ' + str(czas_gry-0.5))\r\nranking_sieci.append([lista_sieci[i],czas_gry-0.5])\r\n<\/pre>\n<p><strong>Stw\u00f3rz now\u0105 populacj\u0119 ANN korzystaj\u0105c z GA na podstawie najlepszych rodzic\u00f3w.<\/strong><\/p>\n<p>Na podstawie wynik\u00f3w sieci, wybieram najlepsze i stosuj\u0119 metody crossover i mutate poprzez wywo\u0142anie create_new_pop z evolution.py (dost\u0119pnego wy\u017cej):<\/p>\n<pre>evolution.create_new_pop(sieci_ranking[0][0],sieci_ranking[1][0],lista_sieci,mutation_rate)\r\n<\/pre>\n<p>Je\u015bli mniej ni\u017c 2 sieci przejd\u0105 przez minimalne wymagania, tworz\u0119 now\u0105 losow\u0105 populacj\u0119 i umieszam w niej mutacje najlepszego sieci z poprzedniej generacji. Tym sposobem nie trac\u0119 poprzednich wynik\u00f3w ca\u0142kowicie.<br \/>\n<strong>Powt\u00f3rz<\/strong><\/p>\n<p>Po stworzeniu nowej populacji, ustawiam i na 0 i pozwalam p\u0119tli kontynuowa\u0107 gr\u0119.<\/p>\n<p>Wyniki okaza\u0142y si\u0119 zaskakuj\u0105co dobre. Po kilku generacjach algorytm stal si\u0119 &#8220;wystarczaj\u0105co dobry&#8221;, \u017ceby gra\u0107 tak d\u0142ugo jak chcia\u0142o mi si\u0119 go pilnowa\u0107 \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Postanowi\u0142em spr\u00f3bowa\u0107 stworzy\u0107 samo-ucz\u0105cy si\u0119 algorytm radz\u0105cy sobie z prostym problemem. Wiem, \u017ce moje rozwi\u0105zanie jest mocno na wyrost, ale i tak chcia\u0142em poeksperymentowa\u0107 z mo\u017cliwo\u015bciami po\u0142\u0105czenia GA i ANN.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-229\" src=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird.jpg\" alt=\"\" width=\"1200\" height=\"628\" srcset=\"https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird.jpg 1200w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-300x157.jpg 300w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-768x402.jpg 768w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_03_nauka-gry-flappy-bird-1024x536.jpg 1024w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<div class=\"tech_read_more\"><a href=\"https:\/\/cwiok.pl\/index.php\/pl\/2017\/11\/14\/nauka-gry-w-flappy-bird-wykorzystujac-ann-i-algorytm-genetyczny\/\">Read More<\/a><\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34],"tags":[],"class_list":["post-157","post","type-post","status-publish","format-standard","hentry","category-python-pl"],"_links":{"self":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts\/157","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/comments?post=157"}],"version-history":[{"count":0,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts\/157\/revisions"}],"wp:attachment":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/media?parent=157"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/categories?post=157"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/tags?post=157"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}