递归和重新启动应用程序需要不必要的返回

时间:2015-04-20 22:19:37

标签: java css recursion javafx return

我用Java重新创建了2048游戏,它实际上是有效的(我没想到自己实际能够做出某些东西"高级"像这样。)

当游戏中的图块移动时,必须创建新的正方形/图块/编号,因此代码通过随机选择0到15之间的数字来搜索可用的点(图块编号为0到15(实际上它是一个包含4列和4行的多维数组))。在选择一个随机点之后,它会检查那里是否已经是正方形/瓦片/数字,如果是,它会通过返回自身来重新调用此函数。因此,当现场没有被占用时,我现在也必须返回一些东西,所以我只是返回了一个之后我不会使用的数字。我做错了什么?

另外,为了开始新游戏,我现在基本上重置了newGame()中的所有变量;功能。有没有办法重新启动应用程序或类似的东西?无法在网站上找到任何内容。

我也想知道我是否遵守了编程惯例,以及关于我为实践重新创建此方法的方法的一般性评论。 (我知道这会消耗你的大部分时间)。

代码:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Test2048 extends Application{

int score = 0;
Label scoreLabel = new Label("Score: 0");
Label statusLabel = new Label("");
int[][] cell;
Label[][] labels = new Label[4][4];

public static void main(String[] args) {launch(args);}

private void init(Stage primaryStage) {

    primaryStage.setTitle("2048");

    GridPane grid = new GridPane();
    grid.setVgap(-10);
    grid.setHgap(-10);
    grid.setStyle("-fx-background-color: #BBADA0; -fx-background-radius: 30; -fx-max-width: 1;  -fx-border-radius: 16; -fx-border-width: 10; -fx-border-color: #F4F4F4; ");
    addLabels(grid);

    newGame();
    Button newGame = new Button("New Game");
    newGame.setOnAction(e -> {
        score = 0;
        statusLabel.setText("");
        newGame();
    });

    VBox layout = new VBox();
    layout.getChildren().addAll(grid, scoreLabel, statusLabel, newGame);

    Scene firstScene = new Scene(layout, 390, 450);
    firstScene.setOnKeyPressed(e -> {
        String arrow = e.getCode().toString();
        switch(arrow){
            case "RIGHT": move(0, 1, 2, 3, 4, 4, 4, 4); break;
            case "DOWN": move(4, 4, 4, 4, 0, 1, 2, 3); break;
            case "LEFT": move(3, 2, 1, 0, 4, 4, 4, 4); break;
            case "UP": move(4, 4, 4, 4, 3, 2, 1, 0); break;
        }
    });
    primaryStage.setScene(firstScene);

}

@Override
public void start(Stage primaryStage) throws Exception {
    init(primaryStage);
    primaryStage.show();
}

private void addLabels(GridPane grid) {
    for (int x=0;x<4;x++){
        for (int y=0;y<4;y++){
            labels[x][y]=new Label();
            grid.add(labels[x][y], x, y);
        }
    }
}

private void newGame(){
    cell = new int[4][4];
    newCell();
    newCell();
    updateScreen();
}

private void move(int ax, int bx, int cx, int dx, int ay, int by, int cy, int dy) {
    boolean hor = false;
    if (ax == 4){
        hor = true;
    }

    Boolean hasMoved = false;
    for (int i = 0; i <= 3; i++) {
        int hasChanged;
        if(hor){
            ax = bx = cx = dx = i;
        }else{
            ay = by = cy = dy = i;
        }

        hasChanged = 4;
        if (cell[cx][cy] != 0) {
            if (cell[dx][dy] != 0) {
                if (cell[cx][cy] == cell[dx][dy]) {
                    cell[cx][cy] = 0;
                    cell[dx][dy] *= 2;
                    score += cell[dx][dy];
                    hasChanged = 1;
                    hasMoved = true;
                }
            } else {
                cell[dx][dy] = cell[cx][cy];
                cell[cx][cy] = 0;
                hasMoved = true;
            }
        }

        if (cell[bx][by] != 0) {
            if (cell[cx][cy] != 0) {
                if (cell[bx][by] == cell[cx][cy]) {
                    cell[bx][by] = 0;
                    cell[cx][cy] *= 2;
                    score += cell[cx][cy];
                    hasChanged = 0;
                    hasMoved = true;
                }
            } else {
                if (cell[dx][dy] != 0) {
                    if (cell[bx][by] == cell[dx][dy] && hasChanged != 1) {
                        cell[bx][by] = 0;
                        cell[dx][dy] *= 2;
                        score += cell[dx][dy];
                        hasChanged = 1;
                        hasMoved = true;
                    } else {
                        cell[cx][cy] = cell[bx][by];
                        cell[bx][by] = 0;
                        hasMoved = true;
                    }
                } else {
                    cell[dx][dy] = cell[bx][by];
                    cell[bx][by] = 0;
                    hasMoved = true;
                }
            }
        }

        if (cell[ax][ay] != 0) {
            if (cell[bx][by] != 0) {
                if (cell[ax][ay] == cell[bx][by]) {
                    cell[ax][ay] = 0;
                    cell[bx][by] *= 2;
                    score += cell[bx][by];
                    hasMoved = true;
                }
            } else {
                if (cell[cx][cy] != 0) {
                    if (cell[ax][ay] == cell[cx][cy] && hasChanged != 0) {
                        cell[ax][ay] = 0;
                        cell[cx][cy] *= 2;
                        score += cell[cx][cy];
                        hasMoved = true;
                    } else {
                        cell[bx][by] = cell[ax][ay];
                        cell[ax][ay] = 0;
                        hasMoved = true;
                    }
                } else {
                    if (cell[dx][dy] != 0) {
                        if (cell[ax][ay] == cell[dx][dy] && hasChanged != 1) {
                            cell[ax][ay] = 0;
                            cell[dx][dy] *= 2;
                            score += cell[dx][dy];
                            hasMoved = true;
                        } else {
                            cell[cx][cy] = cell[ax][ay];
                            cell[ax][ay] = 0;
                            hasMoved = true;
                        }
                    } else {
                        cell[dx][dy] = cell[ax][ay];
                        cell[ax][ay] = 0;
                        hasMoved = true;
                    }
                }
            }
        }
    }

    if(hasMoved) newCell();

    checkStatus();
    updateScreen();
}

private void checkStatus(){

    long noSpace = 1;
    boolean won = false;

    for(int x=0;x<4;x++){
        for(int y=0;y<4;y++){
            noSpace *= cell[x][y];
            if(cell[x][y] == 2048) won = true;
        }
    }
    boolean alive = false;

    if(noSpace != 0){
        for(int x=0;x<3;x++) {
            for(int y=0;y<4;y++) {
                if (cell[x][y] == cell[x + 1][y]) {
                    alive = true;
                }
            }
        }
        for(int x=0;x<4;x++){
            for(int y=0;y<3;y++){
                if (cell[x][y] == cell[x][y+1]){
                    alive = true;
                }
            }
        }
    }else{
        alive = true;
    }

    if (!alive){
        statusLabel.setText("Game Over!");
    } else if(won) {
        statusLabel.setText("Won!");
    }
}

private int newCell(){
    int x = (int) (4 * Math.random());
    int y = (int) (4 * Math.random());
    if(cell[x][y] != 0){
        return newCell();
    } else {
        cell[x][y] = twoOrFour();
        return x; //I don't need this x anywhere, but I need to return newCell()
    }
}

private int twoOrFour(){
    double r = Math.random();
    if(r < 0.125){
        return 4;
    }else{
        return 2;
    }
}

private void updateScreen() {

    for(int x=0;x<4;x++){
        for(int y=0;y<4;y++){
            labels[x][y].setText(Integer.toString(cell[x][y]));
            labels[x][y].setStyle(cellStyle(cell[x][y]));
        }
    }

    scoreLabel.setText("Score: " + Integer.toString(score));
}

private String cellStyle(int cell) {
    String style = "-fx-min-width: 100; -fx-background-radius: 20; -fx-font: bolder 30 'ClearSans'; -fx-min-height: 100; -fx-alignment: center; -fx-border-radius: 14; -fx-border-width: 10; -fx-border-color: #BBADA0; -fx-background-color: #";
    switch(cell){
        case 2: style+= "EEE4DA"; break;
        case 4: style+= "ECE0C8"; break;
        case 8: style+= "F2B179"; break;
        case 16: style+= "F59563"; break;
        case 32: style+= "F57C5F"; break;
        case 64: style+= "F65D3B"; break;
        case 128: style+= "EDCE71"; break;
        case 256: style+= "EDCC61"; break;
        case 512: style+= "ECC850"; break;
        case 1024: style+= "EDC53F"; break;
        case 2048: style+= "ECC400"; break;
        case 0: style+= "CDC1B4"; break;
        default: style+= "000000"; break;
    }

    style+= ";-fx-text-fill: #";

    if(cell==2||cell==4){
        style+= "776E65;";
    }else if(cell==0){
        style+= "CDC1B4;";
    }else{
        style+= "F9F6F2;";
    }
    return style;
}
}

