Mòdul 8

Pràctica 4: El món del Joc de la Vida   
Tornar presentació tema
Pràctica 2 Pràctica 3 Pràctica 4 Pràctica 1 Pràctica 5 Pràctica 6 Pràctica 6  
     
     
  El món i els éssers del món  
     
  El MonVisible que has creat a la pràctica 2 no és res més que un dispositiu per veure les coses que passen. Però a on passen de veritat les coses és a la memòria de la màquina, en algun tros de la memòria que, tot definint classes adequades, has de determinar.  
     
  Hi haurà, doncs, una classe Mon, que ha de contenir:  
     
 
  • la quadrícula on viuran (o moriran) els éssers,

  • les lleis de la vida, és a dir, les regles que fan que uns éssers visquin i d'altres morin, i

  • la manera com l'estat del món ha de pintar-se al MonVisible.
 
     
  Per representar els éssers caldrà definir-los com a objectes de la classe Esser, la qual ha de contenir, com a mínim,  
     
 
  • l'estat de viu o mort de l'ésser que representa, i

  • la manera com aquest Esser ha de pintar-se al MonVisible
 
     
  Els éssers del món:    
     
Comencem pels éssers. Al projecte JocDeLaVida hi crees la nova classe Esser:  
     
/**
 * La classe Esser representa un ésser dels que poblen el món
 * del "Joc de la Vida".
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public class Esser {

    /**
     * L'estat de viu o mort d'aquest Esser.
     */

    private boolean esViu=false;

 
   /**
     * Mètode constructor per a objectes de la classe Esser.
     * @param esViu l'estat de viu o mort d'aquest Esser.
     */

    public Esser(boolean esViu) { // constructor
        this.esViu=esViu;
    }

}

 
     
  i, com que, sovint, haurem de preguntar o variar l'estat de viu o mort d'aquest Esser, calen un mètode getter i un altre mètode setter per a la variable esViu:  
     
/**
 * La classe Esser representa un ésser dels que poblen el món
 * del "Joc de la Vida".
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */
public class Esser {

    /**
     * L'estat de viu o mort d'aquest Esser.
     */
    private boolean esViu=false;

    /**
     * Mètode constructor per a objectes de la classe Esser.
     * @param esViu l'estat de viu o mort d'aquest Esser.
     */
    public Esser(boolean esViu) { // constructor
        this.esViu=esViu;
    }


   
 /**
     * Obtenció de l'estat de viu o mort d'aquest Esser.
     */

    public boolean getEsViu () {
        return esViu;
    }

  
  /**
     * Determinació de l'estat de viu o mort d'aquest Esser.
     * @param esViu l'estat de viu o mort d'aquest Esser que
     * es vol determinar.
     */

    public void setEsViu (boolean esViu) {
        this.esViu=esViu;
    }

}

 
     
  Ara ja només falta decidir com es pinta un ésser viu al MonVisible. Per començar, un cercle vermell viu vorejat d'una circumferència vermella, però més fosca ja farà un bon paper. Naturalment, si l'ésser és mort, no es pinta:  
     
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Color;

/**
 * La classe Esser representa un ésser dels que poblen el món
 * del "Joc de la Vida".
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */
public class Esser {

    /**
     * L'estat de viu o mort d'aquest Esser.
     */
    private boolean esViu=false;

    /**
     * Mètode constructor per a objectes de la classe Esser.
     * @param esViu l'estat de viu o mort d'aquest Esser.
     */
    public Esser(boolean esViu) { // constructor
        this.esViu=esViu;
    }

    /**
     * Obtenció de l'estat de viu o mort d'aquest Esser.
     */
    public boolean getEsViu () {
        return esViu;
    }

    /**
     * Determinació de l'estat de viu o mort d'aquest Esser.
     * @param esViu l'estat de viu o mort d'aquest Esser que
     * es vol determinar.
     */
    public void setEsViu (boolean esViu) {
        this.esViu=esViu;
    }


