using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Reflection.Metadata; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace PuzzlePlayer_Namespace { public enum SOLUTIONS { NONE = 0, UNIQUE = 1, MULTIPLE = 2 } // a struct for a move on a certain location. changeTo is in what the place on the coordinates should change to public struct Move { public int x, y; public int changeTo; public Move(int x, int y, int changeTo) { this.x = x; this.y = y; this.changeTo = changeTo; } } /* * This abstract class can be used to implement any kind of puzzle * One thing that is common for all puzzles is that a empty space is equal to -1 * GetSolveList and IsBoardValid need to be overwriten in a subclass of Board */ public abstract class Board { public const int emptySpace = -1; // for every puzzle -1 represents a empty space public string description; public int drawFactor; // setting this to 1 always works // variables to keep track of the board state and the last generated board public int[,] boardState; public int[,] lastGeneratedBoard; public int[,] solution; // static meathode for filling a int[,] with -1 public static int[,] GetClearBoard(int boardSizeX, int boardSizeY) { int[,] result = new int[boardSizeX, boardSizeY]; // fill the board with empty spaces (-1) for (int i = 0; i < boardSizeX; i++) { for (int j = 0; j < boardSizeY; j++) result[i, j] = emptySpace; } return result; } public abstract void Draw(Graphics gr, Rectangle r); // a methode for solving the whole board. It uses the private SolveStep methode untill the whole board is solved // it has one parameter. setting this to true will only give a return value without changing the current boardState public virtual SOLUTIONS Solve(bool CheckOnly) { // two variables for storing the result and the next solveStep int[,] result = (int[,])boardState.Clone(); List<Move> possibleMoves; // keep looping until the SolveStep returns an empty list // if SolveStep returns a empty list that could mean that either the whole board is solved or it is imposible to solve the board while ((possibleMoves = GetSolveList(result)).Count != 0) { foreach (Move m in possibleMoves) { result[m.x, m.y] = m.changeTo; } } // check if the whole board is filled // if not then the methode will return null because it is imposible to solve the board for (int i = 0; i < result.GetLength(0); i++) for (int j = 0; j < result.GetLength(1); j++) if (result[i, j] == emptySpace) { return SOLUTIONS.NONE; } if(!CheckOnly) boardState = result; return SOLUTIONS.UNIQUE; } // abstract methode for solving one step public virtual Point Hint() { return new Point(0, 0); } // a abstract methode to get a list of all possible moves protected virtual List<Move> GetSolveList(int[,] boardToSolve) { List<Move> result = new List<Move>(); return result; } // abstract methode for generating a random board public abstract void Generate(); // abstract methode for checking if a imputed boardstate is valid public virtual bool IsBoardSolved() { for (int i = 0; i < boardState.GetLength(0); i++) for (int j = 0;j < boardState.GetLength(1); j++) { if (boardState[i,j] != solution[i,j]) return false; } return true; //MessageBox.Show($"{boardState[0, 0]},{boardState[0, 1]},{boardState[1, 0]},{boardState[1, 1]} hjjkjkhj {solution[0, 0]},{solution[0, 1]},{solution[1, 0]},{solution[1, 1]} "); //MessageBox.Show($"{boardState == solution}"); } // changes tile P to value X public abstract bool TileInput(Point? p, Keys k); // performs a left/right (X) click on tile P, changing its value public virtual bool TileClick(Point p, int x) { return false; } // is called by restartbutton on PuzzleForm public virtual void Restart() { boardState = (int[,])lastGeneratedBoard.Clone(); } } // static class for extentions public static class Extensions { private static readonly Random rng = new Random(); // shuffle the elements in a list around to get different results every time from the generator algoritms // First answer from: https://stackoverflow.com/questions/273313/randomize-a-listt public static void Shuffle<T>(this IList<T> list) { int n = list.Count; while (n > 1) { n--; int k = rng.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } } } }