my 2D game, Sokoban, is working, but I want to know if I improve the design
<p>I've made a Sokoban with two classes, logic and SokobanGUI.</p>

<p>Basically, the logicpart builds an ArrayList> from an input String Array, f.ex:</p>

<pre><code>String[] level1 = 
              {"*###########*",
               "#           #",
               "#  ... ...  #",
               "#  *$$ $.$  #",
               "# $*+$ $*$$ #",
               "#  *$$ $.$  #",
               "#  ...  .   #",
               "#           #",
               "*###########*"};
</code></pre>

<p>where '+' is the player position.</p>

<p>Anyway, the ArrayList is updated in the logic class as the game is played (player is moving, characters are interacting etc.)</p>

<p>The graphics part of the game is solved by assigning pictures to each character and looping through the arraylist>. Then this is updated inn an infinite while-loop such that when the arraylist> is updated in the logic part, it is printed again.</p>

<p>If this was difficult to follow, I've printed the code below.</p>

<p><strong>Question1:</strong> I don't think this is the best way to output the game (with a while-lopp) as I am graphically outputting the game all the time, even when no changes have been made. How is this usually dealt with? Is Swing something that can help med with this?</p>

<p><strong>Question2:</strong> Also, in the code below, I don't use the main method, I use the run(). The main method didn't like me making non-statical references, and run worked so I went with it... How am I supposed to use the main method to make the game work?</p>

<p>Maybe it is easier to see my code:</p>

<p><strong>Logic class</strong></p>

<pre><code>package Sokoban2;

import java.util.ArrayList;

public class Logic {


int player_x;
int player_y;
int nextMove_x;
int nextMove_y;
ArrayList&lt;ArrayList&lt;Boolean&gt;&gt; targets;
ArrayList&lt;ArrayList&lt;Character&gt;&gt; grid;
Boolean canMove;


public Logic(){
    buildGrid();
    buildTargets();
    findPlayer();
}

    public void move(int dx, int dy){
    if(CheckCanMove(dx, dy)){
    moveBox(dx, dy);
    movePlayer(dx, dy);
    } 


}


public void movePlayer(int dx, int dy){

    boolean boxAhead = (getChar(dx,dy) == '#');

    if(!boxAhead){

    char pChar = grid.get(player_x ).get(player_y);
    char pCharNext = grid.get(player_x +dx).get(player_y +dy);

    if(pChar == '@'){
        if(pCharNext == ' ' || pCharNext == '$'){
            grid.get(player_x + dx).set(player_y + dy, '@');
            grid.get(player_x).set(player_y, ' ');
        }
        if(pCharNext == '.' || pCharNext == '*'){
            grid.get(player_x + dx).set(player_y + dy, '+');
            if(pChar == '+'){
                grid.get(player_x).set(player_y, '.');
            }
            else{
                grid.get(player_x).set(player_y, ' ');
            }
        }
    }

    else if(pChar == '+'){
        if(pCharNext == ' ' || pCharNext == '$'){
            grid.get(player_x + dx).set(player_y + dy, '@');
            grid.get(player_x).set(player_y, '.');
        }
        if(pCharNext == '.' || pCharNext == '*'){
            grid.get(player_x + dx).set(player_y + dy, '+');
            grid.get(player_x).set(player_y, '.');


        }
    }




    player_x += dx;
    player_y += dy;

    }



}


public void buildGrid(){
    char c = '"';


    grid = new ArrayList&lt;ArrayList&lt;Character&gt;&gt;();

    String[] level1 = 
              {"*###########*",
               "#           #",
               "#  ... ...  #",
               "#  *$$ $.$  #",
               "# $*+$ $*$$ #",
               "#  *$$ $.$  #",
               "#  ...  .   #",
               "#           #",
               "*###########*"};



    int length_i = level1.length;
    System.out.println(length_i);
    int length_i_j = level1[length_i-1].length();



    for(int i = 0; length_i&gt;i; i++){
        grid.add(i, new ArrayList&lt;Character&gt;());
        for(int j = 0; length_i_j&gt;j; j++){
            c = level1[i].charAt(j);                
            grid.get(i).add(c);
        }
    }


}


public void buildTargets(){


    targets = new ArrayList&lt;ArrayList&lt;Boolean&gt;&gt;();

    char c = ' ';
    int length_i = grid.size();

    for(int i = 0; length_i&gt;i; i++){
        targets.add(i, new ArrayList&lt;Boolean&gt;());
        for(int j = 0; grid.get(i).size()&gt;j; j++){
            c = grid.get(i).get(j);
            if(c == '.'){
                targets.get(i).add(false);
            }
            else{
                targets.get(i).add(true);
            }

        }
    }

}

public void findPlayer(){
    char c = ' ';
    int length_i = grid.size();

    for(int i = 0; length_i&gt;i; i++){
        for(int j = 0; grid.get(i).size()&gt;j; j++){
            c = grid.get(i).get(j);
            if(c == '@' || c == '+'){
                player_x = i;
                player_y = j;
            }
        }
    }


}

public Character getChar(int dx, int dy){

    char c = ' ';
    c = grid.get(player_x + dx).get(player_y + dy);
    return c;

}



public void moveBox(int dx, int dy){
    char c1 = getChar((dx),(dy));
    char c2 = getChar((2*dx),(2*dy));


    if(c1 == '*' || c1 == '$'){
        if(c2 == '.'){
            grid.get(player_x +2*dx).set(player_y +2*dy, '*');
        }
        if(c2 == ' '){
            grid.get(player_x +2*dx).set(player_y +2*dy, '$');
        }
    }




}

public boolean CheckCanMove(int dx, int dy){
    canMove = true;

    boolean boxAhead = (getChar(dx,dy) == '#');
    boolean boxAhead2 = (getChar(2*dx,2*dy) == '#');
    boolean movableAhead = (getChar(dx,dy) == '$');
    boolean movableAhead2 = (getChar(2*dx,2*dy) == '$');
    boolean movableAheadS = (getChar(dx,dy) == '*');
    boolean movableAheadS2 = (getChar(2*dx,2*dy) == '*');


    if(boxAhead || (movableAhead &amp;&amp; boxAhead2) || (movableAhead &amp;&amp;     
               movableAhead2) || (movableAheadS &amp;&amp; movableAheadS2) || (movableAheadS &amp;&amp;  
               boxAhead2)){
        canMove = false;
    }

    return canMove;
}





void setPlayerX(int player_x){
    this.player_x = player_x;
}

void setPlayerY(int player_y){
    this.player_y = player_y;
}

}
</code></pre>

