Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Python: Miinaharava Pythonille!

Sivun loppuun

Tuiske [11.08.2016 11:03:47]

#

def pelaa_miinaharavaa(leveys, korkeus, alue, x, y):
    koordinaatit = [(x, y)]
    while len(koordinaatit) > 0:
        x, y = koordinaatit.pop()
        if alue[y][x] == "x":
            print("Astuit miinaan!")
            print("Peli loppui!")
            break
        elif alue[y][x] == " ":
            alue[y][x] == "o"
            for vaaka in range((x - 1), (x + 2)):
                for pysty in range((y - 1), (y + 2)):
                    if vaaka >= 0 and vaaka <= (leveys - 1) and pysty >= 0 and pysty <= (korkeus - 1):
                        koordinaatit.append((vaaka, pysty))
pelaa_miinaharavaa(leveys, korkeus, alue, x, y)

Eli olin tekemässä ohjelmoinnin kurssia varten miinaharavaa. Ongelmaksi muodostui se, että nyt peli ilmoittaa pelaajan osuneen aina miinaan, vaikkei niin olisi käynytkään. Ongelma on ilmeisesti ylläolevassa pätkässä, koska elif-lauseke lisää myös x:n sisältävät ruudut koordinaatit-listaan. Yritin erilaisia vaaka == " " and pysty == " ", mutten keksinyt ratkaisua.

Grez [11.08.2016 11:30:36]

#

Eiks toi nyt lisäile koordinaatit myös valitun pisteen ympäriltä ja testaa ne sekä sen jälkeen lisää koordinaatit niiden ympäriltä ja testaa ne ja jälleen lisäilee koordinaatit niiden ympäriltä ja testaa ne. Eli siis olettaisin että toi koodi sanoo "astuit miinaan" aina jos kentällä ylipäätään on miina.

Toi for vaaka ja for pysty hässäkkä on ilmeisesti sitä varten, että se laskisi niitä miinojen määriä reuna-alueilla, mutta nyt kun se ei laske, niin homma ei toimi.

Chiman [11.08.2016 13:10:54]

#

Käyttäisin kahta erillistä taulukkoa.

Toinen sisältäisi tiedon, onko ruudussa tai sen naapureissa miinaa ('x' tai 0-8). Sen sisältö luotaisiin heti pelin alussa, kun miinat sijoitetaan kentälle.

Toinen, tulostukseen käytettävä taulukko sisältäisi ruudussa kulloinkin näytettävän tiedon (jokin merkeistä 'x 012345678' tai pelaajan asettama apumerkki).

Metabolix [11.08.2016 17:39:57]

#

Itse ongelma varmaan ratkeaisi muuttamalla for-silmukassa olevaa ehtolausetta:

if 0 <= vaaka < leveys and 0 <= pysty < korkeus and alue[pysty][vaaka] == ' ':
    koordinaatit.append((vaaka, pysty))

Tietenkään ei siis pidä verrata vaaka- tai pysty-muuttujaa tiettyyn tekstiin, vaan pitää hakea ruudun sisältö alue-muuttujasta, kuten aiemmissakin vastaavissa kohdissa.

Jos koodisi vastaa muuten tehtävänantoa, tarkoituksena näyttäisi olevan kylläkin alueen täyttäminen (flood fill) eikä miinaharavan pelaaminen, kun miinaharavan idea on kuitenkin siinä, että miinojen sijainnit eivät ole pelaajan tiedossa...

Grez [11.08.2016 18:01:48]

#

Metabolix kirjoitti:

Jos koodisi vastaa muuten tehtävänantoa, tarkoituksena näyttäisi olevan kylläkin alueen täyttäminen (flood fill) eikä miinaharavan pelaaminen, kun miinaharavan idea on kuitenkin siinä, että miinojen sijainnit eivät ole pelaajan tiedossa...

No kyllähän miinaharavassa yleensä on tuollainen "flood fill" kun klikkaa aution alueen keskelle. Sen vaan pitäisi sitten pysäyttää niihin numeroihin eikä mennä miinoihin asti.

Metabolix [11.08.2016 18:06:32]

#

Grez kirjoitti:

No kyllähän miinaharavassa yleensä on tuollainen "flood fill" kun klikkaa aution alueen keskelle.

On, mutta sen nimi ei yleensä ole "pelaa_miinaharavaa", ja se ei etene kaikista pienistäkin raoista vaan juurikin pysähtyy jo ensimmäiseen numeroruutuun.

Grez [11.08.2016 18:07:50]

#

Mun mielestä se kyllä hakee kaikki numeroruudut siitä ympäriltä ja pysähtyy vasta kun pidemmälle ei enää pääse, eli numeroiden välissä ei ole "pienintäkään rakoa". Eli tosta koodista puuttuu kokonaan se numeroiden muodostaminen, niin eihän se tietty niihin voi pysähtyä.

Esim. yhdellä klikkauksella

Metabolix [11.08.2016 18:15:07]

#

Tarkoitin juurikin, että kun aloittajan koodissa ei näytä olevan numeroita ollenkaan, hänen algoritminsa etenee mistä tahansa miinojen välistä (jopa kulmittain), kun pitäisi pysähtyä jo ruutua aiemmin numeroruutuihin. Myöskään miinaharavan haku ei taida hyppiä kulmittain numeroiden välistä.

jalski [11.08.2016 18:20:54]

#

Itse käyttäisin yhtä taulukkoa, mikä olisi yhden ruudun leveämpi ja korkeampi kuin varsinainen pelialue (pysäyttää haun ilman lisätarkistuksia). Peliruudun tilan tallentaisin UDT:hen, missä olisi tieto onko ruudussa miinaa ja ruudun tila (valitsematon, valittu tai merkattu).

Sitten tarvitaan vain pari funktiota, joiden avulla "flood fill" hoituu yksinkertaisella rekursiolla. Esim. PL/I:llä:

/******************************************************************************************************/
 board_check: proc(i, j) returns(type INT);
   dcl (i, j, row, col, c) type INT;

   if board(i,j).mine then return(-1);
   if iand(board(i,j).state, ior(binvalue(SELECTED), binvalue(MARKED))) ^= 0 then
     return(-2);

   c = 0;
   do row = i-1 to i+1;
     do col = j-1 to j+1;
       if board(row,col).mine then
         c += 1;
     end;
   end;

   return(c);
 end board_check;

/******************************************************************************************************/
 display_zeros: proc(hdc, i, j) recursive;
   dcl hdc type HDC;
   dcl (i, j, row, col, tile) type INT;

   do row = i-1 to i+1;
     do col = j-1 to j+1;
       if row < 1 | row > brdsz | col < 1 | col > brdsz then
         iterate;
       tile = board_check(row, col);
       if tile = 0 then
         do;
           score += 1;
           board(row,col).state = binvalue(SELECTED);
           call display_square(hdc, row, col, htilesbm(tile));
           call display_zeros(hdc, row, col);
         end;
       else if tile >= 1 & tile <= 8 then
         do;
           board(row,col).state = binvalue(SELECTED);
           call display_square(hdc, row, col, htilesbm(tile));
           score += 1;
         end;
      end;
   end;
 end display_zeros;

Chiman [14.08.2016 10:57:20]

#

Ruudukkopeleissä on mielestäni selkeää erotella puhtaasti ruudukkoon liittyvät yleiset toiminnot omaan luokkaansa, jotta pelikohtainen koodi pääsee keskittymään itse asiaan.

Tein huvikseni miinaharavan itsekin, tässä siitä pari osaa:
ruudukko.py:

class Ruudukko:
    # ...

    def ruudukossa(self, x, y):
        return (0 <= y < self.kork) and (0 <= x < self.lev)

    def naapurit(self, x, y, viist=True):
        nxy = NAAPURIT_SUORAT + (NAAPURIT_VIISTOT if viist else ())
        for dx, dy in nxy:
            rx, ry = x + dx, y + dy
            if self.ruudukossa(rx, ry):
                yield rx, ry

miinaharava.py:

class Miinaharava:
    # ...

    # kutsutaan pelin alustusvaiheessa yksittäistä miinaa asetettaessa
    def _numeroi_miinaymp(self, x, y):
        for rx, ry in self.data.naapurit(x, y):
            if self.data.ruudut[ry][rx] != MIINA:
                self.data.ruudut[ry][rx] += 1

    def _avaa_nolla_alue(self, x, y):
        avattavat = [(x, y)]
        while avattavat:
            x, y = avattavat.pop()
            if self.naytto.ruudut[y][x] != KIINNI:
                continue
            if self.data.ruudut[y][x] == 0:
                avattavat.extend(self.data.naapurit(x, y))
            self.naytto.ruudut[y][x] = self.data.ruudut[y][x]

jalski [14.08.2016 14:51:36]

#

Chiman kirjoitti:

Ruudukkopeleissä on mielestäni selkeää erotella puhtaasti ruudukkoon liittyvät yleiset toiminnot omaan luokkaansa, jotta pelikohtainen koodi pääsee keskittymään itse asiaan.

Miinaharavan ollessa kyseessä toteutukseen tosin riittää yksinkertaisesti taulukko ja muutama aliohjelma, joten luokkien vääntäminen tuntuu minusta hiukan turhalta hienostelulta.

PL/I:llä kirjoiteltu Win32 miinaharava äksönissä

Chiman kirjoitti:

Tein huvikseni miinaharavan itsekin, tässä siitä pari osaa:

Mikset sisäisesti ympäröisi peliruudukkoa tyhjillä ruuduilla ja hankkiutuisi eroon ruudukossa() funktiosta ja turhista tarkistuksista?

Chiman [14.08.2016 17:01:00]

#

jalski kirjoitti:

Mikset sisäisesti ympäröisi peliruudukkoa tyhjillä ruuduilla ja hankkiutuisi eroon ruudukossa() funktiosta ja turhista tarkistuksista?

Makuasia. Pidän enemmän siitä, että tietorakenteet sisältävät vain varsinaista dataa.


Sivun alkuun

Vastaus

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

Tietoa sivustosta