首页 > 解决方案 > 数组似乎正在更新自己

问题描述

我正在尝试创建一个简单的本地井字游戏,以便在 android studio 中进行一些练习,所以只是为了好玩,我想我会添加一个按钮,允许用户撤消上一次播放的动作,一直回到第一次之前如果他们愿意,可以移动。

为了做到这一点,我有一个二维数组来存储棋盘的当前状态(即每个“x”或“o”相对于实际棋盘的位置),每次有人玩时都会更新。我还创建了第二个存储二维数组的数组列表,以便跟踪每一轮的棋盘状态。因此,arraylist 的第一个元素应该包含一个二维数组,该数组对应于没有玩家玩过时棋盘的状态,第二个元素应该是一个用户玩过一次后的状态,依此类推。

所以我想要发生的是,当用户玩游戏时,在更新棋盘状态之前,它应该将棋盘的当前状态复制到包含所有状态的数组列表中(在当前回合的索引处),然后是棋盘应该更新以及轮数。因此,当用户单击撤消按钮时,它应该将板状态恢复到板最近更新之前的状态。

我的问题是:我的数组列表中的元素似乎没有被正确添加。出于某种原因,其中的所有元素都包含最近板状态的数组,我一生都无法弄清楚为什么。

例如,如果游戏刚开始,我要单击网格上的任何按钮,然后立即单击撤消按钮并在第 0 个索引处打印 arraylist 内容,我应该得到每个网格的默认值(即空白板)但相反,我在玩过之后得到了板的外观,这不是预期的。据我所知,我绝不会将那个董事会状态放在第 0 个索引中。

我在下面显示了一个示例输出,其中我只播放了一次并单击了一次撤消按钮。第一组数字是通过单击网格按钮打印的,第二组数字是从撤消按钮打印的。数字 0-9 代表网格位置,任何“X”或“O”代表玩家玩过的位置。从技术上讲,我应该为两组号码打印 0-9,因为我只玩过一次,但我在第二组玩的地方得到了一个“X”。

这是示例输出:

2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: From button on grid: 
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 0
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 1
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 2
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 3
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 4
2020-02-03 09:12:14.411 14808-14808/com.example.tictactoe I/Anton: 5
2020-02-03 09:12:14.412 14808-14808/com.example.tictactoe I/Anton: 6
2020-02-03 09:12:14.412 14808-14808/com.example.tictactoe I/Anton: 7
2020-02-03 09:12:14.412 14808-14808/com.example.tictactoe I/Anton: 8
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: From undo button: 
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: X
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 1
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 2
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 3
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 4
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 5
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 6
2020-02-03 09:12:16.509 14808-14808/com.example.tictactoe I/Anton: 7
2020-02-03 09:12:16.510 14808-14808/com.example.tictactoe I/Anton: 8

