Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: QB: Matopelin optimointi

Puhveli [16.09.2005 20:29:22]

#

Onhan nuita matopelejä jo täällä nähty, mutta kerron silti oman versioni jossa on kätevällinen ja freshi idea. Tein tämän alun perin Casio FX 1.0 -laskimeeni, jonka hitaan tulkkikielen vuoksi jouduin tekemään koodista mahdollisimman nopean suorittaa.

Miten matopeli toimii?
Matopelin teh idea on, että madon pään sijainti (x, y) tallennetaan taulukkoon, ja samalla madon pää piirretään ruudulle. Madon hännän kohdalla taas tyhjennetään ruudulla oleva madonpala. Helpointa tämä on toteuttaa niin, että jokaisessa framessa taulukon jokaista alkiota aina häntään asti muutetaan (nykyinen sijainti edelliseen sijaintiin), mutta tällöin peli hidastuu madon pitenemisen myötä. Toinen tapa on tallettaa kaksiulotteiseen matriisiin kentän jokainen ruutu, johon sitten tallennetaan esimerkiksi tieto siitä, onko ruudussa mato, mihin suuntaan se siitä kääntyy jne. Laskimissa näin suurien matriisien kutsuminen on usein hidasta, ja kääntymiseen tarvittavat iffit hidastaisivat myös tulkkausta. Lisäksi tätä ei voi soveltaa matopeleissä, jossa mato kääntyy portaattomasti.

Optimointi tässä koodivinkissä
Tässä versiossa muutetaan vain madon pään ja hännän kohdalla olevien taulukon alkioiden indeksinumeron sisältäviä muuttujia (kasvatetaan joka framessa yhdellä), jolloin taulukkoon ei tarvitse koskea kuin kerran madon pään kohdalla. Nyt joudutaan kuitenkin tarkistamaan, etteivät muuttujat ylitä taulukon rajoja, mutta se on koneelle huomattavasti pienempi tehtävä kuin jokaisen alkion läpikäynti joka framessa.

Periaatteessa suoritus ei siis hidastu madon kasvaessa. Toisin kävi laskimessa, Casio kun lukee alkion 1 noin kolme kertaa nopeammin kuin alkion 255. Mutta joo, nopeampi tämä on kuin kavereiden laskinmatopelit. ;)

Koodi

' - Optimoitu matopeli -
'
' Niin ylpeä olen ideastani, että annan sen
' vapaaseen käyttöösi omissa matopeleissäsi ;)
'
' Ideana on, että madon pään koordinaatit tallennetaan taulukkoon ja
' matopalikka piirretään niiden kohdalle. Sen jälkeen pään taulukkoindek-
' sin kertovaa muuttujaa kasvatetaan yhdellä. Jalan taulukkoindeksi myös
' kasvaa yhdellä. Jalan kohdalle piirretään tyhjä palikka. Koko taulukkoa
' ei tarvitse käsitellä, josta varsinainen etu saavutetaan.
'
' (!)LISŽOPTIMOINTI:
' poista sisennykset, kommentit ja turhat rivinvaihdot jos ajat tulkissa xd
'
'
' 16.9.2005 - Phvli

DECLARE SUB teeOmena () 'sijoittaa uuden omenan näytölle

CONST tauko = .1 'framen hidastus sekunneissa
CONST matoja = 3, maxPituus = 500, alkuPituus = 5

DIM pelaajia AS INTEGER
DIM matoX(matoja, maxPituus) AS INTEGER, matoY(matoja, maxPituus) AS INTEGER
DIM pisteet(matoja) AS INTEGER
DIM iPaa(matoja) AS INTEGER, iHanta(matoja) AS INTEGER
DIM liikeVaaka(matoja) AS INTEGER, liikePysty(matoja) AS INTEGER
DIM SHARED omenaX, omenaY

DIM mato    AS INTEGER 'käsiteltävä mato
DIM Btn     AS STRING  'viimeisin INKEY$

DIM alkuTIMER       AS DOUBLE   'delay (TIMER:n arvo ennen delayta)
DIM i               AS INTEGER  'nykyinen taulukkoindeksi
DIM X AS INTEGER, Y AS INTEGER  'väliaikaiset koordinaatit vähän kaikkeen
DIM nimi            AS STRING   'madon nimi (yläpalkissa)

