C# :: Aufgabe #96

3 Lösungen Lösungen öffentlich

Das Damenproblem (Teil II)

Fortgeschrittener - C# von ElPapito - 07.05.2015 um 11:45 Uhr
Das verallgemeinerte Damenproblem besteht aus einem nxn Schachfeld und n Damen.
Die Aufgabe besteht darin die n Damen so zu positionieren, dass sie sich gegenseitig nicht bedrohen, d.h. es dürfen keine zwei Damen in der gleichen Zeile/Spalte/Diagonale stehen.

Schreibe ein kleines Programm, welches für n = 1, ..., 13 ausgibt wie viele Lösungen existieren.

Lösungen:

vote_ok
von eulerscheZhl (5230 Punkte) - 08.05.2015 um 16:10 Uhr
Quellcode ausblenden C#-Code
using System;

namespace trainYourProgrammer
{
	class MainClass
	{
		static long PlaceQueens(int n, bool[,] blocked, int line) {
			if (line == n)
				return 1;
			long result = 0;
			for (int i = 0; i < n; i++) {
				if (blocked [i, line])
					continue;
				result += PlaceQueens (n, PlaceQueenAt (i, line, n, blocked), line + 1);
			}
			return result;
		}

		static long PlaceQueens(int n) {
			bool[,] blocked = new bool[n, n];
			long result = 0;
			for (int i = 0; i < n/2; i++) { //Ausnutzen der Symmetrie
				result += 2 * PlaceQueens (n, PlaceQueenAt (i, 0, n, blocked), 1);
			}
			if (n % 2 == 1)
				result += PlaceQueens (n, PlaceQueenAt (n / 2, 0, n, blocked), 1);
			return result;
		}

		static bool[,] PlaceQueenAt(int x, int y, int n, bool[,] blocked) {
			int[,] offset = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
			bool[,] result = (bool[,]) blocked.Clone();
			for(int dir = 0; dir < 8; dir++) {
				int x_ = x + offset[dir, 0];
				int y_ = y + offset[dir, 1];
				while (x_ >= 0 && x_ < n && y_ >= 0 && y_ < n) {
					result[x_, y_] = true;
					x_ += offset[dir, 0];
					y_ += offset[dir, 1];
				}
			}
			return result;
		}

