IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Game of life - začátečník

Aktivity
Avatar
Dave Petlák
Člen
Avatar
Dave Petlák:15.8.2017 12:02

Zdravím všechny, před nedávnem jsem se pustil do Javy (jako samouk cca 3 týdny zpět a jediné předchozí zkušenosti mám s matlabem a jedním semestrem C# probíhajícím stylem diktátu). Každopádně nějaké pokroky zaznamenávám ale tak nějak nevím, jestli nedělám chyby (respektive vím, že je dělám). Proto bych zde rád požádal zkušenější uživatele, zda by bylo možné se podívat na můj první 100% samostatně napsaný program (pokud nepočítám několik cvičení z projecteuler.net). Budu vděčný za jakoukoliv věcnou kritiku, tipy a postřehy co zlepšit a čeho se vyvarovat.

public class GameOfLife {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        GameLogic gl = new GameLogic();

        int randOccur = 5;

        char[][] gameBoard = gl.randomSeed(randOccur);

        gl.drawGame(gameBoard);
        System.out.println();
        for(int generace = 0; generace < 500; generace++){
            System.out.println(String.format("%d generace. ", generace));
            gameBoard = gl.newGeneration(gameBoard);
            gl.drawGame(gameBoard);
            System.out.println();
            try{
                Thread.sleep(200);
            }
            catch(InterruptedException e){

            }
        }


    }

}

A třída která se stará o vlastní hru:

public class GameLogic {
    Random rd;
    private final char alive = 'X';
    private final char dead = '_' ;

    public GameLogic(){
       rd = new Random();
    }

    /** Vytvoří novou herní plochu a náhodně umístí živé buňky.
     *
     * @param randOccur poměr četnosti 1:randOccur
     * @return  char[][] s herní plocou a generací 0
     */
    public char[][] randomSeed(int randOccur){
        char[][] gameBoard = new char[40][40];
        for (char[] gameBoard1 : gameBoard) {
            for (int j = 0; j < gameBoard[0].length; j++) {
                int rand = rd.nextInt(randOccur);
                if (rand < 1) {
                    gameBoard1[j] = alive;
                } else {
                    gameBoard1[j] = dead;
                }
            }
        }
        return gameBoard;
    }

    /** Vykreslí herní plochu do konzole
     *
     * @param gameBoard 2D pole k vykreslení
     */
    public void drawGame(char[][] gameBoard){
        for (char[] gameBoard1 : gameBoard) {
            for (int j = 0; j < gameBoard[0].length; j++) {
                System.out.print(gameBoard1[j] + " ");
            }
            System.out.println();
        }
    }

    /** Vytvoří pole pro novou generaci.
     *
     * @param previousGen výchozí generace
     * @return 2D pole s příští generací
     */
    public char[][] newGeneration(char[][] previousGen){

        int ROWS = previousGen.length;
        int COLUMNS = previousGen[0].length;
        int living = 1;

        char[][] newGen = new char[ROWS][COLUMNS];
        for(int i = 0; i < ROWS; i++){
            for(int j = 0; j < COLUMNS; j++){
                int aliveAround = checkSurroundings(previousGen, i, j);

                if(aliveNextTurn(aliveAround, previousGen[i][j])== true){
                    newGen[i][j] = alive;
                }
                if(aliveNextTurn(aliveAround, previousGen[i][j]) == false){
                    newGen[i][j] = dead;
                }
            }
        }
        return newGen;
    }

    /**
     *
     * @param previousGen Matice současné generace
     * @param r Souřadnice prověřované buňky
     * @param c Počet živých buňěk v okolí
     * @return
     */
    private int checkSurroundings(char[][] previousGen, int r, int c){
        int noAlive = 0;
        for(int k = r-1; k <= r+1; k++){
            for(int l = c-1; l <= c+1; l++){
                if(((k < 0) || (l < 0)) || ((k >= previousGen.length) || (l >= previousGen[0].length)) || ((k == r)&&(l == c))){
                    continue;
                }
                if(previousGen[k][l] == alive){
                    noAlive++;
                }
            }
        }
        return noAlive;
    }
    /**Dle podmínek posoudí, zda bude buňka naživu v příští gen.
     *
     * @param aliveAround
     * @param cell
     * @return
     */
    private boolean aliveNextTurn(int aliveAround, char cell){

       if(cell == alive){
           if((aliveAround < 2) || (aliveAround > 3)){
               return false;
           }
           else{
               return true;
           }
       }

       if(cell == dead){
           if(aliveAround == 3){
               return true;
           }
           else{
               return false;
           }
       }

       return false;
    }
}