<p><strong>Graphics Class</strong>
    package Sokoban2;</p>

<pre><code>import acm.graphics.GImage;
import java.awt.event.KeyEvent;

import acm.graphics.GImage;
import acm.program.GraphicsProgram;

public class SokobanGUI extends GraphicsProgram {


Logic logic = new Logic();  
GImage wall;
GImage blank;


    @Override
public void init() {
    logic = new Logic();
    addKeyListeners(); // This is required for listening to key events

}


@Override
public void run() {
    System.out.println(logic.player_x);
    System.out.println(logic.player_y);
    while(true){
        paint();
        println("hah");
    }
//      System.out.println("win");
}


public void paint(){
    char c =' ';
    int length_i = logic.grid.size();

    for(int i = 0; length_i&gt;i; i++){
        for(int j = 0; logic.grid.get(i).size()&gt;j; j++){
            c = logic.grid.get(i).get(j);
            switch (c) { 
            case '#':
                GImage wall = new GImage("sokoban/wall16x16.png");
                wall.setLocation(16*j,16*i);
                add(wall);         
                break;
            case ' ':
                GImage blank = new GImage("sokoban/blank16x16.png");
                blank.setLocation(16*j,16*i);
                add(blank);         
                break;
            case '@': 
                GImage player = new GImage("sokoban/mover16x16.png");
                player.setLocation(16*j,16*i);
                add(player);         
                break;
            case '$': 
                GImage movable = new GImage("sokoban/movable16x16.png");
                movable.setLocation(16*j,16*i);
                add(movable);         
                break;
            case '.': 
                GImage target = new GImage("sokoban/target16x16.png");
                target.setLocation(16*j,16*i);
                add(target);         
                break;
            case '*': 
                GImage movable_on_target = new    
GImage("sokoban/movable_on_target16x16.png");
                movable_on_target.setLocation(16*j,16*i);
                add(movable_on_target);         
                break;
            case '+': 
                GImage mover_on_target = new 
GImage("sokoban/mover_on_target16x16.png");
                mover_on_target.setLocation(16*j,16*i);
                add(mover_on_target);         
                break;

            }
            }
        }
}

public boolean win(){
    int length_i = logic.targets.size();
    int win = 0;
    for(int i = 0; length_i&gt;i; i++){
        for(int j = 0; logic.targets.get(i).size()&gt;j; j++){
            if(!logic.targets.get(i).get(j)){
                win += 1;
            }
        }
    }
    return (!(win&gt;0));
}

@Override
public void keyPressed(KeyEvent event) {
    int key;
    if (Character.isLetter(event.getKeyChar())) 
        key = event.getKeyChar();
    else 
        key = event.getKeyCode();

    switch (key) { 

    case 'w':
        logic.move(-1, 0);
        break;
    case 's': 
        logic.move(1, 0);
        break;
    case 'a': 
        logic.move(0, -1);
        break;
    case 'd': 
        logic.move(0, 1);
        break;

    }
}

}
</code></pre>