		static void Main(string[] args) {
			for (int i = 1; i < 14; i++) {
				Console.WriteLine ("n = " + i.ToString().PadLeft(2) + ": " + PlaceQueens(i).ToString().PadLeft(6) + " Möglichkeiten");
			}
		}
	}
}
4 Kommentare
vote_ok
von DaBaschdi (120 Punkte) - 06.08.2015 um 09:31 Uhr
Hier mein Lösungsvorschlag. Da ich noch nicht sehr lange programmiere, mangelt es mir noch am effizienten Design und dem richtigen Kommentieren. Ich hoffe dennoch, dass mein Code verständlich ist. Eine Kontrolle des einzugebenden n habe ich mir erspart.

Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Damenproblem
{
    //Sebastian Woll, 06.08.15

    class Program
    {
        static int n; //Feldlänge
        static int WievieleFelder; //Vermutete Menge der zu findenden Felder
        static string[][,] Felder = new string[WievieleFelder][,]; //Felder werden gespeichert
        static int CounterFelder = 0; // x-tes gefundenes Feld
        static int CounterRandom = 0; /* Seed des Zufallsgenerators für "mehr" Zufall 
                                       * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                                       * Mit diesem Counter werden bei n=8 immer 92 Lösungen gefunden,
                                       * ohne ihn erzeugt jeder Durchlauf ein anderes Ergebnis!                                        
                                       */
        static int CounterVergleichFALSE = 0; //Dient zur Terminierung des Programms nach zu vielen Fehlversuchen

        static void Main(string[] args)
        {
            Console.Write("\nWelche Länge sollen die Felder haben?\t");
            n = Convert.ToInt32(Console.ReadLine());
            WievieleFelder = n * n * n;
            Felder = new string[WievieleFelder][,];
            for (int i = 0; i < Felder.GetUpperBound(0); i++) //JaggedArray wird gefüllt
            {
                Felder[i] = new string[n, n];
                Felder[i][0, 0] = "."; //Der Punkt dient als Zeichen für "FREIES FELD"
            }
        //Feld generieren
        NeuesFeld:

            //Variablen deklarieren/zurücksetzen
            string[,] Feld = new string[n, n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Feld[i, j] = ".";
                }
            }
            Random Zufall = new Random(CounterRandom);
            CounterRandom++;
            int x, y, CounterDame, CounterWuerfeln;
            CounterWuerfeln = 0;
            CounterDame = 0;
            //Variablen deklarieren/zurücksetztn ENDE

            //Feld füllen
            do
            {
            NeuWuerfeln:
                CounterWuerfeln++;
                x = Zufall.Next(n); //Dame bekommt zufällige Position
                y = Zufall.Next(n);
                if (Feld[x, y] == ".") // Ist die Position frei und nicht bedroht?
                {
                    Felderstreichen(x, y, Feld, CounterDame);
                    CounterDame++; //Nächste Dame
                }
                else
                {
                    if (CounterWuerfeln > n * n * 10) //Wuerfeln gegen endlos? / Position nicht lösbar?
                    {
                        break; //Abbruch bei zu langem Wuerfeln
                    }
                    else
                    {
                        goto NeuWuerfeln;
                    }
                }
            } while (CounterDame < n);
            //Feld füllen ENDE

            //Feld generieren ENDE

            if (CounterVergleichFALSE > 1000) //Wenn nach 1000 Treffern kein neues Feld gefunden wird, endet das Programm mit der Ausgabe des Zählers
            {
                Console.WriteLine("\nEs wurden {0} Felder gefunden.", CounterFelder);
            }
            else
            {
                //Damen alle da?
                if (CounterDame == n)
                {
                    //Feld schonmal gefunden?
                    if (ArraysVergleichen(Feld, Felder) == false) //Verlgeich funktioniert nicht
                    {
                        CounterVergleichFALSE = 0;
                        FeldAusgeben(Feld);
                        Felder[CounterFelder] = Feld;
                        CounterFelder++;
                        //FeldAusgeben(Feld);
                        if (CounterFelder < WievieleFelder - 1) //Weniger als WievieleFelder Felder wurden gefunden
                        {
                            //CounterFelder++;
                            goto NeuesFeld;
                        }
                        else
                        {
                            Console.WriteLine("Es wurden {0} Felder gefunden", CounterFelder);
                        }
                    }
                    else //Feld wurde schonmal gefunden
                    {
                        CounterVergleichFALSE++;
                        goto NeuesFeld;
                    }
                    //Feld schonmal gefunden? ENDE
                }
                else //Damen weniger als n
                {
                    goto NeuesFeld;
                }
                //Damen alle da? ENDE
            }

            Console.ReadLine();
        }//Ende Main


        //Felder streichen
        static void Felderstreichen(int x, int y, string[,] Feld, int CounterDame)
        {
            //Der Strich "-" bedeutet, dass das Feld bedroht ist.
            //Striche waagerecht und senkrecht
            for (int i = 0; i < n; i++)
            {
                Feld[x, i] = "-";
                Feld[i, y] = "-";
            }
            Feld[x, y] = "D";

            //Diagonale nach rechts unten
            for (int i = 1; (i < n - x) && (i < n - y); i++)
            {
                Feld[x + i, y + i] = "-";
            }
            //Diagonale nach links oben
            for (int i = 1; (i <= x) && (i <= y); i++)
            {

                Feld[x - i, y - i] = "-";

            }
            //Diagonale nach rechts oben
            for (int i = 1; (i <= x) && (i < n - y); i++)
            {
                Feld[x - i, y + i] = "-";
            }

            //Diagonale nach links unten
            for (int i = 1; (i < n - x) && (i <= y); i++)
            {
                Feld[x + i, y - i] = "-";
            }

        }//FelderstreichenEnde

        //FeldAusgeben
        static void FeldAusgeben(string[,] Feld)
        {
            Console.WriteLine();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write(Feld[i, j] + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        } //FeldAusgeben ENDE


        //Arrays Vergleichen
        static bool ArraysVergleichen(string[,] NeuesFeld, string[][,] GefundeneFelder)
        {
            int CounterStimmt = 0;
            for (int i = 0; i < WievieleFelder - 1; i++)
            {
                CounterStimmt = 0;
                for (int j = 0; j < n; j++)
                {
                    for (int h = 0; h < n; h++)
                    {
                        if (NeuesFeld[j, h] == GefundeneFelder[i][j, h])
                        {
                            CounterStimmt++;
                        }
                    }
                }
                if (CounterStimmt == n * n)
                {
                    return true;
                }
            }
            return false;
        } //ArraysVergleichen ENDE

        //VERGLEICH FUNKTIONIERT NICHT, wurde durch ArrayVergleichen ersetzt
        // static bool IstFeldSchonVorhanden(string[,] NeuesFeld, string[][,] GefundeneFelder)
        //{
        //    for (int i = 0; i < WievieleFelder - 1; i++)
        //    {
        //        if (NeuesFeld.Equals(GefundeneFelder[i]))
        //        {
        //            FeldAusgeben(NeuesFeld);
        //            Console.WriteLine();
        //            FeldAusgeben(GefundeneFelder[i]);
        //            return true;
        //        }
        //    }
        //    return false;
        //}

        //Sebastian Woll, 06.08.15
    }
}
1 Kommentar
vote_ok
von hollst (13980 Punkte) - 06.11.2018 um 15:38 Uhr
Hier eine Lösung in WPF. Über die Checkbox (draw) und den Slider (sleep) kann man eine graphische
Simulation steuern. Die RadioButton beeinflussen bei gesetzter (true) Checkbox weitere graphische Eigenschaften.

Braucht man nur eine Consolenanwendung, genügt es, eine Instanz von class QueensProblem mit bo_run_loop = true
zu erzeugen. Die Ergebnis sind über
Quellcode ausblenden C#-Code
        public int glob_counter { get; private set; }
        public List<int[]> solutions { get; private set; }

abfragbar.

Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using System.Windows.Forms;

namespace aufgabe_95_WPF
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private struct GUI
        {
            public int nqueens;
            public bool bo_draw;
            public int nsleep;
            public bool bo_rb_l;
            public bool bo_rb_r;
        }

        GUI gui = new GUI();
        void update_gui()
        {
            gui.nqueens = (int)slider_nqueens.Value;
            gui.nsleep = (int)slider_sleep.Value;
            gui.bo_draw = (bool)cb_1.IsChecked;
            gui.bo_rb_l = (bool)rb_l.IsChecked;
            gui.bo_rb_r = (bool)rb_r.IsChecked;
            this.lb_nqueens.Content = $"queens: {this.gui.nqueens,2}";
            this.lb_sleep.Content = $"sleep(ms): {this.gui.nsleep,4}";
            this.textBox.Text = sguistate();
        }
        string sguistate() => $"n_queens: {gui.nqueens}{NL}n_sleep: {gui.nsleep}{NL}bo_draw: {gui.bo_draw}{NL}bo_short_steps: {gui.bo_rb_l}{NL}bo_big_steps: {gui.bo_rb_r}{NL}";

        string NL = Environment.NewLine;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

        bool[][] board;
        int[] queens;
        QueensProblem qp;
        int glob_counter;
        List<int[]> glob_solutions = new List<int[]>();

        double canvas_h, canvas_w;
        string textbox_content;

        private void bt_reset_Click(object sender, RoutedEventArgs e)
        {
            update_gui();
            board = new bool[gui.nqueens][];
            for (var i = 0; i < board.Length; i++)
                board[i] = new bool[gui.nqueens];

            queens = Enumerable.Repeat(-1, gui.nqueens).ToArray();
            qp = new QueensProblem(gui.nqueens);

            this.textBox.Clear();
            canvas_h = this.Canvas.ActualHeight; canvas_w = this.Canvas.ActualWidth;
            textbox_content = $"canvas: {canvas_h.ToString("n0")} x {canvas_h.ToString("n0")}";
            this.textBox.Text = textbox_content + NL + sguistate();
            update_canvas(this.board, this.queens);
            lb_result.Content = string.Empty;
            glob_counter = 0;
            glob_solutions = new List<int[]>();
        }

        private void bt_run_Click(object sender, RoutedEventArgs e)
        {
            bt_reset_Click(null, null);

            sw.Restart();

            int[] queens_copy = null;
            bool[][] board_copy = null;
            int max_firfirst_col = (int)Math.Ceiling(gui.nqueens / 2.0);
            for (int first_col = 0; first_col < max_firfirst_col; first_col++)
            {
                queens_copy = new int[queens.Length];
                queens.CopyTo(queens_copy, 0);
                queens_copy[first_col] = 0;

                board_copy = board.DeepCopy(); 

                int[] coord = qp.attacked[0][first_col];
                for (var i = 0; i < coord.Length; i += 2)
                    board_copy[coord[i]][coord[i + 1]] = true;

                if (gui.bo_draw)
                {
                    update_canvas(board_copy, queens_copy, gui.bo_rb_l);
                    System.Threading.Thread.Sleep(gui.nsleep);
                }
                int found = 0;
                run(1, board_copy, queens_copy, ref found, gui.bo_draw, true);

                int faktor = 2;
                if (gui.nqueens % 2 == 1 && first_col == max_firfirst_col - 1)
                    faktor = 1;
                glob_counter += faktor * found;
                lb_result.Content = $"after loop {first_col + 1} glob_counter is {glob_counter.ToString("n0")}";
                System.Windows.Forms.Application.DoEvents();
            }
            update_canvas(board_copy, glob_solutions[glob_solutions.Count - 1]);
            $"ready {glob_counter}    {sw.Elapsed.Duration()}".m();
        }


        private void run(int reihe, bool[][] board, int[] queens, ref int found, bool bo_draw, bool bo_run)
        {
            if (!bo_run)
                return;

            bool[][] board_copy = board.DeepCopy();
            int[] queens_copy = new int[queens.Length];
            queens.CopyTo(queens_copy, 0);

            if (reihe == gui.nqueens)
            {
                if (gui.bo_draw)
                {
                    update_canvas(board_copy, queens_copy);
                    System.Threading.Thread.Sleep(gui.nsleep);
                }
                found++;
                glob_solutions.Add(queens);
                this.lb_result.Content = $"found so far: {glob_solutions.Count.ToString("n0")}";
                System.Windows.Forms.Application.DoEvents();
                return;                
            }
            else
            {
                List<int> empty = new List<int>();
                for (var col = 0; col < board[reihe].Length; col++)
                    if (!board[reihe][col])
                        empty.Add(col);

                if (empty.Count == 0)
                    return;

                foreach(int ccol in empty)
                {
                    board_copy = board.DeepCopy();
                    queens_copy = new int[queens.Length];
                    queens.CopyTo(queens_copy, 0);
                    queens_copy[ccol] = reihe;
                    for (var j = 0; j < qp.attacked[reihe][ccol].Length; j += 2)
                        board_copy[qp.attacked[reihe][ccol][j]][qp.attacked[reihe][ccol][j + 1]] = true;

                    if (bo_draw)
                    {
                        update_canvas(board_copy, queens_copy, gui.bo_rb_l);
                        System.Threading.Thread.Sleep(gui.nsleep);
                    }
                    run(reihe + 1, board_copy, queens_copy, ref found, bo_draw, bo_run);
                }
                return;
            }
        }

        private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (bo_loaded) update_gui();                
        }

        bool bo_loaded = false;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            bo_loaded = true;
        }

        private void cb_1_Click(object sender, RoutedEventArgs e)
        {
            update_gui();
        }

        private void bt_count_Click(object sender, RoutedEventArgs e)
        {
            bt_reset_Click(null, null);
            sw.Restart();
            QueensProblem qp2 = new QueensProblem(gui.nqueens, true);
            string s_erg = $"{qp2.glob_counter.ToString("n0")} position found in {sw.Elapsed.Duration()}";
            this.textBox.Text = s_erg;
            s_erg.m();
        }

        private void update_canvas(bool[][] board, int[] queens, bool bo_attacked = false)
        {
            this.Canvas.Children.Clear();
            double w = Math.Min(canvas_h, canvas_w) / gui.nqueens;
            for(var i = 0; i < board.Length; i++)
                for(var j = 0; j < board[i].Length; j++)
                {
                    double y = i * w;
                    double x = j * w;
                    System.Windows.Shapes.Rectangle rect;
                    rect = new System.Windows.Shapes.Rectangle();
                    rect.Stroke = new SolidColorBrush(Colors.Black);

                    SolidColorBrush c = new SolidColorBrush(Colors.Wheat); 
                    if (bo_attacked && board[i][j])
                        c = new SolidColorBrush(Colors.Red);
                    else
                    {
                        if((i % 2 == 0) && (j % 2 != 0) || (i % 2 != 0) && (j % 2 == 0))
                            c = new SolidColorBrush(Colors.SandyBrown);
                    }
                    if (queens[j] == i)
                    {
                        //c = new SolidColorBrush(Colors.Black); //falls queen2.jpg nicht vorhanden ist
                        BitmapImage theImage = new BitmapImage
                            (new Uri(@"..\..\pics_and_txt\queen2.jpg", UriKind.Relative));
                        ImageBrush myImageBrush = new ImageBrush(theImage);
                        Canvas TempCanvas = new Canvas();
                        TempCanvas.Width = w;
                        TempCanvas.Height = w;
                        TempCanvas.Background = myImageBrush;
                        Canvas.SetLeft(TempCanvas, x);
                        Canvas.SetTop(TempCanvas, y);
                        this.Canvas.Children.Add(TempCanvas);
                    }
                    else
                    {
                        rect.Fill = c;
                        rect.Width = w;
                        rect.Height = w;
                        Canvas.SetLeft(rect, x);
                        Canvas.SetTop(rect, y);
                        this.Canvas.Children.Add(rect);
                    }                    
                }
            System.Windows.Forms.Application.DoEvents();
        }
    }

    public class QueensProblem
    {
        int n;
        bool[][] board;
        public int[][][] attacked { get;  private set; }
        public int glob_counter { get; private set; }
        public List<int[]> solutions { get; private set; }
        private int[] queens;

        public QueensProblem(int nqueens, bool bo_run_loop = false)
        {
            this.n = nqueens;
            this.board = new bool[n][];
            for (var i = 0; i < board.Length; i++)
                this.board[i] = new bool[n];
            this.attacked = new int[n][][];
            for (var i = 0; i < n; i++)
            {
                this.attacked[i] = new int[n][];
                for (var j = 0; j < this.attacked[i].Length; j++)
                {
                    List<int> temp = new List<int>(ListAttacked(i, j));
                    this.attacked[i][j] = new int[temp.Count];
                    temp.ToArray().CopyTo(this.attacked[i][j], 0);
                }
            }
            queens = Enumerable.Repeat(-1, n).ToArray();
            List<int[]> solutions = new List<int[]>();
            if (bo_run_loop)
                run_loop();
        }

        List<int> ListAttacked(int iy, int ix)
        {
            List<int> result = new List<int>();
            int counter = 1;
            for (int i = iy + 1; i < n; i++)
            {
                { result.Add(i); result.Add(ix); }
                if (ix - counter >= 0)
                    { result.Add(i); result.Add(ix - counter); }
                if (ix + counter < n)
                    { result.Add(i); result.Add(ix + counter); }
                counter++;           }
            return result;
        }

        void run(int reihe, bool[][] board, int[] queens, ref int found)
        {
            bool[][] board_copy = DeepCopy(board);
            int[] queens_copy = new int[queens.Length];
            queens.CopyTo(queens_copy, 0);

            if (reihe == n)
            {
                found++;
                solutions.Add(queens_copy);
                return;
            }
            else
            {
                List<int> empty = new List<int>();
                for (var col = 0; col < board[reihe].Length; col++)
                    if (!board[reihe][col])
                        empty.Add(col);

                if (empty.Count == 0)
                    return;

                foreach (int ccol in empty)
                {
                    board_copy = DeepCopy(board);
                    queens_copy = new int[queens.Length];
                    queens.CopyTo(queens_copy, 0);
                    queens_copy[ccol] = reihe;
                    for (var j = 0; j < attacked[reihe][ccol].Length; j += 2)
                        board_copy[attacked[reihe][ccol][j]][attacked[reihe][ccol][j + 1]] = true;
                    run(reihe + 1, board_copy, queens_copy, ref found);
                }
            }
        }
        
        void run_loop()
        {            
            int max_first_col = (int)Math.Ceiling(n / 2.0);
            for (int first_col = 0; first_col < max_first_col; first_col++)
            {
                int[] queens_copy = new int[queens.Length];
                queens.CopyTo(queens_copy, 0);
                queens_copy[first_col] = 0;

                bool[][] board_copy = DeepCopy(board);

                int[] coord = attacked[0][first_col];
                for (var i = 0; i < coord.Length; i += 2)
                    board_copy[coord[i]][coord[i + 1]] = true;
                int found = 0;
                run(1, board_copy, queens_copy, ref found);

                int faktor = 2;
                if (n % 2 == 1 && first_col == max_first_col - 1)
                    faktor = 1;
                glob_counter += faktor * found;
            }
        }

        T[][] DeepCopy<T>(T[][] x)
        {
            T[][] result = new T[x.Length][];
            for (var i = 0; i < result.Length; i++)
            {
                result[i] = new T[x[i].Length];
                x[i].CopyTo(result[i], 0);
            }
            return result;
        }
    }

    public static class tools
    {
        public static string ToMyString(this bool[][] a)
        {
            StringBuilder sb = new StringBuilder();
            for (var i = 0; i < a.Length; i++)
            {
                for (var j = 0; j < a[i].Length; j++)
                {
                    int temp = a[i][j] ? 1 : 0;
                    sb.Append($"{temp,2}");
                }
                 sb.AppendLine();
            }
            return sb.ToString();
        }

        public static string ToMyString(this int[][][] a)
        {
            StringBuilder sb = new StringBuilder();
            for(var i = 0; i < a.Length; i++)
                for(var j = 0; j < a[i].Length; j++)
                {
                    sb.Append($"{i} {j}: ");
                    for (var k = 0; k < a[i][j].Length; k++)
                        sb.Append($"{a[i][j][k],2}");
                    sb.AppendLine();
                }
            return sb.ToString();
        }

        public static string ToMyString(this List<int> a)
        {
            StringBuilder sb = new StringBuilder();
            for (var i = 0; i < a.Count; i++)
              sb.Append($"{a[i],2}");
            return sb.ToString();
        }

        public static void m(this string s) => System.Windows.MessageBox.Show(s);

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

        public static string Duration(this TimeSpan ts) => String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
    }
}


