Когда то давно, обучаясь программированию, я написал свою версию игры Пятнашки на 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>
Комментарии
Отправить комментарий