Disegna una scacchiera in Java

1

Sto leggendo un libro di programmazione e sto avendo problemi a capire alcune parti di questo codice. Il programma disegna una scacchiera e colora i quadrati dispari in nero.

import acm.graphics.*;
import acm.program.*;

public class CheckerBoard extends GraphicsProgram   {

public void run()   {
    double squareSize = (double) getHeight() / numRows;
    for(int i = 0; i <= numRows; i++){
        for(int j = 0; j <= numColumns; j++)    {
            double x = j * squareSize;
            double y = i * squareSize;
            GRect square = new GRect(x,y,squareSize,squareSize);
            square.setFilled((i + j) % 2 != 0);
            add(square);
        }
    }
}

private static final int numRows = 8;
private static final int numColumns = 8;

Capisco la maggior parte del codice, ma sono ancora un po 'confuso.

La mia prima domanda è: in che modo esattamente il programma passa attraverso i cicli for? Sono nidificati, quindi creerebbe prima tutte le colonne (il ciclo j for)? Oppure incrementa sia i che j dopo che il blocco di codice è finito?

In secondo luogo, perché imposto x = j e y = i? x è orizzontale e j è verticale, non dovrei impostare x = i ey = j? Entrambi sembrano dare gli stessi risultati.

Per lo più, vorrei solo sapere come viene eseguito il ciclo for ogni volta. una corsa di base o due attraverso il programma.

Qualsiasi aiuto sarebbe apprezzato, grazie!

    
posta user2400376 19.06.2013 - 02:58
fonte

4 risposte

3

My first question is: How exactly does the program go through the for loops? They are nested, so would it create all of the columns (the j for loop) first? Or does it increment both i and j after the block of code finishes?

Neanche, davvero. I cicli annidati in questo modo non aumentano allo stesso tempo: il ciclo interno verrà eseguito fino a quando j viola la condizione ( j > numColumns ), quindi il ciclo i (il ciclo esterno) aumenterà e l'intero ciclo interno verrà eseguito ancora. Inoltre, come ha detto @ JayElston, viene disegnato solo un quadrato alla volta. Ciò significa che su ogni corsa attraverso il ciclo interno il programma disegna una riga di quadrati, uno in ogni colonna. Il ciclo esterno disegna ripetutamente queste righe per creare l'intera scacchiera. Quindi l'idea è che il ciclo interno non disegna colonne intere, ma piuttosto la parte di ogni colonna nella riga su cui si sta lavorando.

Secondly, why do I set x = j, and y = i? x is horizontal and j is vertical, shouldn't I set x = i and y = j? Both seem to yield the same results.

Per quanto riguarda x=j e y=i , ciò che hai scritto non è abbastanza accurato. x è in realtà impostato su j volte la larghezza di un quadrato e y è impostato su i volte la larghezza di un quadrato. Quindi, se siamo sulla quarta colonna, siamo quattro quadrati orizzontalmente dal punto iniziale, e quindi quattro volte la larghezza di un quadrato nella direzione x dal bordo. Il fatto che entrambi producano gli stessi risultati è una coincidenza; succede solo perché la scacchiera è quadrata. Cambia numRows in 15 ed esegui il programma, poi flip-flop ed eseguilo di nuovo e dovresti vedere la differenza. La prima volta, il numero di righe sarà 15 (o 16 se hai scritto il programma con <= nei cicli for), come previsto dal nome della variabile. Ma quando x=i*squareSize , il numero di colonne sarà 15. Nota che x e y sono posizioni in cui disegnare i quadrati, non i numeri delle righe e delle colonne. Questo potrebbe renderlo più sensato.

Mostly, I would just like to know how the for loop runs each time around. a basic run or two through the program.

Qualcosa che potrebbe aiutare sarebbe includere la riga System.out.println("i:"+i+"; j:"+j+"; x:"+x+"; x:"+y); nel ciclo interno subito dopo GRect square .... (come ho dimostrato nel mio codice qui sotto) In Java, System.out.println mostrerà le cose su la console. Mettendo in questa linea, il programma sputa una riga ogni volta che disegna un quadrato, dando i valori di i , j , x e y .

Infine, ecco una versione estesa del programma con molti commenti. Ti dice anche dei suoi progressi, che speriamo ti aiutino a vedere cosa sta succedendo. Nota che normalmente non utilizzerei i commenti multilinea ( /*...*/ ) ovunque vicino a questo molto.

import acm.graphics.GLabel;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;

public class CheckerBoard extends GraphicsProgram {

  public void run() {
    double squareSize = (double) getHeight() / numRows;

    /*
     * Make a variable to carry the number of the square
     * that's being made. So, the first square will be
     * number 0, the second will be number 1, etc.
     */
    int num = 0;

    /*
     * Run the contents once for each number between 0 and
     * numRows Note the < and not <=. Because we're starting
     * from 0, we need to use <. For example, suppose we
     * wrote int i=0; i<=1; i++. We would get our loop run
     * once with i=0 and once with i=1 before i would not be
     * <= 1. Since our numbers in this case are supposed to
     * be the number of rows, we don't want to loop after we
     * do the one before our numRows or numColumns
     */
    for (int i = 0; i < numRows; i++) {
      /*
       * Run the contents of this loop once for each number
       * between 0 and numColumns, including 0, not
       * including numColumns.
       */
      for (int j = 0; j < numColumns; j++) {
        /*
         * Calculate the position for the next square. If
         * we're in column 4, then the next square should be
         * at 4*(the width of each square).
         */
        double x = j * squareSize;
        double y = i * squareSize;

        /*
         * Create a square that's to be put at our x and y
         * positions calculated just above. Make its width
         * squareSize and its height squareSize.
         */
        GRect square = new GRect(x, y, squareSize, squareSize);

        /*
         * Make some text that will be put down. Use the
         * current value of num for its text
         * (Integer.toString just makes that integer into
         * text), and put it at the x-position we're working
         * with plus 1/4 of a squareSize and the y-position
         * we're working with plus 3/4 of a square. This
         * fakes centering the text in the squares.
         */
        GLabel label = new GLabel(Integer.toString(num), x + squareSize * .25,
            y + squareSize * .75);

        /*
         * Tell the user what our i, j, x, y, and num values
         * are.
         */
        System.out.println("i:" + i + "; j:" + j + "; X:" + x + "; Y:" + y
            + "; num: " + num);

        square.setFilled((i + j) % 2 != 0);
        add(square);

        /*
         * Stick that label on the page, just like with the
         * square.
         */
        add(label);

        /*
         * Increment the number variable (add one to it) so
         * the next square is num+1 (if this is square 0,
         * then the next one should be square 1)
         */
        num++;
      }
    }
  }