任何帮助将不胜感激。我的代码和xml如下:

    package com.example.tictactoe;

    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatActivity;

    import android.content.DialogInterface;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;

    import com.example.tictactoe.Utility.TicTacAlertDialog;

    import java.util.ArrayList;
    import java.util.Arrays;

    public class MainActivity extends AppCompatActivity {

    private boolean player1Turn = true;
    private int roundCount = 1;
    private int player1Points = 0;
    private int player2Points = 0;
    private static String[][] board;


    private ArrayList<String [][]> allBoards;
    private int testing = 0;

    private TextView player1TextView;
    private TextView player2TextView;
    AlertDialog.Builder gameOver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        player1TextView = findViewById(R.id.player1);

        player2TextView = findViewById(R.id.player2);

        gameOver = new AlertDialog.Builder(this);

        board = new String[3][3];
        allBoards = new ArrayList<String[][]>();

        boardSet();
        allBoards.add(0,board);

    }

    //function defines behavior of when a user plays, i.e. clicks any button on the grid

    public void playerPlayed(View view) {
        Button button = (Button) view;
        String userSelect = button.getText().toString();


        //adding current board to arraylist containing all board states per round. Using roundcount as index.
        allBoards.add(roundCount,board);
        Log.i("Anton", "From button on grid: ");
        //debugging code to see content of arraylist
        for(int a = 0; a <3; a++){
            for(int b = 0; b<3;b++){
                Log.i("Anton", "\n" + allBoards.get(0)[a][b]);
            }
        }




        //getting i,j index of what button was just clicked on the grid
        int i = Character.getNumericValue(button.getTag().toString().charAt(4));
        int j = Character.getNumericValue(button.getTag().toString().charAt(5));


        //Printing of X or O on buttons depending on button clicked by user
        if (userSelect.equals("") && player1Turn) {
            button.setText("X");
            roundCount++;


        } else if (userSelect.equals("") && !player1Turn) {
            button.setText("O");
            roundCount++;
        }

        //copying board most recently played button into board state array
        board[i][j] = button.getText().toString();
        Boolean whoWon = winner();

        //checking for winner to display dialog box
        if (player1Turn == true && whoWon == true) {
            player1TextView.setText("Player 1: " + ++player1Points);
            whoWon = false;
            boardSet();

            //Alerts
            new TicTacAlertDialog(this, "Helo", "you won");
            gameOver.setMessage("Game over, Player 1 Won");
            gameOver.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    gameWinReset();
                    boardSet();
                }
            });
            AlertDialog gameEnded = gameOver.create();
            gameEnded.show();

        } else if (player1Turn == false && whoWon == true) {
            player2TextView.setText("Player 2: " + ++player2Points);
            whoWon = false;
            boardSet();

            gameOver.setMessage("Game over, Player 2 Won");
            gameOver.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    gameWinReset();
                    boardSet();
                }
            });
            AlertDialog gameEnded = gameOver.create();
            gameEnded.show();

        } else if (roundCount == 9) {
            whoWon = false;
            boardSet();

            gameOver.setMessage("Game over, it is a draw.");
            gameOver.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    gameWinReset();
                    boardSet();
                }
            });
            AlertDialog gameEnded = gameOver.create();
            gameEnded.show();

        }
        player1Turn = !player1Turn;



    }

    //function to determine winner of the game

    public boolean winner() {

        //columns

        if (board[0][0].equals(board[1][0]) && board[0][0].equals(board[2][0])) {
            return true;
        }

        if (board[0][1].equals(board[1][1]) && board[0][1].equals(board[2][1])) {

            return true;
        }

        if (board[0][2].equals(board[1][2]) && board[0][2].equals(board[2][2])) {
            return true;
        }

        //rows

        if (board[0][0].equals(board[0][1]) && board[0][0].equals(board[0][2])) {

            return true;
        }

        if (board[1][0].equals(board[1][1]) && board[1][0].equals(board[1][2])) {

            return true;
        }

        if (board[2][0].equals(board[2][1]) && board[2][0].equals(board[2][2])) {

            return true;
        }

        //diagonals

        if (board[0][0].equals(board[1][1]) && board[0][0].equals(board[2][2])) {
            return true;
        }

        if (board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0])) {
            return true;
        }
        return false;
    }

    //reset board button behavior

    public void resetBoard(View view) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Button b = (Button) findViewById(getResources().getIdentifier("grid" + i + j, "id", getPackageName()));
                b.setText("");
            }
        }
        boardSet();
    }



    //function to reset the board state array
    public void boardSet() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = Integer.toString(testing);
                testing++;
            }
        }
        roundCount = 0;
        testing = 0;
    }




    //function to set board to initial blank state after game has ended or been drawn
    public void gameWinReset() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Button b = (Button) findViewById(getResources().getIdentifier("grid" + i + j, "id", getPackageName()));
                b.setText("");
                roundCount = 0;
            }
        }
        boardSet();
    }


    //undo button behavior
    public void undoLast(View view) {
        Button eachButton;
        Resources res = getResources();

        //debugging code for weird arraylist behavior
        Log.i("Anton", "From undo button: ");
        for(int i = 0; i<3;i++){
            for(int j = 0; j<3; j++){

                Log.i("Anton", "\n\n" + allBoards.get(0)[i][j]);
            }
        }


        //Resetting board to all blank provided undo button is clicked when round count =1
        if(roundCount ==1)
        {
            //set entire  grid to blank
            for(int i = 0; i <3; i++)
            {
                for(int j = 0; j<3;j++)
                {
                    int id = res.getIdentifier("grid" + i + j, "id", getBaseContext().getPackageName());
                    eachButton = findViewById(id);
                        eachButton.setText("");
                }
            }


        }
        else{
            for(int i = 0; i <3; i++)
            {
                for(int j = 0; j<3;j++)
                {
                    int id = res.getIdentifier("grid" + i + j, "id", getBaseContext().getPackageName());
                    eachButton = findViewById(id);
                    String cellValue = allBoards.get(roundCount-2)[i][j];
                    if(cellValue.equals("X") || cellValue.equals("O"))
                    {
                        eachButton.setText(cellValue);
                    }else{
                        eachButton.setText("");
                    }
                }
            }

        }
    }
}




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:orientation="horizontal"
        >

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_weight="2"
            >
            <TextView
                android:id="@+id/player1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Player 1: 0"
                android:textSize="16dp"
                android:fontFamily="serif"
                />

            <TextView
                android:id="@+id/player2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Player 2: 0"
                android:textSize="16dp"
                android:fontFamily="serif"/>
        </LinearLayout>

        <Button
            android:id="@+id/undo"
            android:onClick="undoLast"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/reset_button_drawable"
            />


        <Button
            android:id="@+id/reset"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="@drawable/reset_button_drawable"
            android:onClick="resetBoard"
            android:text="Reset"
            android:textAllCaps="false"
            android:textColor="#fff"
            android:textSize="20dp"
            android:layout_weight="3"
            />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_weight="1">

        <Button
            android:id="@+id/grid00"
            android:tag="grid00"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="playerPlayed"
            android:textSize="100dp"
            android:textColor="#fff"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            />
        <Button
            android:id="@+id/grid01"
            android:tag="grid01"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="playerPlayed"
            android:text=""
            android:textSize="100dp"
            android:textColor="#fff"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            />
        <Button
            android:id="@+id/grid02"
            android:tag="grid02"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="playerPlayed"
            android:text=""
            android:textSize="100dp"
            android:textColor="#fff"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginBottom="5dp"
            />

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_weight="1">

        <Button
            android:id="@+id/grid10"
            android:tag="grid10"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"

            />
        <Button
            android:id="@+id/grid11"
            android:tag="grid11"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            />
        <Button
            android:id="@+id/grid12"
            android:tag="grid12"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            android:layout_marginRight="5dp"
            />

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_weight="1">

        <Button
            android:id="@+id/grid20"
            android:tag="grid20"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            />
        <Button
            android:id="@+id/grid21"
            android:tag="grid21"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            />
        <Button
            android:id="@+id/grid22"
            android:tag="grid22"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="100dp"
            android:textColor="#fff"
            android:onClick="playerPlayed"
            android:background="@drawable/button_looks"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="5dp"
            android:layout_marginRight="5dp"
            />

    </LinearLayout>

