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



我用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;
}
}

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

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之间(包括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();
}

最新更新