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
C#-Code
public int glob_counter { get; private set; }
public List<int[]> solutions { get; private set; }
abfragbar.
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);
}
}
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>