public TowerOfHanoiTest() { // S ==> S // M ==> M // L ==> L // A B C // // Peg = {A,B,C} // Disc = {S,M,L} hanoiDomain = new Domain().BuildLogic((domain, state) => { state.Relations.Add(new Tuple<string, string, string>("Object Relation", "Disc Small", "Disc Medium")); state.Relations.Add(new Tuple<string, string, string>("Object Relation", "Disc Medium", "Disc Large")); state.Relations.Add(new Tuple<string, string, string>("Object Relation", "Disc Large", "Peg A")); Dictionary<string, int> ObjectRelativeOrder = new Dictionary<string, int>() { {"Peg A", 0}, {"Peg B", 0}, {"Peg C", 0}, {"Disc Large", 1}, {"Disc Medium", 2}, {"Disc Small", 3} }; Func<string, string, bool> IsValidConfiguration = (above, below) => { return (ObjectRelativeOrder[above] > ObjectRelativeOrder[below]); }; Func<State, string, string> PeekStack = (State s, string peg) => { string item = null; bool abort = false; while (!abort) { try { peg = s.Relations.Find(rel => rel.Item1 == "Object Relation" && rel.Item3 == peg).Item2; item = peg; } catch { abort = true; } } if (item == null) return peg; return item; }; Func<State, string, string, bool> IsValidMove = (State st, string fromPeg, string toPeg) => { var itemToBeMoved = PeekStack(st, fromPeg); // Only discs can be moved. if (!itemToBeMoved.Contains("Disc")) return false; return IsValidConfiguration(itemToBeMoved, PeekStack(st, toPeg)); }; Func<State, string, string, string> PopStack = (State s, string peg, string ontop) => { string item = null; while (peg != null) { try { peg = s.Relations.Find(rel => rel.Item1 == "Object Relation" && rel.Item3 == peg).Item2; item = peg; } catch { peg = null; } } s.Relations.Remove(s.Relations.Find(rel => rel.Item1 == "Object Relation" && rel.Item2 == item)); return item; }; Action<State, string, string> PushStack = (State st, string disc, string toPeg) => { st.Relations.Add(new Tuple<string, string, string>("Object Relation", disc, PeekStack(st, toPeg))); }; Action<State, string, string> MoveItem = (State s, string fromPeg, string toPeg) => { PushStack(s, PopStack(s, fromPeg, null), toPeg); }; state.PlanningActions.Add(new PlanningAction("Move A to B") .AssignPrejudicate(st => IsValidMove(st, "Peg A", "Peg B")) .AssignPostAction(st => MoveItem(st, "Peg A", "Peg B")) ); state.PlanningActions.Add(new PlanningAction("Move A to C") .AssignPrejudicate(st => IsValidMove(st, "Peg A", "Peg C")) .AssignPostAction(st => MoveItem(st, "Peg A", "Peg C")) ); state.PlanningActions.Add(new PlanningAction("Move B to A") .AssignPrejudicate(st => IsValidMove(st, "Peg B", "Peg A")) .AssignPostAction(st => MoveItem(st, "Peg B", "Peg A")) ); state.PlanningActions.Add(new PlanningAction("Move B to C") .AssignPrejudicate(st => IsValidMove(st, "Peg B", "Peg C")) .AssignPostAction(st => MoveItem(st, "Peg B", "Peg C")) ); state.PlanningActions.Add(new PlanningAction("Move C to A") .AssignPrejudicate(st => IsValidMove(st, "Peg C", "Peg A")) .AssignPostAction(st => MoveItem(st, "Peg C", "Peg A")) ); state.PlanningActions.Add(new PlanningAction("Move C to B") .AssignPrejudicate(st => IsValidMove(st, "Peg C", "Peg B")) .AssignPostAction(st => MoveItem(st, "Peg C", "Peg B")) ); }).AssignGoal( new Goal("Solve Hanoi").RelationalTarget("Object Relation", "Disc Large", "Peg C") .RelationalTarget("Object Relation", "Disc Medium", "Disc Large") .RelationalTarget("Object Relation", "Disc Small", "Disc Medium") ); }
public void Solve() { puzzle = new Domain().BuildLogic((domain, state) => { // // 01 02 03 04 // 05 06 07 08 // 09 10 11 12 // 13 14 15 // // string[] invalid_north = new string[] { "1", "2", "3", "4" }; string[] invalid_east = new string[] { "4", "8", "12", "16" }; string[] invalid_south = new string[] { "13", "14", "15", "16" }; string[] invalid_west = new string[] { "1", "5", "9", "13" }; Func<State, string> BlankPosition = (st) => { return st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item2 == "Blank").Item3; }; Func<State, bool> CanFlipNorth = (st) => { return !invalid_north.Contains(BlankPosition(st)); }; Func<State, bool> CanFlipEast = (st) => { return !invalid_east.Contains(BlankPosition(st)); }; Func<State, bool> CanFlipSouth = (st) => { return !invalid_south.Contains(BlankPosition(st)); }; Func<State, bool> CanFlipWest = (st) => { return !invalid_west.Contains(BlankPosition(st)); }; Action<State> FlipNorth = (State st) => { var slot = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item2 == "Blank").Item3; int pos = int.Parse(slot); string brick = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos - 4).ToString()).Item2; st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos - 4).ToString())); st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos).ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", brick, pos.ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", "Blank", (pos - 4).ToString())); }; Action<State> FlipEast = (State st) => { var slot = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item2 == "Blank").Item3; int pos = int.Parse(slot); string brick = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos + 1).ToString()).Item2; st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos + 1).ToString())); st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos).ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", brick, pos.ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", "Blank", (pos + 1).ToString())); }; Action<State> FlipSouth = (State st) => { var slot = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item2 == "Blank").Item3; int pos = int.Parse(slot); string brick = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos + 4).ToString()).Item2; st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos + 4).ToString())); st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos).ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", brick, pos.ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", "Blank", (pos + 4).ToString())); }; Action<State> FlipWest = (State st) => { var slot = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item2 == "Blank").Item3; int pos = int.Parse(slot); string brick = st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos - 1).ToString()).Item2; st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos - 1).ToString())); st.Relations.Remove(st.Relations.Find(rel => rel.Item1 == "Board" && rel.Item3 == (pos).ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", brick, pos.ToString())); st.Relations.Add(new Tuple<string, string, string>("Board", "Blank", (pos - 1).ToString())); }; state.PlanningActions.Add(new PlanningAction("Flip North") .AssignPrejudicate(st => CanFlipNorth(st)) .AssignPostAction(st => FlipNorth(st)) ); state.PlanningActions.Add(new PlanningAction("Flip East") .AssignPrejudicate(st => CanFlipEast(st)) .AssignPostAction(st => FlipEast(st)) ); state.PlanningActions.Add(new PlanningAction("Flip South") .AssignPrejudicate(st => CanFlipSouth(st)) .AssignPostAction(st => FlipSouth(st)) ); state.PlanningActions.Add(new PlanningAction("Flip West") .AssignPrejudicate(st => CanFlipWest(st)) .AssignPostAction(st => FlipWest(st)) ); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 1", "1")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 2", "2")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 3", "13")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 4", "12")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 5", "11")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 6", "10")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 7", "9")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 8", "8")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 9", "7")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 10", "6")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 11", "5")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 12", "4")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 13", "3")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 14", "14")); state.Relations.Add(new Tuple<string, string, string>("Board", "Brick 15", "15")); state.Relations.Add(new Tuple<string, string, string>("Board", "Blank", "16")); } ).AssignGoal( new Goal("Solve Puzzle").RelationalTarget("Board", "Brick 15", "16") ); // Todo: write custom goal that uses Manhattan Distance var cg = new CustomGoal().AssignGoal(delegate(State x) { return 0.0; }); var cg2 = new CustomGoal().AssignGoal( state => { return 0.0; }); //puzzle.State.PlanningActions[0].Execute(puzzle.State); IPlan p = new DFSPlan().SetMaxSearchDepth(10); p.Search(puzzle.State, puzzle.Goal); Assert.GreaterOrEqual(puzzle.Goal.Fulfillment(p.GetFinalState()), 1.0); }