Sator-ehizan

Galdera-eragilea

Tamalez, iraganeko kontua dira garai bateko mahai-jolasak. Galtzear daude neguko egun euritsuak su alboan igarotzeko denbora-pasak zein karta-jokoak; arin lapurtu diete lekua bestelako aukera digitalek. Eskerrak, oraindik ere, aisiarako umeentzako egurrezko jostailuak preziatuak diren. Vintage-joeraren eragina izango ote da? Auskalo!

Jostailu horien artean bat aski ezaguna da oraindik ere: Sator-ehizan, hain zuzen. Taulako sator-zuloetatik burua ateratzean, goitik behera mailukada emateko bizkor eta tentuz ibiltzeko jolasa da. Prest al zaude Minecraft bideo-jokoaren barruan funtzionamendu hori imitatuko duen jokoa hutsetik asmatzeko?

Jokoa jokoaren barruan programatzea da ideia. Hori da hori errekurtsiboa izatea!

Aurrekariak

Sator-ehizan jolasa imitatzen hasteko, diz-diz egiten duten blokeak ezpataz kolpatu behar dira. Ez dago jakiterik zein bloke izango diren, ausaz agertzen baitira. Gainera, programatzaile profesionalak ez garenez, dagoenarekin konformatzea dagokigu: ez dago satorrik Minecraft munduan, eta mozorroekin eta objektuekin (entitateen klaseak) zerbait apaindu daitekeen arren, lana aurrezten da blokeekin eginda.

Beraz, distira egiten duten harriak garaiz harrapatu eta zanpatuta utzi behar dira; bestela, hasierako harriaren kolorea berreskuratuko dute eta galdu egingo da aldi bateko aukera. Denak astindutakoan bukatzen da jokoa.

Eskema

Proiektu honetan ez dago beste programa edo aplikazioen beharrik, eta beraz, guztia egiten da Python IDLE programazio-ingurunean eta Minecraften bideo-jokoan. Honako ezaugarri hauek lantzen dira, besteak beste: koordenatuak erabiltzen ikastea blokeak ezartzeko; objektuen atributuak kudeatzea blokeen ID zehatzak ezartzeko; random modulua erabiltzea ausazko zenbakiak sortzeko; eta baldintzak (if) eta begiztak (while eta for) zuzen aplikatzea egoerak kontrolatzeko eta jardun errepikakorrak arintzeko.

Bestetik, taula egiteko harrizko bloke arrutak (STONE, 1) erabiltzen dira batetik, eta, bestetik, dirdira egiten dutenak (GLOWSTONE_BLOCK, 89). Neurriari dagokionez, 3 bloke zabal eta 3 bloke garai dira (3 x 3). Horrekin batera, bost urrats nabarmen hauek egin behar dira egitasmoan: sortu scripta eta egiaztatu egindakoaren funtzionamendua; programatu harrizko taula Alexen aurrean sortzeko; programatu diz-diz blokeak ausaz sortzeko; jolastu blokeak egurtzera; eta, bukatzeko, zenbatu puntuak eta bistaratu sailkapen xume bat

.

Beste liburutegiekiko mendekotasunak

Antzerako helburuak dituzten funtzioak, aldagaiak, konstanteak zein bestelako elementuak dituzten biltegiak dira liburutegiak; izenez bereizten dira eta barruan dutena berrerabiltzeko aukera ematen dute. Horrez gain, hutsetik programatzen hasi ordez, denbora irabazten da erronka berriei ekiteko.

Liburutegiak erabiltzen hasteko, izenak programaren goiburuan aipatu behar dira. Hala, idatzitakoa exekutatzean, lerroz lerro aginduak irakurtzen dituen exekuzio-fluxua iturburua dagoen fitxategira zuzendu daiteke (salto egiten duela ere esaten zaio), eta, gainera, kanpoko funtzioa bete dezake dagoen lekuan bertan eskatutako kodea irakurrita (erreferentzia egindako liburutegian). Hori guztia betetzean, fluxua hasierako fitxategira itzultzen da, utzitako lekuari heldu eta exekuzioarekin jarraitzeko. Izan ere, erreferentzia hori gabe, fluxuak ez du jakiten non bilatu eta unean bertan uzten du programa bertan behera, akatsa adierazita. Horregatik esaten da liburutegiak erabiltzen dituzten kodeak liburutegi horien mende daudela.

Proiektu honetan ere moduluak inportatu behar dira. Inoiz gertatzen da behar den liburutegia sisteman lehenetsita ez egotea eta instalatu behar izatea erabili orduko. Raspbianen lehentasunez instalaturik datozenez, nahikoa da erreferentzia zehaztea.