Program jako takový funguje, ale nepochybuji, že je plný špatných (byť možná funčních) postupů a špatných praktik. Pokud tedy mohu poprosit o co nejtvrdší zhodnocení tohoto kódu abych se pro příště mohl vyvarovat těchto chyb (preferuji tvrdou školu)? Předem moc děkuji.

 
Odpovědět
15.8.2017 12:02
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:15.8.2017 15:28

Předně palec nahoru za dobrý přístup. Místo fňukání jdeš do učení s elánem;) šikula

a teď teda věcně:

  • nervi všechno do metody main. Lepší je využít konstruktor (už jen proto, že jej můžeš v budoucnu přetěžovat). Main metodu využívej jednak ke spuštění projektu, ale hlavně když ještě potřebuješ před spuštěním nastavit nějaké procedury (využívat statických metod)
  • + za používání dokuemtačních komentářů. To je veliké a významné plus.
  • + určitě kladné body za koncepci oop. Krásně jsi to rozdělil do class a metod, což považuju za dobrý krůček. Pochopitelně malá poznámečka:) zkus už teď používat balíky (třeba jen jeden), ale také si na to zvykej už ze začátku. Ať máš později lehčí práci.
  • + za používání camelNotice. Jestli jsi předtím dělal v C#, kde je víc zavedená konvence podtržítek v názvech, tak supr, že si zvykáš rychle na velbloudí notaci. V Javě sice lze používat i podtržítka, ale všichni programátoři vyžadují nepsané pravidlo camelNotice, takže supr
  • + za používání anglických název proměnných
  • za velmi stručné názvy proměnných:) rd, alive, dead.... slova sice chápu, ale k čemu vlastně jsou? (to si budeš říkat za půl roku, až se na tento projekt podíváš). Pochybuju, že budeš psát kód v texťáku. Vždycky na to budeš využívat nějaké IDE. Dneska všechny IDE bez výjimky používají dokončování slov. Takže se neboj psát velmi dlouhé proměnné. Př.:
private int number = 5;  // stručné, jasné a lehké na zapamatování.

o dva roky později...

private int number = 5; // co to kurva je? k čemu ta proměnná je????

pracnější, ale po letech se takhle ptát nebudeš:

private int numberForCountingTotalValueOfMembersInABank = 5; // a když zmáčkneš CTRL+Space, tak ti IDE vždy takový název dokončí samo, ale ty se v tom vyznáš

Pokud budeš psát kód, aby nějak fungoval, tak na to ti stačí třeba i baltík. Dobrý kód poznáš tak, že se v něm nejpozději do dvou minut orientuješ.

  • ta jednoduchá ifka, kterou máš v metodě GameLogic.Ran­domSeed(int) by se dala napsat třeba i takhle:
int rand = rd.nextInt(randOccur);
if (rand < 1) {
        gameBoard1[j] = alive;
} else {
        gameBoard1[j] = dead;
}
//je to samé, jako
int rand = rd.nextInt(randOccur) < 1 ? gameBoard1[j] = alive : gameBoard1[j] = dead;

je to podmínka na jeden řádek, která dělá to samé, ale.... přece jen jeden řádek je lepší než 5 se závorkama:) takže tohle je spíš info, že se to dá zapsat i jinak

  • + zase chválím. Na začátečníka jak říkáš používáš for-each, což je supr;)
  • ta metoda aliveNextTurn(int, char) je vcelku dost zmatkovitě napsaná. Myslím, že by to šlo napsat do jedné ifky a podmínku přetížit. Navíc koukám (kdyžtak mě oprav), že proměnná cell nabývá pouze dvou hodnot (alive a dead). Nebylo by jednodušší použít boolean a ty dva znaky X a _ nastavovat přímo tady v té podmínce? Boolean přece jen pracuje rychleji než char (v řádu milisekund) a zjednodušili by se ti rovnou dvě podmínky - v metodě aliveNextTurn(int, char) a v metodě randomSeed(int)
  • předpokládám, že random nenastavuješ nikde jinde, než v konstruktoru. Obvykle v celém projektu většinou budeš používat jen jednu proměnnou třídy random (na co taky dělat více, když budou vždycky dělat to samé). Tak ji odstraň z konstruktoru, inicializuj ji přímo v deklaraci a nastav jako třídní konstantu (final static).
  • v metodě newGeneration(char[][]) používáš lokální proměnné s upperCase. Troška konvence:
    1. u deklarace lokálních proměnných se používá modifikátor final. Je to takové zabezpečení a máš jistotu, že tu proměnnou nikde nepřepíšeš, kde bys neměl. Pochopitelně pokud s přepsáním počítáš, tak ji tak nedaklaruj:)
    2. upperCase se používá pouze při třídních konstantách s podtržítkovou syntaxí. Nikde jinde se nevyužívá.