</LinearLayout>

标签: javaandroidarrays

解决方案


您需要board在添加时克隆allBoards- 您当前正在保存对一个棋盘状态的引用(在每次移动时),并且每次移动都会改变,因此所有条目allBoards 似乎都会改变 - 这条线(和类似的) 是你的问题:

allBoards.add(0,board);

因此,无论您在哪里allBoards.add(slot,board);替换为cloneBoard(slot)在第二个片段中找到的调用...(请注意对深度克隆方法的引用)。

例子...

public class Main
{

    private static String[][] board;
    private static ArrayList<String[][]> allBoards = new ArrayList<>();
    public static void main(String[] args) {

        board = new String[3][3];
        setBoard("A");
        allBoards.add(0,board);
        setBoard("B");
        allBoards.add(1,board);
        dumpAllBoards();
    }
    private static void dumpAllBoards() {
        int bCnt = 0;
        for (String[][] b : allBoards) {
            System.out.print(bCnt+": ");
            for (int i = 0; i < 9; i++) {
                System.out.print(b[i/3][i%3]+" ");
            }
            System.out.println();
            bCnt++;
        }
    }

    private static void setBoard(String v) {
        for (int i = 0; i < 9; i++) {
            board[i/3][i%3] = v;
        }
    }
}

印刷:

0: B B B B B B B B B                                                                                                                                                               
1: B B B B B B B B B

public class Main
{

    private static String[][] board;
    private static ArrayList<String[][]> allBoards = new ArrayList<>();
    public static void main(String[] args) {

        board = new String[3][3];
        setBoard("A");
        cloneBoard(0);
        setBoard("B");
        cloneBoard(1);
        dumpAllBoards();


    }

    // omitted dumpAllBoards - see previous

    private static void cloneBoard(int slot) {
            allBoards.add(slot,deepCopyStrMatrix(board));
    }

    // copied from: https://stackoverflow.com/a/9106176/2711811
    public static String[][] deepCopyStrMatrix(String[][] input) {
        if (input == null)
            return null;
        String[][] result = new String[input.length][];
        for (int r = 0; r < input.length; r++) {
            result[r] = input[r].clone();
        }
        return result;
    }
}

印刷:

0: A A A A A A A A A                                                                                                                                                               
1: B B B B B B B B B                                                                                                                                                               

推荐阅读