Board.cs 5.42 KiB
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;
}
}
}
}