Skip to content
Snippets Groups Projects
Sudoku.cs 10.50 KiB
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PuzzlePlayer_Namespace
{
    internal class Sudoku : Board
    {
        private static int boardLength;
        private static int rootBoardLength;
        private static Random random = new Random();
        public Sudoku(int boardSize = 9)
        {
            boardState = GetClearBoard(boardSize, boardSize);
            lastGeneratedBoard = GetClearBoard(boardSize, boardSize);
            boardLength = boardSize;
            rootBoardLength = (int)Math.Sqrt(boardLength);

            description = "Sudoku is played on any perfect square-numbered grid, with some cells initially containing numbers. The goal of the puzzle is to fill all cells such that:\r\n● Each row and column must contain all of the numbers exactly once\r\n● Each box indicated by thicker lines must also contain all of the numbers exactly once\r\n● Every sudoku must have an unique solution";
            drawFactor = 1;
        }

        public override void Draw(Graphics gr, Rectangle r)
        {
            StringFormat format = new StringFormat
            {
                LineAlignment = StringAlignment.Center,
                Alignment = StringAlignment.Center,
            };
            Size tilesize = new Size(r.Width / boardState.GetLength(0), r.Height / boardState.GetLength(1));
            Pen border = new Pen(Color.Black, 2);
            gr.FillRectangle(Brushes.Beige, r.X, r.Y, tilesize.Width * boardState.GetLength(0), tilesize.Height * boardState.GetLength(1));
            for (int i = 0; i < boardState.GetLength(0); i++)
            {
                for (int j = 0; j < boardState.GetLength(1); j++)
                {

                    gr.DrawRectangle(Pens.LightGray,
                        r.X + i * tilesize.Width,
                        r.Y + j * tilesize.Height,
                        tilesize.Width,
                        tilesize.Height);

                    if (boardState[i,j] != -1)
                    {
                        gr.DrawString(
                            (boardState[i, j]).ToString(),
                            new Font("Arial", tilesize.Width / 2),
                            Brushes.Black,
                            (float)(r.X + (i + 0.27) * tilesize.Width + tilesize.Width / 4),
                            (float)(r.Y + (j + 0.33) * tilesize.Height + tilesize.Height / 4),
                            format
                        );
                    }

                    if (lastGeneratedBoard[i, j] != Board.emptySpace)
                    {
                        gr.FillRectangle(Brushes.LightGray,
                            (int)(r.X + ((double)i + 0.4375) * tilesize.Width),
                            (int)(r.Y + ((double)j + 0.4375) * tilesize.Height),
                            tilesize.Width / 8,
                            tilesize.Height / 8);
                    }
                }
            }
            for (int i = 1; i < Math.Sqrt(boardState.GetLength(0)); i++)
            {
                gr.DrawLine(Pens.Black,
                    r.X + i * (int)Math.Sqrt((double)boardState.GetLength(0)) * tilesize.Width,
                    r.Y,
                    r.X + i * (int)Math.Sqrt((double)boardState.GetLength(0)) * tilesize.Width,
                    r.Bottom);
                gr.DrawLine(Pens.Black,
                    r.X,
                    r.Y + i * (int)Math.Sqrt((double)boardState.GetLength(1)) * tilesize.Height,
                    r.Right,
                    r.Y + i * (int)Math.Sqrt((double)boardState.GetLength(1)) * tilesize.Height);
            }
        }

        public override void Generate()
        {

            boardState = GetClearBoard(boardLength, boardLength);

            for (int i = 0; i < boardLength; i += rootBoardLength)
            {
                FillBox(i, i);
            }

            SolveSudoku();

            RemoveSpaces((int)(boardLength * boardLength - 30));
        }

        public override SOLUTIONS Solve(bool b)
        {
            if (SolveSudoku())
            {
                return SOLUTIONS.UNIQUE;
            }
            return SOLUTIONS.NONE;
        }

        private int RandomNumber(int number)
        {
            return (int)Math.Floor((double)(random.NextDouble() * number + 1));
        }

        private void FillBox(int row, int col)
        {
            int num;

            for (int i = 0; i < rootBoardLength; i++)
            {
                for (int j = 0; j < rootBoardLength; j++)
                {
                    do
                    {
                        num = RandomNumber(boardLength);
                    }
                    while (BoxFlag(row, col, num));

                    boardState[row + i, col + j] = num;
                }
            }
        }

        private bool DoAllChecks(int i, int j, int num)
        {
            return (BoxFlag(i - i % rootBoardLength, j - j % rootBoardLength, num) || ColFlag(i, num) || RowFlag(j, num));
        }

        private bool BoxFlag(int row, int col, int num)
        {
            for (int i = 0; i < rootBoardLength; i++)
            {
                for (int j = 0; j < rootBoardLength; j++)
                {
                    if (boardState[row + i, col + j] == num)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        private bool ColFlag(int i, int num)
        {
            for (int j = 0; j < boardLength; j++)
            {
                if (num == boardState[i, j])
                {
                    return true;
                }
            }
            return false;
        }

        private bool RowFlag(int j, int num)
        {
            for (int i = 0; i < boardLength; i++)
            {
                if(num == boardState[i, j])
                {
                    return true;
                }
            }
            return false;
        }

        // Heilige piramide
        private bool SolveSudoku()
        {
            for (int row = 0; row < boardLength; row++)
            {
                for (int col = 0; col < boardLength; col++)
                {
                    if (boardState[row, col] == emptySpace)
                    {
                        for (int num = 1; num <= boardLength; num++)
                        {
                            if (!DoAllChecks(row, col, num))
                            {
                                boardState[row, col] = num;

                                if (SolveSudoku())
                                {
                                    return true;
                                }

                                boardState[row, col] = emptySpace;
                            }
                        }
                        return false;
                    }
                }
            }
            return true;
        }

        private static string BoardToString(int[,] board)
        {
            string result = "";

            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    result += (board[i, j] == emptySpace ? "." : board[i, j].ToString());
                }
                result += "|";
            }
            return result;
        }

        private static int[,] BoardFromString(string board)
        {
            string[] parts = board.Split('|', StringSplitOptions.RemoveEmptyEntries);
            int[,] result = new int[parts.Length, parts.Length];

            for (int i = 0; i < result.GetLength(0); i++)
            {
                for (int j = 0; j < result.GetLength(1); j++)
                {
                    string s = parts[i][j].ToString();
                    if (s == ".")
                        result[i, j] = emptySpace;
                    else if (int.Parse(s) >= 0 && int.Parse(s) <= 8)
                        result[i, j] = int.Parse(s);
                    else
                        return null;
                }

            }

            return result;
        }

        public override void TileInput(Point? p, Keys k)
        {
            if (p == null) return;
            int num = (int)k - 48;
            if (num >= 1 && num <= boardLength) boardState[((Point)p).X, ((Point)p).Y] = num;

        }
        public override void TileClick(Point p, int x)
        {
            if (x == 1)
            {
                x = -1;
            }
            if (x == 0)
            {
                x = 1;
            }

            if (boardState[p.X, p.Y] == emptySpace)
            {
                if (x == 1)
                {
                    boardState[p.X, p.Y] = 1;
                    return;
                }
                else
                {
                    boardState[p.X, p.Y] = boardLength;
                    return;
                }
            }
            else if (boardState[p.X, p.Y] == boardLength)
            {
                if (x == 1)
                {
                    boardState[p.X, p.Y] = emptySpace;
                    return;
                }
                else
                {
                    boardState[p.X, p.Y] += x;
                    return;
                }
            }
            else if (boardState[p.X, p.Y] == 1)
            {
                if (x == -1)
                {
                    boardState[p.X, p.Y] = emptySpace;
                    return;
                }
                else
                {
                    boardState[p.X, p.Y] += x;
                    return;
                }
            }
            else
            {
                boardState[p.X, p.Y] += x;
                return;
            }
        }

        private void RemoveSpaces(int k)
        {
            for(int i = 0; i < k; i++)
            {
                int row;
                int col;

                row = RandomNumber(boardLength) - 1;
                col = RandomNumber(boardLength) - 1;
                
                if (boardState[row, col] != emptySpace)
                {
                    boardState[row, col] = emptySpace;
                }
                else
                {
                    i--;
                }
            }
        }

        protected override List<Move> GetSolveList(int[,] boardToSolve)
        {
            List<Move> result = new List<Move>();

            return result;
        }

    }
}