C# :: Aufgabe #222 :: Lösung #2

3 Lösungen Lösungen öffentlich
#222

Generierung eines SUDOKU

Anfänger - C# von hollst - 13.08.2018 um 16:23 Uhr
Für alle, denen es nicht bekannt sein sollte: Ein SUDOKU ist ein 9 × 9 - Gitter,
das mit den Ziffern 1 bis 9 so ausgefüllt ist, dass jede Ziffer in jeder Spalte,
in jeder Zeile und in jedem 3 x 3 - Unterblock genau ein einziges Mal vorkommt (Bild 1).

Insgesamt sind fast 6.7 Trilliarden (10 hoch 21) unterschiedliche SUDOKUS konstruierbar
(genau 6.670.903.752.021.072.936.960).

Die Programmieraufgabe bestehe darin, mittels Zufallsgenerator SUDOKUS zu erzeugen
und anzuzeigen.

Durch Ausblendung einiger Felder entsteht aus einem SUDOKU ein SUDOKU-Rätsel. Dabei
müssen allerdings mindestens 17 Felder unausgeblendet sein, um eine eindeutige Lösung
zu erhalten (Beweis siehe McGuire, Gary; Tugemann, Bastian; Civario, Gilles:
There is no 16-Clue Sudoku: Solving the Sudoku Minimum Number of Clues Problem.
2012arXiv1201.0749M, Sep 2013). Die Erzeugung eines solchen SUDOKU-Rätsels sei
Fortgeschrittenen vorbehalten, da hierbei auch die Eindeutigkeit einer Lösung nachgewiesen
werden sollte. Der Gipfel wäre anschließend, einen computergestützten SUDOKU-Löser zu entwickeln;
aber, wir wollen es hier noch nicht übertreiben, eines nach dem anderen und nur, wer die
Herausforderung nich scheut.

Viel Spaß!
#2
vote_ok
von hollst (13980 Punkte) - 04.09.2018 um 13:48 Uhr
Quellcode ausblenden C#-Code
using System;
using static System.Console;
using System.Collections.Generic;

namespace aufgabe_222
{
    class Program
    {
        static string NL = Environment.NewLine;

        static void Main()
        {
            
            int leer_stellen = 45; 
            Random rand = new Random();
            ConsoleKeyInfo ki;
            do
            {
                Clear();
                Sudoku_Class sudoku = new Sudoku_Class();

                WriteLine(sudoku.grid.GridToString());

                int counter_leer_stellen = 0;
                while  (counter_leer_stellen < leer_stellen)
                {
                    int y = rand.Next(9), x = rand.Next(9);
                    if (sudoku.grid[y][x] != 0) {
                        sudoku.grid[y][x] = 0;
                        counter_leer_stellen++;
                    };
                }

                WriteLine("SUDOKU-Grid creation counter_loops: " + sudoku.counter_loops.ToString("n0"));
                WriteLine(NL + sudoku.grid.GridToString());

                WriteLine("should I solve (yes/no)?");
                ki = ReadKey(false); WriteLine();

                if (ki.Key == ConsoleKey.Y)
                {
                    int solution_number = 0;
                    sudoku.solution(0, 0, sudoku.grid, 0, ref solution_number);
                    WriteLine("org_sudoku" + Environment.NewLine + sudoku.org_grid.GridToString());
                    string or_more = "(or more) ";
                    if (solution_number < 10)
                        or_more = string.Empty;
                    WriteLine($"sudoku puzzle has {solution_number} {or_more}solutions {NL}{sudoku.grid.GridToString()}");
                }

                WriteLine("exit ESC" + Environment.NewLine);
                ki = ReadKey(false);
            }
            while (ki.Key != ConsoleKey.Escape);
        }
    }

    public class Sudoku_Class
    {
        public byte[][] grid;
        public byte[][] org_grid { private set; get; }
        public int counter_loops = 0;

        Random rand = new Random();        

        public Sudoku_Class() //CONSTRUCTOR
        {
            bool bo_okay = false;
            while (!bo_okay)
            {
                this.grid = new byte[9][];
                for (var i = 0; i < this.grid.Length; i++)
                    this.grid[i] = new byte[9];

                int max_counter_not_ok = (int)1e+2; //100 ist "guter" wert

                for (var i = 0; i < grid.Length; i++)
                    for (var j = 0; j < grid[i].Length; j++)
                    {
                        bo_okay = false;
                        int counter_not_ok = 0;

                        while (counter_not_ok < max_counter_not_ok && !bo_okay)
                        {
                            byte value = (byte)(rand.Next(9) + 1);

                            bo_okay = CheckSudokuValue(value, this.grid, i, j);

                            if (bo_okay)
                                this.grid[i][j] = value;
                            else
                                counter_not_ok++;
                        }

                        bool bo_test = counter_not_ok == max_counter_not_ok;
                        if (bo_test)
                            counter_loops++;
                    }

                if (bo_okay) //check, ob grid vollständig belegt worden ist
                    for (var i = 0; i < grid.Length; i++)
                        for (var j = 0; j < grid[i].Length; j++)
                            if (grid[i][j] == 0)
                                bo_okay = false;
            }
            org_grid = grid.DeepCopy();
        }

