[英]Output of List of game board states shows all states to be identical
我正在制作Tic Tac Toe游戲。 我在邏輯上有3個班級。
我已經附上了程序的代碼片段。
ar = getAllStates(b,2);
這意味着如果我通過類似
000000000
這應該返回具有所有可能狀態的ArrayList:
200
000
000
和
020
000
000
和
002
000
000
依此類推
000
000
002
但是,當! 執行代碼並檢查存儲在ArrayList中的值,我得到一個9個對象的ArrayList,每個對象都有配置:
000
000
000
編碼
public class Game2 {
static int player1 = 1;
static int player2 = 2;
public static void main(String[] args) {
//playGame();
ArrayList<Board> ar ;
Board b = new Board();
Computer comp = new Computer();
ar = getAllStates(b,2);
//System.out.println(comp.getConfigScore(b));
}
public static ArrayList<Board> getAllStates(Board b, int player)
{
ArrayList<Board> arr = new ArrayList<Board>();
for(int i = 0;i <3; i ++)
{
for (int j=0;j<3;j++)
{
if(!b.isPosOccupied(i, j))
{
int previousState = b.getVal(i, j);
b.setVal(i, j, player);
b.display();
arr.add(b);
b.setVal(i, j, previousState);
}
}
}
System.out.println(arr.size());
return arr;
}
}
The Board Class is :
public class Board {
// Defines Board Configuration
static int[][] data = new int[3][3];
public Board()
{
for(int i=0;i<data.length;i++ )
{
for(int j=0;j<data.length;j++ )
{
data[i][j] = 0;
}
}
}
//Displays Current State of the board
public void display()
{
System.out.println("Board");
for(int i = 0; i< data.length;i++)
{
for(int j = 0; j< data.length;j++)
{
System.out.print(data[i][j] + " ");
}
System.out.println();
}
}
// Gets the Value on a specific board configuration
public int getVal(int i, int j)
{
return data[i][j];
}
//Sets the value to a particular board location
public void setVal(int i, int j,int val)
{
data[i][j] = val;
}
public boolean isBoardFull()
{
for(int i=0;i< data.length ; i++)
{
for(int j=0;j< data.length ;j++)
{
if(data[i][j] == 0)
return false;
}
}
return true;
}
public boolean isVictoriousConfig(int player)
{
//Noting down victory rules
//Horizontal Victory
if ( (data[0][0] != 0) && ((data[0][0] == data [0][1]) && (data[0][1] == data [0][2]) && (data[0][2] == player)))
return true;
if ((data[1][0] != 0) && ((data[1][0] == data [1][1]) && (data[1][1] == data [1][2]) && (data[1][2] == player)))
return true;
if ((data[2][0] != 0) && ((data[2][0] == data [2][1]) && (data[2][1] == data [2][2]) && (data[2][2] == player)))
return true;
//Vertical Victory
if ( (data[0][0] != 0) && ((data[0][0] == data [1][0]) && (data[1][0] == data [2][0]) && (data[2][0] == player)))
return true;
if ((data[0][1] != 0) && ((data[0][1] == data [1][1]) && (data[1][1] == data [2][1]) && (data[2][1] == player)))
return true;
if ((data[0][2] != 0) && ((data[0][2] == data [1][2]) && (data[1][2] == data [2][2]) && (data[2][2] == player)))
return true;
//Diagonal Victory
if ( (data[0][0] != 0) && ((data[0][0] == data [1][1]) && (data[1][1] == data [2][2]) && (data[2][2] == player)))
return true;
if ( (data[0][2] != 0) && ((data[0][2] == data [1][1]) && (data[1][1] == data [2][0]) && (data[2][0] == player)))
return true;
//If none of the victory rules are met. No one has won just yet ;)
return false;
}
public boolean isPosOccupied(int i, int j)
{
if(data[i][j] != 0)
{
return true;
}
return false;
}
}
因為我正在更新getAllStates()函數中的電路板配置以提供所有可能的電路板配置,所以我不明白為什么ArrayList()會顯示這樣的結果。
我覺得我正在某個地方覆蓋此陣列列表,或者根本沒有使用預期的板卡配置更新陣列列表。 我真的很感激這里的任何想法。 提前致謝。
添加了編輯:好的,因此,如果我將設置器更改為還給b一個不同的對象,它應該可以工作。 那這個修改對嗎?
public Board setVal(int i, int j,int val)
{
Board newboard = new Board();
data[i][j] = val;
newboard.data = data;
return newboard;
}
之后,我將在getAllStates()函數中添加類似的操作
Board newboard = b.setVal(i, j, player);
arr.add(newboard);
您必須克隆該板才能在存儲以前的狀態時一次又一次地更改它。 否則,您將更改同一對象。 您最終得到一個引用同一對象的列表。
您可以這樣驗證:
ar = getAllStates(b,2);
ar.get(0) == ar.get(1); // returns true
我將重寫Board.clone()
方法並像這樣使用它:
arr.add(b.clone()); // replaced arr.add(b);
另一種選擇是使Board
對象不可變 。 這可以通過總是創建另一個被突變的對象來完成(通常是在setter中)。 因此, Board.setVal(...)
將返回具有新設置值的新板對象:
public Board setVal(...) {
// ...
// TODO: create a clone of the board named newBoard
// ...
return newBoard;
}
更改界面后,您可以執行以下操作:
// keeps old object that may still be referenced from changing
b = b.setVal(i, j, player);
注意 :要使對象在概念上不可變,可能還需要使其內部對象不可變。 如果您要使用內部陣列表示Board
,則需要通過從不更改它來使其不可變。
這可以在構造時通過傳遞數組並立即將其復制以丟棄對外部數組的引用來完成:
public Board(int[][] data) {
this.data = Arrays.copyOf(data, data.length); // copy array
// do not reference 'data'. Do not expose 'this.data'.
}
您期望ArrayList
在添加時為您的主板拍攝快照,但這不是它的功能。
像這樣想:您有一個棋盤,它位於X位置。您坐在棋盤的前面,並在其上標記以指示可能的比賽位置。 然后,將ArrayList的紙條交給“位置X的木板”。 然后,您刪除該標記並制作另一個標記。 然后,將另一張紙條交給ArrayList,上面寫着“位置X的木板”。 再重復幾次。
到最后,您有了一個ArrayList,里面裝有9張紙條,上面都寫着“位置X的木板”,這是您一直在重復標記和擦除的同一塊木板。 當您輸出列表時,它將忠實地輸出該單板9次,並且由於您擦除了其上的所有標記,因此每個打印輸出都將為空。
為了使其正常工作,您必須制作一個全新的電路板,並每次在列表中引用該電路板。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.