Beispiel #1
0
        /// <summary>
        /// Creates a square puzzle that starts at 1, and finishes at size * size.
        /// So if the size = 3 then it will produce 3 * 3 = 9:
        /// 1 2 3
        /// 4 5 6
        /// 7 8 9
        /// The highest number is the "space" square.
        /// This is good for generating a linear "goal state" square puzzle.
        /// </summary>
        /// <param name="size">Size of the square puzzle. eg size * size.  The size must be >= 2.</param>
        /// <returns>Returns a linear square puzzle.</returns>
        public static SquarePuzzle CreateLinear(int size)
        {
            SquarePuzzle goal = new SquarePuzzle();

            goal.Grid = new SquareNode[size][];
            for (int i = 0; i < size; i++)
            {
                goal.Grid[i] = new SquareNode[size];
            }
            int number = 1;

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    goal.Grid[i][j] = new SquareNode(new Point(i, j), number++);
                }
            }

            //for (int i = 0; i < size; i++)
            //	for (int j = 0; j < size; j++)
            //		goal.Grid[i][j].Initialize(new Node.Point(i, j), new Node.Point(i, j), number++);
            goal.Grid[goal.Grid.Length - 1][goal.Grid.Length - 1].IsSpace = true;
            return(goal);
        }
Beispiel #2
0
        /// <summary>
        /// Sets the estimated cost, or h, for this square puzzle state.
        /// This heuristic uses a modified version of Nilsson's sequence score.
        /// If the "space" node is not in the correct position, then add 1.
        /// Check each node and if its neighbors are not correct, then score two per non-corect neighbor.
        /// Multiply this by 3.
        /// Add the manhatten distance for each node, except the "space" node to the total.
        /// </summary>
        /// <param name="goal">Access to the square puzzle state that is the goal for calculating the heuristic.</param>
        public void SetEstimatedCost(INode goal)
        {
            SquarePuzzle g = (SquarePuzzle)goal;

            int[] pos =
            {
                1, -1, 0, 0,                                    //x
                0,  0, 1, -1                                    //y
            };
            int[] plus = { 1, -1, 3, -3 };
            // Uses Nilsson's sequence score.
            for (int i = 0; i < Grid.Length; i++)
            {
                for (int j = 0; j < Grid[i].Length; j++)
                {
                    SquareNode node = Grid[i][j];
                    //Any nodes next to it that are in the "correct" spot get a +2
                    List <SquareNode> neighbors = Neighbors(node);
                    for (int k = 0; k < neighbors.Count; k++)
                    {
                        for (int z = 0; z < 4; z++)
                        {
                            //todo should only check 4x1 instead of 4x4.
                            if (neighbors[k].Position.X == node.Position.X + pos[z] &&
                                neighbors[k].Position.Y == node.Position.Y + pos[z + 4])
                            {
                                if (neighbors[k].Number != node.Number + plus[z])
                                {
                                    EstimatedCost += 2;
                                }
                            }
                        }
                    }
                }
            }
            //If the goal "space" node is not "space" then add 1.
            if (!Grid[Grid.Length - 1][Grid.Length - 1].IsSpace)
            {
                EstimatedCost += 1;
            }

            EstimatedCost *= 3;

            for (int i = 0; i < Grid.Length; i++)
            {
                for (int j = 0; j < Grid[i].Length; j++)
                {
                    SquareNode node     = Grid[i][j];
                    SquareNode goalNode = GetNodeByNumber(g, node.Number);
                    //If the node isn't where it should be then add its manhattan distance to its goal position.
                    if (!node.IsSpace &&
                        (goalNode.Position.X != node.Position.X ||
                         goalNode.Position.Y != node.Position.Y))
                    {
                        EstimatedCost += Math.Abs(node.Position.X - goalNode.Position.X) +
                                         Math.Abs(node.Position.Y - goalNode.Position.Y);
                    }
                }
            }
        }
Beispiel #3
0
        public static void Shuffle(SquarePuzzle puzzle, int iterations)
        {
            for (int i = 0; i < iterations; i++)
            {
                var children = (List <INode>)puzzle.Children;
                children.Shuffle();
                var child = (SquarePuzzle)children[0];
                var space = puzzle.GetSpace();

                Swap(puzzle.Grid, space.Position, child.GetSpace().Position);
            }
        }
Beispiel #4
0
 /// <summary>
 /// Gets a node in the square puzzle by its number.
 /// Returns null if no node has that number.
 /// </summary>
 /// <param name="p">Puzzle to search in.</param>
 /// <param name="num">The node with this number to get.</param>
 /// <returns>Returns the node in the square puzzle with the specified number.</returns>
 public static SquareNode GetNodeByNumber(SquarePuzzle p, int num)
 {
     for (int i = 0; i < p.Grid.Length; i++)
     {
         for (int j = 0; j < p.Grid.Length; j++)
         {
             if (p.Grid[i][j].Number == num)
             {
                 return(p.Grid[i][j]);
             }
         }
     }
     return(null);
 }
Beispiel #5
0
        public Program()
        {
            Current = SquarePuzzle.CreateLinear(3);
            SquarePuzzle.Shuffle(Current, 10);                  // even a small shuffle can result in huge search times
            Goal = SquarePuzzle.CreateLinear(3);

            Console.WriteLine("Starting position:");
            Current.Print();

            Console.WriteLine("Goal position:");
            Goal.Print();

            aStar = new AStar(Current, Goal);
        }
