我試圖編寫一些AI的跳棋遊戲。我的節目說白棋手有0步棋,儘管我知道有這些棋步。 GetValidMoves()
功能已經過測試,並可用於其他代碼領域。爲什麼這段代碼給出了兩個不同的輸出(似乎是)相同的輸入?
要嘗試並隔離我救出來的問題板狀態的程序再裝回去了,看看我是否會得到同樣的問題:
using(Stream s = File.Open("board.dat", FileMode.Create))
{
var bf = new BinaryFormatter();
bf.Serialize(s, board);
}
Debug.WriteLine(board.GetValidMoves(Color.White).Count());
using (Stream s = File.Open("board.dat", FileMode.Open))
{
var bf = new BinaryFormatter();
board = (Board)bf.Deserialize(s);
}
Debug.WriteLine(board.GetValidMoves(Color.White).Count());
此打印:
0
7
當我期望輸出是相同的(7是正確的)。
什麼可能導致這個在反序列化之後開始工作?董事會的兩個實例看起來都是一樣的......我打印出所有的屬性,他們都一樣正確。我不確定該從哪裏出發?
董事會的第一個實例(反序列化之前)是克隆的結果。我可以克隆它錯嗎?有沒有「懸掛參考」?
GetValidMoves:
public IEnumerable<Move> GetValidMoves(Color c)
{
var jumps = GetJumps(c);
if (jumps.Any())
foreach (var j in jumps)
yield return j;
else
foreach (var s in GetSlides(c))
yield return s;
}
public IEnumerable<Move> GetSlides(Color c)
{
foreach (int i in Enumerate(c))
foreach (var s in GetSlides(c, i))
yield return s;
}
public IEnumerable<Move> GetJumps(Color c)
{
foreach (int i in Enumerate(c))
foreach (var j in GetJumps(c, i))
yield return j;
}
public IEnumerable<Move> GetJumps(Color c, int i)
{
Checker checker = this[c, i] as Checker;
bool indentedRow = i % Width < rowWidth;
int column = i % rowWidth;
int offset = indentedRow ? 0 : -1;
bool againstLeft = column == 0;
bool againstRight = column == rowWidth - 1;
int moveSW = i + rowWidth + offset;
int moveSE = moveSW + 1;
int jumpSW = i + rowWidth * 2 - 1;
int jumpSE = jumpSW + 2;
if (!againstLeft && jumpSW < Count && IsEnemy(c, moveSW) && IsEmpty(c, jumpSW))
yield return new Move(c, i, jumpSW, jump: true, crown: IsCrowned(checker, jumpSW));
if (!againstRight && jumpSE < Count && IsEnemy(c, moveSE) && IsEmpty(c, jumpSE))
yield return new Move(c, i, jumpSE, jump: true, crown: IsCrowned(checker, jumpSE));
if (checker.Class == Class.King)
{
int moveNW = i - rowWidth + offset;
int moveNE = moveNW + 1;
int jumpNW = i - rowWidth * 2 - 1;
int jumpNE = jumpNW + 2;
if (!againstLeft && jumpNW >= 0 && IsEnemy(c, moveNW) && IsEmpty(c, jumpNW))
yield return new Move(c, i, jumpNW, jump: true);
if (!againstRight && jumpNE >= 0 && IsEnemy(c, moveNE) && IsEmpty(c, jumpNE))
yield return new Move(c, i, jumpNE, jump: true);
}
}
public IEnumerable<Move> GetSlides(Color c, int i)
{
Checker checker = this[c, i] as Checker;
bool indentedRow = i % Width < rowWidth;
int column = i % rowWidth;
int offset = indentedRow ? 0 : -1;
bool againstLeft = !indentedRow && column == 0;
bool againstRight = indentedRow && column == rowWidth - 1;
int moveSW = i + rowWidth + offset;
int moveSE = moveSW + 1;
if (!againstLeft && moveSW < Count && IsEmpty(c, moveSW))
yield return new Move(c, i, moveSW, crown: IsCrowned(checker, moveSW));
if (!againstRight && moveSE < Count && IsEmpty(c, moveSE))
yield return new Move(c, i, moveSE, crown: IsCrowned(checker, moveSE));
if (checker.Class == Class.King)
{
int moveNW = i - rowWidth + offset;
int moveNE = moveNW + 1;
if (!againstLeft && moveNW >= 0 && IsEmpty(c, moveNW))
yield return new Move(c, i, moveNW, crown: IsCrowned(checker, moveNW));
if (!againstRight && moveNE >= 0 && IsEmpty(c, moveNE))
yield return new Move(c, i, moveNE, crown: IsCrowned(checker, moveNE));
}
}
它不應該有副作用。
要回答您的疑問是否有效移動無意中改變電路板狀態:
var board = new Board(8, 8);
board.SetUp();
foreach(var m in board.GetValidMoves(Color.White))
Console.WriteLine(m);
Console.WriteLine("---");
foreach(var m in board.GetValidMoves(Color.White))
Console.WriteLine(m);
打印:
8-12
8-13
9-13
9-14
10-14
10-15
11-15
---
8-12
8-13
9-13
9-14
10-14
10-15
11-15
(同樣的輸出兩次)正如你所期望。
您可以顯示Board類以及'GetValidMoves'函數,以便我們可以重現行爲嗎? – 2010-09-05 21:46:54
'board.GetValidMoves'有副作用嗎?也就是說,如果你叫它,它會改變'board'的狀態嗎? – Oded 2010-09-05 21:47:22
如果連續調用'GetValidMoves',將序列化/反序列化放在一邊,會發生什麼?正如其他人所說,似乎這個函數修改了對象的狀態。 – 2010-09-05 21:51:39