Co dále?
trošku bych Tě nasměroval, čím by ses mohl zabývat a jak rozšířit program a případně jak myslet:)

  • celá aplikace ti jede v jednom vlákně. Zkus si s tím pohrát a třeba se zaměř na funkci, aby jsi mohl dělat při běhu pauzu. (pochopitelně jestli jsi nedělal s vlákny, tak začít nejdřív tím:) )
  • Pochopitelně převést celou aplikaci do desktopového programu
  • Aplikuj přetěžování (minimálně v tom konstruktoru - přetěžování je jedna z nejpoužívanějších praktik OOP v praxi)
  • Zabal celý projekt do balíku (extra easy, co ti může trvat max. 10 sekund:) )
  • Rozepiš se v proměnných
  • Komentáře ponechej jak jsou, ale připisuj k nim úpravy;) Klidně vždycky na další řádek pod to vypisuj, co jsi změnil případně proč, ale fakt Tě moc chválím za ty komenty. Šikula - nemusel jsem vůbec bádat nad tím, proč tam ta či ona metoda je. To je fakt perfektní úspěch a buď na to pyšný.

A pochopitelně rozšiřovat se dál a dál. Jestli jsi student - věnuj se tomu, jestli jsi dělňas, chvilku to vydrž v práci, věnuj se tomu a pak hledej práci v IT, protože ten potenciál máš slušný, snahu očividně taky (což je to nejdůležitější) a rozhodně se za ten kód nemusíš stydět. Rozhodně to není nic, co by sesmolil absolutní začátečník. Jen tak dál;)

Editováno 15.8.2017 15:30
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
15.8.2017 15:28
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:15.8.2017 15:42

Jo a ještě jsem chtěl jednu věc, kterou bys mohl praktikovat.
Vždycky, když vytvoříš nějakou třídu, tak ji vyjmi z projektu, založ nový projekt (třeba v netbeanech s zázvem JavaApplicationXY) klidně do samého nebo do defaultního balíku a zkus, že ti tam ta třída bude fungovat. Je to taková kontrola a jistota, že programuješ objektově.
V OOP totiž nemůžeš přemýšlet jen tak, že například podlaha drží židli, ale že židle stojí na podlaze.
Takže když bys třeba právě tyto dvě třídy programoval, tak bys otestoval, že na podlaze bude držet i obdelník, trojúhelník, vlak, barák, maminka prostě všechno a nic jí tim nepropadne.
Současně tak si ověříš, že židle bude stát na stole, druhé židli, na jablku, na slonovi prostě že se nikdy nebude vznášet nebo nebude propadat texturou.
To byl velmi jednoduchý příklad, ale smyslem toho je, že ať už naprogramuješ cokoliv, neměl bys to moc specifikovat a vázat na jednu třídu. Pomocné třídy je lepší dělat soukromými;) Když třída ke svému chodu vyžaduje nějakou jinou třídu, tak tě to právě upozorní na to, že je čas zamyslet se, jestli neimplementovat nějaké rozhraní nebo jestli vážně nikdo jiný než ta jedna třídu tu druhou využívat nebude.
To jen taková finta, jak nabýt jistotu, že programuješ objektově.

Nahoru Odpovědět
15.8.2017 15:42
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Odpovídá na Lubor Pešek
Štefan Melich:16.8.2017 10:23