        bool CheckSudokuValue(byte value, byte[][] grid, int row, int col)
        {
            for (var i = 0; i < grid.Length; i++)
                if (grid[row][i] == value)
                    return false;
            for (var i = 0; i < grid.Length; i++)
                if (grid[i][col] == value)
                    return false;
            byte br = (byte)(row / 3);
            byte bc = (byte)(col / 3);
            for (var i = 3 * br; i < 3 * (br + 1); i++)
                for (var j = 3 * bc; j < 3 * (bc + 1); j++)
                    if (grid[i][j] == value)
                        return false;
            return true;
        }

        //Rekursives Lösen
        public void solution(int ab_iy, int ab_ix, byte[][] grid, int loop, ref int solution_number)
        {
            if (solution_number > 9)
                return;

            byte[][] grid_copy = grid.DeepCopy();
            int[] next_empty = find_next_empty(ab_iy, ab_ix, grid_copy);

            if (next_empty[0] < 0)
            {
                solution_number++;
                WriteLine($"solution number {solution_number}");
                WriteLine(grid_copy.GridToString());
                return;
            }

            byte[] possibilities = find_possible_values(next_empty[0], next_empty[1], grid_copy);
            if (possibilities.Length == 0)
                return;

            for (var i = 0; i < possibilities.Length; i++)
            {
                grid_copy[next_empty[0]][next_empty[1]] = possibilities[i];
                solution(next_empty[0], next_empty[1], grid_copy, loop + 1, ref solution_number);
            }
        }

        int[] find_next_empty(int ab_iy, int ab_ix, byte[][] grid, byte search_for = 0)
        {
            int[] result = new int[] { -1, -1 };
            bool bo_found = false;
            while (ab_iy < grid.Length && !bo_found)
            {
                if (grid[ab_iy][ab_ix] == search_for)
                {
                    result = new int[] { ab_iy, ab_ix };
                    bo_found = true;
                }
                ab_ix++;
                if (ab_ix == grid[ab_iy].Length)
                {
                    ab_ix = 0;
                    ab_iy++;
                }
            }
            return result;
        }

        byte[] find_possible_values(int row, int col, byte[][] grid)
        {
            List<byte> LB = new List<byte>();
            for (var iv = 1; iv <= grid.Length; iv++)
            {
                bool bo_add = true;
                for (var i = 0; i < grid.Length; i++)
                {
                    if (grid[row][i] == iv)
                        bo_add = false;
                    if (grid[i][col] == iv)
                        bo_add = false;
                }

                int br = row / 3;
                int bc = col / 3;
                for (var i = 3 * br; i < 3 * (br + 1); i++)
                    for (var j = 3 * bc; j < 3 * (bc + 1); j++)
                        if (grid[i][j] == iv)
                            bo_add = false;

                if (bo_add)
                    LB.Add((byte)iv);
            }
            return LB.ToArray();
        }
    }

    public static class MyExtensions
    {
        public static string GridToString(this byte[][] grid)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (var i = 0; i < grid.Length; i++)
            {
                if (i % 3 == 0)
                    sb.AppendLine(" " + new String('-', 25));
                for (var j = 0; j < grid[i].Length; j++)
                {
                    if (j % 3 == 0)
                        sb.Append(" |");
                    if (grid[i][j] == 0)
                        sb.Append($"  ");
                    else
                        sb.Append($"{grid[i][j],2}");
                }
                sb.AppendLine(" |");
            }
            sb.AppendLine(" " + new String('-', 25));
            return sb.ToString();
        }

        public static string ToMyString<T>(this T[][] grid)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (var i = 0; i < grid.Length; i++)
            {
                sb.Append($"{i,3}: ");
                for (var j = 0; j < grid[i].Length; j++)
                    sb.Append($"{grid[i][j],2}");
                sb.AppendLine();
            }
            return sb.ToString();
        }

        public static string ToMyString<T>(this T[] grid, bool bo_nl = true)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (var i = 0; i < grid.Length; i++)
                sb.Append($"{grid[i],2}");
            if (bo_nl)
                sb.AppendLine();
            return sb.ToString();
        }

        public static T[][] DeepCopy<T>(this T[][] grid)
        {
            T[][] result = new T[grid.Length][];
            for (var i = 0; i < grid.Length; i++)
            {
                result[i] = new T[grid[i].Length];
                for (var j = 0; j < result[i].Length; j++)
                    result[i][j] = grid[i][j];
            }
            return result;
        }
    }
}

Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben
2107535

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.