mirror of
https://github.com/lscharen/iigs-sprite-compiler.git
synced 2024-08-31 18:29:06 +00:00
Clean up test framework a bit
This commit is contained in:
parent
69599c5643
commit
b1a3bd8f4e
@ -8,6 +8,19 @@ namespace AI.Test
|
|||||||
{
|
{
|
||||||
public static class DirectionExtensions
|
public static class DirectionExtensions
|
||||||
{
|
{
|
||||||
|
public static bool IsOppositeOf(this Direction direction, Direction otherDirection)
|
||||||
|
{
|
||||||
|
switch (direction)
|
||||||
|
{
|
||||||
|
case Direction.LEFT: return otherDirection.Equals(Direction.RIGHT);
|
||||||
|
case Direction.RIGHT: return otherDirection.Equals(Direction.LEFT);
|
||||||
|
case Direction.UP: return otherDirection.Equals(Direction.DOWN);
|
||||||
|
case Direction.DOWN: return otherDirection.Equals(Direction.UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool CanMove(this Direction direction, int p)
|
public static bool CanMove(this Direction direction, int p)
|
||||||
{
|
{
|
||||||
switch (direction)
|
switch (direction)
|
||||||
@ -45,6 +58,9 @@ namespace AI.Test
|
|||||||
|
|
||||||
public class EightPuzzleBoard
|
public class EightPuzzleBoard
|
||||||
{
|
{
|
||||||
|
// The goal state is the canonical end state
|
||||||
|
public static EightPuzzleBoard GOAL = new EightPuzzleBoard();
|
||||||
|
|
||||||
protected static Random rng = new Random();
|
protected static Random rng = new Random();
|
||||||
|
|
||||||
|
|
||||||
@ -75,14 +91,16 @@ namespace AI.Test
|
|||||||
public EightPuzzleBoard Scramble(int n)
|
public EightPuzzleBoard Scramble(int n)
|
||||||
{
|
{
|
||||||
var newPuzzle = new EightPuzzleBoard(this);
|
var newPuzzle = new EightPuzzleBoard(this);
|
||||||
var direction = Enum.GetValues(typeof(Direction)).Cast<Direction>().ToList();
|
var directions = Enum.GetValues(typeof(Direction)).Cast<Direction>().ToList();
|
||||||
|
var lastDirection = Direction.DOWN;
|
||||||
|
|
||||||
for (int i = 0; i < n;)
|
for (int i = 0; i < n;)
|
||||||
{
|
{
|
||||||
int j = rng.Next(direction.Count);
|
var direction = directions[rng.Next(directions.Count)];
|
||||||
if (newPuzzle.CanMoveGap(direction[j]))
|
if (newPuzzle.CanMoveGap(direction) && (i == 0 || !direction.IsOppositeOf(lastDirection)))
|
||||||
{
|
{
|
||||||
newPuzzle.MoveGap(direction[j]);
|
newPuzzle.MoveGap(direction);
|
||||||
|
lastDirection = direction;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,9 @@ namespace AI.Test
|
|||||||
|
|
||||||
public class EightPuzzleStepCost : IStepCostFunction<Direction, EightPuzzleBoard, IntegerCost>
|
public class EightPuzzleStepCost : IStepCostFunction<Direction, EightPuzzleBoard, IntegerCost>
|
||||||
{
|
{
|
||||||
private static readonly IntegerCost UNIT_STEP_COST = (IntegerCost) 1;
|
|
||||||
|
|
||||||
public IntegerCost StepCost(EightPuzzleBoard fromState, Direction action, EightPuzzleBoard toState)
|
public IntegerCost StepCost(EightPuzzleBoard fromState, Direction action, EightPuzzleBoard toState)
|
||||||
{
|
{
|
||||||
return UNIT_STEP_COST;
|
return IntegerCost.ONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,18 +114,15 @@ namespace AI.Test
|
|||||||
private ISearchProblem<Direction, EightPuzzleBoard, IntegerCost> problem_h1;
|
private ISearchProblem<Direction, EightPuzzleBoard, IntegerCost> problem_h1;
|
||||||
private ISearchProblem<Direction, EightPuzzleBoard, IntegerCost> problem_h2;
|
private ISearchProblem<Direction, EightPuzzleBoard, IntegerCost> problem_h2;
|
||||||
|
|
||||||
// Define the goal state
|
|
||||||
private EightPuzzleBoard goal = new EightPuzzleBoard(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 });
|
|
||||||
|
|
||||||
[TestInitialize]
|
[TestInitialize]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
// These objects define the abstract search problem
|
// These objects define the abstract search problem
|
||||||
var goalTest = new EightPuzzleGoalTest(goal);
|
var goalTest = new EightPuzzleGoalTest(EightPuzzleBoard.GOAL);
|
||||||
var stepCost = new EightPuzzleStepCost();
|
var stepCost = new EightPuzzleStepCost();
|
||||||
var successorFn = new EightPuzzleSuccessorFunction();
|
var successorFn = new EightPuzzleSuccessorFunction();
|
||||||
var heuristic1 = new MisplacedHeuristic(goal);
|
var heuristic1 = new MisplacedHeuristic(EightPuzzleBoard.GOAL);
|
||||||
var heuristic2 = new ManhattanHeuristic(goal);
|
var heuristic2 = new ManhattanHeuristic(EightPuzzleBoard.GOAL);
|
||||||
|
|
||||||
// Create three search problem objects. One without a heuristic and two with the different
|
// Create three search problem objects. One without a heuristic and two with the different
|
||||||
// heuristics
|
// heuristics
|
||||||
@ -136,11 +131,31 @@ namespace AI.Test
|
|||||||
problem_h2 = new SearchProblem<Direction, EightPuzzleBoard, IntegerCost>(goalTest, stepCost, successorFn, heuristic2);
|
problem_h2 = new SearchProblem<Direction, EightPuzzleBoard, IntegerCost>(goalTest, stepCost, successorFn, heuristic2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
private void PrintSolution(IEnumerable<EightPuzzleNode> solution)
|
||||||
public void TestMethod1()
|
|
||||||
{
|
{
|
||||||
int N = 1;
|
if (solution == null)
|
||||||
int dmax = 3;
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine("No solution");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Diagnostics.Trace.WriteLine(solution.First().State.ToString());
|
||||||
|
foreach (var node in solution.Skip(1))
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine("");
|
||||||
|
System.Diagnostics.Trace.WriteLine(node.Action.ToString());
|
||||||
|
System.Diagnostics.Trace.WriteLine(node.State.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void EightPuzzleTest()
|
||||||
|
{
|
||||||
|
// Number of trials to run
|
||||||
|
int N = 10;
|
||||||
|
|
||||||
|
// Maximum depth of the solution
|
||||||
|
int dmax = 6;
|
||||||
|
|
||||||
// Now we define the search algorithm and the type of node expansion. Russell & Norvig discuss
|
// Now we define the search algorithm and the type of node expansion. Russell & Norvig discuss
|
||||||
// two type of expansion strategies: tree search and graph search. One will avoid cycles in the search
|
// two type of expansion strategies: tree search and graph search. One will avoid cycles in the search
|
||||||
@ -149,51 +164,61 @@ namespace AI.Test
|
|||||||
// They state that a tree search was used to generate Figure 4.8;
|
// They state that a tree search was used to generate Figure 4.8;
|
||||||
var expander = new InstrumentedNodeExpander<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(new EightPuzzleNodeExpander());
|
var expander = new InstrumentedNodeExpander<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(new EightPuzzleNodeExpander());
|
||||||
var treeSearch = new TreeSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(expander);
|
var treeSearch = new TreeSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(expander);
|
||||||
|
|
||||||
var ids = new IterativeDeepeningSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, dmax);
|
var ids = new IterativeDeepeningSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, dmax);
|
||||||
var aStarH1 = new AStarSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, new QueueAdapter<EightPuzzleNode, IntegerCost>());
|
var aStarH1 = new AStarSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, new QueueAdapter<EightPuzzleNode, IntegerCost>());
|
||||||
var aStarH2 = new IterativeDeepeningAStarSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, (IntegerCost)dmax);
|
var aStarH2 = new IterativeDeepeningAStarSearch<Direction, EightPuzzleBoard, EightPuzzleNode, IntegerCost>(treeSearch, (IntegerCost)dmax);
|
||||||
|
|
||||||
// Depth runs from 0 to dmax
|
// Depth runs from 0 to dmax
|
||||||
int[,] d = new int[dmax + 2, 3];
|
int[,] d = new int[dmax + 1, 3];
|
||||||
int[,] n = new int[dmax + 2, 3];
|
int[,] n = new int[dmax + 1, 3];
|
||||||
|
|
||||||
|
for (int _d = 1; _d <= dmax; _d++)
|
||||||
|
{
|
||||||
for (int i = 0; i < N; i++)
|
for (int i = 0; i < N; i++)
|
||||||
{
|
{
|
||||||
// Invoke the search on the problem with a particular starting state
|
// Invoke the search on the problem with a particular starting state. Scramble creates a new instance
|
||||||
var initialState = goal.Scramble(dmax);
|
var initialState = EightPuzzleBoard.GOAL.Scramble(_d);
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
{
|
||||||
expander.ClearMetrics();
|
expander.ClearMetrics();
|
||||||
var solution = ids.Search(problem_none, initialState);
|
var solution = ids.Search(problem_none, new EightPuzzleBoard(initialState));
|
||||||
System.Diagnostics.Trace.WriteLine("IDS Solution has " + solution.Count() + " nodes and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
var depth = solution.Count() - 1;
|
||||||
d[solution.Count(), 0] += 1;
|
|
||||||
n[solution.Count(), 0] += expander[IntrumentedParameters.NODES_EXPANDED];
|
System.Diagnostics.Trace.WriteLine("IDS Solution has depth " + depth + " and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
||||||
|
d[depth, 0] += 1;
|
||||||
|
n[depth, 0] += expander[IntrumentedParameters.NODES_EXPANDED];
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
expander.ClearMetrics();
|
expander.ClearMetrics();
|
||||||
var solution = aStarH1.Search(problem_h1, initialState);
|
var solution = aStarH1.Search(problem_h1, new EightPuzzleBoard(initialState));
|
||||||
System.Diagnostics.Trace.WriteLine("A* (h1) Solution has " + solution.Count() + " nodes and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
var depth = solution.Count() - 1;
|
||||||
d[solution.Count(), 1] += 1;
|
|
||||||
n[solution.Count(), 1] += expander[IntrumentedParameters.NODES_EXPANDED];
|
System.Diagnostics.Trace.WriteLine("A* (h1) Solution has depth " + depth + " nodes and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
||||||
}
|
d[depth, 1] += 1;
|
||||||
*/
|
n[depth, 1] += expander[IntrumentedParameters.NODES_EXPANDED];
|
||||||
{
|
|
||||||
expander.ClearMetrics();
|
// PrintSolution(solution);
|
||||||
var solution = aStarH2.Search(problem_h2, initialState);
|
|
||||||
System.Diagnostics.Trace.WriteLine("A* (h2) Solution has " + solution.Count() + " nodes and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
|
||||||
d[solution.Count(), 2] += 1;
|
|
||||||
n[solution.Count(), 2] += expander[IntrumentedParameters.NODES_EXPANDED];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
expander.ClearMetrics();
|
||||||
|
var solution = aStarH2.Search(problem_h2, new EightPuzzleBoard(initialState));
|
||||||
|
var depth = solution.Count() - 1;
|
||||||
|
|
||||||
|
System.Diagnostics.Trace.WriteLine("A* (h2) Solution has depth " + depth + " nodes and expanded " + expander[IntrumentedParameters.NODES_EXPANDED] + " nodes");
|
||||||
|
d[depth, 2] += 1;
|
||||||
|
n[depth, 2] += expander[IntrumentedParameters.NODES_EXPANDED];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Trace.WriteLine("| Search Cost Branching Factor |");
|
Trace.WriteLine("| Search Cost Branching Factor |");
|
||||||
Trace.WriteLine("+--+---------+--------+--------++---------+--------+--------+");
|
Trace.WriteLine("+--+---------+--------+--------++---------+--------+--------+");
|
||||||
Trace.WriteLine("| d| IDS | A*(h1) | A*(h2) || IDS | A*(h1) | A*(h2) |");
|
Trace.WriteLine("| d| IDS | A*(h1) | A*(h2) || IDS | A*(h1) | A*(h2) |");
|
||||||
Trace.WriteLine("+--+---------+--------+--------++---------+--------+--------+");
|
Trace.WriteLine("+--+---------+--------+--------++---------+--------+--------+");
|
||||||
|
|
||||||
for (int i = 0; i <= dmax + 1; i++)
|
for (int i = 0; i <= dmax; i++)
|
||||||
{
|
{
|
||||||
var bf0 = ComputeBranchingFactor((float)n[i, 0] / (float)d[i, 0], i);
|
var bf0 = ComputeBranchingFactor((float)n[i, 0] / (float)d[i, 0], i);
|
||||||
var bf1 = ComputeBranchingFactor((float)n[i, 1] / (float)d[i, 1], i);
|
var bf1 = ComputeBranchingFactor((float)n[i, 1] / (float)d[i, 1], i);
|
||||||
|
Loading…
Reference in New Issue
Block a user