{"id":869,"date":"2022-12-22T09:04:59","date_gmt":"2022-12-22T09:04:59","guid":{"rendered":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/?post_type=chapter&#038;p=869"},"modified":"2023-02-02T05:34:51","modified_gmt":"2023-02-02T05:34:51","slug":"ussimang-pygameiga","status":"publish","type":"chapter","link":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/chapter\/ussimang-pygameiga\/","title":{"raw":"Ussim\u00e4ng PyGame'iga","rendered":"Ussim\u00e4ng PyGame&#8217;iga"},"content":{"raw":"Loome siin ussim\u00e4ngu. M\u00e4ngu tegemiseks tuleb k\u00f5igepealt v\u00e4lja m\u00f5elda (kirja panna), mida m\u00e4ng tegema peab ehk millised on n\u00f5uded. K\u00f5igepealt s\u00f5nastame \u00fcldiselt, mida t\u00e4hendab \"ussim\u00e4ng\":\r\n\r\nM\u00e4ngija juhib ussi, kes ei tohi liikuda vastu seinu ega vastu iseenda saba. Uss peab korjama v\u00f5imalikult palju \u00f5unu. Iga \u00f5una korjamisega ussi saba pikeneb.\r\n\r\nKohe oleks m\u00f5istlik proovida panna reeglid t\u00e4psemalt kirja, sest nendest s\u00f5ltub, mismoodi ja mida me peaksime programmeerima hakkama.\r\n\r\n<section id=\"ussimangu-nouded\">\r\n<h2 id=\"ussimangu-nouded\">Ussim\u00e4ngu n\u00f5uded<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussimangu-nouded\">\uf0c1<\/a><\/h2>\r\nKirjeldame lihtlausetega, mida meie m\u00e4ng peab v\u00f5imaldama:\r\n<ul class=\"simple\">\r\n \t<li>ussil on pikkus<\/li>\r\n \t<li>algne pikkus on 5<\/li>\r\n \t<li>ussil on pea<\/li>\r\n \t<li>ussi pead saab juhtida<\/li>\r\n \t<li>uss saab liikuda paremale, vasakule, \u00fcles, alla - diagonaalis liikuda ei saa<\/li>\r\n \t<li>uss ei saa liikuda oma saba suunas (seda liikumist m\u00e4ng ei luba)<\/li>\r\n \t<li>kui ussi pea liigub vastu seina, saab m\u00e4ng l\u00e4bi<\/li>\r\n \t<li>ekraani \u00e4\u00e4red on seinad (otsustamise koht, kas need on n\u00e4htavad seinad v\u00f5i seinu n\u00e4ha pole, aga sinan vastu ei tohi liikuda)<\/li>\r\n \t<li>kui uss liigub oma saba pihta, saab m\u00e4ng l\u00e4bi<\/li>\r\n \t<li>maailma tekivad juhuslikku kohta \u00f5unad<\/li>\r\n \t<li>\u00f5una s\u00f6\u00f6misel uss pikeneb 2 \u00fchiku v\u00f5rra<\/li>\r\n<\/ul>\r\nProovime m\u00f5elda ka tehniliste n\u00f5uete peale:\r\n<ul class=\"simple\">\r\n \t<li>uss liigub n\u00e4htamatul ruudustikul<\/li>\r\n \t<li>\u00fcks ruut on 30 x 30 pikslit<\/li>\r\n \t<li>kui ussi pikkus on 5 ruutu, siis liikumisel \"pea\" liigub ussi liikumise suunas, viimane sama t\u00fckk \"kaob\" \u00e4ra<\/li>\r\n \t<li>kui uss s\u00f6\u00f6b \u00f5una ja pikeneb, siis kahe k\u00e4igu v\u00f5rra ta saba lihtsalt ei liigu kaasa (see pikeneb nii, et uued t\u00fckid tekivad kahe j\u00e4rgmise liikumisega viimase ruudu kohale)<\/li>\r\n \t<li>\u00f5un tekib ruudu sisse (mitte kahe ruudu vahele)<\/li>\r\n<\/ul>\r\nSiin on n\u00e4ide, kuidas uss liigub ruudustikus:\r\n\r\n<img class=\"alignnone size-medium wp-image-875\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-300x283.png\" alt=\"\" width=\"300\" height=\"283\" \/>\r\n\r\nUssi pikkus on 5 (roheline pea + 4 saba t\u00fckki). Uss liigub paremale. Alustame \u00fclemisest seisust. \u00dche liikumise j\u00e4rel tekib olukord \"2)\", kus pea on liikunud \u00fche v\u00f5rra paremale ning saba viimane t\u00fckk on \"kadunud\". J\u00e4rgmise sammuga on j\u00e4lle pea liikunud \u00fche v\u00f5rra paremale ning viimane saba t\u00fckk on \"kadunud\".\r\n\r\nSiin on n\u00e4ide, kuidas toimub \u00f5una s\u00f6\u00f6mise puhul pikenemine:\r\n\r\n<img class=\"alignnone size-medium wp-image-873\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-217x300.png\" alt=\"\" width=\"217\" height=\"300\" \/>\r\n\r\nAlguses on ussi pikkus 5 (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">1)<\/span><\/code>). Uss liigub paremale ja pea satub \u00f5una ruutu (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">2)<\/span><\/code>). See t\u00e4hendab, et uss s\u00f6\u00f6b \u00f5una \u00e4ra ning pikeneb 2 ruudu v\u00f5rra. Pikenemine ei toimu kohe, vaid kahe j\u00e4rgmise sammu v\u00e4ltel. Ehk siis \u00f5una s\u00f6\u00f6mise hetkel pikeneb uss kokku 1 ruudu v\u00f5rra. See uus pikendus tekib saba l\u00f5ppu ehk sinna, kus oli enne saba viimane t\u00fckk. J\u00e4rgmisel sammul (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">3)<\/span><\/code>) toimub sama - saba siimase t\u00fcki positsioonile tekib veel \u00fcks uus saba t\u00fckk. N\u00fc\u00fcd on ussi pikkus kokku 7. J\u00e4rgmisel sammul (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">4)<\/span><\/code>) toimub juba tavaline liikumine ehk saba viimane t\u00fckk liigub kaasa.\r\n\r\n<\/section><section id=\"ussi-hoidmine-malus\">\r\n<h2 id=\"ussi-hoidmine-malus\">Ussi hoidmine m\u00e4lus<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussi-hoidmine-malus\">\uf0c1<\/a><\/h2>\r\nVaatame, kuidas oleks m\u00f5istlik ussi m\u00e4lus hoida. L\u00f5puks peab ekraanile j\u00f5udma ussi pilt. Uss v\u00f5ib vabalt koosneda ristk\u00fclikutest. Seega t\u00e4itsa m\u00f5istlik ongi ussi hoida m\u00e4lus mitme ristk\u00fclikuna. Need ristk\u00fclikud saab hoida n\u00e4iteks j\u00e4rjendis. Saame kokku leppida, et j\u00e4rjendi esimene element on pea, j\u00e4rgmine element on saba esimene t\u00fckk jne. Alguses on j\u00e4rjendi pikkus 5. Alustame olukorrast, kus pikkus on juba 5, ning vaatame, kuidas toimuks liikumine. Hiljem vaatame seda, kuidas m\u00e4ng v\u00f5iks alata.\r\n\r\nTeeme praegu lihtsustuse, et me liigume m\u00f6\u00f6da sirget ning igal ruudul on indeks (0, 1, 2, jne). Uss liigub vasakult paremale. T\u00e4histame ussi j\u00e4rjendis ristk\u00fclikuid nende positsioonidega. N\u00e4iteks v\u00f5ib meil olla uss <code class=\"docutils literal notranslate\"><span class=\"pre\">[7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>.\r\n\r\n<img class=\"alignnone size-medium wp-image-876\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-300x167.png\" alt=\"\" width=\"300\" height=\"167\" \/>\r\n\r\nNagu pildilt n\u00e4ha, siis j\u00e4rgmisel sammul peaks uss olema <code class=\"docutils literal notranslate\"><span class=\"pre\">[8,<\/span> <span class=\"pre\">7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4]<\/span><\/code>. \u00dcks variant oleks m\u00f5elda nii, et me liigutame igat t\u00fckki \u00fche v\u00f5rra. Ehk siis pea liiguks \u00fche v\u00f5rra (ristk\u00fcliku positsioon muutub, meie n\u00e4ites saame +1 teha), j\u00e4rgmine t\u00fckk liiguks \u00fche v\u00f5rra jne. Eriti lihtne tundub see meie n\u00e4ites, kus kasutame arve. Aga kui n\u00fc\u00fcd m\u00f5elda selle n\u00e4ite peale, mida eelneval pildil n\u00e4gime, kus uss oli keeranud (liikus alla ja siis keeras paremale), siis seal see t\u00fckkide liigutamine nii kerge pole. M\u00f5ned t\u00fckid peavad liikuma alla, m\u00f5ned aga paremale. Ja mida pikem uss ja mida rohkem keeramisi, seda keerukamaks see t\u00fckkide nihutamine l\u00e4heb. Pigem v\u00f5iks teha nii, et lisame uue t\u00fcki j\u00e4rjendi etteotsa (ehk siis tekib n-\u00f6 uus \"pea\") ning eemaldame viimase elemendi. Meie positsioonide j\u00e4rjendi n\u00e4itel tehakse siis sellised operatsioonid:\r\n<div class=\"highlight-python notranslate\">\r\n<div class=\"highlight\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)\r\nsnake.pop()\r\n<\/pre>\r\nKui m\u00f5tleme \u00f5una s\u00f6\u00f6mise peale, siis pea liikus edasi, aga saba j\u00e4i paigale pikenemise t\u00f5ttu paariks sammuks. Vaatleme samamoodi ussi <code class=\"docutils literal notranslate\"><span class=\"pre\">[7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>.\r\n\r\n<\/div>\r\n<\/div>\r\n<img class=\"alignnone size-medium wp-image-874\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-300x187.png\" alt=\"\" width=\"300\" height=\"187\" \/>\r\n\r\n\u00dche sammu tulemusena peaksime saama j\u00e4rjendi <code class=\"docutils literal notranslate\"><span class=\"pre\">[8,<\/span> <span class=\"pre\">7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>. Erinevus tavalise liikumisega on see, et me ei eemalda viimast t\u00fckki. Seega koodis oleks see lihtsalt pea t\u00fcki lisamine:\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)<\/pre>\r\nKui n\u00fc\u00fcd proovida need kaks liikumist kokku panna, siis on vaja otsustada, millal on vaja sama t\u00fckk eemaldada ja millal mitte. Kuna ussil on kindel pikkus, siis ussi j\u00e4rjendi pikkus peab olema v\u00f5rdne ussi pikkusega. Kui ussi pikkus on 5, siis ka j\u00e4rjendis on 5 elementi. Kui uss s\u00f6\u00f6b \u00f5una \u00e4ra, muutub ussi pikkus 2 v\u00f5rra suuremaks. Seega v\u00f5ime m\u00f5elda nii, et kui j\u00e4rjendi pikkus on v\u00e4iksem kui ussi pikkus, siis j\u00e4relikult peab saba paigale j\u00e4\u00e4ma. Kui j\u00e4rjendi pikkus on suurem kui ussi pikkus, peab saba liikuma (ehk tuleb viimane element eemaldada).\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)\r\nif len(snake) &gt; snake_length:\r\n    snake.pop()\r\n<\/pre>\r\nSiin tegime n\u00e4ite \u00fchem\u00f5\u00f5tmelise v\u00e4ljaku peal arvudega, aga analoogselt saab j\u00e4rjendis hoida kahem\u00f5\u00f5tmelisi koordinaate v\u00f5i ristk\u00fclikuid. Muus osas loogika j\u00e4\u00e4b samaks.\r\n\r\n<\/section><section id=\"ruudustik\">\r\n<h2 id=\"ruudustik\">Ruudustik<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ruudustik\">\uf0c1<\/a><\/h2>\r\nM\u00e4nguplats on tinglikult jagatud ruudustikuks. Visuaalselt jooni t\u00f5mbama ei hakka, aga kogu m\u00e4ngu loogika peaks ruudustikku toetama. Vaatame, kuidas me \u00fchte ruutu saame ristk\u00fclikuna t\u00e4histada.\r\n\r\n<img class=\"alignnone size-medium wp-image-872\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-300x285.png\" alt=\"\" width=\"300\" height=\"285\" \/>\r\n\r\nRoheline ristk\u00fclik on see, mida tahame kuidagi esitada ekraanil. Ruudustiku iga ruudu k\u00f5rgus ja laius on 30 pikslit. N\u00fc\u00fcd selleks, et arvutada v\u00e4lja punane t\u00e4pp (mis t\u00e4histab ristk\u00fcliku \u00fclemist vasakut \u00e4\u00e4rt), saame kasutada ruudu x ja y suunalist positsiooni. \u00dclemine vasak ruut on positsioon <code class=\"docutils literal notranslate\"><span class=\"pre\">0,<\/span> <span class=\"pre\">0<\/span><\/code>. Meie roheline ruut on positsioonil <code class=\"docutils literal notranslate\"><span class=\"pre\">5,<\/span> <span class=\"pre\">8<\/span><\/code> (esimesena x-suunaline positsioon, siis y-suunaline positsioon). Punase t\u00e4pi asukoht on vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">(5<\/span> <span class=\"pre\">*<\/span> <span class=\"pre\">30,<\/span> <span class=\"pre\">8<\/span> <span class=\"pre\">*<\/span> <span class=\"pre\">30)<\/span><\/code>. Ja kuna me teame iga ruudu laiust ja k\u00f5rgust (m\u00f5lemas suunas 30), saame sealt ristk\u00fcliku laiuse ja k\u00f5rguse.\r\n\r\nSeega, meil on m\u00f5istlik oma objekte (ussi t\u00fckid, \u00f5un jms) hoida ruudustiku koordinaatides (nagu joonisel 0, 1, 2 jne on t\u00e4histatud). Ja sealt saame hiljem need arvutada vajadusel t\u00e4pseteks koordinaatideks ekraanil. See annab veel selle mugavuse, et kui hiljem on vaja ruudu suurust muuta (n\u00e4iteks 30 pealt 40 peale), siis me ei pea arvutusi mitmes kohas muutma hakkama. Aga igal juhul on koodis m\u00f5istlik otse <code class=\"docutils literal notranslate\"><span class=\"pre\">30<\/span><\/code> asemel kasutada konstanti (muutujat). Sedasi on hiljem mugavam muudatusi teha.\r\n\r\nLisame siia \u00fche video, kus oleme teinud ussim\u00e4ngu alge (siin lehel olev n\u00e4ide l\u00e4heb kaugemale):\r\n\r\n\r\n[embed]https:\/\/www.youtube.com\/embed\/gB0oKZcbcFQ[\/embed]\r\n\r\n<\/section><section id=\"koodi-kirjutamine\">\r\n<h2 id=\"koodi-kirjutamine\">Koodi kirjutamine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#koodi-kirjutamine\">\uf0c1<\/a><\/h2>\r\n<section id=\"ussi-liikumine\">\r\n<h3 id=\"ussi-liikumine\">Ussi liikumine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussi-liikumine\">\uf0c1<\/a><\/h3>\r\nAlustame sellest, et meil on uss ja seda saab juhtida.\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pygame\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((600, 600))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    snake.insert(0, (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1]))\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\r\nKui see k\u00e4ima panna, peaks saama nooltega ussi juhtida.\r\n\r\n<img class=\"alignnone size-medium wp-image-879\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-285x300.png\" alt=\"\" width=\"285\" height=\"300\" \/>\r\n\r\nUss on pidevalt liikumises. Me peame kuidagi t\u00e4histama, kuhu suunas ta liigub. \u00dcks variant on defineerida liikumine n\u00e4iteks nii, et 1 t\u00e4histab \u00fcles, 2 t\u00e4histab paremale jne. Ja siis vastavalt liikumise v\u00e4\u00e4rtusele arvutame uue koordinaadi. Me oleme kasutanud aga teist l\u00e4henemist: kasutame liikumie t\u00e4histamiseks ennikut <code class=\"docutils literal notranslate\"><span class=\"pre\">(delta_x,<\/span> <span class=\"pre\">delta_y)<\/span><\/code>, kus esimene v\u00e4\u00e4rtus v\u00e4\u00e4rtus t\u00e4histab x-suunalist koordinaadi muutust, teine t\u00e4histab y-suunalist koordinaadi muutust. Muutus saab olla kas -1 v\u00f5i +1. Seda on hiljem mugav kasutada, kui hakkame uut positsiooni arvutama: <code class=\"docutils literal notranslate\"><span class=\"pre\">new_head_position<\/span> <span class=\"pre\">=<\/span> <span class=\"pre\">(old_head_x<\/span> <span class=\"pre\">+<\/span> <span class=\"pre\">delta_x,<\/span> <span class=\"pre\">old_head_y<\/span> <span class=\"pre\">+<\/span> <span class=\"pre\">delta_y)<\/span><\/code>. Meil siis vana pea positsiooni saame <code class=\"docutils literal notranslate\"><span class=\"pre\">snake<\/span><\/code> listi esimesest elemendist: <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0]<\/span><\/code>. Kuna see on ennik, siis x-koordinaat on vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0][0]<\/span><\/code> ja y-koordinaat <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0][1]<\/span><\/code>. Ning suund on meil <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction<\/span><\/code> muutujas. x-koordinaadi muutus vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction[0]<\/span><\/code> ja y-koordinaadi muutus <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction[1]<\/span><\/code>. Uus positsioon lisatakse j\u00e4rjendi algusesse.\r\n\r\nSelleks, et programm oleks d\u00fcnaamilisem, defineerime kaks konstanti (muutuja, mille nimetus on l\u00e4bivalt suurte t\u00e4htedega; tegelikult on see Pythonis ikka muudetav, aga nimetus annab m\u00e4rku, et m\u00f5eldakse pigem muutumatut v\u00e4\u00e4rtust): <code class=\"docutils literal notranslate\"><span class=\"pre\">GRID_SIZE_X<\/span><\/code> ja <code class=\"docutils literal notranslate\"><span class=\"pre\">GRID_SIZE_Y<\/span><\/code>. Need t\u00e4histavad \u00fche ruudu laiust (x-suunalist suurust) ja k\u00f5rgust (y-suunalist suurust) pikslites. Neid v\u00e4\u00e4rtusi kasutame joonistamisel. Sedasi saame mugavalt muuta \u00fche kasti suurust. Vajadusel saame ka laiuse teha suuremaks kui pikkuse.\r\n\r\nAlguses defineerime \u00e4ra ussi algse pikkuse (5) ja lisame ussi algpositsiooni listi. Algne uss on tegelikult pikkusega 1 ning tal on vaid \u00fcks t\u00fckk (pea) positsioonil <code class=\"docutils literal notranslate\"><span class=\"pre\">(3,<\/span> <span class=\"pre\">3)<\/span><\/code>. Algne liikumissuund on paremale <code class=\"docutils literal notranslate\"><span class=\"pre\">(0,<\/span> <span class=\"pre\">1)<\/span><\/code>. Edasi juba uss pikeneb vastavalt sellele, mida eelnevalt vaatlesime: kuna ussi j\u00e4rjendi pikkus on v\u00e4iksem kui ussi pikkus, peab saba pikenema. Selliselt esimese 4 sammuga saavutab uss oma soovitud pikkuse (5).\r\n\r\n<\/section><section id=\"ouna-soomine\">\r\n<h3 id=\"ouna-soomine\">\u00d5una s\u00f6\u00f6mine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ouna-soomine\">\uf0c1<\/a><\/h3>\r\nLisame maailma \u00fche \u00f5una juhuslikule positsioonile. Ja kui ussi pea satub \u00f5una peale, siis uss pikeneb.\r\n\r\nSelleks, et juhuslikku arvu saada, kasutame <code class=\"docutils literal notranslate\"><span class=\"pre\">random<\/span><\/code> moodulit. Lisame eraldi muutuja <code class=\"docutils literal notranslate\"><span class=\"pre\">apple_position<\/span><\/code>, kus hoiame \u00f5una positsiooni <code class=\"docutils literal notranslate\"><span class=\"pre\">(x,<\/span> <span class=\"pre\">y)<\/span><\/code>. Kui ussi pea satub \u00f5una positsioonile toimuvad j\u00e4rgmised tegevused:\r\n<ul class=\"simple\">\r\n \t<li>\u00f5un tekib uuele positsioonile<\/li>\r\n \t<li>ussi pikkus suureneb 2 v\u00f5rra<\/li>\r\n<\/ul>\r\nUued read on m\u00e4rgitud teise v\u00e4rviga.\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"2,18-21,52-56\">import pygame\r\nimport random\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((600, 600))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n# how much the snake grows when eating\r\nsnake_growth = 2\r\n\r\napple_position = (random.randint(0, 20), random.randint(0, 20))\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    snake.insert(0, (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1]))\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    if snake[0] == apple_position:\r\n        apple_position = (random.randint(0, 20), random.randint(0, 20))\r\n        snake_length += snake_growth\r\n    # draw apple\r\n    pygame.draw.rect(screen, (255, 128, 0), (apple_position[0] * GRID_SIZE_X, apple_position[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\r\n<div class=\"highlight-python notranslate\">\r\n<div class=\"highlight\">\r\n<pre><\/pre>\r\n<\/div>\r\n<\/div>\r\nKui ussi pea (<code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0]<\/span><\/code>) satub samale positsioonile nagu \u00f5un (<code class=\"docutils literal notranslate\"><span class=\"pre\">apple_position<\/span><\/code>), siis uss s\u00f6\u00f6b \u00f5una. Sellisel juhul leiame \u00f5unale uue juhusliku asukoha ja suurendame ussi pikkust. Kuna meil pikkuse suurenemine on eelnevalt juba koodis sisse arvestatud, siis me ussiga seoses midagi muutma ei pea.\r\n<div class=\"admonition-harjutus admonition\">\r\n<div class=\"textbox textbox--exercises\"><header class=\"textbox__header\">\r\n<p class=\"textbox__title\">Harjutus<\/p>\r\n\r\n<\/header>\r\n<div class=\"textbox__content\">\r\n\r\nHetkel v\u00f5ib \u00f5un sattuda suvalisele positsioonile, seal hulgas ussi peale. Kuidas teha nii, et \u00f5un ei saaks tekkida ussi t\u00fcki peale?\r\n\r\nVihjeks: \u00f5una positsiooni tuleb nii mitu korda genereerida, kuni tulemus meid rahuldab. Seega on m\u00f5istlik teha <code class=\"docutils literal notranslate\"><span class=\"pre\">while<\/span> <span class=\"pre\">True<\/span><\/code> ts\u00fckkel, mille sees genereerime uue \u00f5una asukoha. Kui asukoht sobib, siis l\u00f5petame ts\u00fckli \u00e4ra (<code class=\"docutils literal notranslate\"><span class=\"pre\">break<\/span><\/code>). Kui aga \u00f5un satub ussi peale, siis j\u00e4tkame ts\u00fckli kordamist.\r\n\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n<\/section><section id=\"mangu-lopp\">\r\n<h3 id=\"mangu-lopp\">M\u00e4ngu l\u00f5pp<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#mangu-lopp\">\uf0c1<\/a><\/h3>\r\nLisame kontrolli, et uss ei saaks vastu \u00e4\u00e4rt ega vastu ennast liikuda. Kui see juhtub, siis m\u00e4ng saab l\u00e4bi.\r\n\r\nMeil piisab sellest, et kontrollida uut pea asukohta. \u00c4\u00e4re kontrollimiseks on m\u00f5istlik kasutusele v\u00f5tta konstant (muutuja), mis \u00fctleb, mitu ruutu meie m\u00e4ngupind x ja y suunal on. Ja tegelikult ruutude arvu ja ruutude suuruse j\u00e4rgi saame arvutada vajaliku akna suuruse. Kui meil m\u00e4nguala laius on 20 ruutu ja uss tahab liikuda 21. ruudule, siis saab m\u00e4ng l\u00e4bi. Samamoodi kui uss \u00fcritab liikuda 1. ruudult vasakule, saab m\u00e4ng l\u00e4bi.\r\n\r\nSelleks, et kontrollida, ega uss vastu enda saba ei liigu, saame kontrollida, kas uus pea asukoht on juba ussi j\u00e4rjendis olemas. Kui n\u00e4iteks uss tahab liikuda positsioonile <code class=\"docutils literal notranslate\"><span class=\"pre\">(5,<\/span> <span class=\"pre\">5)<\/span><\/code>, aga ussi j\u00e4rjendis on selline positsioon olemas (mis t\u00e4hendab, et seal paikneb ussi t\u00fckk), siis oleme liikunud vastu ennast ja m\u00e4ng saab l\u00e4bi.\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"4-7,10,24,46-54,64\">import pygame\r\nimport random\r\n\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\nGRID_WIDTH = 20\r\nGRID_HEIGHT = 20\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((GRID_WIDTH * GRID_SIZE_X, GRID_HEIGHT * GRID_SIZE_Y))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n# how much the snake grows when eating\r\nsnake_growth = 2\r\n\r\napple_position = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    new_head = (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1])\r\n    # check whether we go off the grid?\r\n    if new_head[0] &lt; 0 or new_head[0] &gt;= GRID_WIDTH or new_head[1] &lt; 0 or new_head[1] &gt;= GRID_HEIGHT:\r\n        running = False\r\n    # check whether we go into our tail\r\n    if new_head in snake:\r\n        running = False\r\n\r\n    snake.insert(0, new_head)\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    if snake[0] == apple_position:\r\n        apple_position = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))\r\n        snake_length += snake_growth\r\n    # draw apple\r\n    pygame.draw.rect(screen, (255, 128, 0), (apple_position[0] * GRID_SIZE_X, apple_position[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\r\n<div class=\"highlight-python notranslate\">\r\n<div class=\"highlight\">\r\n<pre><\/pre>\r\n<\/div>\r\n<\/div>\r\nMuudetud ja lisatud read on m\u00e4rgitud koodis teise v\u00e4rviga. Alguses loome konstandid ruudustiku suuruse ja iga lahtri suuruse jaoks. Real 10 arvutame akna suuruse vastavalt m\u00e4\u00e4ratud konstantidele. Real 24 kasutame konstante, et leida juhuslik asukoht \u00f5unale. Real 46 arvutame uue ussi pea asukoha eraldi muutujasse, et sellega oleks mugavam operatsioone teha. Rida 48 kontrollib, ega me ei liigu ekraanist v\u00e4lja. Kui uue pea x positsioon on v\u00e4iksem kui 0 v\u00f5i suurem-v\u00f5rdne akna laiusega, siis on pea juba ekraanilt v\u00e4ljas ja peame m\u00e4ngu \u00e4ra l\u00f5petama. Real 51 kontrollime, ega uue pea positsioon pole juba praeguses ussi j\u00e4rjendis. Kui on, siis j\u00e4relikult toimub liikumine vastu ussi saba. Real 64 on muudetud see, et kasutame konstante, et arvutada uus \u00f5una asukoht.\r\n<div class=\"textbox textbox--exercises\"><header class=\"textbox__header\">\r\n<p class=\"textbox__title\">Harjutus<\/p>\r\n\r\n<\/header>\r\n<div class=\"textbox__content\">\r\n\r\nPraegune kood t\u00f6\u00f6tab ussi sabasse liikudes natuke valesti. Probleem on selles, et kui uss liigub, siis ta saba viimane t\u00fckk ka \"liigub\". Kood arvutab praegu uus pea asukoha ning kontrollib kohe, ega see ei satu sellesse positsiooni, mis on juba ussi j\u00e4rjendis. Tegelikult peaks see kontroll toimuma peale liikumist.\r\n\r\n<img class=\"alignnone size-medium wp-image-877\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-300x180.png\" alt=\"\" width=\"300\" height=\"180\" \/>\r\n\r\nKui selle pildi j\u00e4rgi uss liigub \u00fcles, siis meie koodi j\u00e4rgi saab ta surma. Tegelikult aga peaks saba eest \u00e4ra liikuma. J\u00e4rgmine samm peaks olema selline:\r\n\r\n<img class=\"alignnone size-medium wp-image-878\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-300x176.png\" alt=\"\" width=\"300\" height=\"176\" \/>\r\n\r\n<\/div>\r\n<\/div>\r\n<\/section><\/section>","rendered":"<p>Loome siin ussim\u00e4ngu. M\u00e4ngu tegemiseks tuleb k\u00f5igepealt v\u00e4lja m\u00f5elda (kirja panna), mida m\u00e4ng tegema peab ehk millised on n\u00f5uded. K\u00f5igepealt s\u00f5nastame \u00fcldiselt, mida t\u00e4hendab &#8220;ussim\u00e4ng&#8221;:<\/p>\n<p>M\u00e4ngija juhib ussi, kes ei tohi liikuda vastu seinu ega vastu iseenda saba. Uss peab korjama v\u00f5imalikult palju \u00f5unu. Iga \u00f5una korjamisega ussi saba pikeneb.<\/p>\n<p>Kohe oleks m\u00f5istlik proovida panna reeglid t\u00e4psemalt kirja, sest nendest s\u00f5ltub, mismoodi ja mida me peaksime programmeerima hakkama.<\/p>\n<section id=\"ussimangu-nouded\">\n<h2 id=\"ussimangu-nouded\">Ussim\u00e4ngu n\u00f5uded<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussimangu-nouded\">\uf0c1<\/a><\/h2>\n<p>Kirjeldame lihtlausetega, mida meie m\u00e4ng peab v\u00f5imaldama:<\/p>\n<ul class=\"simple\">\n<li>ussil on pikkus<\/li>\n<li>algne pikkus on 5<\/li>\n<li>ussil on pea<\/li>\n<li>ussi pead saab juhtida<\/li>\n<li>uss saab liikuda paremale, vasakule, \u00fcles, alla &#8211; diagonaalis liikuda ei saa<\/li>\n<li>uss ei saa liikuda oma saba suunas (seda liikumist m\u00e4ng ei luba)<\/li>\n<li>kui ussi pea liigub vastu seina, saab m\u00e4ng l\u00e4bi<\/li>\n<li>ekraani \u00e4\u00e4red on seinad (otsustamise koht, kas need on n\u00e4htavad seinad v\u00f5i seinu n\u00e4ha pole, aga sinan vastu ei tohi liikuda)<\/li>\n<li>kui uss liigub oma saba pihta, saab m\u00e4ng l\u00e4bi<\/li>\n<li>maailma tekivad juhuslikku kohta \u00f5unad<\/li>\n<li>\u00f5una s\u00f6\u00f6misel uss pikeneb 2 \u00fchiku v\u00f5rra<\/li>\n<\/ul>\n<p>Proovime m\u00f5elda ka tehniliste n\u00f5uete peale:<\/p>\n<ul class=\"simple\">\n<li>uss liigub n\u00e4htamatul ruudustikul<\/li>\n<li>\u00fcks ruut on 30 x 30 pikslit<\/li>\n<li>kui ussi pikkus on 5 ruutu, siis liikumisel &#8220;pea&#8221; liigub ussi liikumise suunas, viimane sama t\u00fckk &#8220;kaob&#8221; \u00e4ra<\/li>\n<li>kui uss s\u00f6\u00f6b \u00f5una ja pikeneb, siis kahe k\u00e4igu v\u00f5rra ta saba lihtsalt ei liigu kaasa (see pikeneb nii, et uued t\u00fckid tekivad kahe j\u00e4rgmise liikumisega viimase ruudu kohale)<\/li>\n<li>\u00f5un tekib ruudu sisse (mitte kahe ruudu vahele)<\/li>\n<\/ul>\n<p>Siin on n\u00e4ide, kuidas uss liigub ruudustikus:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-875\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-300x283.png\" alt=\"\" width=\"300\" height=\"283\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-300x283.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-1024x966.png 1024w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-768x724.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-65x61.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-225x212.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement-350x330.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement.png 1072w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Ussi pikkus on 5 (roheline pea + 4 saba t\u00fckki). Uss liigub paremale. Alustame \u00fclemisest seisust. \u00dche liikumise j\u00e4rel tekib olukord &#8220;2)&#8221;, kus pea on liikunud \u00fche v\u00f5rra paremale ning saba viimane t\u00fckk on &#8220;kadunud&#8221;. J\u00e4rgmise sammuga on j\u00e4lle pea liikunud \u00fche v\u00f5rra paremale ning viimane saba t\u00fckk on &#8220;kadunud&#8221;.<\/p>\n<p>Siin on n\u00e4ide, kuidas toimub \u00f5una s\u00f6\u00f6mise puhul pikenemine:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-873\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-217x300.png\" alt=\"\" width=\"217\" height=\"300\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-217x300.png 217w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-739x1024.png 739w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-768x1064.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-65x90.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-225x312.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement-350x485.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement.png 1090w\" sizes=\"auto, (max-width: 217px) 100vw, 217px\" \/><\/p>\n<p>Alguses on ussi pikkus 5 (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">1)<\/span><\/code>). Uss liigub paremale ja pea satub \u00f5una ruutu (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">2)<\/span><\/code>). See t\u00e4hendab, et uss s\u00f6\u00f6b \u00f5una \u00e4ra ning pikeneb 2 ruudu v\u00f5rra. Pikenemine ei toimu kohe, vaid kahe j\u00e4rgmise sammu v\u00e4ltel. Ehk siis \u00f5una s\u00f6\u00f6mise hetkel pikeneb uss kokku 1 ruudu v\u00f5rra. See uus pikendus tekib saba l\u00f5ppu ehk sinna, kus oli enne saba viimane t\u00fckk. J\u00e4rgmisel sammul (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">3)<\/span><\/code>) toimub sama &#8211; saba siimase t\u00fcki positsioonile tekib veel \u00fcks uus saba t\u00fckk. N\u00fc\u00fcd on ussi pikkus kokku 7. J\u00e4rgmisel sammul (pildil samm <code class=\"docutils literal notranslate\"><span class=\"pre\">4)<\/span><\/code>) toimub juba tavaline liikumine ehk saba viimane t\u00fckk liigub kaasa.<\/p>\n<\/section>\n<section id=\"ussi-hoidmine-malus\">\n<h2 id=\"ussi-hoidmine-malus\">Ussi hoidmine m\u00e4lus<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussi-hoidmine-malus\">\uf0c1<\/a><\/h2>\n<p>Vaatame, kuidas oleks m\u00f5istlik ussi m\u00e4lus hoida. L\u00f5puks peab ekraanile j\u00f5udma ussi pilt. Uss v\u00f5ib vabalt koosneda ristk\u00fclikutest. Seega t\u00e4itsa m\u00f5istlik ongi ussi hoida m\u00e4lus mitme ristk\u00fclikuna. Need ristk\u00fclikud saab hoida n\u00e4iteks j\u00e4rjendis. Saame kokku leppida, et j\u00e4rjendi esimene element on pea, j\u00e4rgmine element on saba esimene t\u00fckk jne. Alguses on j\u00e4rjendi pikkus 5. Alustame olukorrast, kus pikkus on juba 5, ning vaatame, kuidas toimuks liikumine. Hiljem vaatame seda, kuidas m\u00e4ng v\u00f5iks alata.<\/p>\n<p>Teeme praegu lihtsustuse, et me liigume m\u00f6\u00f6da sirget ning igal ruudul on indeks (0, 1, 2, jne). Uss liigub vasakult paremale. T\u00e4histame ussi j\u00e4rjendis ristk\u00fclikuid nende positsioonidega. N\u00e4iteks v\u00f5ib meil olla uss <code class=\"docutils literal notranslate\"><span class=\"pre\">[7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-876\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-300x167.png\" alt=\"\" width=\"300\" height=\"167\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-300x167.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-1024x571.png 1024w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-768x428.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-65x36.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-225x125.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line-350x195.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_line.png 1094w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Nagu pildilt n\u00e4ha, siis j\u00e4rgmisel sammul peaks uss olema <code class=\"docutils literal notranslate\"><span class=\"pre\">[8,<\/span> <span class=\"pre\">7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4]<\/span><\/code>. \u00dcks variant oleks m\u00f5elda nii, et me liigutame igat t\u00fckki \u00fche v\u00f5rra. Ehk siis pea liiguks \u00fche v\u00f5rra (ristk\u00fcliku positsioon muutub, meie n\u00e4ites saame +1 teha), j\u00e4rgmine t\u00fckk liiguks \u00fche v\u00f5rra jne. Eriti lihtne tundub see meie n\u00e4ites, kus kasutame arve. Aga kui n\u00fc\u00fcd m\u00f5elda selle n\u00e4ite peale, mida eelneval pildil n\u00e4gime, kus uss oli keeranud (liikus alla ja siis keeras paremale), siis seal see t\u00fckkide liigutamine nii kerge pole. M\u00f5ned t\u00fckid peavad liikuma alla, m\u00f5ned aga paremale. Ja mida pikem uss ja mida rohkem keeramisi, seda keerukamaks see t\u00fckkide nihutamine l\u00e4heb. Pigem v\u00f5iks teha nii, et lisame uue t\u00fcki j\u00e4rjendi etteotsa (ehk siis tekib n-\u00f6 uus &#8220;pea&#8221;) ning eemaldame viimase elemendi. Meie positsioonide j\u00e4rjendi n\u00e4itel tehakse siis sellised operatsioonid:<\/p>\n<div class=\"highlight-python notranslate\">\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)\r\nsnake.pop()\r\n<\/pre>\n<p>Kui m\u00f5tleme \u00f5una s\u00f6\u00f6mise peale, siis pea liikus edasi, aga saba j\u00e4i paigale pikenemise t\u00f5ttu paariks sammuks. Vaatleme samamoodi ussi <code class=\"docutils literal notranslate\"><span class=\"pre\">[7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>.<\/p>\n<\/div>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-874\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-300x187.png\" alt=\"\" width=\"300\" height=\"187\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-300x187.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-768x479.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-65x41.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-225x140.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line-350x218.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_eat_movement_line.png 1021w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>\u00dche sammu tulemusena peaksime saama j\u00e4rjendi <code class=\"docutils literal notranslate\"><span class=\"pre\">[8,<\/span> <span class=\"pre\">7,<\/span> <span class=\"pre\">6,<\/span> <span class=\"pre\">5,<\/span> <span class=\"pre\">4,<\/span> <span class=\"pre\">3]<\/span><\/code>. Erinevus tavalise liikumisega on see, et me ei eemalda viimast t\u00fckki. Seega koodis oleks see lihtsalt pea t\u00fcki lisamine:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)<\/pre>\n<p>Kui n\u00fc\u00fcd proovida need kaks liikumist kokku panna, siis on vaja otsustada, millal on vaja sama t\u00fckk eemaldada ja millal mitte. Kuna ussil on kindel pikkus, siis ussi j\u00e4rjendi pikkus peab olema v\u00f5rdne ussi pikkusega. Kui ussi pikkus on 5, siis ka j\u00e4rjendis on 5 elementi. Kui uss s\u00f6\u00f6b \u00f5una \u00e4ra, muutub ussi pikkus 2 v\u00f5rra suuremaks. Seega v\u00f5ime m\u00f5elda nii, et kui j\u00e4rjendi pikkus on v\u00e4iksem kui ussi pikkus, siis j\u00e4relikult peab saba paigale j\u00e4\u00e4ma. Kui j\u00e4rjendi pikkus on suurem kui ussi pikkus, peab saba liikuma (ehk tuleb viimane element eemaldada).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">snake.insert(0, 8)\r\nif len(snake) &gt; snake_length:\r\n    snake.pop()\r\n<\/pre>\n<p>Siin tegime n\u00e4ite \u00fchem\u00f5\u00f5tmelise v\u00e4ljaku peal arvudega, aga analoogselt saab j\u00e4rjendis hoida kahem\u00f5\u00f5tmelisi koordinaate v\u00f5i ristk\u00fclikuid. Muus osas loogika j\u00e4\u00e4b samaks.<\/p>\n<\/section>\n<section id=\"ruudustik\">\n<h2 id=\"ruudustik\">Ruudustik<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ruudustik\">\uf0c1<\/a><\/h2>\n<p>M\u00e4nguplats on tinglikult jagatud ruudustikuks. Visuaalselt jooni t\u00f5mbama ei hakka, aga kogu m\u00e4ngu loogika peaks ruudustikku toetama. Vaatame, kuidas me \u00fchte ruutu saame ristk\u00fclikuna t\u00e4histada.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-872\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-300x285.png\" alt=\"\" width=\"300\" height=\"285\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-300x285.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-1024x971.png 1024w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-768x728.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-65x62.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-225x213.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid-350x332.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/grid.png 1028w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Roheline ristk\u00fclik on see, mida tahame kuidagi esitada ekraanil. Ruudustiku iga ruudu k\u00f5rgus ja laius on 30 pikslit. N\u00fc\u00fcd selleks, et arvutada v\u00e4lja punane t\u00e4pp (mis t\u00e4histab ristk\u00fcliku \u00fclemist vasakut \u00e4\u00e4rt), saame kasutada ruudu x ja y suunalist positsiooni. \u00dclemine vasak ruut on positsioon <code class=\"docutils literal notranslate\"><span class=\"pre\">0,<\/span> <span class=\"pre\">0<\/span><\/code>. Meie roheline ruut on positsioonil <code class=\"docutils literal notranslate\"><span class=\"pre\">5,<\/span> <span class=\"pre\">8<\/span><\/code> (esimesena x-suunaline positsioon, siis y-suunaline positsioon). Punase t\u00e4pi asukoht on vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">(5<\/span> <span class=\"pre\">*<\/span> <span class=\"pre\">30,<\/span> <span class=\"pre\">8<\/span> <span class=\"pre\">*<\/span> <span class=\"pre\">30)<\/span><\/code>. Ja kuna me teame iga ruudu laiust ja k\u00f5rgust (m\u00f5lemas suunas 30), saame sealt ristk\u00fcliku laiuse ja k\u00f5rguse.<\/p>\n<p>Seega, meil on m\u00f5istlik oma objekte (ussi t\u00fckid, \u00f5un jms) hoida ruudustiku koordinaatides (nagu joonisel 0, 1, 2 jne on t\u00e4histatud). Ja sealt saame hiljem need arvutada vajadusel t\u00e4pseteks koordinaatideks ekraanil. See annab veel selle mugavuse, et kui hiljem on vaja ruudu suurust muuta (n\u00e4iteks 30 pealt 40 peale), siis me ei pea arvutusi mitmes kohas muutma hakkama. Aga igal juhul on koodis m\u00f5istlik otse <code class=\"docutils literal notranslate\"><span class=\"pre\">30<\/span><\/code> asemel kasutada konstanti (muutujat). Sedasi on hiljem mugavam muudatusi teha.<\/p>\n<p>Lisame siia \u00fche video, kus oleme teinud ussim\u00e4ngu alge (siin lehel olev n\u00e4ide l\u00e4heb kaugemale):<\/p>\n<p><iframe loading=\"lazy\" id=\"oembed-1\" title=\"PyGame: Ussim\u00e4ngu n\u00e4ide\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/gB0oKZcbcFQ?feature=oembed&#38;rel=0\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<\/section>\n<section id=\"koodi-kirjutamine\">\n<h2 id=\"koodi-kirjutamine\">Koodi kirjutamine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#koodi-kirjutamine\">\uf0c1<\/a><\/h2>\n<section id=\"ussi-liikumine\">\n<h3 id=\"ussi-liikumine\">Ussi liikumine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ussi-liikumine\">\uf0c1<\/a><\/h3>\n<p>Alustame sellest, et meil on uss ja seda saab juhtida.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pygame\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((600, 600))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    snake.insert(0, (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1]))\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\n<p>Kui see k\u00e4ima panna, peaks saama nooltega ussi juhtida.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-879\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-285x300.png\" alt=\"\" width=\"285\" height=\"300\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-285x300.png 285w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-973x1024.png 973w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-768x808.png 768w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-65x68.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-225x237.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple-350x368.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_preview_simple.png 1048w\" sizes=\"auto, (max-width: 285px) 100vw, 285px\" \/><\/p>\n<p>Uss on pidevalt liikumises. Me peame kuidagi t\u00e4histama, kuhu suunas ta liigub. \u00dcks variant on defineerida liikumine n\u00e4iteks nii, et 1 t\u00e4histab \u00fcles, 2 t\u00e4histab paremale jne. Ja siis vastavalt liikumise v\u00e4\u00e4rtusele arvutame uue koordinaadi. Me oleme kasutanud aga teist l\u00e4henemist: kasutame liikumie t\u00e4histamiseks ennikut <code class=\"docutils literal notranslate\"><span class=\"pre\">(delta_x,<\/span> <span class=\"pre\">delta_y)<\/span><\/code>, kus esimene v\u00e4\u00e4rtus v\u00e4\u00e4rtus t\u00e4histab x-suunalist koordinaadi muutust, teine t\u00e4histab y-suunalist koordinaadi muutust. Muutus saab olla kas -1 v\u00f5i +1. Seda on hiljem mugav kasutada, kui hakkame uut positsiooni arvutama: <code class=\"docutils literal notranslate\"><span class=\"pre\">new_head_position<\/span> <span class=\"pre\">=<\/span> <span class=\"pre\">(old_head_x<\/span> <span class=\"pre\">+<\/span> <span class=\"pre\">delta_x,<\/span> <span class=\"pre\">old_head_y<\/span> <span class=\"pre\">+<\/span> <span class=\"pre\">delta_y)<\/span><\/code>. Meil siis vana pea positsiooni saame <code class=\"docutils literal notranslate\"><span class=\"pre\">snake<\/span><\/code> listi esimesest elemendist: <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0]<\/span><\/code>. Kuna see on ennik, siis x-koordinaat on vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0][0]<\/span><\/code> ja y-koordinaat <code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0][1]<\/span><\/code>. Ning suund on meil <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction<\/span><\/code> muutujas. x-koordinaadi muutus vastavalt <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction[0]<\/span><\/code> ja y-koordinaadi muutus <code class=\"docutils literal notranslate\"><span class=\"pre\">snake_direction[1]<\/span><\/code>. Uus positsioon lisatakse j\u00e4rjendi algusesse.<\/p>\n<p>Selleks, et programm oleks d\u00fcnaamilisem, defineerime kaks konstanti (muutuja, mille nimetus on l\u00e4bivalt suurte t\u00e4htedega; tegelikult on see Pythonis ikka muudetav, aga nimetus annab m\u00e4rku, et m\u00f5eldakse pigem muutumatut v\u00e4\u00e4rtust): <code class=\"docutils literal notranslate\"><span class=\"pre\">GRID_SIZE_X<\/span><\/code> ja <code class=\"docutils literal notranslate\"><span class=\"pre\">GRID_SIZE_Y<\/span><\/code>. Need t\u00e4histavad \u00fche ruudu laiust (x-suunalist suurust) ja k\u00f5rgust (y-suunalist suurust) pikslites. Neid v\u00e4\u00e4rtusi kasutame joonistamisel. Sedasi saame mugavalt muuta \u00fche kasti suurust. Vajadusel saame ka laiuse teha suuremaks kui pikkuse.<\/p>\n<p>Alguses defineerime \u00e4ra ussi algse pikkuse (5) ja lisame ussi algpositsiooni listi. Algne uss on tegelikult pikkusega 1 ning tal on vaid \u00fcks t\u00fckk (pea) positsioonil <code class=\"docutils literal notranslate\"><span class=\"pre\">(3,<\/span> <span class=\"pre\">3)<\/span><\/code>. Algne liikumissuund on paremale <code class=\"docutils literal notranslate\"><span class=\"pre\">(0,<\/span> <span class=\"pre\">1)<\/span><\/code>. Edasi juba uss pikeneb vastavalt sellele, mida eelnevalt vaatlesime: kuna ussi j\u00e4rjendi pikkus on v\u00e4iksem kui ussi pikkus, peab saba pikenema. Selliselt esimese 4 sammuga saavutab uss oma soovitud pikkuse (5).<\/p>\n<\/section>\n<section id=\"ouna-soomine\">\n<h3 id=\"ouna-soomine\">\u00d5una s\u00f6\u00f6mine<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#ouna-soomine\">\uf0c1<\/a><\/h3>\n<p>Lisame maailma \u00fche \u00f5una juhuslikule positsioonile. Ja kui ussi pea satub \u00f5una peale, siis uss pikeneb.<\/p>\n<p>Selleks, et juhuslikku arvu saada, kasutame <code class=\"docutils literal notranslate\"><span class=\"pre\">random<\/span><\/code> moodulit. Lisame eraldi muutuja <code class=\"docutils literal notranslate\"><span class=\"pre\">apple_position<\/span><\/code>, kus hoiame \u00f5una positsiooni <code class=\"docutils literal notranslate\"><span class=\"pre\">(x,<\/span> <span class=\"pre\">y)<\/span><\/code>. Kui ussi pea satub \u00f5una positsioonile toimuvad j\u00e4rgmised tegevused:<\/p>\n<ul class=\"simple\">\n<li>\u00f5un tekib uuele positsioonile<\/li>\n<li>ussi pikkus suureneb 2 v\u00f5rra<\/li>\n<\/ul>\n<p>Uued read on m\u00e4rgitud teise v\u00e4rviga.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"2,18-21,52-56\">import pygame\r\nimport random\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((600, 600))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n# how much the snake grows when eating\r\nsnake_growth = 2\r\n\r\napple_position = (random.randint(0, 20), random.randint(0, 20))\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    snake.insert(0, (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1]))\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    if snake[0] == apple_position:\r\n        apple_position = (random.randint(0, 20), random.randint(0, 20))\r\n        snake_length += snake_growth\r\n    # draw apple\r\n    pygame.draw.rect(screen, (255, 128, 0), (apple_position[0] * GRID_SIZE_X, apple_position[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\n<div class=\"highlight-python notranslate\">\n<div class=\"highlight\">\n<pre><\/pre>\n<\/div>\n<\/div>\n<p>Kui ussi pea (<code class=\"docutils literal notranslate\"><span class=\"pre\">snake[0]<\/span><\/code>) satub samale positsioonile nagu \u00f5un (<code class=\"docutils literal notranslate\"><span class=\"pre\">apple_position<\/span><\/code>), siis uss s\u00f6\u00f6b \u00f5una. Sellisel juhul leiame \u00f5unale uue juhusliku asukoha ja suurendame ussi pikkust. Kuna meil pikkuse suurenemine on eelnevalt juba koodis sisse arvestatud, siis me ussiga seoses midagi muutma ei pea.<\/p>\n<div class=\"admonition-harjutus admonition\">\n<div class=\"textbox textbox--exercises\">\n<header class=\"textbox__header\">\n<p class=\"textbox__title\">Harjutus<\/p>\n<\/header>\n<div class=\"textbox__content\">\n<p>Hetkel v\u00f5ib \u00f5un sattuda suvalisele positsioonile, seal hulgas ussi peale. Kuidas teha nii, et \u00f5un ei saaks tekkida ussi t\u00fcki peale?<\/p>\n<p>Vihjeks: \u00f5una positsiooni tuleb nii mitu korda genereerida, kuni tulemus meid rahuldab. Seega on m\u00f5istlik teha <code class=\"docutils literal notranslate\"><span class=\"pre\">while<\/span> <span class=\"pre\">True<\/span><\/code> ts\u00fckkel, mille sees genereerime uue \u00f5una asukoha. Kui asukoht sobib, siis l\u00f5petame ts\u00fckli \u00e4ra (<code class=\"docutils literal notranslate\"><span class=\"pre\">break<\/span><\/code>). Kui aga \u00f5un satub ussi peale, siis j\u00e4tkame ts\u00fckli kordamist.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/section>\n<section id=\"mangu-lopp\">\n<h3 id=\"mangu-lopp\">M\u00e4ngu l\u00f5pp<a class=\"headerlink\" title=\"Permalink to this heading\" href=\"#mangu-lopp\">\uf0c1<\/a><\/h3>\n<p>Lisame kontrolli, et uss ei saaks vastu \u00e4\u00e4rt ega vastu ennast liikuda. Kui see juhtub, siis m\u00e4ng saab l\u00e4bi.<\/p>\n<p>Meil piisab sellest, et kontrollida uut pea asukohta. \u00c4\u00e4re kontrollimiseks on m\u00f5istlik kasutusele v\u00f5tta konstant (muutuja), mis \u00fctleb, mitu ruutu meie m\u00e4ngupind x ja y suunal on. Ja tegelikult ruutude arvu ja ruutude suuruse j\u00e4rgi saame arvutada vajaliku akna suuruse. Kui meil m\u00e4nguala laius on 20 ruutu ja uss tahab liikuda 21. ruudule, siis saab m\u00e4ng l\u00e4bi. Samamoodi kui uss \u00fcritab liikuda 1. ruudult vasakule, saab m\u00e4ng l\u00e4bi.<\/p>\n<p>Selleks, et kontrollida, ega uss vastu enda saba ei liigu, saame kontrollida, kas uus pea asukoht on juba ussi j\u00e4rjendis olemas. Kui n\u00e4iteks uss tahab liikuda positsioonile <code class=\"docutils literal notranslate\"><span class=\"pre\">(5,<\/span> <span class=\"pre\">5)<\/span><\/code>, aga ussi j\u00e4rjendis on selline positsioon olemas (mis t\u00e4hendab, et seal paikneb ussi t\u00fckk), siis oleme liikunud vastu ennast ja m\u00e4ng saab l\u00e4bi.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"4-7,10,24,46-54,64\">import pygame\r\nimport random\r\n\r\nGRID_SIZE_X = 30\r\nGRID_SIZE_Y = 30\r\nGRID_WIDTH = 20\r\nGRID_HEIGHT = 20\r\n\r\npygame.init()\r\nscreen = pygame.display.set_mode((GRID_WIDTH * GRID_SIZE_X, GRID_HEIGHT * GRID_SIZE_Y))\r\nrunning = True\r\n# actual snake pieces with grid coordinates\r\nsnake = []\r\n# movement for x and y; start with moving right\r\nsnake_direction = (1, 0)\r\n\r\n# let's add a starting \"head\"\r\nsnake.append((3, 3))\r\n# snake length\r\nsnake_length = 5\r\n# how much the snake grows when eating\r\nsnake_growth = 2\r\n\r\napple_position = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))\r\n\r\nclock = pygame.time.Clock()\r\n\r\nwhile running:\r\n\r\n    for event in pygame.event.get():\r\n        if event.type == pygame.QUIT:\r\n            running = False\r\n        elif event.type == pygame.KEYDOWN:\r\n            if event.key == pygame.K_LEFT:\r\n                snake_direction = (-1, 0)\r\n            if event.key == pygame.K_RIGHT:\r\n                snake_direction = (1, 0)\r\n            if event.key == pygame.K_DOWN:\r\n                snake_direction = (0, 1)\r\n            if event.key == pygame.K_UP:\r\n                snake_direction = (0, -1)\r\n\r\n    screen.fill((0, 0, 0))\r\n    # move\r\n    # take the current head and use direction to calculate new head\r\n    new_head = (snake[0][0] + snake_direction[0], snake[0][1] + snake_direction[1])\r\n    # check whether we go off the grid?\r\n    if new_head[0] &lt; 0 or new_head[0] &gt;= GRID_WIDTH or new_head[1] &lt; 0 or new_head[1] &gt;= GRID_HEIGHT:\r\n        running = False\r\n    # check whether we go into our tail\r\n    if new_head in snake:\r\n        running = False\r\n\r\n    snake.insert(0, new_head)\r\n    # should we remove the tail?\r\n    if len(snake) &gt;= snake_length:\r\n        snake.pop()\r\n\r\n    # let's draw the snake\r\n    for piece in snake:\r\n        pygame.draw.rect(screen, (0, 0, 255), (piece[0] * GRID_SIZE_X, piece[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    if snake[0] == apple_position:\r\n        apple_position = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))\r\n        snake_length += snake_growth\r\n    # draw apple\r\n    pygame.draw.rect(screen, (255, 128, 0), (apple_position[0] * GRID_SIZE_X, apple_position[1] * GRID_SIZE_Y, GRID_SIZE_X, GRID_SIZE_Y))\r\n\r\n    pygame.display.flip()\r\n\r\n    clock.tick(10)\r\n<\/pre>\n<div class=\"highlight-python notranslate\">\n<div class=\"highlight\">\n<pre><\/pre>\n<\/div>\n<\/div>\n<p>Muudetud ja lisatud read on m\u00e4rgitud koodis teise v\u00e4rviga. Alguses loome konstandid ruudustiku suuruse ja iga lahtri suuruse jaoks. Real 10 arvutame akna suuruse vastavalt m\u00e4\u00e4ratud konstantidele. Real 24 kasutame konstante, et leida juhuslik asukoht \u00f5unale. Real 46 arvutame uue ussi pea asukoha eraldi muutujasse, et sellega oleks mugavam operatsioone teha. Rida 48 kontrollib, ega me ei liigu ekraanist v\u00e4lja. Kui uue pea x positsioon on v\u00e4iksem kui 0 v\u00f5i suurem-v\u00f5rdne akna laiusega, siis on pea juba ekraanilt v\u00e4ljas ja peame m\u00e4ngu \u00e4ra l\u00f5petama. Real 51 kontrollime, ega uue pea positsioon pole juba praeguses ussi j\u00e4rjendis. Kui on, siis j\u00e4relikult toimub liikumine vastu ussi saba. Real 64 on muudetud see, et kasutame konstante, et arvutada uus \u00f5una asukoht.<\/p>\n<div class=\"textbox textbox--exercises\">\n<header class=\"textbox__header\">\n<p class=\"textbox__title\">Harjutus<\/p>\n<\/header>\n<div class=\"textbox__content\">\n<p>Praegune kood t\u00f6\u00f6tab ussi sabasse liikudes natuke valesti. Probleem on selles, et kui uss liigub, siis ta saba viimane t\u00fckk ka &#8220;liigub&#8221;. Kood arvutab praegu uus pea asukoha ning kontrollib kohe, ega see ei satu sellesse positsiooni, mis on juba ussi j\u00e4rjendis. Tegelikult peaks see kontroll toimuma peale liikumist.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-877\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-300x180.png\" alt=\"\" width=\"300\" height=\"180\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-300x180.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-65x39.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-225x135.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail-350x210.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail.png 543w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Kui selle pildi j\u00e4rgi uss liigub \u00fcles, siis meie koodi j\u00e4rgi saab ta surma. Tegelikult aga peaks saba eest \u00e4ra liikuma. J\u00e4rgmine samm peaks olema selline:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-878\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-300x176.png\" alt=\"\" width=\"300\" height=\"176\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-300x176.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-65x38.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-225x132.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2-350x206.png 350w, https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-content\/uploads\/sites\/18\/2022\/12\/snake_movement_to_tail_step2.png 546w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<\/div>\n<\/div>\n<\/section>\n<\/section>\n","protected":false},"author":36,"menu_order":6,"template":"","meta":{"pb_show_title":"on","pb_short_title":"","pb_subtitle":"","pb_authors":[],"pb_section_license":""},"chapter-type":[],"contributor":[],"license":[],"class_list":["post-869","chapter","type-chapter","status-publish","hentry"],"part":780,"_links":{"self":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapters\/869","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapters"}],"about":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/wp\/v2\/types\/chapter"}],"author":[{"embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/wp\/v2\/users\/36"}],"version-history":[{"count":7,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapters\/869\/revisions"}],"predecessor-version":[{"id":1023,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapters\/869\/revisions\/1023"}],"part":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/parts\/780"}],"metadata":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapters\/869\/metadata\/"}],"wp:attachment":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/wp\/v2\/media?parent=869"}],"wp:term":[{"taxonomy":"chapter-type","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/pressbooks\/v2\/chapter-type?post=869"},{"taxonomy":"contributor","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/wp\/v2\/contributor?post=869"},{"taxonomy":"license","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/tarkvara2\/wp-json\/wp\/v2\/license?post=869"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}