    /**
     * Mètode paint per a aquest Esser.
     * @param dimensions les dimensions en píxels d'aquest Esser.
     * @param posicio la posició en píxels d'aquest Esser.
     * @param un objecte Graphics2D.
     */

    public void paint (Dimension dimensions,
                       Dimension posicio,
                       Graphics2D g) {
        if (esViu) {
// Només pintar-lo si és viu
            // Color vermell viu
            g.setColor(Color.RED.brighter());

            
// Omplir un cercle una mica més petit
            g.fillOval(posicio.width+1,posicio.height+1,
                       dimensions.width-2,dimensions.height-2);
            // Color vermell fosc
            g.setColor(Color.RED.darker().darker().darker());
            
// Envoltar-lo amb una circumferència
            g.drawOval(posicio.width+1,posicio.height+1,
                       dimensions.width-2,dimensions.height-2);
        }
    }


}

 
     
  No oblidéssis pas importar les classes necessàries!  
     
  El món:    
     
Ja t'hem dit que, bàsicament, ha de ser la quadrícula que conté els éssers. Així, doncs, la nova classe Món (que has d'afegir al projecte JocDeLaVida) ha de tenir com a variable d'instància una matriu doble (files i columnes) d'objectes Esser:  
     

/**
 * La classe Mon conté la matriu que determina la situació dels
 * éssers que poblen el mon del "Joc de la Vida" i les rutines que
 * governen el seu comportament.
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public class Mon {

    /**
     * La matriu d'Esser's que conformen aquest Mon.
     */

    private Esser[][] elMon;

}

 
     
  Però, per construir efectivament la quadrícula d'aquest Mon, la variable elMon, has d'haver decidit abans quantes columnes i quantes files ha de tenir i, ja pensant en el MonVisible, quanta pantalla n'ocuparà la visualització: has d'haver decidit, doncs, quines dimensions, en píxels, ha de tenir un ésser. Resultarà força pràctic definir una nova classe, Constants, que contingui aquests paràmetres com a variables static:  
     

import java.awt.Dimension;

/**
 * La classe Constants conté els paràmetres del "Joc de la Vida".
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public final class Constants {

    /**
     * Les dimensions del mon, en nombre d'éssers.
     */

    public static Dimension dimensionsMon=new Dimension(40,30);

    /**
     * Les dimensions d'un ésser.
     */

    public static Dimension dimensionsEsser=new Dimension(12,12);

}

 
     
  (Hi podries posar, a més, els colors de les coses si volguéssis) Observa que si reuneixes tots els paràmetres de l'aplicació en una classe com aquesta (que es declara final perquè no serà instanciada i només conté elements static) simplement canviant-ne els valors de les constants que s'hi defineixen, canvies l'aspecte de tota l'aplicació!  
     
  Com a exemple d'això, ara és el moment d'escriure el codi definitiu del mètode getDimensionsMonVisible() de la classe Finestra: recorda que, a la pràctica 2, hi havies escrit un codi provisional que ara canviaràs:  
     
 

    /**
     * Mètode que fixa les dimensions del MonVisible.
     *
ATENCIÓ: CONTINGUT PROVISIONAL!
     * @return les dimensions del MonVisible
     */

    public Dimension getDimensionsMonVisible () {
        return new Dimension(400,300);
    }

 
     
  L'amplada del MonVisible (en píxels) ha de ser igual a l'amplada (en éssers) del Mon, multiplicada per l'amplada d'un ésser i, igualment, l'altura del MonVisible (en píxels) ha de ser igual a l'altura (en éssers) del Mon, multiplicada per l'altura d'un ésser. Ja ho pots escriure: al mètode getDimensionsMonVisible() de la classe Finestra escriu-hi:  
     

    /**
     * Mètode que fixa les dimensions del MonVisible.
     * @return les dimensions del MonVisible
     */

    public Dimension getDimensionsMonVisible () {
        int ampleMonVisible=Constants.dimensionsMon.width*
                            Constants.dimensionsEsser.width;
        int alturaMonVisible=Constants.dimensionsMon.height*
                             Constants.dimensionsEsser.height;
        return new Dimension(ampleMonVisible,alturaMonVisible);
    }

 
     
  Compila i crea un objecte Finestra i veuràs com n'han canviat les dimensions...  
     
  Ara ja podem construir el Mon:  
     