Gauzak horrela, random eta time moduluak erabiliko dira: lehena ausazko zenbakiak sortzeko eta bestea denborarekin eragiketak egiteko.

Scripta sortzen hastea

Zabaldu Python 3 programatzeko ingurunea Menua > Programazioa > Python 3 (IDLE) sakatuta. Bertan, sakatu File > New File eta sortu fitxategi berri bat. Mahaigainean propio sortutako karpetan gorde dezakezu File > Save eginda, eta hasi beharrezko liburutegiak aipatzen, betiko legez:

import mcpi.minecraft as minecraft
import mcpi.block as block
import random
import time
    • mcpi.minecraft: Minecraft munduari eragiteko objektuen, aginduen eta aldagaien multzoa da. Eraikitzeko erabili dena funtsezkoa da eraldatzeko ere.
    • mcpi.block: Beharrezkoa da blokeak izenez adierazteko, zenbaki hutsez adierazi ordez.
    • random: Ausazko zenbakiak sortzeko erabiltzen da.
    • time: Programan itxaron-uneak ezartzeko erabiltzen da, besteak beste.

Ezarri konexioa zabalik dagoen partidarekin eta eman jokalariei datorren ekitaldiaren berri:

mc = minecraft.Minecraft.create()
mc.postToChat("Minecrafteko Sator-ehiza")

Jarraian, abiarazi Minecraft: idatzi terminalean minecraft-pi, edo sakatu menu-barrako aplikazioen erlaitzean Jokoak atalaren barruan dagoen lasterbidea. Sortu barruan mundu berria edo kargatu mapa kutun hori. Gero, abiarazi idazten ari zaren programa Run > Run Module sakatuta IDLEan edo teklatuan F5 botoiari sakatuz. Mezua zuzen agertzen da; akatsa eginez gero, gorriz agertzen da agindu-lerroan. Besterik programatu ez denez, honako hau baino ezin dezake egin:

Non dago harrizko taula?

Prestaketa-lanak egin behar dira taula Alexen aurrean ager dadin. 3 x 3 bloke izango ditu, eta horien artetik ausazko batzuek diz-diz egingo dute. Taula jokalariaren aurrean agertu dadin, ordea, hura non dagoen ezagutu behar da. Honela eginda gordetzen da uneko kokapen hori:

pos = mc.player.getTilePos()

Koordenatuen datuak eskura izanda, taularen blokeak inongo arazorik gabe jar daitezke. Nahi izanez gero, marraztu zirriborroa paperean posizio erlatiboen arabera kokatzeko.

mc.setBlocks(pos.x - 1, pos.y, pos.z + 3, pos.x + 1, pos.y + 2, pos.z + 3, block.STONE.id)

Aurrera egin aurretik, konektaturiko jokalariei mezua bidali behar zaie jolasa hastera doala jakinarazteko. Ondoren, tarte txiki batean zain geratu behar da time.sleep(segunduak) aginduarekin:

mc.postToChat("Hastera doa!")
time.sleep(2)
mc.postToChat("Gertu ...")
time.sleep(1)
mc.postToChat("Aurrera!")

Bukatzeko, gorde eta berrabiarazi egin behar da idatzitako programa. Taula Alexen aurrean agertzen denean, atzerako kontaketa hasten da… eta kito, momentuz.

Diz-diz blokeak nonahi

Sasoia da behingoz taulako bloke batzuk distiratsu ipintzeko. Partida guztiak berdinak izan ez daitezen, ausaz egiteko programa daiteke. Horretarako, random liburutegiko randint(hasierakoa, amaierakoa) funtzioari agindu behar zaio zenbaki-tarte bateko blokeak ausaz itzultzeko. Bestalde, gorde egiten dira piztutako blokeak atzerako kontagailu gisa erabiltzeko (blokeakPiztuta). Jolasa berriro hutsetik hasteko, berriz, puntuazio gordetzeko aldagaia 0 balioarekin hasieratzen da (puntuak).

blokeakPiztuta = 0
puntuak = 0

Programaren fluxua begiztan preso egoten da ezpatak argi guztiak hautsi bitartean. while motako begizta behar da hemen, mota horietako begiztak eten egiten baitira baldintza baten pean. Hortaz, komeni da begiztaren iterazio edo buelta bakoitzetik bestera pixka bat itxarotea, bestela, blokeak bizkorregi aldatuko lirateke kolorez eta jokalari koitaduak ezingo lituzke blokeak garaiz jo. Izan ere, aurrena funtzionamendua bermatzen da, eta gero egiten zaio erronka jokalariari.

