//依據棋局狀態找出最高分點(依ScoreMode排序分數高低之後, 再以陣營(type)個別對格子進行評分) private List <MaxMinNode> ReturnHighestList(int[,] grid, int type, ScoreMode mode, int amount, int layer, string numberName) { List <MaxMinNode> nodeList = new List <MaxMinNode>(); //記錄所有棋盤格的分數 for (int i = 0; i <= grid.GetUpperBound(1); i++) { for (int j = 0; j <= grid.GetUpperBound(0); j++) { if (grid[j, i] == 0) { int score = 0; switch (mode) { case ScoreMode.此陣營最高分: score += ScoreChessPoint(new Vector2(j, i), grid, type, false, false); break; case ScoreMode.方最高分: int awayType = type == 1 ? 2 : 1; score += ScoreChessPoint(new Vector2(j, i), grid, awayType, false, false); break; case ScoreMode.雙方合計最高分: score += ScoreChessPoint(new Vector2(j, i), grid, 1, false, false); score += ScoreChessPoint(new Vector2(j, i), grid, 2, false, false); break; } if (score != 0) //只有分數不為0時才會採用至List { if (score > c_maxScore) { score = c_maxScore; //設置上限 } MaxMinNode _n = new MaxMinNode(score, new Vector2(j, i), layer, numberName); nodeList.Add(_n); } } } } //排序 nodeList.Sort((MaxMinNode x, MaxMinNode y) => { if (x.score < y.score) { return(1); } if (x.score > y.score) { return(-1); } return(0); } ); //只保留amount個最大值 if (nodeList.Count != 0) { nodeList.RemoveRange(amount, nodeList.Count - amount); } //設定編號名稱 for (int i = 0; i < nodeList.Count; i++) { nodeList[i].number = nodeList[i].number + i.ToString(); } if (mode != ScoreMode.此陣營最高分) //根據陣營(type)改變node分數(但如果mode為"此陣營最高分", 則無需重複評分) { for (int i = 0; i < nodeList.Count; i++) { nodeList[i].score = ScoreChessPoint(new Vector2(nodeList[i].pos.x, nodeList[i].pos.y), grid, type, false, false); } } return(nodeList); }
public List <MaxMinNode> BuildNodeList(int[,] grid, int amount, int deep, string numberName, bool assOrAway, MaxMinNode headNode) { List <MaxMinNode> _nodeList = new List <MaxMinNode>(); bool breakBranch = false; //是否斷枝 if (assOrAway && deep > 0) //我方回合且深度大於0時(非最後一項), 抓出amount個分數最大值位置 { _nodeList = ReturnHighestList(grid, aiChessType, ScoreMode.雙方合計最高分, amount, deep, numberName); } else if (assOrAway && deep == 0) //我方回合且深度等於0時(最後一項), 只取最大分數位置 { //_nodeList = ReturnHighestList(grid, aiChessType, ScoreMode.雙方合計最高分, 1, deep, numberName); _nodeList = Deduce(grid, aiChessType, deep, numberName); } else if (!assOrAway) //對方回合時, 使用特殊演算法去預測可能會下的位置 { _nodeList = Deduce(grid, playerType, deep, numberName); for (int i = 0; i < _nodeList.Count; i++) { _nodeList[i].score *= -1; } } //若分數在分數上限值以上時剪枝, 不繼續推演 for (int i = 0; i < _nodeList.Count; i++) { if (Mathf.Abs(_nodeList[i].score) >= c_maxScore) { breakBranch = true; } } for (int i = 0; i < _nodeList.Count; i++) //生成的所有node再往下生成分支 { if (deep > 0) //若深度大於0(尚未到最後一項), 則向下生成分枝 { int[,] nextGrid = (int[, ])grid.Clone(); nextGrid[(int)_nodeList[i].pos.x, (int)_nodeList[i].pos.y] = assOrAway ? aiChessType : playerType; //推演棋盤 if (!breakBranch) { _nodeList[i].childBranch = BuildNodeList(nextGrid, amount, deep - 1, _nodeList[i].number, !assOrAway, _nodeList[i]); } } if (_nodeList[i].nodeAcc.Count == 0) { _nodeList[i].nodeAcc.Add(_nodeList[i].score); //若累計分數的項目數等於0(最後一項), 則將自己的分數加進累計總分 } else //若累計分數的項目數大於1(前面已有子分枝將分數加上來), 則只要對累計總分再累加自己的分數上去即可 { for (int j = 0; j < _nodeList[i].nodeAcc.Count; j++) { _nodeList[i].nodeAcc[j] += _nodeList[i].score; if (_nodeList[i].nodeAcc[j] >= c_maxScore) { _nodeList[i].nodeAcc[j] = c_maxScore; //設置分數上限 } } } if (headNode != null) //若上層node不為null, 則將累計總分往母分枝丟, 若項目數為多個(來自不同子分枝的累加總分), 則只挑出最大值 { if (_nodeList[i].nodeAcc.Count > 1) { _nodeList[i].nodeAcc.Sort(); } headNode.nodeAcc.Add(_nodeList[i].nodeAcc[_nodeList[i].nodeAcc.Count - 1]); } else { _nodeList[i].nodeAcc.Sort(); } //_nodeList[i].TestMessage(); } return(_nodeList); }