/**
 * La classe Mon conté la matriu que determina la situació dels
 * éssers que poblen el mon del "Joc de la Vida" i les rutines que
 * governen el seu comportament.
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public class Mon {

    /**
     * La matriu d'Esser's que conformen aquest Mon.
     */
    private Esser[][] elMon;

    /**
     * Mètode constructor per a objectes de la classe Mon
     */

    public Mon() { //constructor
        int amplada=Constants.dimensionsMon.width;
        int altura=Constants.dimensionsMon.height;
        elMon=new Esser[amplada][altura];
    }

}

 
     
  Ara cal omplir d'essers la matriu elMon:  
     

/**
 * La classe Mon conté la matriu que determina la situació dels
 * éssers que poblen el mon del "Joc de la Vida" i les rutines que
 * governen el seu comportament.
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public class Mon {

    /**
     * La matriu d'Esser's que conformen aquest Mon.
     */
    private Esser[][] elMon;

    /**
     * Mètode constructor per a objectes de la classe Mon
     */
    public Mon() { //constructor
        int amplada=Constants.dimensionsMon.width;
        int altura=Constants.dimensionsMon.height;
        elMon=new Esser[amplada][altura];

        ompleMon();
    }

    /**
     * Inicialització d'aquest Mon. La matriu elMon s'omple
     * d'Esser's morts.
     */
    public void ompleMon () {
            for (int i=0;i<elMon.length;i++) {
                    for (int j=0;j<elMon[0].length;j++) {
                        elMon[i][j]=new Esser(false);
                    }
            }
    }

}

 
     
  Finalment (per ara!) cal pintar el Mon en el MonVisible. Es tracta de pintar els Essers a la seva posició:  
     

import java.awt.Graphics2D;
import java.awt.Dimension;

/**
 * La classe Mon conté la matriu que determina la situació dels
 * éssers que poblen el mon del "Joc de la Vida" i les rutines que
 * governen el seu comportament.
 *
 * @author (el vostre nom)
 * @version (un número de versió o la data)
 */

public class Mon {

    /**
     * La matriu d'Esser's que conformen aquest Mon.
     */
    private Esser[][] elMon;

    /**
     * Mètode constructor per a objectes de la classe Mon
     */
    public Mon() { //constructor
        int amplada=Constants.dimensionsMon.width;
        int altura=Constants.dimensionsMon.height;
        elMon=new Esser[amplada][altura];
        ompleMon();
    }

    /**
     * Inicialització d'aquest Mon. La matriu elMon s'omple
     * d'Esser's morts.
     */
    public void ompleMon () {
            for (int i=0;i<elMon.length;i++) {
                    for (int j=0;j<elMon[0].length;j++) {
                        elMon[i][j]=new Esser(false);
                    }
            }
    }


    /**
     * Mètode paint per a aquest Mon.
     * @param un objecte Graphics2D.
     */

    public void paint (Graphics2D g) {
            for (int i=0;i<elMon.length;i++) {
                int x=i*Constants.dimensionsEsser.width;
                    for (int j=0;j<elMon[0].length;j++) {
                        int y=j*Constants.dimensionsEsser.height;
                        Esser esser=elMon[i][j];
                        esser.paint(Constants.dimensionsEsser,
                                    new Dimension(x,y),
                                    g);
                    }
            }

    }

}

 
     
  El Mon, el MonVisible i la Finestra...    
     
  Ja fa massa estona que escrius codi, compiles... però que no veus en funcionament res d'allò que has escrit! Passa que aquest Mon (inacabat!) no està relacionat amb la Finestra, no és una peça del muntatge posada al seu lloc. Ara toca posar-la: ves a la classe Finestra i crea la variable d'instància public Mon mon :  
     