Ide to aj jednoduchšie. Program môže mať metódu main v každej svojej triede a iba ty rozhoduješ, ktorý main sa pri spustení bude volať. Lokálne spustenie mainu je v Netbeanse cez skratku Shift+F6. Je to rýchlejšie, ako vytvárať vždy nový projekt. Ale myšlienka je dobrá testovať sa dá aj takto zjednodušene.

 
Nahoru Odpovědět
16.8.2017 10:23
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:16.8.2017 10:26

Jo, ale main metoda ti nezaručí, že je třída objektová. Stejně pořád pracuješ ve stejném projektu a neupozorní tě to na nebezpečné vázání na jiné třídy. Navíc sám neuznávám více main metod v celém projektu. Ano, když máš 5 tříd, tak se v tom zorientuješ, ale hlavně v práci se s tak extrémně malým projektem nikdy nesetkáš. Pokud nemáš v sources aspoň 30 class, tak děláš pořád soukromý projekt:) (a to nepočítám testovací classy). A v každé z nich dělat main metody? by ses z toho zbláznil

Nahoru Odpovědět
16.8.2017 10:26
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Štefan Melich:16.8.2017 10:37

Tú závislosť si vieš odsledovať a myslím si, že vždy sa to aj tak nedá. Ak to dokážeš v každom prípade tak ťa uznávam, ako skutočného odborníka. Niekedy viac mainov práve že uľahčuje orientáciu vo veľkom projekte, ale to je vec názoru (pre mňa to tak platí) a každý vytvorený main si vieš po odtestovaní odstrániť, ak je ďalej v projekte zbytočný. Mne osobne to príde logickejšie a jednoduchšie riešenie a podal som to len ako alternatívu.

Editováno 16.8.2017 10:38
 
Nahoru Odpovědět
16.8.2017 10:37
Avatar
Dave Petlák
Člen
Avatar
Dave Petlák:17.8.2017 10:43

Tak jsem se v tom trošku povrtal a aplikoval některé Luborovy rady. Rozhodně to vypadá líp a kód je o něco kratší ale problém je v tom, že tato verze běží o něco pomaleji než původní (pro plochu 1000x1000 při 10generacích: stará verze 66sec a nová 77sec). Otázka tedy zní: kde mám hledat problém? Zatím největší podezřelý je podle mě metoda drawGame() kde podle hodnoty prvků pole které jsou boolean vypisuje patřičný symbol.

package gameoflife;

import java.util.Random;

/**
 *
 * @author David Petlák
 */
public class GameLogic {
    final static Random RANDOM_NUMBER_GENERATOR = new Random();
    private final char alive = 'X';
    private final char dead = '.' ;
    private final int width;
    private final int height;
    private final int randOccur;
    private final int numberOfGenerations;
    private boolean[][] gameBoard;

    public GameLogic(int randOccur, int width, int height, int numberOfGenerations){

       this.randOccur = randOccur;
       this.width = width;
       this.height = height;
       this.numberOfGenerations = numberOfGenerations;

    }

    /** Vytvoří a odehraje novou hru podle pravidel definovaných v konstruktoru
     *
     */
    public void newGame(){
        /*char[][]*/ gameBoard = randomSeed(randOccur, width, height);

        drawGame(gameBoard);

        for(int generation = 0; generation < numberOfGenerations; generation++){
            System.out.println();
            System.out.println(String.format("%d generace. ", generation+1));
            gameBoard = newGeneration(gameBoard);
            drawGame(gameBoard);

            try{
                Thread.sleep(200);
            }
            catch(InterruptedException e){
                System.out.println("Proces byl probuzen předčasně");
            }
        }
    }