Beispiel #6
0
        /// <summary>
        /// Returns whether or not this square puzzle state is equal to the parameter square puzzle state.
        /// </summary>
        /// <param name="state">State to compare for equality.</param>
        /// <returns>Returns whether or not this square puzzle state is equal to the parameter square puzzle state.</returns>
        public bool Equal(INode state)
        {
            SquarePuzzle s = (SquarePuzzle)state;

            for (int i = 0; i < s.Grid.Length; i++)
            {
                for (int j = 0; j < s.Grid[i].Length; j++)
                {
                    if (s.Grid[i][j].Number != Grid[i][j].Number)
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// Generates a random square puzzle of size * size.
        /// Not all random puzzles are solvable.
        /// </summary>
        /// <param name="size">Size of the square puzzle. eg size * size.  The size must be >= 2.</param>
        public static SquarePuzzle CreateRandom(int size)
        {
            SquarePuzzle start = new SquarePuzzle();
            Random       rand  = new Random();

            start.Grid = new SquareNode[size][];
            for (int i = 0; i < size; i++)
            {
                start.Grid[i] = new SquareNode[size];
            }

            int number = 1;

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    int x;
                    int y;
                    while (true)
                    {
                        x = rand.Next(0, size);
                        y = rand.Next(0, size);
                        if (start.Grid[x][y] != null)
                        {
                            continue;
                        }
                        break;
                    }
                    start.Grid[x][y] = new SquareNode(new Point(x, y), number++);
                    if (i == size - 1 && j == size - 1)
                    {
                        start.Grid[x][y].IsSpace = true;
                    }
                }
            }
            return(start);
        }
Beispiel #8
0
        /// <summary>
        /// Creates a copy of the square puzzle that is passed.
        /// </summary>
        public static SquarePuzzle Copy(SquarePuzzle puzzle)
        {
            SquarePuzzle copy = new SquarePuzzle();

            copy.Grid = new SquareNode[puzzle.Grid.Length][];
            for (int i = 0; i < puzzle.Grid.Length; i++)
            {
                copy.Grid[i] = new SquareNode[puzzle.Grid.Length];
            }

            for (int i = 0; i < puzzle.Grid.Length; i++)
            {
                for (int j = 0; j < puzzle.Grid.Length; j++)
                {
                    copy.Grid[i][j] = new SquareNode(puzzle.Grid[i][j].Position, puzzle.Grid[i][j].Number);
                    if (puzzle.Grid[i][j].IsSpace)
                    {
                        copy.Grid[i][j].IsSpace = true;
                    }
                }
            }
            return(copy);
        }
Beispiel #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="userDefined"></param>
        /// <returns></returns>
        public static SquarePuzzle CreateUserDefined(int[][] userDefined)
        {
            //Error checking, make sure that the provided arrays are qualified to make a square puzzle.
            for (int i = 0; i < userDefined.Length; i++)
            {
                if (userDefined.Length != userDefined[i].Length)
                {
                    return(null);
                }
            }
            int[][] errorUserDefined = new int[userDefined.Length][];
            for (int i = 0; i < errorUserDefined.Length; i++)
            {
                errorUserDefined[i] = new int[errorUserDefined.Length];
            }
            for (int i = 0; i < errorUserDefined.Length; i++)
            {
                for (int j = 0; j < errorUserDefined.Length; j++)
                {
                    errorUserDefined[i][j] = new int();
                }
            }
            int currentNumber = 1;

            for (int i = 0; i < userDefined.Length; i++)
            {
                for (int j = 0; j < userDefined.Length; j++)
                {
                    for (int k = 0; k < userDefined.Length; k++)
                    {
                        for (int z = 0; z < userDefined.Length; z++)
                        {
                            if (userDefined[k][z] == currentNumber)
                            {
                                if (errorUserDefined[i][j] == currentNumber)                                 //check for duplicates.
                                {
                                    return(null);
                                }
                                errorUserDefined[i][j] = currentNumber;
                            }
                        }
                    }
                    currentNumber++;
                }
            }
            currentNumber = 1;
            for (int i = 0; i < userDefined.Length; i++)
            {
                for (int j = 0; j < userDefined.Length; j++)
                {
                    if (errorUserDefined[i][j] != currentNumber)                        // check to make sure we have 1 through length * length
                    {
                        return(null);
                    }
                    currentNumber++;
                }
            }
            //End error checking.
            SquarePuzzle puzzle = new SquarePuzzle();

            puzzle.Grid = new SquareNode[userDefined.Length][];

            for (int i = 0; i < userDefined.Length; i++)
            {
                puzzle.Grid[i] = new SquareNode[userDefined.Length];
            }

            for (int i = 0; i < userDefined.Length; i++)
            {
                for (int j = 0; j < userDefined.Length; j++)
                {
                    puzzle.Grid[i][j] = new SquareNode(new Point(i, j), userDefined[i][j]);
                    // if it is the highest number, then it is the "space".
                    if (userDefined[i][j] == userDefined.Length * userDefined.Length)
                    {
                        puzzle.Grid[i][j].IsSpace = true;
                    }
                }
            }
            return(puzzle);
        }
Beispiel #10
0
 /// <summary>
 /// No space exception is thrown when a SquarePuzzle does not contain a ' ' node.
 /// </summary>
 /// <param name="puzzle">The invalid square puzzle.</param>
 public NoSpaceException(SquarePuzzle puzzle)
     : base("No space square was found in this square puzzle state.")
 {
     Puzzle = puzzle;
 }