  // Change this to make the checkerboard non-square.
  private static final int numRows = 8;
  private static final int numColumns = 8;
}

Ed ecco cosa ottengo sulla mia console quando la eseguo:

i:0; j:0; X:0.0; Y:0.0; num: 0
i:0; j:1; X:25.0; Y:0.0; num: 1
i:0; j:2; X:50.0; Y:0.0; num: 2
i:0; j:3; X:75.0; Y:0.0; num: 3
i:0; j:4; X:100.0; Y:0.0; num: 4
i:0; j:5; X:125.0; Y:0.0; num: 5
i:0; j:6; X:150.0; Y:0.0; num: 6
i:0; j:7; X:175.0; Y:0.0; num: 7
i:1; j:0; X:0.0; Y:25.0; num: 8
i:1; j:1; X:25.0; Y:25.0; num: 9
i:1; j:2; X:50.0; Y:25.0; num: 10
i:1; j:3; X:75.0; Y:25.0; num: 11
i:1; j:4; X:100.0; Y:25.0; num: 12
i:1; j:5; X:125.0; Y:25.0; num: 13
i:1; j:6; X:150.0; Y:25.0; num: 14
i:1; j:7; X:175.0; Y:25.0; num: 15
i:2; j:0; X:0.0; Y:50.0; num: 16
i:2; j:1; X:25.0; Y:50.0; num: 17
i:2; j:2; X:50.0; Y:50.0; num: 18
i:2; j:3; X:75.0; Y:50.0; num: 19
i:2; j:4; X:100.0; Y:50.0; num: 20
i:2; j:5; X:125.0; Y:50.0; num: 21
i:2; j:6; X:150.0; Y:50.0; num: 22
i:2; j:7; X:175.0; Y:50.0; num: 23
i:3; j:0; X:0.0; Y:75.0; num: 24
i:3; j:1; X:25.0; Y:75.0; num: 25
i:3; j:2; X:50.0; Y:75.0; num: 26
i:3; j:3; X:75.0; Y:75.0; num: 27
i:3; j:4; X:100.0; Y:75.0; num: 28
i:3; j:5; X:125.0; Y:75.0; num: 29
i:3; j:6; X:150.0; Y:75.0; num: 30
i:3; j:7; X:175.0; Y:75.0; num: 31
i:4; j:0; X:0.0; Y:100.0; num: 32
i:4; j:1; X:25.0; Y:100.0; num: 33
i:4; j:2; X:50.0; Y:100.0; num: 34
i:4; j:3; X:75.0; Y:100.0; num: 35
i:4; j:4; X:100.0; Y:100.0; num: 36
i:4; j:5; X:125.0; Y:100.0; num: 37
i:4; j:6; X:150.0; Y:100.0; num: 38
i:4; j:7; X:175.0; Y:100.0; num: 39
i:5; j:0; X:0.0; Y:125.0; num: 40
i:5; j:1; X:25.0; Y:125.0; num: 41
i:5; j:2; X:50.0; Y:125.0; num: 42
i:5; j:3; X:75.0; Y:125.0; num: 43
i:5; j:4; X:100.0; Y:125.0; num: 44
i:5; j:5; X:125.0; Y:125.0; num: 45
i:5; j:6; X:150.0; Y:125.0; num: 46
i:5; j:7; X:175.0; Y:125.0; num: 47
i:6; j:0; X:0.0; Y:150.0; num: 48
i:6; j:1; X:25.0; Y:150.0; num: 49
i:6; j:2; X:50.0; Y:150.0; num: 50
i:6; j:3; X:75.0; Y:150.0; num: 51
i:6; j:4; X:100.0; Y:150.0; num: 52
i:6; j:5; X:125.0; Y:150.0; num: 53
i:6; j:6; X:150.0; Y:150.0; num: 54
i:6; j:7; X:175.0; Y:150.0; num: 55
i:7; j:0; X:0.0; Y:175.0; num: 56
i:7; j:1; X:25.0; Y:175.0; num: 57
i:7; j:2; X:50.0; Y:175.0; num: 58
i:7; j:3; X:75.0; Y:175.0; num: 59
i:7; j:4; X:100.0; Y:175.0; num: 60
i:7; j:5; X:125.0; Y:175.0; num: 61
i:7; j:6; X:150.0; Y:175.0; num: 62
i:7; j:7; X:175.0; Y:175.0; num: 63
    
risposta data 19.06.2013 - 05:01
fonte
1

Il doppio ciclo è essenzialmente lo stesso di questo codice:

int i = 0;

while (i <= numRows) {
    int j = 0;

    while (j <= numColumns) {
        double x = j * squareSize;
        double y = i * squareSize;
        GRect square = new GRect(x,y,squareSize,squareSize);
        square.setFilled((i + j) % 2 != 0);
        add(square);

        j++;
    }

    i++;
}

C'è una piccola differenza: alla fine del ciclo while esterno, i avrà il valore numRows + 1 . Se utilizzi il ciclo for, la variabile i sarà fuori ambito.

    
risposta data 19.06.2013 - 03:36
fonte
1

Ogni volta attraverso il loop interno, viene disegnato un singolo quadrato (aggiungendolo alla tavola). Le seguenti tre righe di codice tracciano il quadrato:

GRect square = new GRect(x,y,squareSize,squareSize);
square.setFilled((i + j) % 2 != 0);
add(square);

(x, y) nella prima riga specifica la coordinata in alto a sinistra del quadrato da disegnare.

La seconda riga determina il colore quadrato. Mentre i cicli interno ed esterno si ripetono, il valore di i + j si alterna tra pari e dispari.

I quadrati vengono aggiunti in ordine di colonna. Dopo un ciclo completo del ciclo interno, verrà aggiunta una nuova riga di otto quadrati.

Il ciclo esterno esegue l'iterazione una volta per ogni riga, passando per il ciclo interno per aggiungere la riga.

    
risposta data 19.06.2013 - 03:37
fonte
-1

Un ciclo for è forse la forma di iterazione più comunemente utilizzata. Questo ciclo esegue l'inizializzazione prima della prima iterazione. Quindi esegue test condizionali e, alla fine di ogni iterazione, una forma di "stepping".

    
risposta data 19.06.2013 - 12:16
fonte

Leggi altre domande sui tag