    /** Vytvoří novou herní plochu a náhodně umístí živé buňky.
     *
     * @param randOccur poměr četnosti 1:randOccur
     * @param width šířka herní plochy
     * @param height výška herní plochy
     * @return  boolean[][] s herní plocou a generací 0
     */
    private boolean[][] randomSeed(int randOccur, int width, int height){
        gameBoard = new boolean[height][width];
        for (boolean[] gameBoard1 : gameBoard) {
            for (int j = 0; j < gameBoard[0].length; j++) {
                int randomNumber = RANDOM_NUMBER_GENERATOR.nextInt(randOccur);
                gameBoard1[j] = randomNumber < 1;
            }
        }
        return gameBoard;
    }
    /** Vykreslí herní plochu do konzole
     *
     * @param gameBoard 2D pole k vykreslení
     */
    private void drawGame(boolean[][] gameBoard){

        for (boolean[] gameBoard1 : gameBoard) {
            for (int j = 0; j < gameBoard[0].length; j++) {
                char symbolToPrint = gameBoard1[j] ? alive : dead;
                System.out.print(symbolToPrint + "  ");
            }
            System.out.println();
        }
    }
    /** Vytvoří pole pro novou generaci.
     *
     * @param previousGen výchozí generace
     * @return 2D pole s příští generací
     */
    private boolean[][] newGeneration(boolean[][] previousGen){

        int newGenHeight = previousGen.length;
        int newGenWidth = previousGen[0].length;

        boolean[][] newGen = new boolean[newGenHeight][newGenWidth];
        for(int i = 0; i < newGenHeight; i++){
            for(int j = 0; j < newGenWidth; j++){
                int aliveAround = checkSurroundings(previousGen, i, j);

                newGen[i][j] = aliveNextTurn(aliveAround, previousGen[i][j]);
            }
        }
        return newGen;
    }
    /** Projde postupně okolí jedné buňky kolem právě posuzované a sečte
     *  všechny živé buňky v tomto okolí
     * @param previousGen Matice současné generace
     * @param r Souřadnice prověřované buňky
     * @param c -"-
     * @return Počet živých buňěk v okolí
     */
    private int checkSurroundings(boolean[][] currentGeneration, int row, int column){
        int noOfCellsAlive = 0;
        for(int k = row-1; k <= row+1; k++){
            for(int l = column-1; l <= column+1; l++){
                if(((k < 0) || (l < 0)) || ((k >= currentGeneration.length) || (l >= currentGeneration[0].length)) || ((k == row)&&(l == column))){
                    continue; //pokud je prověřovaná souřadnice mimo pole nebo stejná jako prověřovaná buňka tak pokračuje na další souřadnici
                }
                if(currentGeneration[k][l]){
                    noOfCellsAlive++; //pokud je buňka na souřadnicích naživu inkrementuje proměnnou
                }
            }
        }
        return noOfCellsAlive;
    }
    /** Posoudí, zda je buňka v příští generaci naživu.
     * Pokud je živá a má 2 nebo 3 živé sousedy žije.
     * Pokud je mrtvá a má 3 živé sousedy obživne
     * @param aliveAround počet živých buněk v okolí
     * @param cell        posuzovaná buňka
     * @return
     */
    private boolean aliveNextTurn(int aliveAround, boolean currentGenCell){
       if(currentGenCell){
             return !((aliveAround < 2) || (aliveAround > 3));
       }else{
             return aliveAround == 3;
       }
    }
}

a kód třídy s main()

package gameoflife;

/**
 *
 * @author David Petlák
 */
public class GameOfLife {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int randOccur = 2;
        int width = 1000;
        int height = 1000;
        int numberOfGenerations = 10;

        GameLogic gl = new GameLogic(randOccur, width, height, numberOfGenerations);
        gl.newGame();

    }
}
Editováno 17.8.2017 10:44
 
Nahoru Odpovědět
17.8.2017 10:43
Avatar
Matěj Kripner
Tvůrce
Avatar
Odpovídá na Dave Petlák
Matěj Kripner:21.8.2017 14:54

Zběžně jsem ten kód prošel a mám pár připomínek.
K návrhu:

  • Smyčka by určitě neměla být v konstruktoru. Konstruktor slouží k připravení objektu pro použití.
  • drawGame a newGeneration by neměly přijímat parametr gameBoard (měly by využívat atribut) a neměly by nic vracet (jen upravovat atribut gameBoard). V konstruktoru měla být logika stávající metody randomSeed, takže po vytvoření by každá hra už byla náhodně inicializovaná. Samotnou smyčku bych umístil do metody main.
  • Buď konzistentní v tom co je a není konstanta. Konstanty (static final) jsou stejné pro všechny instance. To se hodí i pro alive a dead, což jsou nyní atributy (i když neměnné) a všechny 'magická' čísla, která se ti v programu objevují (200 = STEP_DELAY, 2 = MIN_ALIVE_AROUND, 3 = MAX_ALIVE_AROUND, 3 = AROUND_TO_BORN)