WIDTH 80, 50
CLS
PRINT "''' OPTIMOITU MATOPELI (QBasic-koodivinkki) '''''''''''''''''''''''''''''''"
PRINT "'                                                                         '"
PRINT "' Ohjelma esittelee matopelin optimointi-ideaa. Käytännön hyötyä          '"
PRINT "' siitä ei nykytietokoneilla ole, mutta esimerkiksi laskimiin portattuna  '"
PRINT "' nopeusetu on huomattava (tein tämän alun perin Casio FX 1.0:lle).       '"
PRINT "'                                                                         '"
PRINT "' Ennätyksiä ei tallenneta, koska perusideana oli vain itse pelin         '"
PRINT "' ja sorsan kikkailun esittäminen.                                        '"
PRINT "'                                                                         '"
PRINT "'                                                                         '"
PRINT "' Phvli (joe_eronen@suomi24.fi) 16.9.2005                                 '"
PRINT "'                                                                         '"
PRINT "'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"
PRINT : PRINT
COLOR 14
PRINT " Matojen ohjaus:"
PRINT ""
COLOR 15
PRINT "   Sininen: nuolet            Vihreä: A, D, W ja S"
PRINT "    Syaani: J, L, I, K      Punainen: NumPad (Scroll Lock OFF)"

'luetaan pelaajien määrä käyttäjän syötteestä
LOCATE 26, 5: PRINT "Pelaajia (1 - " + LTRIM$(STR$(matoja + 1)) + "): ";
INPUT "", pelaajia

'koska taulukot yleensä alkavat nollasta, vähennetään muuttujaa yhdellä
    pelaajia = pelaajia - 1

'tarkistetaan vielä, että pelaajat mahtuvat taulukkoihin
IF pelaajia < 0 THEN pelaajia = 0
IF pelaajia > matoja THEN pelaajia = matoja

COLOR , 0: CLS

'ALUSTUS (käsitellään kaikkien pelaajien madot)
FOR mato = 0 TO pelaajia

    'Madon pää ja häntä
    iPaa(mato) = alkuPituus: iHanta(mato) = 0
    pisteet(matoja) = 0

    SELECT CASE mato

    CASE 0
        nimi = "Sininen"
        X = 77
        Y = 45
        liikeVaaka(mato) = -1
        liikePysty(mato) = 0

    CASE 1
        nimi = "Vihreä"
        X = 4
        Y = 7
        liikeVaaka(mato) = 1
        liikePysty(mato) = 0

    CASE 2
        nimi = "Syaani"
        X = 4
        Y = 45
        liikeVaaka(mato) = 0
        liikePysty(mato) = -1

    CASE 3
        nimi = "Punainen"
        X = 77
        Y = 7
        liikeVaaka(mato) = 0
        liikePysty(mato) = 1

    END SELECT

    'mato kartalle
    FOR i = 0 TO maxPituus
        matoX(mato, i) = X
        matoY(mato, i) = Y
    NEXT

    'madon nimi ylös
    COLOR 15, mato + 1
    LOCATE 1, mato * 22 + 3: PRINT " " + nimi + " "

    COLOR 14, 0
    LOCATE 2, mato * 22 + 5: PRINT pisteet(mato)

NEXT

'tehdään kenttä
COLOR 0, 4
LOCATE 4: PRINT STRING$(80, 254)
FOR Y = 5 TO 47
    PRINT "þ";
    COLOR , 1: PRINT SPACE$(78);
    COLOR , 4: PRINT "þ"
NEXT
LOCATE Y: PRINT STRING$(80, 254)

LOCATE 16, 24: PRINT STRING$(34, 254)
LOCATE 36, 24: PRINT STRING$(34, 254)

omenat = 0
teeOmena