<codi anterior>
public class Finestra extends JFrame {

    /**
     * L'objecte Mon en el qual viuen i moren els éssers.
     */

    protected Mon mon;

    /**
     * L'objecte MonVisible que fa visibles els éssers
     * del món.
     */
    protected MonVisible monVisible;

    /**
     * Mètode getter per a la variable mon
     * @return el Mon d'aquesta finestra
     */

    public Mon getMon () {
        return mon;
    }

    /**
     * Mètode getter per a la variable monVisible
     * @return el MonVisible d'aquesta finestra
     */
    public MonVisible getMonVisible () {
        return monVisible;
    }

    <segueix>

 
     
  i, al mètode constructor de la classe Finestra, construeix efectivament el mon:  
     

    <codi anterior>
    /**
     * Mètode constructor per a objectes de la classe Finestra.
     */
    public Finestra () { // constructor
        setConfiguracio();
        setControls();
        mon=new Mon();
        inicia();
    }

    <segueix>

 
     
  Finalment, al mètode paint() de la classe MonVisible falta afegir-hi la instrucció de pintar-hi el contingut de l'objecte mon, és a dir, la de pintar els éssers que conté:  
     

    <codi anterior>
    /**
     * Mètode paint per a aquest MonVisible.
     * @param un objecte java.awt.Graphics
     */
    public void paint (Graphics g) {
        Graphics2D g2d=(Graphics2D)g; // La classe Graphics2D di-
                                      // buixa molt millor que la
                                      // classe Graphics
        // Els RenderingHint(s) per millorar els gràfics
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                             RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.BLUE); // Pinta blau...
        int ample=getSize().width; // Les dimensions del MonVisible
        int alt=getSize().height;
        g2d.fill3DRect(0,0,ample,alt,false); // Pinta un rectangle
                                             // esfonsat de color
                                             // blau, que ocupa
                                             // tot el MonVisible

        finestra.getMon().paint(g2d);
    }
    <segueix>

 
     
  Arriba el moment de veure la feina feta! Per poder veure els éssers, fes que, provisionalment, el mètode ompleMon() de la classe Mon ompli la matriu elMon d'éssers vius:  
     
 

     /**
     * Inicialització d'aquest Mon. La matriu elMon s'omple
     * d'Esser's morts.
     */
    public void ompleMon () {
            for (int i=0;i<elMon.length;i++) {
                    for (int j=0;j<elMon[0].length;j++) {

                        // elMon[i][j]=new Esser(false);
                        // PROVISIONAL! Només per a veurel's

                        elMon[i][j]=new Esser(true);
                    }
            }
    }
    <segueix>

 
     
  Compila i crea un objecte Finestra:  
     
 
 
     
  Bé! bé! no?  
     
  Ara pots provar de canviar els valors de les constants en el fitxer Constants.java i veure com es comporta la finestra...  
     
  Canviar l'estat d'un ésser:    
     
  Només queda, per ara, un mètode a afegir a la classe Mon: un mètode que serveixi per canviar l'estat viu/mort de l'Esser que és a la cel·la de coordenades i,j:  
     
 

    /**
     * Canvia l'estat de l'Esser situat a una certa posició
     * d'aquest Mon.
     * @param i la posició "x" de l'Esser.
     * @param j la posició "y" de l'Esser.
     */

    public void canviaEstatViuOMort (int i,int j) {
        Esser esser=elMon[i][j]; // Quin Esser hi ha en aquesta
                                 // posició?

        boolean estat=esser.getEsViu(); // En quin estat està ara?
        esser.setEsViu(!estat); // Canvi a l'estat contrari
    }