Drobnosti:

  • Nech si kód čas od času zformátovat od IDE (bude na to zkratka). Pak se koukni jak má být formátovaná dokumentace, závorky, atd.
  • Používej popisnější názvy. Např. row místo gameBoard1 v metodě randomSeed.
  • Vypisuješ přes 10 * 1000 * 1000 * 3 = 30 000 000 znaků, což bude pomalé vždycky. Teď vypisuješ dvě mezery místo jedné, to by mohlo způsobit zpomalení. Optimalizace ostatních věcí je trošku těžší.

Komentář k radám od Lubor Pešek (nekompletní):

  • numberForCountin­gTotalValueOf­MembersInABank je špatný název. membersTotalValue je lepší.

Boolean přece jen pracuje rychleji než char (v řádu milisekund)

Ne

  • Vlákny se zatím nemusíš zabývat.
 
Nahoru Odpovědět
21.8.2017 14:54
Avatar
Dave Petlák
Člen
Avatar
Dave Petlák:21.8.2017 16:43

To zní poměrně rozumně, ale pár věcí nechápu.

  • Ať hledám sebevíc tak v konstruktoru žádnou smyčku nemůžu najít. (Nebo se mé pochopení toho co to je konstruktor zásadně odchyluje od reality, podle mě je konstruktor níže uvedený úsek kódu)
public GameLogic(int randOccur, int width, int height, int numberOfGenerations){

       this.randOccur = randOccur;
       this.width = width;
       this.height = height;
       this.numberOfGenerations = numberOfGenerations;

    }
  • Toto celkem smysl dává, matici současné generace nemusím předávat jako paramer Díky za tip.
  • Takže v praxi platí, že jakákoliv konstanta je lepší zapsaná jako static proměnná? I pokud je jako zde využívaná pouze jednou jednoúčelovou metodou?
  • Samotné vypisování jsem o něco málo zrychlil tím, že místo
System.out.print(symbolToPrint + "  ");

používám

System.out.print(symbolToPrint);
System.out.print(" ");

Vycházím z informace, že první varianta před samotným vypsáním defacto nejdříve tyto 2 znaky sloučila do jednoho stringu a až poté vypsala což je (evidentně) o něco málo pomalejší, než vypsání stejných 2 znaků zvlášť.

  • numberForCountin­g...... Myslím si, že šlo jen o do extrému vyhnaný příklad :)
  • Možná že ne, ale po převedení na boolean je ten kód čitelnější a zároveň kratší
  • Vlákna momentálně neřeším příliš do hloubky, (asi bych se z toho zbláznil) ale chci aspoň rámcově vědět jak se s nimi pracuje.
 
Nahoru Odpovědět
21.8.2017 16:43
Avatar
Matěj Kripner
Tvůrce
Avatar
Odpovídá na Dave Petlák
Matěj Kripner:21.8.2017 18:02

Promiň, s tím konstruktorem jsem se přehlídl. Ohledně konstant to záleží. Určitě bys je měl vytvořit pokud je používáš na více místech. Jinak to můžeš udělat taky, nic tím nezkazíš a bude snazší kód pochopit. Třeba u těch 200 ms číslo asi nevadí, protože každý ví co dělá Thread.sleep a jaké přebírá argumenty. Naopak v metodě aliveNextTurn by konstanta ulehčila pochopit co ty podmínky dělají.

Editováno 21.8.2017 18:03
 
Nahoru Odpovědět
21.8.2017 18:02
Avatar
Neználek
Člen
Avatar
Odpovídá na Dave Petlák
Neználek:22.8.2017 22:19

Také bych tipoval, že nejpomalejší bude výpis.
Mohlo by pomoci vypisovat řádek do pomocného bufferu (StringBuilder) a ten pak vypsat najednou na standardní výstup.

Příklad:

private void drawGame(boolean[][] gameBoard) {
    StringBuilder row = new StringBuilder();
    for (boolean[] gameBoard1 : gameBoard) {
        row.setLength(0);
        for (int j = 0; j < gameBoard[0].length; j++) {
            char symbolToPrint = gameBoard1[j] ? alive : dead;
            row.append(symbolToPrint);
            row.append(' ');
        }
        row.append(System.lineSeparator());
        System.out.print(row.toString());
    }
}

Jedná se ale o optimalizaci. Výsledný kód je hůře čitelný.

Doporučoval bych se spíše zaměřit na čitelnost programu.

 
Nahoru Odpovědět
22.8.2017 22:19
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.