Когда то давно, обучаясь программированию, я написал свою версию игры Пятнашки на C++ Builder. Обшаривая интернет, я нашел разные алгоритмы "случайной" расстановки кнопок на поле. Попадались разные, в том числе и достаточно экзотичные, но наиболее популярным является алгоритм многократного (в некоторых случаях до 200 раз) цикличного вызова функции
random
. Оптимальнее выглядит алгоритм с использованием двух контейнеров (в случае С++ это был std::vector), с нахождением случайного значения индекса элемента в контейнере, а не самого элементы. Для WPF этот алгоритм представлен ниже.
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace Fifteens { public class FButton : Button { public int X; public int Y; } /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private int _x; private int _y; private Dictionary<int, FButton> _buttons = new Dictionary<int, FButton>(16); public MainWindow() { InitializeComponent(); gameItem.Click += (s, e) => Random(); int i = 1; foreach (var obj in grid.Children) if (obj is FButton) { var btn = (FButton)obj; btn.X = Grid.GetRow(btn); btn.Y = Grid.GetColumn(btn); btn.Padding = new Thickness(10); btn.Click += OnFButtonClick; _buttons.Add(i++, btn); } _buttons.Add(0, null); Random(); } protected void OnFButtonClick(object sender, RoutedEventArgs e) { var button = (FButton)sender; int x = Grid.GetRow(button); int y = Grid.GetColumn(button); // При нажатии на левый Ctrl можно и по диагонали! var down = Keyboard.IsKeyDown(Key.LeftCtrl); if ((down && (Math.Abs(_x - x) == 1 || Math.Abs(_y - y) == 1)) || ((Math.Abs(_x - x) == 1 && _y == y) || (Math.Abs(_y - y) == 1 && _x == x))) { Grid.SetRow(button, _x); Grid.SetColumn(button, _y); _x = x; _y = y; } else return; if (!_new) return; bool ok = _buttons.Values .Where(b => b != null) .All(b => b.X == Grid.GetRow(b) && b.Y == Grid.GetColumn(b)); if (!ok) return; MessageBox.Show("Игра закончена!"); _new = false; } private bool _new; private void Random() { _new = true; var r = new Random(); var a = new List<int>(16); var v = new List<int>(_buttons.Keys); int k = 0, n = 0; for (var x = 0; x < 4; x++) for (var y = 0; y < 4; y++) { do { k = r.Next(0, v.Count); } while (a.Any(o => o == v[k])); a.Add(v[k]); v.RemoveAt(k); var button = _buttons[a[n]]; if (button == null) { _x = x; _y = y; } else { Grid.SetRow(button, x); Grid.SetColumn(button, y); } n++; } } } }
<?xml version="1.0" encoding="utf-8"?> <Window x:Class="Fifteens.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Fifteens" Height="300" Width="300" Title="Пятнашки"> <DockPanel LastChildFill="True"> <Menu DockPanel.Dock="Top"> <MenuItem x:Name="gameItem" Header="Пуск" /> </Menu> <Grid x:Name="grid" ShowGridLines="True"> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <local:FButton Grid.Column="0" Grid.Row="0" Content="1"></local:FButton> <local:FButton Grid.Column="1" Grid.Row="0" Content="2"></local:FButton> <local:FButton Grid.Column="2" Grid.Row="0" Content="3"></local:FButton> <local:FButton Grid.Column="3" Grid.Row="0" Content="4"></local:FButton> <local:FButton Grid.Column="0" Grid.Row="1" Content="5"></local:FButton> <local:FButton Grid.Column="1" Grid.Row="1" Content="6"></local:FButton> <local:FButton Grid.Column="2" Grid.Row="1" Content="7"></local:FButton> <local:FButton Grid.Column="3" Grid.Row="1" Content="8"></local:FButton> <local:FButton Grid.Column="0" Grid.Row="2" Content="9"></local:FButton> <local:FButton Grid.Column="1" Grid.Row="2" Content="10"></local:FButton> <local:FButton Grid.Column="2" Grid.Row="2" Content="11"></local:FButton> <local:FButton Grid.Column="3" Grid.Row="2" Content="12"></local:FButton> <local:FButton Grid.Column="0" Grid.Row="3" Content="13"></local:FButton> <local:FButton Grid.Column="1" Grid.Row="3" Content="14"></local:FButton> <local:FButton Grid.Column="2" Grid.Row="3" Content="15"></local:FButton> </Grid> </DockPanel> </Window>
Комментарии
Отправить комментарий