diff --git a/SpriteCompiler.Test/SpriteCompiler.Test.csproj b/SpriteCompiler.Test/SpriteCompiler.Test.csproj index 97dd1ed..5a699df 100644 --- a/SpriteCompiler.Test/SpriteCompiler.Test.csproj +++ b/SpriteCompiler.Test/SpriteCompiler.Test.csproj @@ -62,6 +62,7 @@ + diff --git a/SpriteCompiler.Test/StateTests.cs b/SpriteCompiler.Test/StateTests.cs new file mode 100644 index 0000000..9e5d623 --- /dev/null +++ b/SpriteCompiler.Test/StateTests.cs @@ -0,0 +1,32 @@ +using System; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SpriteCompiler.Problem; +using SpriteCompiler.AI; +using System.Diagnostics; +using System.Collections.Generic; +using FluentAssertions; + +namespace SpriteCompiler.Test +{ + [TestClass] + public class StateTests + { + [TestMethod] + public void TestStateEquivalence() + { + // States are used in HashSet, so we need to + // test that two instances of the same state + // are recognized as equivalent + var state1 = new SpriteGeneratorState(); + var state2 = new SpriteGeneratorState(); + + Assert.AreEqual(state1, state2); + + var set = new HashSet(); + set.Add(state1); + + Assert.IsTrue(set.Contains(state2)); + } + } +} diff --git a/SpriteCompiler.Test/Tests.cs b/SpriteCompiler.Test/Tests.cs index 33ab430..a2026ac 100644 --- a/SpriteCompiler.Test/Tests.cs +++ b/SpriteCompiler.Test/Tests.cs @@ -103,8 +103,8 @@ namespace SpriteCompiler.Test // Write out the solution WriteOutSolution(solution); - //Assert.AreEqual(3, solution.Count()); - //Assert.AreEqual(10, (int)solution.Last().PathCost); + Assert.AreEqual(6, solution.Count()); + Assert.AreEqual(25, (int)solution.Last().PathCost); } private void WriteOutSolution(IEnumerable solution) diff --git a/SpriteCompiler/AI/AbstractAISearch.cs b/SpriteCompiler/AI/AbstractAISearch.cs index 99f06ab..522f3ea 100644 --- a/SpriteCompiler/AI/AbstractAISearch.cs +++ b/SpriteCompiler/AI/AbstractAISearch.cs @@ -47,8 +47,9 @@ while (!fringe.Empty) { var node = fringe.Remove(); +#if DEBUG Console.WriteLine(string.Format("Removed {0} from the queue with g = {1}, c(n, n') = {2}", node.State, node.PathCost, node.StepCost)); - +#endif if (problem.IsGoal(node.State)) { return Solution(node); diff --git a/SpriteCompiler/AI/GraphSearch.cs b/SpriteCompiler/AI/GraphSearch.cs index 39d9594..9cd2319 100644 --- a/SpriteCompiler/AI/GraphSearch.cs +++ b/SpriteCompiler/AI/GraphSearch.cs @@ -16,7 +16,7 @@ namespace SpriteCompiler.AI /// /// Generic graph search. See page 83 in Russell and Norvig. This only works in informed - /// search if the heuristic is admissible.However, if a heuristic is not admissible and + /// search if the heuristic is admissible. However, if a heuristic is not admissible and /// you still want to use, that means you should know enough to extend this class or write /// your own Search class. /// diff --git a/SpriteCompiler/AI/InformedNodeExpander.cs b/SpriteCompiler/AI/InformedNodeExpander.cs index 4db5129..39e8223 100644 --- a/SpriteCompiler/AI/InformedNodeExpander.cs +++ b/SpriteCompiler/AI/InformedNodeExpander.cs @@ -16,8 +16,10 @@ namespace SpriteCompiler.AI var successors = problem.Successors(node.State); // Debug + #if DEBUG Console.WriteLine(String.Format("There are {0} successors for {1}", successors.Count(), node)); Console.WriteLine(String.Format("This node has a current path cost of {0}", node.PathCost)); + #endif foreach (var successor in successors) { @@ -29,8 +31,9 @@ namespace SpriteCompiler.AI next.StepCost = problem.StepCost(node.State, action, state); next.Heuristic = problem.Heuristic(state); +#if DEBUG Console.WriteLine(" Action = " + next.Action + ", g(n') = " + next.PathCost + ", h(n') = " + next.Heuristic); - +#endif yield return next; } } diff --git a/SpriteCompiler/Adapters/QueueAdapter.cs b/SpriteCompiler/Adapters/QueueAdapter.cs index 288faed..9fa48c7 100644 --- a/SpriteCompiler/Adapters/QueueAdapter.cs +++ b/SpriteCompiler/Adapters/QueueAdapter.cs @@ -20,7 +20,9 @@ { foreach (var item in items) { +#if DEBUG Console.WriteLine("Enqueuing " + item + " with cost " + item.EstCost); +#endif queue.Enqueue(item, item.EstCost); } } diff --git a/SpriteCompiler/Problem/Register.cs b/SpriteCompiler/Problem/Register.cs index 4751593..7459a36 100644 --- a/SpriteCompiler/Problem/Register.cs +++ b/SpriteCompiler/Problem/Register.cs @@ -69,6 +69,11 @@ } } + public override int GetHashCode() + { + return Value.GetHashCode() + Tag.GetHashCode(); + } + public override bool Equals(object obj) { return Equals(obj as Register); diff --git a/SpriteCompiler/Problem/SpriteGeneratorSearchProblem.cs b/SpriteCompiler/Problem/SpriteGeneratorSearchProblem.cs index 387ab78..bdf5ed2 100644 --- a/SpriteCompiler/Problem/SpriteGeneratorSearchProblem.cs +++ b/SpriteCompiler/Problem/SpriteGeneratorSearchProblem.cs @@ -17,7 +17,8 @@ public static ISearch Create() { var expander = new SpriteGeneratorNodeExpander(); - var strategy = new TreeSearch(expander); + //var strategy = new TreeSearch(expander); + var strategy = new GraphSearch(expander); return new AStarSearch(strategy); } diff --git a/SpriteCompiler/Problem/SpriteGeneratorState.cs b/SpriteCompiler/Problem/SpriteGeneratorState.cs index 66f3f22..267b387 100644 --- a/SpriteCompiler/Problem/SpriteGeneratorState.cs +++ b/SpriteCompiler/Problem/SpriteGeneratorState.cs @@ -117,6 +117,18 @@ ; } + public override int GetHashCode() + { + return + A.GetHashCode() + + X.GetHashCode() + + Y.GetHashCode() + + D.GetHashCode() + + S.GetHashCode() + + P.GetHashCode() + ; + } + public static bool operator ==(SpriteGeneratorState state1, SpriteGeneratorState state2) { if (((object)state1) == null || ((object)state2) == null) diff --git a/SpriteCompiler/Program.cs b/SpriteCompiler/Program.cs index c4f0226..f63d6d8 100644 --- a/SpriteCompiler/Program.cs +++ b/SpriteCompiler/Program.cs @@ -4,6 +4,7 @@ using SpriteCompiler.Problem; using System; using System.Collections.Generic; + using System.Drawing; using System.Linq; public class ApplicationArguments @@ -26,11 +27,57 @@ static void Main(string[] args) { - byte[] data = null; + IEnumerable data = null; - Console.WriteLine(string.Join(", ", args.Select(s => "'" + s + "'"))); - data = args.Select(s => Convert.ToByte(s, 16)).ToArray(); + try + { + data = args.Select((s, i) => new SpriteByte(Convert.ToByte(s, 16), (ushort)i)); + } + catch (FormatException e) + { + // If there is only one or two arguments, them marybe the user passed in a file + if (args.Length <= 2) + { + var palette = new Dictionary(); + int nextIndex = 1; + // Convert the image / mask to a paletted image + var bitmap = new Bitmap(args[0]); + int[,] buffer = new int[bitmap.Width, bitmap.Height]; + + for (int r = 0; r < bitmap.Height; r++) + { + for (int w = 0; w < bitmap.Width; w++) + { + var rgb = bitmap.GetPixel(w, r); + + if (!palette.ContainsKey(rgb)) + { + if (palette.Count >= 15) + { + throw new Exception("Image cannot have more than 15 unique colors"); + } + palette[rgb] = nextIndex++; + } + + buffer[w, r] = palette[rgb]; + } + } + + // Pair up pixles to build bytes + var sprite = new List(); + + for (int r = 0; r < bitmap.Height; r++) + { + for (int w = 0; w < bitmap.Width; w += 2) + { + sprite.Add(new SpriteByte((byte)((buffer[w, r] << 4) + buffer[w + 1, r]), (ushort)(r * 160 + (w / 2)))); + } + } + + data = sprite; + } + } /* return; diff --git a/SpriteCompiler/Samples/SpriteX2_000.gif b/SpriteCompiler/Samples/SpriteX2_000.gif new file mode 100644 index 0000000..2d7075e Binary files /dev/null and b/SpriteCompiler/Samples/SpriteX2_000.gif differ diff --git a/SpriteCompiler/Samples/SpriteX2_001.gif b/SpriteCompiler/Samples/SpriteX2_001.gif new file mode 100644 index 0000000..29fde57 Binary files /dev/null and b/SpriteCompiler/Samples/SpriteX2_001.gif differ diff --git a/SpriteCompiler/SpriteCompiler.csproj b/SpriteCompiler/SpriteCompiler.csproj index 1615ddd..dc24373 100644 --- a/SpriteCompiler/SpriteCompiler.csproj +++ b/SpriteCompiler/SpriteCompiler.csproj @@ -43,6 +43,7 @@ + @@ -92,6 +93,10 @@ + + + +