while blokeakPiztuta < 9:
    time.sleep(1)

Hortik aurrerako kode guztia ere while begiztaren barruan ezartzen da, iterazio bakoitzean berdin jarduteko.

Hurrengo pausoa da harrizko bloke arruntak menturaz diz-diz egiten jartzea. Kontu handiz egin behar da, eta dirudiena baino zailagoa da: zer gertatzen da pizteko ausaz aukeratu den blokea dagoeneko zanpatu bada? Modu asko daude emaitza bera lortzeko, baina buruari eraginez gainditzen dira zailtasunak; izan ere, programatzeak erronka txiki askori aurre egitea dakar, eta inoiz ez dator txarto pentsatzeko txoko bat izatea ere.

Ez larritu! Programazioaren hastapenak lantzen ari gara eta honako proposamen honek laguntzen du edalontzian ez itotzen: sortu zorizko zenbakia, eta bertako blokea harri distiratsua bada, egin salto iterazioan eta aukeratu berriro ausazko zenbaki bat. Errepikatu prozesu hori harri bihurturik ez dagoen blokeren bat topatu arte eta, bestela, zanpatu bloke guztiak jolasa bukatu arte.

Azaldu berri den proposamen hori honela kodetzen da: sortu piztuta izeneko aldagaia eta egokitu False balioa. Sortu while begizta bat ere, piztuta True denean etengo dena, hots, nabarmendu daitekeen bloke bat bilatu bitartean dabilena. Begizta hori piztea lortzen badu, kontuan izan aurreko blokeakPiztuta aldagaiari ere balio bat erantsi behar zaiola. Hona hemen kodea:

    blokeakPiztuta = blokeakPiztuta + 1
    piztuta = False
    while not piztuta:   # “pizten ez den bitartean”

Bloke bat GLOWSTONE_BLOCK bihurtzen denean, piztuta = True aldagaia ezartzen zaio eta begizta eten egiten da. Une horretan erabili behar da random.randint(hasierakoa, amaierakoa), eta ausazko zenbaki bat asmatu. Aukerak oso murritzak dira, taularen beraren tamaina bezainbestekoak, alegia: batetik, x ematea -1 eta 1 arteko balio bat itzul dezan, eta, bestetik, y ematea, 0 eta 2 balioen arteko bat itzul dezan. Argi ikusten da irudi honetan:

Irudian ausaz bihurtutako dir-dir blokeak hartu dituen koordenatuak dira xPos=-1, yPos=0 eta zPos=3.

Honako hau da kodea:

        xPos = pos.x + random.randint(-1,1)
        yPos = pos.y + random.randint(0,2)
        zPos = pos.z + 3

if baldintza erabilita, getBlock(x,y,z) funtzioari galdetzen zaio ea koordenatu berri horietako blokea harri arrunta (STONE) den. Hala bada, blokea aldatu behar da setBlock(x,y,z,blokearenId) funtzioarekin eta piztuta aldagaia ere eguneratu egin behar da egiazko bihurtzeko. Honatx:

        if mc.getBlock(xPos, yPos, zPos) == block.STONE.id:
            mc.setBlock(xPos, yPos, zPos, block.GLOWSTONE_BLOCK.id)
            piztuta = True

Ikusten denez, id balioak erabili ordez izenak erabiltzeko hautua egin da. Esaterako, 1 jarri beharrean block.STONE.id erabili da: alde batetik, liburutegiak esportatzen dituen konstanteak lehenesteko, eta, bestetik, gogoratzeko errazagoak direlako. Gainera, blokearen identifikazioa aldatzea erabakiko balute ere, ez lioke kodeari eragingo eta zuzen funtzionatzen jarraituko luke, nekezagoa baita bloke bati izena aldatzea balioa baino.

Bukatzeko, gorde eta berrabiarazi idatzitako programa Run > Run Module aukera erabilita edo teklatuko F5 botoiari sakatuta. Hori egitean, jolas-taula agertzen da, eta baita sasi-satorrak ere banan-banan, harik eta bloke guztiek diz-diz egiten duten arte.

Bizkor, bildu blokeak egurtzera!

Alexek ezpata eskuan duenean, saguaren eskuineko botoian klik egin eta zartakoak ematen ditu. Ezpataz gain, beste tresna batzuekin ere jo dezake, baina Minecraften API liburutegian soilik ezpataz egindako ekintzak biltzen dira (event gertaeren bidez, hain zuzen). Esan beharrik ez dago sator-ehiza programatzen amaitzeko eta puntuak behar bezala banatzeko jakin beharra dagoela Alexek zer eta non jo duen. Horretarako, jo ezpatarekin eta deitu events.pollBlockHits() funtzioari jokoko gertaeren informazioa eskuratzeko, tartean zein bloke astindu diren.

