private MctsNode createNode(BoardState state, MctsNode parent, int incomingMove) { GameObject gob = Instantiate(m_nodePrefab.gameObject); MctsNode node = gob.GetComponent <MctsNode>(); node.m_unexpandedMoves = new List <int>(); for (int i = 0; i < 9; i++) { if (state.m_cellState[i] == 0) { node.m_unexpandedMoves.Add(i); } } node.m_incomingMove = incomingMove; node.m_incomingMovePlayer = 3 - state.m_currentPlayer; node.m_parent = parent; if (parent != null) { parent.m_children.Add(node); } if (parent != null) { node.m_depth = parent.m_depth + 1; } else { node.m_depth = 0; } Vector3 position; if (parent == null) { position = transform.position + Vector3.back * transform.localScale.z; } else { position = parent.transform.position + Vector3.forward * transform.localScale.z; int cx = (incomingMove % 3) - 1; int cy = (incomingMove / 3) - 1; position.x += cx * transform.localScale.x * Mathf.Pow(0.25f, node.m_depth - 1); position.y += cy * transform.localScale.y * Mathf.Pow(0.25f, node.m_depth - 1); //const float expansion = 1.1f; //position.x *= Mathf.Pow(expansion, node.m_depth - 1); //position.y *= Mathf.Pow(expansion, node.m_depth - 1); } node.setPosition(position); m_nodes.Add(node); return(node); }
private IEnumerator doMCTS() { clearNodes(); MctsNode rootNode = createNode(m_state, null, -1); for (int t = 0; t < m_iterations; t++) { MctsNode currentNode = rootNode; BoardState currentState = new BoardState(m_state); // Selection while (!currentState.IsTerminal && currentNode.m_unexpandedMoves.Count == 0) { currentNode = currentNode.selectChild(); currentState.playMove(currentNode.m_incomingMove); } // Expansion if (!currentState.IsTerminal) { int index = Random.Range(0, currentNode.m_unexpandedMoves.Count); int move = currentNode.m_unexpandedMoves[index]; currentNode.m_unexpandedMoves.RemoveAt(index); currentState.playMove(move); currentNode = createNode(currentState, currentNode, move); } // Simulation while (!currentState.IsTerminal) { int index = Random.Range(0, 9); currentState.playMove(index); } // Backpropagation for (; currentNode != null; currentNode = currentNode.m_parent) { currentNode.updateStatistics(currentState.m_terminalReward); } if (t % m_iterationsPerFrame == 0) { yield return(null); } } int chosenMove = rootNode.getMostVisitedChild().m_incomingMove; m_state.playMove(chosenMove); updateBoard(); m_waitingForPlayerMove = true; }
public MctsNode selectChild() { float bestScore = 0; MctsNode bestChild = null; foreach (MctsNode child in m_children) { float score = child.calculateUcb() + Random.Range(0, 1.0e-5f); if (bestChild == null || score > bestScore) { bestChild = child; bestScore = score; } } return(bestChild); }
public MctsNode getMostVisitedChild() { float bestScore = 0; MctsNode bestChild = null; foreach (MctsNode child in m_children) { float score = child.m_visits + Random.Range(0, 1.0e-5f); if (bestChild == null || score > bestScore) { bestChild = child; bestScore = score; } } return(bestChild); }