
- •Кафедра информатики
- •Курсовая работа
- •По программированию
- •Игра «Пятнашки»
- •1. Постановка задачи.
- •1.1. Задание.
- •1.2. Алгоритмическое решение задачи.
- •1.3. Контрольные примеры
- •2. Решение задачи.
- •2.1. Выбор средств реализации.
- •2.2. Описание основных классов.
- •2.3. Интерфейс приложения.
- •3. Результат работы приложения.
2.2. Описание основных классов.
В программе используется единственный нестандартный класс App, который представляет собой реализацию коробки с костяшками, содержит игровую логику и управляет отображением графики на экране. Класс App наследуется от стандартного класса JFrame, что даёт ему функциональность окна (в понимании операционной системы Windows или оконных менеджеров других ОС).
Переменная _grid — двумерный массив чисел, который является абстракцией игрового поля (набора костяшек с числами), а двумерный массив кнопок (экземпляров класса JButton) _btns выполняет роль визуализатора этой абстракции.
В игре также используется класс Timer для подсчёта времени, которое было затрачено на решение головоломки.
// Двумерный массив, хранящий номера фишек на игровом поле.
private int _grid[][];
// Двумерный массив кнопок, представляющих фишки на игровом поле.
private JButton _btns[][];
// Размер игрового поля.
private final int _gridSize = 4;
// Статическая переменная, хранящая экземпляр текущего приложения.
private static App _app;
// Хранит информацию о том, не завершена ли ещё игра.
private boolean _gameOver;
// Таймер для подсчёта времени.
private javax.swing.Timer _timer;
// Количество затраченных на игру секунд.
private int _time;
// Заголовок окна.
final String _title = "Пятнашки";
Класс App содержит следующие методы:
tryMove — пытается совершить перемещение костяшки (вызывается при нажатии соответствующей кнопки-костяшки) и в случае удачного перемещения, обновляет вид игрового поля, а также проверяет, не завершена ли после данного действия игра. /*
* Пытается совершить перемещение фишки.
*/
private void tryMove(JButton btn) {
int value = Integer.parseInt(btn.getText());
int i = 0, j = 0;
// Поиск координат пустой клетки.
search: {
for (; j < _gridSize; ++j)
for (i = 0; i < _gridSize; ++i)
if (_grid[j][i] == value)
break search;
}
// Было ли совершено перемещение.
boolean moved = false;
// Пытаемся переместить фишку в четырёх направлениях.
if (i > 0 && _grid[j][i - 1] == 0)
{
// Влево...
_grid[j][i - 1] = value;
moved = true;
}
else if (i < _gridSize - 1 && _grid[j][i + 1] == 0)
{
// Вправо...
_grid[j][i + 1] = value;
moved = true;
}
else if (j > 0 && _grid[j - 1][i] == 0)
{
// Вверх...
_grid[j - 1][i] = value;
moved = true;
}
else if (j < _gridSize - 1 && _grid[j + 1][i] == 0)
{
// Вниз...
_grid[j + 1][i] = value;
moved = true;
}
// Если удалось совершить перемещение, обновляем игровое поле.
if (moved)
{
_grid[j][i] = 0;
updateGrid();
// Если это было первое перемещение за текущую игру,
// запускаем таймер.
if (!_gameOver && !_timer.isRunning()) {
_time = 0;
_timer.start();
}
}
}
shuffle — перемешивает костяшки на игровом поле. Вызывается перед началом новой игры. /*
* Перемешивает цифры на игровом поле.
*/
private void shuffle() {
// Сначала расставляем фишки в порядке возрастания.
for (int j = 0; j < _gridSize; ++j)
for (int i = 0; i < _gridSize; ++i)
_grid[j][i] = i + j * 4 + 1;
_grid[_gridSize - 1][_gridSize - 1] = 0;
// Генератор случайных чисел.
Random rnd = new Random();
// Начальные координаты пустой клетки.
int x = _gridSize - 1;
int y = _gridSize - 1;
// Перемешиваем...
for (int k = 0; k < 100; ++k)
{
// Выбираем случайное направление, откуда будет перемещена
// фишка в пустую клетку.
int dir = rnd.nextInt(4);
// Пытаемся переместить...
switch(dir)
{
case 0:
if (x > 0)
{
_grid[y][x] = _grid[y][x-1];
_grid[y][x - 1] = 0;
--x;
}
else
--k;
break;
case 1:
if (y > 0)
{
_grid[y][x] = _grid[y-][x];
_grid[y - 1][x] = 0;
--y;
}
else
--k;
break;
case 2:
if (x < _gridSize - 1)
{
_grid[y][x] = _grid[y][x+1];
_grid[y][x + 1] = 0;
++x;
}
else
--k;
break;
case 3:
if (y < _gridSize - 1)
{
_grid[y][x] = _grid[y+][x];
_grid[y + 1][x] = 0;
++y;
}
else
--k;
break;
}
}
// Если вдруг оказалось, что фишки всё ещё стоят упорядоченно
// (что крайне маловероятно), перемешиваем их ещё раз.
if (testGrid())
shuffle();
// Обновляем игровое поле.
updateGrid();
_gameOver = false;
}
testGrid — проверяет, не завершена ли игра (игра считается завершённой, когда все костяшки расположены в порядке возрастания, а пустая клетка находится в конце после пятнадцатой костяшки). /*
* Проверяет, не завершена ли игра.
*/
private boolean testGrid() {
// Проверяем чтобы фишки располагались на поле в порядке
// ворзрастания номеров. Если нашли несоответствие этому правилу,
// то возвращаем false.
for (int j = 0; j < _gridSize; ++j)
for (int i = 0; i < _gridSize; ++i)
if (_grid[j][i] != i + j * 4 + 1 && _grid[j][i] != 0)
return false;
// Если всё хорошо, отключаем счётчик времени и завершаем игру.
_timer.stop();
_gameOver = true;
return true;
}
updateGrid —обновляет состояние игрового поля (массива кнопок) в соответствии с его абстракцией (массивом _grid). /*
* Обновляет кнопки по информации из двумерного массива.
*/
private void updateGrid() {
// Всем кнопкам задаём номера в соответствии с массивом _grid.
for (int j = 0; j < _gridSize; ++j)
for (int i = 0; i < 4; ++i)
{
int value = _grid[j][i];
JButton btn = _btns[j][i];
btn.setText(Integer.toString(value));
btn.setVisible(value != 0);
}
}
createMenu —метод утилитарного характера, предназначен для создания меню в программе, вызывается в конструкторе класса App. /*
* Создаёт меню.
*/
private void createMenu() {
// Полоска меню.
JMenuBar menu = new JMenuBar();
setJMenuBar(menu);
// Кнопка "Игра".
JMenu mnuGame = new JMenu("Игра");
menu.add(mnuGame);
// Кнопка "Новая игра"...
JMenuItem mnuNewGame = new JMenuItem("Новая игра");
mnuGame.add(mnuNewGame);
// ...при нажатии на неё, нужно перемешать игровое поле.
mnuNewGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setTitle(_title);
_app.shuffle();
}
});
// Кнопка "Выход"...
JMenuItem mnuExit = new JMenuItem("Выход");
mnuGame.add(mnuExit);
// ...при нажатии на неё, завершаем приложение.
mnuExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_app = null;
System.exit(0);
}
});
}
Конструктор основного класса приложения:
public App() {
// Начальные настройки окна.
setTitle(_title);
_app = this;
createMenu();
setLayout(new GridLayout(4, 4, 5, 5));
setSize(400, 400);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// Создаём массивы для хранения фишек.
_grid = new int[_gridSize][_gridSize];
_btns = new JButton[_gridSize][_gridSize];
// Создаём кнопки.
for (int j = 0; j < _gridSize; ++j) {
_btns[j] = new JButton[_gridSize];
for (int i = 0; i < 4; ++i)
{
JButton btn = new JButton();
_btns[j][i] = btn;
add(btn);
// Обработчик нажатия на кнопку.
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!_gameOver)
{
tryMove((JButton)e.getSource());
if (testGrid())
JOptionPane.showMessageDialog(
_app,
"Вы правильно собрали головоломку!\nЗатрачено времени: " +
Integer.toString(_time) + " секунд.",
"Победа!",
JOptionPane.INFORMATION_MESSAGE);
}
}
});
}
}
// Создаём таймер для подсчёта времени.
_timer = new javax.swing.Timer(
1000,
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
++_time;
setTitle(_title + " (время: " +
Integer.toString(_time) + " секунд)");
}
});
// Перемешиваем фишки на поле.
shuffle();
}