'päägotosilmukka
DO
    'varsinainen pelisilmukka, murretaan nappia painettaessa
    DO

        'käsitellään kaikkien pelaajien madot
        FOR mato = 0 TO pelaajia

            X = matoX(mato, iPaa(mato))
            Y = matoY(mato, iPaa(mato))

            'pyyhitään madon jalka
            LOCATE matoY(mato, iHanta(mato)), matoX(mato, iHanta(mato))
            COLOR , 1: PRINT " "

            'kasvatetaan pään ja jalan taulukkoindeksiä, eli siiheen
            'viittaavaa muuttujaa, yhdellä
            iPaa(mato) = iPaa(mato) + 1
            iHanta(mato) = iHanta(mato) + 1

            'tarkistetaan, etteivät taulukkoviittaajat ylitä rangea
            IF iPaa(mato) > maxPituus THEN iPaa(mato) = 0
            IF iHanta(mato) > maxPituus THEN iHanta(mato) = 0

            'liikutetaan matoa
            matoX(mato, iPaa(mato)) = X + liikeVaaka(mato)
            matoY(mato, iPaa(mato)) = Y + liikePysty(mato)

            'asetetaan väri madon piirtämistä varten
            COLOR mato + 9, 0

            'omenan keräys
            IF ABS(X - omenaX) < 1 AND ABS(Y - omenaY) < 1 THEN GOSUB syoOmena

            'törmäyksen tarkistus
            IF NOT SCREEN(Y, X) = 32 THEN

                'ihkuinen ääniteaseri
                SOUND 400, 1: SOUND 300, 3

                'pelin lopetus
                SLEEP
                END

            END IF

            'piirretään madolle pää (vasta törmäystarkistuksen jälkeen)
            LOCATE Y, X: PRINT "þ"


        NEXT

        'odotetaan tomaattien kypsymistä
        alkuTIMER = TIMER
        DO: LOOP WHILE TIMER < alkuTIMER + tauko

        Btn = INKEY$

    LOOP WHILE Btn = ""'Ei hidasteta pääsilmukkaa näppäinten tarkistuksella

    SELECT CASE UCASE$(Btn)

    'sinisen madon liikutus (nuolet)
    CASE CHR$(0) + "K": IF NOT liikeVaaka(0) = 1 THEN liikeVaaka(0) = -1: liikePysty(0) = 0
    CASE CHR$(0) + "M": IF NOT liikeVaaka(0) = -1 THEN liikeVaaka(0) = 1: liikePysty(0) = 0
    CASE CHR$(0) + "H": IF NOT liikePysty(0) = 1 THEN liikeVaaka(0) = 0: liikePysty(0) = -1
    CASE CHR$(0) + "P": IF NOT liikePysty(0) = -1 THEN liikeVaaka(0) = 0: liikePysty(0) = 1

    'vihreän madon liikutus (ASWD)
    CASE "A": IF NOT liikeVaaka(1) = 1 THEN liikeVaaka(1) = -1: liikePysty(1) = 0
    CASE "D": IF NOT liikeVaaka(1) = -1 THEN liikeVaaka(1) = 1: liikePysty(1) = 0
    CASE "W": IF NOT liikePysty(1) = 1 THEN liikeVaaka(1) = 0: liikePysty(1) = -1
    CASE "S": IF NOT liikePysty(1) = -1 THEN liikeVaaka(1) = 0: liikePysty(1) = 1

    'syaanin madon liikutus (JLIK)
    CASE "J": IF NOT liikeVaaka(2) = 1 THEN liikeVaaka(2) = -1: liikePysty(2) = 0
    CASE "K": IF NOT liikeVaaka(2) = -1 THEN liikeVaaka(2) = 1: liikePysty(2) = 0
    CASE "I": IF NOT liikePysty(2) = 1 THEN liikeVaaka(2) = 0: liikePysty(2) = -1
    CASE "L": IF NOT liikePysty(2) = -1 THEN liikeVaaka(2) = 0: liikePysty(2) = 1

    'punaisen madon liikutus (NP)
    CASE "4": IF NOT liikeVaaka(3) = 1 THEN liikeVaaka(3) = -1: liikePysty(3) = 0
    CASE "6": IF NOT liikeVaaka(3) = -1 THEN liikeVaaka(3) = 1: liikePysty(3) = 0
    CASE "8": IF NOT liikePysty(3) = 1 THEN liikeVaaka(3) = 0: liikePysty(3) = -1
    CASE "5", "2": IF NOT liikePysty(3) = -1 THEN liikeVaaka(3) = 0: liikePysty(3) = 1

    CASE CHR$(27) 'Esc murtaa silmukan -> peli loppuu
        EXIT DO
    END SELECT

