Найти в Дзене
Программы от меня

Пишем культовую игру «Пятнашки» на C# за один вечер

Привет, любители покодить и поностальгировать! Помните те времена, когда на каждом кнопочном телефоне и в каждой Windows были «Пятнашки»? Простая, как три копейки, но безумно залипательная головоломка. Сегодня мы не просто вспомним детство, а создадим свою собственную версию этой игры на C#. И не абы как, а с красивым интерфейсом, таймером, подсчетом ходов и... маленькой хитростью, которая поможет нам всегда выигрывать. Спойлер: будем использовать магию чётности перестановок . Многие начинающие программисты пишут очередной «Калькулятор» или «Блокнот». Скука смертная. «Пятнашки» же дают простор для фантазии: Кстати, знали ли вы, что авторство головоломки приписывают знаменитому шахматисту Сэму Лойду? В 19 веке он предложил $1000 тому, кто соберёт комбинацию, где костяшки 14 и 15 поменяны местами. Приз так никто и не получил, потому что... это было невозможно! . Мы сегодня такой ошибки не допустим. Я буду использовать старый добрый Windows Forms. Во-первых, это наглядно. Во-вторых, код
Оглавление

Привет, любители покодить и поностальгировать! Помните те времена, когда на каждом кнопочном телефоне и в каждой Windows были «Пятнашки»? Простая, как три копейки, но безумно залипательная головоломка.

Сегодня мы не просто вспомним детство, а создадим свою собственную версию этой игры на C#. И не абы как, а с красивым интерфейсом, таймером, подсчетом ходов и... маленькой хитростью, которая поможет нам всегда выигрывать. Спойлер: будем использовать магию чётности перестановок .

Почему «Пятнашки» — это крутой учебный проект?

Многие начинающие программисты пишут очередной «Калькулятор» или «Блокнот». Скука смертная. «Пятнашки» же дают простор для фантазии:

  • Нужно придумать, как хранить состояние поля (массивы).
  • Разобраться с обработкой событий мыши/клавиатуры.
  • Написать логику перемещения костяшек.
  • Придумать генератор случайных, но решаемых комбинаций (вот тут и начинается алгебра!).

Кстати, знали ли вы, что авторство головоломки приписывают знаменитому шахматисту Сэму Лойду? В 19 веке он предложил $1000 тому, кто соберёт комбинацию, где костяшки 14 и 15 поменяны местами. Приз так никто и не получил, потому что... это было невозможно! . Мы сегодня такой ошибки не допустим.

Проектируем интерфейс (Windows Forms)

Я буду использовать старый добрый Windows Forms. Во-первых, это наглядно. Во-вторых, код будет минимальным и понятным.

Создадим форму, накидаем на неё кнопку «Старт», панель TableLayoutPanel для нашего поля 4x4 и MenuStrip для пунктов меню .

Важный момент: Мы не будем создавать 16 кнопок вручную в дизайнере. Это моветон. Создадим их динамически, в коде.

-2

В методе CreateGameField мы в цикле создаем кнопки, задаем им размер, шрифт, вешаем обработчик события Click и добавляем на форму.

Пишем логику игры: Swap и проверка победы

Сердце игры — это метод, который обрабатывает клик по кнопке. Когда игрок жмет на кнопку, мы должны понять: а можно ли её подвинуть? То есть, есть ли рядом с ней пустая клетка?

private void Button_Click(object sender, EventArgs e)
{
Button clickedBtn = sender as Button;
// Находим координаты нажатой кнопки в массиве
int row = -1, col = -1;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (cells[i, j] == clickedBtn)
{
row = i; col = j; break;
}

// Проверяем, соседствует ли она с пустой клеткой
if ( (Math.Abs(row - emptyRow) == 1 && col == emptyCol) ||
(Math.Abs(col - emptyCol) == 1 && row == emptyRow) )
{
// Меняем местами числа в массиве numbers
numbers[emptyRow, emptyCol] = numbers[row, col];
numbers[row, col] = 16;
// 16 - это у нас пустота

// Обновляем текст на кнопках
cells[emptyRow, emptyCol].Text = numbers[emptyRow, emptyCol].ToString();
clickedBtn.Text = "";
// Старая кнопка стала пустой

// Теперь пустая клетка переместилась
emptyRow = row;
emptyCol = col;

movesCount++;
lblMoves.Text = $"Ходы: {movesCount}";

CheckVictory();
}
}

CheckVictory — проходим по массиву и проверяем, идут ли числа по порядку от 1 до 15, а на последней позиции пустота.

Секретный ингредиент: правильное перемешивание

Самая частая ошибка новичков — просто переставить кнопки в случайном порядке. В половине случаев такая головоломка будет нерешаемой .

Как сделать правильно? Нужно взять собранное поле и сделать из него N случайных ХОДОВ (а не перестановок). То есть, запустить программу, которая 100-200 раз случайно подвинет костяшки.

-3

Вот теперь головоломка гарантированно имеет решение!

Украшаем: Добавляем таймер

Какая же игра без секундомера? Добавим на форму компонент Timer из панели элементов. Установим интервал в 1000 миллисекунд (1 секунда) и в обработчике Tick будем увеличивать счетчик времени на 1 .

-4

Запускать таймер по кнопке «Старт», останавливать — при победе.

Бонус-уровень: Решатель для профи

Мы уже написали игру. Но, признайтесь, иногда хочется просто посмотреть на красивое решение, а не мучиться самому. Можно добавить кнопку «Решить».

Здесь нам понадобится алгоритм A* (поиск кратчайшего пути) . Звучит страшно, но суть проста: компьютер просчитывает возможные ходы и выбирает тот, который приближает нас к цели.

Мы не будем вдаваться в дебри эвристических функций в этой статье (это тема для отдельного материала), но структура класса для "узла" состояния может выглядеть так :

-5

Чем меньше TotalCost, тем выгоднее этот путь.

Частые ошибки и как их избежать

На форумах часто жалуются на две проблемы :

  1. "Победа" наступает сразу после старта. Это значит, что вы забыли скрыть текст на кнопке, которая должна быть пустой. При инициализации поля кнопка с числом 16 должна иметь текст "".
  2. Игра вылетает при клике. Забыли проверить границы массива. Перед тем, как обращаться к элементам emptyRow-1, всегда проверяйте, что индекс больше или равен нулю.

Заключение

Мы создали полноценную игру меньше чем за 100 строк кода (без учета дизайна). У неё есть интерфейс, логика, таймер и даже «честное» перемешивание.

А если вы хотите пойти дальше:

  • Попробуйте заменить цифры на картинки (разрезанное изображение).
  • Добавьте сохранение рекордов в файл.
  • Сделайте адаптивный дизайн, чтобы поле меняло размер при изменении окна .

Пишите в комментариях, получилось ли у вас обыграть компьютер? Или может, вы знаете более быстрый алгоритм сборки?

Не забудьте подписаться на канал, чтобы не пропустить разбор кода любимых игр!