/// <summary> /// Builds the tree /// </summary> /// <returns>tree</returns> static MinimaxTree <Configuration> BuildTree() { // build root node binContents.Clear(); binContents.Add(3); //3,2;2,1;1,0 binContents.Add(2); //2,2;2,2;0,0 binContents.Add(1); //1,1;0,0;0,0 Configuration rootConfiguration = new Configuration(binContents); // build complete tree MinimaxTree <Configuration> tree = new MinimaxTree <Configuration>(rootConfiguration); LinkedList <MinimaxTreeNode <Configuration> > nodeList = new LinkedList <MinimaxTreeNode <Configuration> >(); nodeList.AddLast(tree.Root); while (nodeList.Count > 0) { MinimaxTreeNode <Configuration> currentNode = nodeList.First.Value; nodeList.RemoveFirst(); List <Configuration> children = GetNextConfigurations(currentNode.Value); foreach (Configuration child in children) { MinimaxTreeNode <Configuration> childNode = new MinimaxTreeNode <Configuration>( child, currentNode); tree.AddNode(childNode); nodeList.AddLast(childNode); } } return(tree); }
/// <summary> /// Removes the given node as a child this node /// </summary> /// <param name="child">child to remove</param> /// <returns>true if the child was removed, false otherwise</returns> public bool RemoveChild(MinimaxTreeNode <T> child) { // only remove children in list if (children.Contains(child)) { child.Parent = null; return(children.Remove(child)); } else { return(false); } }
/// <summary> /// Assigns minimax scores to the tree nodes /// </summary> /// <param name="tree">tree to mark with scores</param> /// <param name="maximizing">whether or not we're maximizing</param> static void Minimax(MinimaxTreeNode <Configuration> tree, bool maximizing) { // recurse on children IList <MinimaxTreeNode <Configuration> > children = tree.Children; if (children.Count > 0) { foreach (MinimaxTreeNode <Configuration> child in children) { // toggle maximizing as we move down Minimax(child, !maximizing); } // set default node minimax score if (maximizing) { tree.MinimaxScore = int.MinValue; } else { tree.MinimaxScore = int.MaxValue; } // find maximum or minimum value in children foreach (MinimaxTreeNode <Configuration> child in children) { if (maximizing) { // check for higher minimax score if (child.MinimaxScore > tree.MinimaxScore) { tree.MinimaxScore = child.MinimaxScore; } } else { // minimizing, check for lower minimax score if (child.MinimaxScore < tree.MinimaxScore) { tree.MinimaxScore = child.MinimaxScore; } } } } else { // leaf nodes are the base case AssignMinimaxScore(tree, maximizing); } }
/// <summary> /// Clears all the nodes from the tree /// </summary> void Clear() { // remove all the children from each node // so nodes can be garbage collected foreach (MinimaxTreeNode <T> node in nodes) { node.Parent = null; node.RemoveAllChildren(); } // now remove all the nodes from the tree and set root to null for (int i = nodes.Count - 1; i >= 0; i--) { nodes.RemoveAt(i); } root = null; }
/// <summary> /// Assigns a minimax score to the given node /// </summary> /// <param name="node">node to mark with score</param> static void AssignMinimaxScore( MinimaxTreeNode <Configuration> node, bool maximizing) { // for the lecture, only score end-of-game configurations if (node.Value.Empty) { if (maximizing) { // player 2 took the last teddy node.MinimaxScore = 1; } else { // player 1 took the last teddy node.MinimaxScore = 0; } } }
/// <summary> /// Removes the given node from the tree. If the node isn't /// found in the tree, the method returns false. /// /// Note that the subtree with the node to remove as its /// root is pruned from the tree /// </summary> /// <param name="removeNode">node to remove</param> /// <returns>true if the node is removed, false otherwise</returns> public bool RemoveNode(MinimaxTreeNode <T> removeNode) { if (removeNode == null) { return(false); } else if (removeNode == root) { // removing the root clears the tree Clear(); return(true); } else { // remove as child of parent bool success = removeNode.Parent.RemoveChild(removeNode); if (!success) { return(false); } // remove node from tree success = nodes.Remove(removeNode); if (!success) { return(false); } // check for branch node if (removeNode.Children.Count > 0) { // recursively prune subtree IList <MinimaxTreeNode <T> > children = removeNode.Children; for (int i = children.Count - 1; i >= 0; i--) { RemoveNode(children[i]); } } return(true); } }
/// <summary> /// Adds the given node as a child this node /// </summary> /// <param name="child">child to add</param> /// <returns>true if the child was added, false otherwise</returns> public bool AddChild(MinimaxTreeNode <T> child) { // don't add duplicate children if (children.Contains(child)) { return(false); } else if (child == this) { // don't add self as child return(false); } else { // add as child and add self as parent children.Add(child); child.Parent = this; return(true); } }
/// <summary> /// Adds the given node to the tree. If the given node is /// null the method returns false. If the parent node is null /// or isn't in the tree the method returns false. If the given /// node is already a child of the parent node the method returns /// false /// </summary> /// <param name="node">node to add</param> /// <returns>true if the node is added, false otherwise</returns> public bool AddNode(MinimaxTreeNode <T> node) { if (node == null || node.Parent == null || !nodes.Contains(node.Parent)) { return(false); } else if (node.Parent.Children.Contains(node)) { // node already a child of parent return(false); } else { // add child as tree node and as a child to parent nodes.Add(node); return(node.Parent.AddChild(node)); } }
/// <summary> /// Executes minimax search /// </summary> /// <param name="args">command-line arguments</param> static void Main(string[] args) { // build and mark the tree with minimax scores MinimaxTree <Configuration> tree = BuildTree(); Minimax(tree.Root, true); // find child node with maximum score IList <MinimaxTreeNode <Configuration> > children = tree.Root.Children; MinimaxTreeNode <Configuration> maxChildNode = children[0]; for (int i = 1; i < children.Count; i++) { if (children[i].MinimaxScore > maxChildNode.MinimaxScore) { maxChildNode = children[i]; } } Console.WriteLine("Best move is to configuration " + maxChildNode.Value); Console.WriteLine(); }
/// <summary> /// Constructor /// </summary> /// <param name="value">value for the node</param> /// <param name="parent">parent for the node</param> public MinimaxTreeNode(T value, MinimaxTreeNode <T> parent) { this.value = value; this.parent = parent; children = new List <MinimaxTreeNode <T> >(); }
/// <summary> /// Constructor /// </summary> /// <param name="value">value of the root node</param> public MinimaxTree(T value) { root = new MinimaxTreeNode <T>(value, null); nodes.Add(root); }