LOOP
CLS
COLOR 7

END


'omenan syödään optimoinnin vuoksi muualla kuin pääsilmukassa.
'Gotoleimatoteutus siksi, etteivät kaikki laskimet tue funktioita
'tai toisten ohjelmien kutsua
syoOmena:

    'pyyhi wanha omena ja tee uusi tilalle
    COLOR , 1: LOCATE omenaY, omenaX: PRINT " "
    teeOmena

    'Pidennetään matoa (pienennetään hännän taulukkoindeksiä
    '               -> häntänä toimii silloin vanhempi sijainti),
    'ja tarkistetaan, ettei uusi indeksi ylitä rajoja.
    i = iHanta(mato)
    iUusi = iHanta(mato) - 5
    IF iUusi < 0 THEN iUusi = iUusi + maxPituus

    'Siirretään kaikki hännän vahan ja uuden sijainnin väliin jäävät
    'palat samaan kohtaan (muuten jo pyyhitty osa pyyhittäisiin uudestaan,
    'ja esimerkiksi paikalle ehtinyt toinen mato katkeaisi).
    DO
        matoX(mato, i) = matoX(mato, iHanta(mato))
        matoY(mato, i) = matoY(mato, iHanta(mato))
        i = i - 1
        IF i < 0 THEN i = i + maxPituus
    LOOP UNTIL i = iUusi
    iHanta(mato) = i

    IF iHanta(mato) < 0 THEN
        iHanta(mato) = iHanta(mato) + maxPituus
    END IF

    'kasvatetaan pisteitä
    pisteet(mato) = pisteet(mato) + 1
    COLOR 14, 0
    LOCATE 2, mato * 22 + 5: PRINT pisteet(mato)

    'jätetään madolle kirkas hömöhaha
    COLOR 15, 7

RETURN

SUB teeOmena

    'etsitään omenalle vapaa paikka
    DO

        omenaX = CINT(RND * 77) + 2
        omenaY = CINT(RND * 43) + 5

    LOOP UNTIL SCREEN(omenaY, omenaX) = 32


    'piirrä omena kartalle
    LOCATE omenaY, omenaX
    COLOR 14, 6: PRINT "þ"

END SUB

Antti Laaksonen [18.09.2005 17:40:07]

#

Minäkin olen tehnyt matopelin Casio FX 1.0 -laskimella ja päätynyt samanlaiseen ratkaisuun. :)

tgunner [19.09.2005 13:11:17]

#

No jopas, näyttää aika hauskalta. Olen koulussa joten en voi nyt mitenkään testata sitä, mutta jahka pääsen kotiin niin sitten.

viznut [26.09.2005 11:35:20]

#

Näinhän ne BASIC-matopelit tehtiin 80-luvulla. Periaate on aika lailla se hyvä ja optimaaliseksi todettu, joskin luulen että saisit vielä nopeammaksi jos muuttaisit matoX- ja matoY-taulukot yksiulotteisiksi. Taulukon wrappailussa voit kokeilla ylärajavertailun sijaan myös AND-operaattoria :)

viznut [26.09.2005 11:41:47]

#

Niin, ja näyttöindeksitkin mielellään yksiulotteisiksi mikäli vain suinkin mahdollista niin häipyy monesta kohti tarve kahdelle erilliselle taulukolle. Lisäksi voit tutkia omenan läsnäolon suoraan näytöltä, jolloin luultavasti saat pienen nopeusedun ja siinä sivussa "rajattoman" omenamäärän :)

Puhveli [26.09.2005 19:53:48]

#

viznut kirjoitti:

voit tutkia omenan läsnäolon suoraan näytöltä, jolloin luultavasti saat pienen nopeusedun ja siinä sivussa "rajattoman" omenamäärän

Tässä tapauksessa tuo kyllä toimisi, mutta 'grafiikkatiloissa' se vain hidastaisi ohjelman ajoa. Totta on myös, että yksiulotteinen taulukko on nopeampi käsitellä, mutta silloin on paha simuloida useita matoja helposti. Muuten kiitos vinkeistä, pitää nuiden boolean-operaattoreiden käyttöön vielä perehtyä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta