Game of Life - vaihe 3

Tässä vaiheessa tehdään ruuduista värjättäviä ja laitetaan ne elämään. Ratkaisuun tarvitaan edellisen vaiheen rakenteiden lisäksi ehtolauseita, loogisia operaattoreita ja taulukoita. Palauta taas ensin mieleesi, miten nämä toimivat.

Klikkauksen kuuntelu

Muokataan LuoRuutu-aliohjelmaa ja lisätään ruuduille hiiren kuuntelija, jotta ruutuja voidaan värjätä klikkaamalla.

void LuoRuutu(double x, double y)
{
    GameObject ruutu = new GameObject(RUUDUN_KOKO-2, RUUDUN_KOKO-2);
    ruutu.Position = new Vector(x, y);

    Mouse.ListenOn(ruutu, MouseButton.Left, ButtonState.Pressed,
        () => { VaihdaVaria(ruutu); }, "Vaihdetaan ruudun väriä");

    ruudut.Add(ruutu);
    Add(ruutu);
}

 
Kirjoitetaan seuraavaksi tarvittava VaihdaVaria-aliohjelma, joka värjää ruudun mustaksi, kun sitä klikataan. Jos ruutu on jo musta, muutetaan se klikattaessa takaisin valkoiseksi.

void VaihdaVaria(GameObject ruutu)
{
    if (ruutu.Color == Color.White)
        ruutu.Color = Color.Black;
    else ruutu.Color = Color.White;
}


Nyt ruutuja voi värjäillä klikkailemalla niitä.

Ruutujen elämä

Lisätään Begin-aliohjelmaan näppäimistön kuuntelija, jonka avulla laitetaan ruudut elämään. Ohjeessa kuunnellaan välilyöntinäppäintä, mutta sen tilalla voi halutessaan käyttää muitakin näppäimiä.

public override void Begin()
{
    Mouse.IsCursorVisible = true;
    IsFullScreen = false;
    Window.Width = 500;
    Window.Height = 500;

    LuoKentta();

    Keyboard.Listen(Key.Space, ButtonState.Pressed, ElaKerran, "Eletään yksi kierros");
    
    Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
}


Sitten kirjoitetaan ElaKerran-aliohjelma, joka luo uuden sukupolven eläviä ruutuja pelin sääntöjen mukaisesti. Tälle aliohjelmalle voisi sopia nimeksi myös YOLO.

void ElaKerran()
{

}


Tämä aliohjelma käy silmukassa läpi kaikki kentällä olevat ruudut ja tarkistaa ruudun elävien naapurien määrän. Naapurien määrän perusteella päätetään, kuoleeko hengissä oleva ruutu pois tai herääkö kuollut ruutu henkiin. Voit tarkistaa pelin säännöt tutoriaalin alusta, jos ne ovat ehtineet unohtua. Mieti tarkkaan, mitä tämän aliohjelman sisällä tapahtuu.

void ElaKerran()
{
    for (int i = 0; i < ruudut.Count; i++)
    {
        int naapurit = LaskeNaapurit(ruudut[i]);
        if (ruudut[i].Color == Color.Black)
            if (naapurit < 2 || naapurit > 3)
                ruudut[i].Color = Color.White;
        if (ruudut[i].Color == Color.White)
            if (naapurit == 3)
                ruudut[i].Color = Color.Black;
    }
}


Seuraavaksi pitäisi toteuttaa LaskeNaapurit-aliohjelma, joka laskee ruudun elävien naapurien määrän. Tehdään tämä tarkistamalla kaikkien naapurien paikat vektorien avulla, kuten alla olevassa kuvassa.


Liikutaan siis jokaisen ruudun paikasta kahdeksaan eri suuntaan ja tarkistetaan, onko näissä paikoissa eläviä ruutuja. Nämä kahdeksan eri suuntaa voidaan määrittää vektoritaulukkossa heti ohjelman alussa, ruudun koon asettamisen jälkeen:

Vector[] suunnat = { new Vector(0,RUUDUN_KOKO),
                     new Vector(RUUDUN_KOKO,0),
                     new Vector(0,-RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,0),
                     new Vector(RUUDUN_KOKO,RUUDUN_KOKO),
                     new Vector(RUUDUN_KOKO,-RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,-RUUDUN_KOKO) };


Nyt voimme kirjoittaa LaskeNaapurit-aliohjelman näiden suuntien avulla. Ruudusta liikutaan jokaiseen eri suuntaan, ja jos uudesta paikasta löytyy elävä ruutu, kasvatetaan elävien naapurien määrää yhdellä. Lopuksi palautetaan elävien naapurien määrä aliohjelman kutsujalle.

int LaskeNaapurit(GameObject ruutu)
{
    int naapurienMaara = 0;
    foreach (Vector v in suunnat)
    {
        GameObject naapuri = GetObjectAt(ruutu.Position + v);
        if (naapuri != null && naapuri.Color == Color.Black)
            naapurienMaara++;
    }
    return naapurienMaara;
}


Voit nyt ajaa ohjelman, naputella kentälle eläviä ruutuja ja laittaa simulaation käyntiin. Ruudut elävät yhden kierroksen jokaisella napinpainalluksella.

Ruutujen elämää
Ohjelma ei kuitenkaan toimi vielä aivan oikein, joten jatketaan!

Siirry seuraavan vaiheeseen



Koko koodin pitäisi vaiheen lopuksi näyttää suurinpiirtein tältä:

using System.Collections.Generic;
using Jypeli;
using Jypeli.Controls;    

public class GameOfLife : Game
{
    const int RUUDUN_KOKO = 50;
    List<GameObject> ruudut = new List<GameObject>();
    Vector[] suunnat = { new Vector(0,RUUDUN_KOKO),
                     new Vector(RUUDUN_KOKO,0),
                     new Vector(0,-RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,0),
                     new Vector(RUUDUN_KOKO,RUUDUN_KOKO),
                     new Vector(RUUDUN_KOKO,-RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,RUUDUN_KOKO),
                     new Vector(-RUUDUN_KOKO,-RUUDUN_KOKO) };    

    public override void Begin()
    {
        Mouse.IsCursorVisible = true;
        IsFullScreen = false;
        Window.Width = 500;
        Window.Height = 500;    

        LuoKentta();    

        Keyboard.Listen(Key.Space, ButtonState.Pressed, ElaKerran, "Eletään yksi kierros");    

        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
    }    

    void LuoKentta()
    {
        double alkuX = -Window.Width / 2 + RUUDUN_KOKO / 2;
        double alkuY = -Window.Height / 2 + RUUDUN_KOKO / 2;    

        for (double x = alkuX; x < Window.Width / 2; x += RUUDUN_KOKO)
            for (double y = alkuY; y < Window.Height / 2; y += RUUDUN_KOKO)
                LuoRuutu(x, y);
    }    

    void LuoRuutu(double x, double y)
    {
        GameObject ruutu = new GameObject(RUUDUN_KOKO - 2, RUUDUN_KOKO - 2);
        ruutu.Position = new Vector(x, y);    

        Mouse.ListenOn(ruutu, MouseButton.Left, ButtonState.Pressed,
        () => { VaihdaVaria(ruutu); }, "Vaihdetaan ruudun väriä");    

        ruudut.Add(ruutu);
        Add(ruutu);
    }    

    void VaihdaVaria(GameObject ruutu)
    {
        if (ruutu.Color == Color.White)
            ruutu.Color = Color.Black;
        else ruutu.Color = Color.White;
    }    

    void ElaKerran()
    {
        for (int i = 0; i < ruudut.Count; i++)
        {
            int naapurit = LaskeNaapurit(ruudut[i]);
            if (ruudut[i].Color == Color.Black)
                if (naapurit < 2 || naapurit > 3)
                    ruudut[i].Color = Color.White;
            if (ruudut[i].Color == Color.White)
                if (naapurit == 3)
                    ruudut[i].Color = Color.Black;
        }
    }    

    int LaskeNaapurit(GameObject ruutu)
    {
        int naapurienMaara = 0;
        foreach (Vector v in suunnat)
        {
            GameObject naapuri = GetObjectAt(ruutu.Position + v);
            if (naapuri != null && naapuri.Color == Color.Black)
                naapurienMaara++;
        }
        return naapurienMaara;
    }
}

These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.