Quellcode ausblenden C#-Code
<Window x:Class="aufgabe_95_WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:aufgabe_95_WPF"
        mc:Ignorable="d"
        Title="n x n queens problem" Height="441.445" Width="745.018" FontFamily="Courier New" Background="{DynamicResource {x:Static SystemColors.ActiveCaptionBrushKey}}" WindowState="Maximized" Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="75"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <GridSplitter x:Name="gridSplitter" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0" Grid.Row="1" Width="5"/>
        <StackPanel  Margin="0" Orientation="Horizontal" Grid.ColumnSpan="3">

            <Button x:Name="bt_reset" Content="reset" Width="75" Margin="5,0" Click="bt_reset_Click" Height="35"/>

            <GroupBox x:Name="gb_2" Height="50" Header=" slider queens " Margin="5,0">
                <StackPanel Orientation="Horizontal">
                    <Slider x:Name="slider_nqueens" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,5,0" Minimum="1" Maximum="20" Width="100" TickPlacement="BottomRight" Value="8" ValueChanged="slider_ValueChanged"/>
                    <Label x:Name="lb_nqueens" Content="queens:  8" Margin="0,0,15,0" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>
                </StackPanel>
            </GroupBox>

            <GroupBox x:Name="gb_4" Height="50" Header=" drawing " Margin="5,0">
                <StackPanel Orientation="Horizontal">
                    <CheckBox x:Name="cb_1" Content="drawing" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0" Click="cb_1_Click" IsChecked="True"></CheckBox>
                    <RadioButton x:Name="rb_l" Content="short steps " IsChecked="True" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/>
                    <RadioButton x:Name="rb_r" Content="big steps   " HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0"/>
                </StackPanel>
            </GroupBox>

            <GroupBox x:Name="gb_3" Height="50" Header=" slider sleep ">
                <StackPanel Orientation="Horizontal">
                    <Slider x:Name="slider_sleep" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,5,0" Maximum="5000" Width="100" TickFrequency="250" TickPlacement="BottomRight" ValueChanged="slider_ValueChanged" Value="1000"/>
                    <Label x:Name="lb_sleep" Content="sleep(ms):    0" Margin="0,0,20,0" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>
                </StackPanel>
            </GroupBox>

            <Button x:Name="bt_run" Content="run" Width="75" Margin="15,0,5,0" Click="bt_run_Click" Height="35" />
            <Button x:Name="bt_count" Content=" just count " Margin="15,0,5,0" Height="35" Click="bt_count_Click" />

        </StackPanel>
        <StackPanel Height="25" Margin="0" Orientation="Horizontal" Grid.ColumnSpan="3" Grid.Row="2">
            <Label x:Name="lb_version"  HorizontalAlignment="Center" VerticalAlignment="Center" Content="2018/11/05 VERSION 2018/11/06" Margin="5,0,0,0"></Label>
            <Label x:Name="lb_result" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"></Label>
        </StackPanel>
        <Canvas x:Name="Canvas" Margin="5,50,5,5" Grid.Row="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
        <Expander Grid.Column="2" Grid.Row="1" IsExpanded="True">
            <GroupBox x:Name="groupBox" Grid.Column="2" Header="INFO" Margin="5" Grid.Row="1">
                <TextBox x:Name="textBox" Margin="5" Text="TextBox" VerticalScrollBarVisibility="Auto" AcceptsReturn="True" AcceptsTab="True" HorizontalScrollBarVisibility="Auto" FontSize="36" FontWeight="Bold"/>
            </GroupBox>
        </Expander>

    </Grid>
</Window>