using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AI.Test { 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) { switch (direction) { case Direction.LEFT: return (p % 3) != 0; case Direction.RIGHT: return (p % 3) != 2; case Direction.UP: return (p > 2); case Direction.DOWN: return (p < 6); } throw new ArgumentException(); } public static int MoveFrom(this Direction direction, int p) { switch (direction) { case Direction.LEFT: return p - 1; case Direction.RIGHT: return p + 1; case Direction.UP: return p - 3; case Direction.DOWN: return p + 3; } throw new ArgumentException(); } } public enum Direction { LEFT, RIGHT, UP, DOWN } public class EightPuzzleBoard { // The goal state is the canonical end state public static EightPuzzleBoard GOAL = new EightPuzzleBoard(); protected static Random rng = new Random(); private int[] board; public EightPuzzleBoard() : this(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) { } public EightPuzzleBoard(int[] aBoard) { this.board = aBoard; } public EightPuzzleBoard(EightPuzzleBoard aBoard) { this.board = (int[])aBoard.board.Clone(); } public int[] Board { get { return board; } } public EightPuzzleBoard Scramble() { return Scramble(10); } public EightPuzzleBoard Scramble(int n) { var newPuzzle = new EightPuzzleBoard(this); var directions = Enum.GetValues(typeof(Direction)).Cast().ToList(); var lastDirection = Direction.DOWN; for (int i = 0; i < n;) { var direction = directions[rng.Next(directions.Count)]; if (newPuzzle.CanMoveGap(direction) && (i == 0 || !direction.IsOppositeOf(lastDirection))) { newPuzzle.MoveGap(direction); lastDirection = direction; i += 1; } } return newPuzzle; } private int[] ind2sub(int x) { if (x < 0 || x > 8) { return null; } return new int[] { x / 3, x % 3 }; } protected int sub2ind(int x, int y) { return x * 3 + y; } public int this[int key] { get { return board[key]; } set { board[key] = value; } } private int GapPosition { get { return GetPositionOf(0); } } public int CountMismatches(EightPuzzleBoard aBoard) { int count = 0; for (int i = 0; i < 9; i++) { if (board[i] != aBoard[i] && board[i] != 0) { count++; } } return count; } private int GetPositionOf(int val) { int retVal = -1; for (int i = 0; i < 9; i++) { if (board[i] == val) { retVal = i; } } return retVal; } public int[] GetLocationOf(int val) { return ind2sub(GetPositionOf(val)); } public EightPuzzleBoard MoveGap(Direction direction) { var pos1 = GapPosition; if (direction.CanMove(pos1)) { var pos2 = direction.MoveFrom(pos1); Swap(pos1, pos2); } return this; } private void Swap(int pos1, int pos2) { var val = this[pos1]; this[pos1] = this[pos2]; this[pos2] = val; } public override bool Equals(object obj) { return (this == obj) || board.SequenceEqual(((EightPuzzleBoard)obj).board); } public override int GetHashCode() { return board.GetHashCode(); } public bool CanMoveGap(Direction where) { return where.CanMove(GetPositionOf(0)); } public override string ToString() { return board[0] + " " + board[1] + " " + board[2] + Environment.NewLine + board[3] + " " + board[4] + " " + board[5] + Environment.NewLine + board[6] + " " + board[7] + " " + board[8]; } } }