1 个答案:

答案 0 :(得分:1)

与@ RyanJ的评论一样,您只需使用newCell()返回类型定义void

private void newCell() {
    int x = (int)(Math.random() * 4);
    int y = (int)(Math.random() * 4);
    if (cell[x][y] != 0) {
        newCell();
    } else {
        cell[x][y] = twoOrFour();
    }
}

请注意,您可以使用循环执行相同的操作:

private void newCell() {
    int x ;
    int y ;
    do {
        x = (int)(Math.random() * 4);
        y = (int)(Math.random() * 4);
    } while (cell[x][y] != 0);
    cell[x][y] = twoOrFour();
}

但这些都不是特别好,因为它可能需要任意长的时间来找到一个空的空间。在递归版本中,情况更糟,因为你可能只是运气不足以使递归运行得足够深,导致StackOverflowException。 (这是非常不可能的,但是如果你玩的时间足够长(并且让它面对它,这个游戏很容易上瘾),它会在某个时候发生。)

这是一个更好的解决方案。创建一个空单元格列表(只是一个介于0和15之间的整数列表)。然后随机选择一个:

private void newCell() {
    List<Integer> availableCells = new ArrayList<>();
    for (int i = 0; i < 16; i++) {
        int x = i / 4 ;
        int y = i % 4 ;
        if (cell[x][y] == 0) {
            availableCells.add(i);
        }
    }
    int nextCell = availableCells.get((int)(Math.random() * availableCells.size()));
    cell[nextCell / 4][nextCell % 4] = twoOrFour();
}