/// <summary> /// 插入一个新的值。 /// </summary> /// <param name="v">待插入的新值。</param> public void Insert(Key v) { this.n++; MinMaxNode.GetNodes(v, this.n, out MinMaxNode minNode, out MinMaxNode maxNode); this.maxPQ.Insert(maxNode); this.minPQ.Insert(minNode); }
/// <summary> /// 插入一个新的值。 /// </summary> /// <param name="v">待插入的新值。</param> public void Insert(TKey v) { _n++; MinMaxNode.GetNodes(v, _n, out var minNode, out var maxNode); _maxPq.Insert(maxNode); _minPq.Insert(minNode); }
public override void PlayChess() { if (CheckBoard.Instance.chessStack.Count == 0) { CheckBoard.Instance.chessDown(new int[2] { 7, 7 }); return; } float alpha = int.MinValue; float beta = int.MaxValue; int[,] g = (int[, ])CheckBoard.Instance.grid.Clone(); List <MinMaxNode> node = findNextLevel(g, (int)playChess); MinMaxNode res = new MinMaxNode(); res.value = float.MinValue; foreach (var n in node) { float t = findMNode(g, 6, n, true, ref alpha, ref beta); if (t > res.value) { res = n; } } CheckBoard.Instance.chessDown(res.pos); }
/// <summary> /// 插入一个新的值。 /// </summary> /// <param name="v">待插入的新值。</param> public void Insert(Key v) { n++; MinMaxNode.GetNodes(v, n, out var minNode, out var maxNode); maxPQ.Insert(maxNode); minPQ.Insert(minNode); }
MinMaxTree() { Root = new MinMaxNode <int>(0, 0); System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew(); this.AddChildren(Root, new BoardState(), 0); timer.Stop(); #if DEBUG Debug.LogFormat("MinMaxTree nodes count: {0}. Construction time: {1}. Check tree: {2}", this.GetNodesCountByDepth(), timer.Elapsed.TotalSeconds, this.CheckTree(Root, 9)); #endif }
public PlayersMove?ApplyRandomMove(ref MinMaxNode <int> node) { if (node.Children == null || node.Children.Length == 0) { return(null); } node = node.RandomChild; return(new PlayersMove(node.Data)); }
static public MinMaxNode CalculateBestMove(GameManager.CELL_DATA[,] currentTable) { // Treating the special situations MinMaxNode aiFirstMoveNode = new MinMaxNode(); aiFirstMoveNode.StartMinMaxNode(currentTable); MinMaxNode bestMove = aiFirstMoveNode.CalculateInternalBestMove(); return(bestMove); }
/// <summary> /// 根据已有元素建立一个最大-最小堆。(O(n)) /// </summary> /// <param name="keys">需要建堆的元素。</param> public MinMaxPQ(Key[] keys) { this.n = keys.Length; MinMaxNode[] minNodes = new MinMaxNode[keys.Length]; MinMaxNode[] maxNodes = new MinMaxNode[keys.Length]; for (int i = 0; i < this.n; i++) { MinMaxNode.GetNodes(keys[i], i + 1, out minNodes[i], out maxNodes[i]); } this.minPQ = new MinPQ(minNodes); this.maxPQ = new MaxPQ(maxNodes); }
public bool TryApplyMove(ref MinMaxNode <int> node, PlayersMove move) { MinMaxNode <int> nextNode = node.Children.FirstOrDefault(n => n.Data == move.Hash); if (nextNode != null) { node = nextNode; return(true); } return(false); }
public PlayersMove?ApplyBestMove(ref MinMaxNode <int> node, bool maximize) { if (node.Children == null || node.Children.Length == 0) { return(null); } MinMaxNode <int> nextNode = maximize ? node.MaxChild : node.MinChild; node = nextNode; return(new PlayersMove(nextNode.Data)); }
/// <summary> /// 根据已有元素建立一个最大-最小堆。(O(n)) /// </summary> /// <param name="keys">需要建堆的元素。</param> public MinMaxPQ(Key[] keys) { n = keys.Length; var minNodes = new MinMaxNode[keys.Length]; var maxNodes = new MinMaxNode[keys.Length]; for (var i = 0; i < n; i++) { MinMaxNode.GetNodes(keys[i], i + 1, out minNodes[i], out maxNodes[i]); } minPQ = new MinPQ(minNodes); maxPQ = new MaxPQ(maxNodes); }
/// <summary> /// 根据已有元素建立一个最大-最小堆。(O(n)) /// </summary> /// <param name="keys">需要建堆的元素。</param> public MinMaxPq(TKey[] keys) { _n = keys.Length; var minNodes = new MinMaxNode[keys.Length]; var maxNodes = new MinMaxNode[keys.Length]; for (var i = 0; i < _n; i++) { MinMaxNode.GetNodes(keys[i], i + 1, out minNodes[i], out maxNodes[i]); } _minPq = new MinPq(minNodes); _maxPq = new MaxPq(maxNodes); }
MinMaxNode CalculateInternalBestMove() { if (GetTreeChildrenCount() == 0) { return(this); } int ChoosedChild = 0; float resultValue = (MoveType == TYPE.MAX) ? -20.0f : 20.0f; int resultIIndex = 0; for (int i = 0; i < GetTreeChildrenCount(); i++) { MinMaxNode node = (MinMaxNode)GetTreeChild(i); if (node.MoveResult == 0.0f) { node.CalculateInternalBestMove(); } if (MoveType == TYPE.MAX && node.MoveResult > resultValue) { ChoosedChild = i; resultValue = node.MoveResult; resultIIndex = node.IndexI; } else if (MoveType == TYPE.MIN && node.MoveResult < resultValue) { ChoosedChild = i; resultValue = node.MoveResult; resultIIndex = node.IndexI; } else if (node.MoveResult == resultValue && node.IndexI > resultIIndex) { ChoosedChild = i; resultValue = node.MoveResult; resultIIndex = node.IndexI; } else if (node.MoveResult == resultValue && Random.value > 0.5f) { ChoosedChild = i; resultValue = node.MoveResult; resultIIndex = node.IndexI; } } MoveResult = resultValue; return((MinMaxNode)GetTreeChild(ChoosedChild)); }
private float findMNode(int[,] grid, int level, MinMaxNode node, bool myself, ref float alpha, ref float beta) { if (level == 0 || node.value >= int.MaxValue) { return(findNextLevel(grid, node.chess == 1 ? 2 : 1)[0].value); } if (myself) { //遍历所有可能走法 grid[node.pos[0], node.pos[1]] = node.chess; node.children = findNextLevel(grid, node.chess == 1 ? 2 : 1);//下一步对方的走法 foreach (MinMaxNode child in node.children) { //grid[child.pos[0], child.pos[1]] = child.chess; float newNode = findMNode((int[, ])grid.Clone(), level - 1, child, !myself, ref alpha, ref beta); if (newNode > alpha) { alpha = newNode; } if (alpha > beta) { return(alpha); } } return(alpha); } else { grid[node.pos[0], node.pos[1]] = node.chess; node.children = findNextLevel(grid, node.chess == 1 ? 2 : 1);//下一步对方的走法 foreach (MinMaxNode child in node.children) { //grid[child.pos[0], child.pos[1]] = child.chess; float newNode = findMNode((int[, ])grid.Clone(), level - 1, child, !myself, ref alpha, ref beta); if (newNode < beta) { beta = newNode; } if (alpha > beta) { return(beta); } } return(beta); } }
public void GetTree(MinMaxNode node, int[,] grid, int depth, bool isSelf) { //if game is over, no need to go forward if (depth == 0 || node.value == float.MaxValue) { return; } grid[node.pos[0], node.pos[1]] = node.chessColor; node.childNode = GetList(grid, node.chessColor, !isSelf); foreach (MinMaxNode item in node.childNode) { GetTree(item, (int[, ])grid.Clone(), depth - 1, !isSelf); } }
bool CheckTree(MinMaxNode <int> node, int maxChildren) { if (node.Children == null) { return(true); } if (node.Children.Length > maxChildren) { return(false); } for (int i = 0; i < node.Children.Length; ++i) { if (!CheckTree(node.Children[i], maxChildren - 1)) { return(false); } } return(true); }
public float AlphaBeta(MinMaxNode node, int depth, bool isSelf, float alpha, float beta) { if (depth == 0 || node.value == float.MaxValue || node.value == float.MinValue) { return(node.value); } //if is player, find the max value if (isSelf) { foreach (MinMaxNode child in node.childNode) { //compare to self and childnodes alpha = Mathf.Max(alpha, AlphaBeta(child, depth - 1, !isSelf, alpha, beta)); //cut alpha branch if (alpha >= beta) { return(alpha); } } return(alpha); } //if is enemy, find the min value else { foreach (MinMaxNode child in node.childNode) { //compare to self and childnodes beta = Mathf.Min(beta, AlphaBeta(child, depth - 1, !isSelf, alpha, beta)); //cut beta branch if (alpha >= beta) { return(beta); } } return(beta); } }
int AddChildren(MinMaxNode <int> node, BoardState state, int depth) { MinMaxNode <int>[] children = new MinMaxNode <int> [9 - depth]; int playerType = depth % 2; int childIdx = -1; for (int i = 0; i < 9; ++i) { if (state[i] == 0) { PlayersMove move = new PlayersMove(i / 3, i % 3); MinMaxNode <int> child = new MinMaxNode <int>(move.Hash, 0); state.SetTile(i, playerType + 1); int winner = state.GetWinner(); if (winner != -1) { child.Score = winner == 1 ? int.MaxValue : (winner == 2 ? int.MinValue : 0); } else { child.Score = this.AddChildren(child, state, depth + 1); } // Restore board state as it was before this move state.SetTile(i, 0); // Add child to current node children[++childIdx] = child; ++this.nodesCountByDepth[depth]; } } System.Array.Sort <MinMaxNode <int> >(children); node.Children = children; return((playerType == 0 ? node.MaxChild : node.MinChild).Score); }
public override void StartPlay() { //if AI is black, let it occupy the center if (Board.Instance.chessPos.Count == 0) { Board.Instance.StarterPlay(new int[2] { halfBoard, halfBoard }); return; } MinMaxNode node = null; foreach (var item in GetList(Board.Instance.grid, (int)chessColor, true)) { //create tree for each node GetTree(item, (int[, ])Board.Instance.grid.Clone(), 3, false); //find the alpha, beta value float a = float.MinValue; float b = float.MaxValue; item.value += AlphaBeta(item, 3, false, a, b); if (node != null) { if (node.value < item.value) { node = item; } } else { node = item; } } Board.Instance.StarterPlay(node.pos); }
List <MinMaxNode> GetList(int[,] grid, int chess, bool isSelf) { List <MinMaxNode> nodes = new List <MinMaxNode>(); MinMaxNode node; for (int i = 0; i < boardLength; i++) { for (int j = 0; j < boardLength; j++) { int[] pos = new int[2] { i, j }; //if the current position is not empty if (grid[pos[0], pos[1]] != 0) { continue; } //initialize a new node and set up information node = new MinMaxNode(); node.pos = pos; node.chessColor = chess; //if the chess belongs to player if (isSelf) { node.value = GetScore(grid, pos); } //if the chess belongs to enmey[ else { node.value = -GetScore(grid, pos); } //one chess have four options to go(right,up,right up, right bottom) if (nodes.Count < 4) { nodes.Add(node); } else//if count >=4 , compare node value { foreach (MinMaxNode item in nodes) { if (isSelf)//belongs to player, find max value { if (node.value > item.value) { nodes.Remove(item); nodes.Add(node); break; } } else//belongs to enemy, find min value { if (node.value < item.value) { nodes.Remove(item); nodes.Add(node); break; } } } } } } return(nodes); }
internal void MinMax(decimal min, decimal max) { ContentNode n; if (stack.Count > 0) { InternalNode n1; n = (ContentNode)stack.Pop(); if (isPartial && n.NodeType != ContentNode.Type.Terminal && n.NodeType != ContentNode.Type.Any) { // need to reach in and wrap _pRight hand side of element. // and n remains the same. InternalNode inNode = (InternalNode)n; n1 = new MinMaxNode(inNode.RightNode, min, max); n1.ParentNode = n; if (inNode.RightNode != null) inNode.RightNode.ParentNode = n1; inNode.RightNode = n1; } else { // wrap terminal or any node n1 = new MinMaxNode(n, min, max); n.ParentNode = n1; n = n1; } stack.Push(n); } else { // wrap whole content n = new MinMaxNode(contentNode, min, max); contentNode.ParentNode = n; contentNode = n; } abnormalContent = true; }
/// <summary> /// Class constructor /// </summary> /// <param name="depth">Maximum depth when running the algorithm</param> /// <param name="maxProcessingTime">Maximum thread job time</param> public MinMaxJob(int depth, float maxProcessingTime) : base(maxProcessingTime) { m_origin = new ChessNode(BoardManager.Singleton.CurrentStatus, depth, null, NodeType.MAX); m_processedNodes = 0; }
void DoMainMaxMove() { MinMaxNode bestMoveNode = MinMaxNode.CalculateBestMove(Cells); DoAiMove(bestMoveNode.GetSelectedColumn()); }
public int CompareTo(MinMaxNode <T> other) { return(this.Score.CompareTo(other.Score)); }
/// <summary> /// Class constructor /// </summary> /// <param name="depth">Depth from the origin node</param> /// <param name="parentNode">Parent node</param> /// <param name="nodeType">Node type</param> public MinMaxNode(int depth, ChessNode parentNode, NodeType nodeType) { m_Depth = depth; m_parent = parentNode; m_NodeType = nodeType; }
public override void PrepareForGame(TileMark playerType) { base.PrepareForGame(playerType); this.currentNode = MinMaxTree.Instance.Root; }
/// <summary> /// Recursive function of MinMax Algorithm. /// /// This version of the algorithm uses Apha-Beta bound optimization. /// </summary> /// <param name="node">Reference node to start the algorithm</param> /// <param name="alpha">Current alpha value</param> /// <param name="beta">Current beta value</param> /// <param name="nodeType">NodeType: MIN or MAX node</param> /// <returns>Optimal value for the Current Node</returns> private float MinMax(MinMaxNode node, float alpha, float beta, NodeType nodeType) { //Debug.Log("recursivo - depth: "+depth+" alpha: "+alpha+" beta: "+beta+" NodeType: "+nodeType); m_processedNodes++; if (node.IsEndNode()) { //Debug.Log("retorno valor de funcion estatica"); return node.StaticValueFunction(); } else if (nodeType == NodeType.MAX) { foreach (MinMaxNode child in node.getChildren()) { float newAlpha = MinMax(child, alpha, beta, NodeType.MIN); //Debug.Log("Alpha score: " + newAlpha); if (newAlpha > alpha) { node.BestChildren.Clear(); node.BestChildren.Add(child); alpha = newAlpha; //Debug.LogWarning("New best Alpha score: " + newAlpha); } else if (newAlpha == alpha) { node.BestChildren.Add(child); } if (beta <= alpha) { //Debug.LogWarning("Poda alpha!!"); break; } } //Debug.Log("retorno alpha"); return alpha; } else { foreach (MinMaxNode child in node.getChildren()) { float newBeta = MinMax(child, alpha, beta, NodeType.MAX); //Debug.Log("Beta score: " + newBeta); if (newBeta < beta) { node.BestChildren.Clear(); node.BestChildren.Add(child); beta = newBeta; //Debug.LogWarning("new Best Beta Score: " + newBeta); } else if (newBeta == beta) { node.BestChildren.Add(child); } if (beta <= alpha) { //Debug.LogWarning("Poda Beta!!!"); break; } } //Debug.Log("retorno beta"); return beta; } }
public void StartMinMaxNode(GameManager.CELL_DATA[,] currentTable, int level = 0, TYPE type = TYPE.MAX, int indexI = 0, int indexJ = 0, GameManager.CELL_MARKING marking = GameManager.CELL_MARKING.PLAYER) { CurrentLevel = level; MoveType = type; // Copying table GameTable = new GameManager.CELL_DATA[6, 7]; for (int i = 0; i < 6; i++) { for (int j = 0; j < 7; j++) { GameTable[i, j].Marking = currentTable[i, j].Marking; } } if (CurrentLevel > 0) { IndexI = indexI; IndexJ = indexJ; GameTable[IndexI, IndexJ].Marking = marking; // Check if there are more children (only if game is not finished) GameManager.CELL_MARKING victory = GameManager.Instance.CheckVictory(GameTable); if (victory == GameManager.CELL_MARKING.AI) { MoveResult = 10.0f - (float)CurrentLevel; return; } else if (victory == GameManager.CELL_MARKING.PLAYER) { MoveResult = -1.0f * (10.0f - (float)CurrentLevel); return; } else if (IsGameTableFull(GameTable)) { return; } } // Checking if it's possible to go down on tree int maxTreeLevel = GameManager.Instance.GetMinMaxTreeLevel(); if (CurrentLevel + 1 <= maxTreeLevel) { GameManager.CELL_MARKING newMarking = (marking == GameManager.CELL_MARKING.PLAYER) ? GameManager.CELL_MARKING.AI : GameManager.CELL_MARKING.PLAYER; TYPE newType = (MoveType == TYPE.MAX) ? TYPE.MIN : TYPE.MAX; for (int j = 0; j < 7; j++) { if (GameTable[0, j].Marking != GameManager.CELL_MARKING.NONE) { continue; } int i = 1; while (GameTable[i, j].Marking == GameManager.CELL_MARKING.NONE) { i++; if (i == 6) { break; } } i--; // Creating new min max move MinMaxNode node = new MinMaxNode(); AddTreeChild(node); node.StartMinMaxNode(GameTable, CurrentLevel + 1, newType, i, j, newMarking); } } }
private List <MinMaxNode> findNextLevel(int[,] grid, int chess) { List <MinMaxNode> poslist = new List <MinMaxNode>(); for (int i = 0; i < 15; i++) { for (int j = 0; j < 15; j++) { if (grid[i, j] != 0) { continue; } float p = checkScore(grid, new int[] { i, j }); MinMaxNode n = new MinMaxNode(); n.pos = new int[2] { i, j }; n.chess = chess; if (chess == (int)playChess) { n.value = p; if (poslist.Count < depth) { poslist.Add(n); } else { for (int m = 0; m < depth; m++) { if (p > poslist[m].value) { poslist.Insert(m, n); poslist.RemoveAt(depth); break; } } } } else { n.value = -p; if (poslist.Count < depth) { poslist.Add(n); } else { for (int m = 0; m < depth; m++) { if (n.value < poslist[m].value) { poslist.Insert(m, n); poslist.RemoveAt(depth); break; } } } } } } return(poslist); }