// Updates the planning problem this mediator is tracking with new literals for the initial state // and for the goal state. public void ExpandProblem(List <IPredicate> newInitLiterals, List <IPredicate> newGoalLiterals) { // Add each init literal to the initial state. foreach (IPredicate literal in newInitLiterals) { // Update the current world state. this.state = this.state.AddLiteralToState(literal); // Update the initial state. this.problem.Initial = this.state.Predicates; } // Add each goal literal to the goal state. foreach (IPredicate literal in newGoalLiterals) { if (!this.problem.Goal.Contains(literal)) { this.problem.Goal.Add(literal); } } // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
// Updates the planning problem this mediator is tracking by adding the first goal literal // and removing the second. public void ExpandInitialStateAndSwapProblemGoalLiteral(IPredicate newInitLiteral, IPredicate newGoalLiteral, IPredicate goalLiteralToRemove) { // Update the goal literals accordingly. if (this.problem.Goal.Contains(goalLiteralToRemove)) { this.problem.Goal.Remove(goalLiteralToRemove); } if (!this.problem.Goal.Contains(newGoalLiteral)) { this.problem.Goal.Add(newGoalLiteral); } // Update the initial literal this.state = this.state.AddLiteralToState(newInitLiteral); this.problem.Initial = this.state.Predicates; // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
protected override void UpdatePlan() { if (incoming != null) { if (incoming.ActionType.Equals(ActionType.Exceptional)) { Superposition super = state as Superposition; foreach (State current in super.States) { plan = PlannerInterface.Plan(Planner.FastDownward, domain, GetProblem(current)); if (plan.Steps.Count > 0) { return; } } } else if (incoming.ActionType.Equals(ActionType.Constituent)) { plan = plan.GetPlanUpdate(problem, incoming.Action as Operator); } } else { Superposition super = state as Superposition; foreach (State current in super.States) { plan = PlannerInterface.Plan(Planner.FastDownward, domain, GetProblem(current)); if (plan.Steps.Count > 0) { return; } } } }
// Updates the planning problem this mediator is tracking by removing the given literal from the problem's goal state. public void ContractGoalState(IPredicate goalLiteralToRemove) { // Update the goal literals accordingly. if (this.problem.Goal.Contains(goalLiteralToRemove)) { this.problem.Goal.Remove(goalLiteralToRemove); } // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
// Updates the planning problem this mediator is tracking by adding the given literal to the problem's goal state. public void ExpandGoalState(IPredicate newGoalStateLiteral) { // Add the literal to the goal state. if (!this.problem.Goal.Contains(newGoalStateLiteral)) { this.problem.Goal.Add(newGoalStateLiteral); } // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
// Updates the planning problem this mediator is tracking by adding the given literal to the problem's init state. public void ExpandInitialState(IPredicate newInitLiteral) { // Update the current world state. this.state = this.state.AddLiteralToState(newInitLiteral); // Update the initial state. this.problem.Initial = this.state.Predicates; // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
/// <summary> /// Given a planner, a mediation tree node, and a mediation tree, return an event revision plan and state to set for the node. /// </summary> /// <param name="planner">The planner to use.</param> /// <param name="node">The current node in the mediation tree.</param> /// <param name="tree">The mediation tree.</param> /// <returns>A plan state pair for the current node.</returns> public static void EventRevision(Planner planner, MediationTreeNode node, MediationTree tree) { // Compute the event revision problem and domain for the current node. Tuple <Domain, Problem> pair = GetEventRevisionPair(node, tree); // Use the planner to find an event revision plan. Plan plan = PlannerInterface.Plan(planner, pair.First, pair.Second); if (plan.Steps.Count > 0) { Tuple <Plan, State> planState = GetPlanStatePair(plan, node, tree); node.Plan = planState.First; node.State = planState.Second; node.Problem.Initial = node.State.Predicates; } }
// Updates the planning problem this mediator is tracking by removing the first literal and adding the second // literal from/to the problem's initial state. public void SwapProblemInitialStateLiterals(IPredicate initLiteralToRemove, IPredicate initLiteralToAdd) { // Remove the first literal. this.state = this.state.RemoveLiteralFromState(initLiteralToRemove); // Add the second literal. this.state = this.state.AddLiteralToState(initLiteralToAdd); // Update the initial state. this.problem.Initial = this.state.Predicates; // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); }
protected virtual void UpdatePlan() { if (incoming != null) { if (incoming.ActionType.Equals(ActionType.Exceptional)) { plan = PlannerInterface.Plan(Planner.FastDownward, domain, problem); } else if (incoming.ActionType.Equals(ActionType.Constituent)) { plan = plan.GetPlanUpdate(problem, incoming.Action as Operator); } } else { plan = PlannerInterface.Plan(Planner.FastDownward, domain, problem); } }
// Updates the planning problem this mediator is tracking with two new literals, // one new literal for the initial state and one for the goal state. public void ExpandProblem(IPredicate newInitLiteral, IPredicate newGoalLiteral) { // Update the current world state. this.state = this.state.AddLiteralToState(newInitLiteral); // Update the initial state. this.problem.Initial = this.state.Predicates; // Update the goal state. this.problem.Goal.Add(newGoalLiteral); // Force the system to come up with a new plan that includes all new information. this.plan = PlannerInterface.Plan(Mediation.Enums.Planner.SIWthenBFS, this.domain, this.problem); // Trigger a no-op for the player to give the system the first chance to respond. PlayerUpdate("(donothing " + this.problem.Player + ")"); // FIXME: The above "no-op" action should be encoded as part of the system's internals, // but it is currently dependent on the planning domain file. }
public static void DomainRevision(Planner planner, MediationTreeNode node, MediationTree tree) { // Store the incoming action. Operator incoming = node.Incoming.Action as Operator; // Create a new plan object. Plan newPlan = new Plan(); List <Tuple <Operator, State> > knowledge = EventRevisor.GetWorldKnowledge(tree.Player, node, tree); knowledge.RemoveAt(knowledge.Count - 1); List <Operator> observedActions = new List <Operator>(); foreach (Tuple <Operator, State> pair in knowledge) { if (pair.First != null) { if (pair.First.Name.Equals(incoming.Name)) { observedActions.Add(pair.First); } } } // Examine each exceptional effect. foreach (Predicate effect in incoming.ExceptionalEffects) { // Create a new domain object. Domain newDomain = node.Domain.Clone() as Domain; newDomain.Operators = new List <IOperator>(); // If the current effect is conditional... if (incoming.IsConditional(effect)) { bool observed = false; // If the conditional effect has not been observed by the player. foreach (Operator action in observedActions) { if (!observed) { foreach (IAxiom conditional in action.Conditionals) { if (conditional.Effects.Contains(effect) && !observed) { observed = true; } } } } // Remove the conditional effect from the domain. if (!observed) { // Copy the current operator templates into a list. List <IOperator> templates = new List <IOperator>(); foreach (IOperator templ in node.Domain.Operators) { templates.Add(templ.Clone() as IOperator); } // Create a clone of the incoming action's unbound operator template. IOperator temp = incoming.Template() as Operator; // Find the incoming action template in the domain list. Operator template = templates.Find(t => t.Equals(temp)) as Operator; // Remove the incoming action template from the domain list. templates.Remove(template); // Create a clone of the incoming action. Operator clone = incoming.Clone() as Operator; // Create a list of conditional effects to remove from the template. List <IAxiom> remove = new List <IAxiom>(); foreach (IAxiom conditional in clone.Conditionals) { if (conditional.Effects.Contains(effect)) { remove.Add(conditional); } } // Remove each conditional effect from the template. foreach (IAxiom rem in remove) { template.Conditionals.Remove(rem.Template() as IAxiom); } // Add the modified template to the domain list. templates.Add(template); // Push the modified list to the new domain object. newDomain.Operators = templates; // Clone the modified incoming action template. Operator newAction = template.Clone() as Operator; // Bind the cloned action with the incoming action's bindings. newAction.Bindings = incoming.Bindings; MediationTreeEdge newEdge = new MediationTreeEdge(newAction, ActionType.Exceptional, node.Incoming.Parent, node.ID); Problem newProblem = node.Problem.Clone() as Problem; newProblem.Initial = tree.GetSuccessorState(newEdge).Predicates; // Find a new plan. newPlan = PlannerInterface.Plan(planner, newDomain, newProblem); // If the modified domain can accommodate the player's action... if (newPlan.Steps.Count > 0) { node.Plan = newPlan; node.Incoming.Action = newAction; node.State = tree.GetSuccessorState(node.Incoming); node.Domain = newDomain; } } } } }
// Use this for initialization void Start( ) { // Set the path to the top directory. Parser.path = Directory.GetParent(Application.dataPath).FullName + "/"; // Parse the domain and problem files, and get the initial plan. domain = Parser.GetDomain(Parser.GetTopDirectory() + @"Benchmarks/" + domainName + @"/domain.pddl", PlanType.StateSpace); problem = Parser.GetProblem(Parser.GetTopDirectory() + @"Benchmarks/" + domainName + "/" + problemName + ".pddl"); plan = PlannerInterface.Plan(planner, domain, problem); // A test for the planner. if (plan.Steps.Count > 0) { Debug.Log("System loaded."); } else { Debug.Log("System not working or no plan exists."); } state = plan.GetFirstState(); // Find the first state. validState = true; // Initialize the valid state. GameObject level = GameObject.Find("Level"); // Find the level game object. stateManager = level.GetComponent <StateManager>(); // Set the state manager. stateManager.Problem = problem; stateManager.Predicates = state.Predicates; // Set the state manager's predicates. generator = level.GetComponent <MapManager>(); // Set the level generator. generator.CreateLevel(); // Generate the level. // Create the initial node of mediation. root = StateSpaceMediator.BuildTree(planner, domain, problem, plan, state, 0); frontier = new Hashtable(); // Initialize the frontier. frontierThread = new Thread(ExpandFrontier); // Expand the frontier in a new thread. frontierThread.Start(); // Start the thread. // Initialize the player's environment model and action log. playerEnvironmentModel = new EnvironmentModel(stateManager.PlayerName, domain, problem); actionLog = new List <Tuple <string, string> >(); // Initialize the player log with a decent size. playerLog = new Queue <IOperator>(3 * plan.Steps.Count); #region Initialize the Experiment // Generate the participant's ID participantIDGenerator = new RNGCryptoServiceProvider(); byte[] idBytes = new byte[4]; participantIDGenerator.GetBytes(idBytes); participantID = BitConverter.ToInt32(idBytes, 0); PlayerPrefs.SetInt("participantID", participantID); // Compute and create the participant's output folder. participantFolder = Parser.GetTopDirectory() + @"Benchmarks/" + domain.Name.ToLower() + @"/output/" + participantID + @"/"; Directory.CreateDirectory(participantFolder); playerTurnCounter = 0; #endregion // Start the wizard conversation. DialogueManager.StartConversation("Wizard"); }
// Creates a child node. private static StateSpaceNode CreateChild(Planner planner, Domain domain, Problem problem, Plan plan, State state, StateSpaceEdge edge) { // Create a new problem object. Problem newProblem = new Problem(); // Create a new domain object. Domain newDomain = domain; // Create a new plan object. Plan newPlan = new Plan(); // Store actions the system takes. List <IOperator> systemActions = new List <IOperator>(); // If the outgoing action is an exceptional step... if (edge.ActionType == ActionType.Exceptional) { // Count the exceptional edge. Exceptional++; // Create a new problem object. newProblem = NewProblem(newDomain, problem, state, edge.Action); // Find a new plan. newPlan = PlannerInterface.Plan(planner, newDomain, newProblem); // If the action was accommodated and the first step of the new plan isn't taken by the player... if (newPlan.Steps.Count > 0) { // Add the action to the system action list. systemActions = GetSystemActions(newPlan, new List <string> { problem.Player }, new List <IOperator>()); // Update the problem object with the system's next move. newProblem = NewProblem(newDomain, newProblem, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), systemActions); // Update the plan with the system's next move. newPlan = newPlan.GetPlanUpdate(newProblem, systemActions); } else if (CEDeletion) { // Try to find a domain revision alibi. Tuple <Domain, Operator> alibi = ReviseDomain(planner, newDomain, problem, state, edge.Action as Operator); // If domain revision worked. if (alibi != null) { // Remember the new domain. newDomain = alibi.First; // Push the modified action to the edge object. edge.Action = alibi.Second; // Create a new problem object. newProblem = NewProblem(newDomain, problem, state, edge.Action); // Find a new plan. newPlan = PlannerInterface.Plan(planner, newDomain, newProblem); // Add the action to the system action list. systemActions = GetSystemActions(newPlan, new List <string> { problem.Player }, new List <IOperator>()); // Update the problem object with the system's next move. newProblem = NewProblem(newDomain, newProblem, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), systemActions); // Update the plan with the system's next move. newPlan = newPlan.GetPlanUpdate(newProblem, systemActions); } } } // Otherwise, if the action is a consistent step... else if (edge.ActionType == ActionType.Consistent) { // Count the consistent edge. Consistent++; // Create a new problem object. newProblem = NewProblem(newDomain, problem, state, edge.Action); // Add the action to the system action list. systemActions = GetSystemActions(plan, new List <string> { problem.Player }, new List <IOperator>()); // Create a new state. State newState = new State(newProblem.Initial, state.nextStep, (Operator)plan.Steps.First()); // Create a new problem object. newProblem = NewProblem(newDomain, newProblem, newState, systemActions); // Create a new plan. newPlan = plan.GetPlanUpdate(newProblem, systemActions); } // Otherwise, the action is a constituent step... else { // Count the constituent edge. Constituent++; // If there are effects of the constituent action... if (edge.Action.Effects.Count > 0) { // Create a new problem object. newProblem = NewProblem(newDomain, problem, state, edge.Action); // Create a new plan. newPlan = plan.GetPlanUpdate(newProblem, edge.Action as Operator); } // Otherwise, initialize to the old problem and plan... else { newProblem = problem; newPlan = plan.Clone() as Plan; } // If there are still plan actions... if (newPlan.Steps.Count > 0) { // Add the action to the system action list. systemActions = GetSystemActions(newPlan, new List <string> { problem.Player }, new List <IOperator>()); // Update the problem object with the system's next move. newProblem = NewProblem(newDomain, newProblem, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), systemActions); // Update the plan with the system's next move. newPlan = newPlan.GetPlanUpdate(newProblem, systemActions); } } // Add the system actions to the current edge. edge.SystemActions = systemActions; // Create an empty child node. StateSpaceNode child = null; // If there are remaining plan steps... if (newPlan.Steps.Count > 0) { // Build a new tree using the first step of the plan as the next step. child = StateSpaceSearchTools.CreateNode(planner, newDomain, newProblem, newPlan, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First())); } else { // Terminate the tree by adding a goal node. child = StateSpaceSearchTools.CreateNode(planner, newDomain, newProblem, newPlan, new State(newProblem.Initial, newPlan.InitialStep, newPlan.GoalStep)); } // Store the system actions. child.systemActions = systemActions; // Record the action that triggered the node's generation. child.incoming = edge; return(child); }
// Expand an edge. public static StateSpaceNode ExpandTree(Planner planner, Domain domain, Problem problem, Plan plan, State state, StateSpaceEdge edge, int depth) { // Create a new problem object. Problem newProblem = new Problem(); // Create a new plan object. Plan newPlan = new Plan(); // Store actions the system takes. List <IOperator> systemActions = new List <IOperator>(); // If the action is an exceptional step... if (edge.ActionType == ActionType.Exceptional) { // Count the exceptional edge. Exceptional++; // Create a new problem object. newProblem = NewProblem(domain, problem, state, edge.Action); // Find a new plan. newPlan = PlannerInterface.Plan(planner, domain, newProblem); // If the action was accommodated and the first step of the new plan isn't taken by the player... if (newPlan.Steps.Count > 0) { // Add the action to the system action list. systemActions = GetSystemActions(newPlan, new List <string> { problem.Player }, new List <IOperator>()); // Update the problem object with the system's next move. newProblem = NewProblem(domain, newProblem, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), systemActions); // Update the plan with the system's next move. newPlan = newPlan.GetPlanUpdate(newProblem, systemActions); } else if (CEDeletion) { StateSpaceNode alibi = GenerateAlibi(planner, domain, problem, plan, state, edge, depth); if (alibi != null) { return(alibi); } } } // Otherwise, if the action is a consistent step... else if (edge.ActionType == ActionType.Consistent) { // Count the consistent edge. Consistent++; // Create a new problem object. newProblem = NewProblem(domain, problem, state, edge.Action); // Add the action to the system action list. systemActions = GetSystemActions(plan, new List <string> { problem.Player }, new List <IOperator>()); // Create a new state. State newState = new State(newProblem.Initial, state.nextStep, (Operator)plan.Steps.First()); // Create a new problem object. newProblem = NewProblem(domain, newProblem, newState, systemActions); // Create a new plan. newPlan = plan.GetPlanUpdate(newProblem, systemActions); } // Otherwise, the action is a constituent step... else { // Count the constituent edge. Constituent++; // If there are effects of the constituent action... if (edge.Action.Effects.Count > 0) { // Create a new problem object. newProblem = NewProblem(domain, problem, state, edge.Action); // Create a new plan. newPlan = plan.GetPlanUpdate(newProblem, edge.Action as Operator); } // Otherwise, initialize to the old problem and plan... else { newProblem = problem; newPlan = plan.Clone() as Plan; } // If there are still plan actions... if (newPlan.Steps.Count > 0) { // Add the action to the system action list. systemActions = GetSystemActions(newPlan, new List <string> { problem.Player }, new List <IOperator>()); // Update the problem object with the system's next move. newProblem = NewProblem(domain, newProblem, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), systemActions); // Update the plan with the system's next move. newPlan = newPlan.GetPlanUpdate(newProblem, systemActions); } } // Add the system actions to the current edge. edge.SystemActions = systemActions; // Create an empty child node. StateSpaceNode child = null; // If there are remaining plan steps... if (newPlan.Steps.Count > 0) { // Build a new tree using the first step of the plan as the next step. child = BuildTree(planner, domain, newProblem, newPlan, new State(newProblem.Initial, newPlan.InitialStep, (Operator)newPlan.Steps.First()), depth - 1); } else { // Terminate the tree by adding a goal node. child = BuildTree(planner, domain, newProblem, newPlan, new State(newProblem.Initial, newPlan.InitialStep, newPlan.GoalStep), depth - 1); } // Store the system actions. child.systemActions = systemActions; // Record the action that triggered the node's generation. child.incoming = edge; return(child); }
// Revises a domain to remove any possible exceptional conditional effect. public static Tuple <Domain, Operator> ReviseDomain(Planner planner, Domain domain, Problem problem, State state, Operator incoming) { // Create a new plan object. Plan newPlan = new Plan(); // Examine each exceptional effect. foreach (Predicate effect in incoming.ExceptionalEffects) { // Create a new domain object. Domain newDomain = new Domain(); // Save the domain's name. newDomain.Name = domain.Name; newDomain.staticStart = domain.staticStart; // If the current effect is conditional... if (incoming.IsConditional(effect)) { // If the conditional effect has not been observed by the player. // Remove the conditional effect from the domain. // Copy the current operator templates into a list. List <IOperator> templates = new List <IOperator>(); foreach (IOperator templ in domain.Operators) { templates.Add(templ.Clone() as IOperator); } // Create a clone of the incoming action's unbound operator template. IOperator temp = incoming.Template() as Operator; // Find the incoming action template in the domain list. Operator template = templates.Find(t => t.Equals(temp)) as Operator; // Remove the incoming action template from the domain list. templates.Remove(template); // Create a clone of the incoming action. Operator clone = incoming.Clone() as Operator; // Create a list of conditional effects to remove from the template. List <IAxiom> remove = new List <IAxiom>(); foreach (IAxiom conditional in clone.Conditionals) { if (conditional.Effects.Contains(effect)) { remove.Add(conditional); } } // Remove each conditional effect from the template. foreach (IAxiom rem in remove) { template.Conditionals.Remove(rem.Template() as IAxiom); } // Add the modified template to the domain list. templates.Add(template); // Push the modified list to the new domain object. newDomain.Operators = templates; // Write new problem and domain files. Writer.ProblemToPDDL(Parser.GetTopDirectory() + @"Benchmarks/" + domain.Name.ToLower() + @"/probrob.pddl", newDomain, problem, state.Predicates); Writer.DomainToPDDL(Parser.GetTopDirectory() + @"Benchmarks/" + domain.Name.ToLower() + @"/domrob.pddl", newDomain); // Find a new plan. newPlan = PlannerInterface.Plan(planner, newDomain, problem); // If the modified domain can accommodate the player's action... if (newPlan.Steps.Count > 0) { // Clone the modified incoming action template. Operator newAction = template.Clone() as Operator; // Bind the cloned action with the incoming action's bindings. newAction.Bindings = incoming.Bindings; // Expand the tree using the new domain. return(new Tuple <Domain, Operator> (newDomain, newAction)); } } } return(null); }
/// <summary> /// Chooses a set of superposed states based on a simple utility function. /// </summary> /// <param name="observations">The sets of possible literals observed by the player mapped to the sets of states consistent with each observation.</param> /// <param name="node">The current node in the mediation tree.</param> /// <returns>A set of states chosen by the system.</returns> public static HashSet <State> ChooseUtility(Dictionary <List <IPredicate>, HashSet <State> > observations, MediationTreeNode node) { // Create a dictionary of utilities that map to sets of states. Dictionary <float, HashSet <State> > utilities = new Dictionary <float, HashSet <State> >(); // If there is more than one observation the player can make. if (observations.Keys.Count > 1) { // Loop through each set of observed literals. foreach (List <IPredicate> key in observations.Keys) { // Store how many wins and losses the set of states has. float wins = 0; float losses = 0; // Loop through each state in the set of states consistent with the current observation. foreach (State state in observations[key]) { // Store whether we are at a goal state. bool satisfiesGoal = false; // Store whether a goal state is reached by the planner. bool win = true; // Check whether the current state is a goal state. if (state.Satisfies(node.Problem.Goal)) { satisfiesGoal = true; } // Create a new problem object for the current state. Problem problem = new Problem("rob", node.Problem.OriginalName, node.Problem.Domain, node.Problem.Player, node.Problem.Objects, state.Predicates, node.Problem.Intentions, node.Problem.Goal); // Find a plan from the current state if one exists. Plan plan = PlannerInterface.Plan(Planner.FastDownward, node.Domain, problem); // Check if a goal has been reached by the state or the plan. if (plan.Steps.Count == 0 && !satisfiesGoal) { win = false; } // Record the win or loss. if (win) { wins++; } else { losses++; } } // Initialize the utility. float utility = 0; // If none of the states lost, go ahead and return the current state. if (losses == 0) { return(observations[key]); } // Otherwise, record the utility as wins divided by losses. else { utility = wins / losses; } // Map the utility onto the current state set in the dictionary. utilities[utility] = observations[key]; } } else { // Store the single set of observations. List <IPredicate> key = observations.Keys.ToArray()[0]; // Use the observations to return the single set of states. return(observations[key]); } // Return the set of states with the highest utility value. return(utilities[utilities.Keys.Max()]); }