Beraz, kolpea jaso duten blokeen kokapena lortu ostean, begiratu behar da zein motatakoa den bloke bakoitza (getBlock(x,y,z)), eta bloke distiratsuak berriro harri bihurtu behar dira (setBlock(x,y,z,block.STONE.id)). Hori egitean, piztuta aldagaiari balio bat kentzen zaio eta puntuazio handiagoa lortzen da.

Aurrera egiteko, arestiko while begiztaren barruan beste begizta bat txertatu behar da. events gertaerek hainbat balio itzultzen dituzte aldi berean, nahiz eta banaka aztertu behar diren:

    for kolpatutakoBlokeak in mc.events.pollBlockHits():

Hala eginda, hainbat datu biltzen dira leku bakarrean, kolpatutakoBlokeak aldagaiaren baitan, hain zuzen ere. Honako datu hauek biltzen dira, besteak beste: zein bloke jo den azkena, zein aurpegitan jaso duen zartada edo nork eman dion. Horrez gain, print kolpatutakoBlokeak sartuz gero Python inguruneko agindu-lerroan, aldagaiak bildu duenaren xehetasunak ikus daitezke. Programako beste edozein aldagairekin ere beste hainbeste egin daiteke eta exekuzioan hartzen duen edukia ikusi. Hori Pythonen bitxikeria da, martxan dagoen programaren barneko balioak ikusi ahal izatea, alegia.

Bestalde, mc.events.pollBlockHits()taula bat bailitzan, kolpatutakoBlokeak aldagaiak taula edo matrize horren lerroak jasotzen ditu banan-banan. Taulak hainbat lerro ditu ezpata-kolpe bakoitza adierazteko eta lerro horietako bakoitzean biltzen dira aipatutako xehetasunak. Hortaz, aztertu lerrook banaka getBlock(x,y,z) funtzioarekin eta begiratu zein eratako blokea jo duen (if baldintza batekin alderatu). Honatx:

        if mc.getBlock(kolpatutakoBlokeak.pos.x, kolpatutakoBlokeak.pos.y, kolpatutakoBlokeak.pos.z) == block.GLOWSTONE_BLOCK.id:
            mc.setBlock(kolpatutakoBlokeak.pos.x, kolpatutakoBlokeak.pos.y, kolpatutakoBlokeak.pos.z, block.STONE.id)
            piztuta = piztuta - 1
            puntuak = puntuak + 1

Atala bukatzeko, gorde eta berrabiarazi idatzitako programa Run > Run Module aukera erabiliz zein teklatuko F5 botoiari sakatuta. Hori egitean, joko-taula berria agertzen da eta baita sasi-satorrak ere, baina oraingoan ezpatak jotakoan harri bihurtzen dira berriz!

Game Over

Azkeneko pausoa da jokoa bukatutzat eman eta jokalariari batutako puntuak erakustea. Horretarako, erantsi kodeari behean honako hau:

mc.postToChat("Game Over - puntuazioa = " + str(puntuak))

Bertsio berriak: hobekuntzak

Proiektuaren amaiera izan behar luke honek, baina ezer ez da betiko, eta zer esanik ez informatika kontuetan. Bertsioak egiten dira aplikazio bati zuzenketak eransteko, segurtasuna bermatzeko eta ezaugarri berriak ezartzeko. Hona hemen hobetzeko proposamen batzuk:

    • Jolasaren zailtasuna blokeak bihurtzeko abiadan datza. Orain, esaterako, time.sleep(1) balio du. Denbora luzatzeak jarduna erraztuko die jokalariei, eta murrizteak, ostera, zaildu. Egin probak!
    • Gauzak zaildu nahi izanez gero zoroen modura taula egurtzen dabilen jokalari traketsari, egin honako hau: diz-diz egiten duen blokea jo beharrean harrizkoari ematen badio, argiztatu harrizkoa eta utzi bere horretan. Hartara, puntuatzeko aukera galduko du eta estrategia aldatu beharko du.
    • Bideo-jokoak hasieran samurrak izan ohi dira eta zaildu egiten dira aurrera egin ahala. Saiatu horretan.
    • Azkeneko jokaldiaren puntuazioa inprimatzen du pantailan. Baina ez litzateke ederragoa sailkapen xume bat erakustea jokalarien artean lehia sortzeko? Zerrendak (lists) eta hiztegiak (dictionary) konbinatuta erabil ditzakezu. Ikertu zure kasa...