Добавить в корзинуПозвонить
Найти в Дзене
パラダイス 分隊

Как Это Сделано: Пишем Сапера за 4 минуты

Уникальность игры в том, что она очень простая и при этом весьма увлекательная. В «Сапере» нет никакой хитрой геймплейной механики, вы просто нажимаете на квадратики, надеясь, что под ними нет мины. Предлагаю попробовать написать «Сапера» на Processing. Это отличный инструмент, который позволяет создавать графические приложения на Java. Прежде чем начать, скажу, что этот туториал рассчитан на тех, кто уже знает Java. Опыт работы с Processing необязателен. Итак, начинаем. Первый шаг — определение состояния игры. Я решил реализовать это вот так.
1 // int gridW; // grid width
int gridH; // grid height
int numMines; // number of mines on the board
int[][] mines; // entry is 1 for having a mine and 0 for not
boolean[][] flags; // entry is true if you have flagged that spot
boolean[][] revealed; // entry is true if that spot is revealed
// Здесь, кажется, имеет смысл все, кроме вот этого участка: int[][] mines. Почему сетка мин является целым числом, а не булевым? Дело в том, что это

Уникальность игры в том, что она очень простая и при этом весьма увлекательная. В «Сапере» нет никакой хитрой геймплейной механики, вы просто нажимаете на квадратики, надеясь, что под ними нет мины.

Предлагаю попробовать написать «Сапера» на Processing. Это отличный инструмент, который позволяет создавать графические приложения на Java.

Прежде чем начать, скажу, что этот туториал рассчитан на тех, кто уже знает Java. Опыт работы с Processing необязателен.

Итак, начинаем. Первый шаг — определение состояния игры. Я решил реализовать это вот так.

1 //

int gridW; // grid width
int gridH; // grid height
int numMines; // number of mines on the board

int[][] mines; // entry is 1 for having a mine and 0 for not
boolean[][] flags; // entry is true if you have flagged that spot
boolean[][] revealed; // entry is true if that spot is revealed

//

Здесь, кажется, имеет смысл все, кроме вот этого участка: int[][] mines. Почему сетка мин является целым числом, а не булевым? Дело в том, что это позволяет легко подсчитать, сколько мин находится рядом с определенной позицией.

2//

int calcNear(int x, int y) {
int i=0;
for (int offsetX=-1; offsetX<=1; offsetX++) {
for (int offsetY=-1; offsetY<=1; offsetY++) {
i+=mines[offsetX+x][offsetY+y];
}
}
return i;
}

//

Этот код определяет, сколько мин находится рядом с определенным участком. После того, как мы уберем исключения, мы получим что-то похожее на это:

3//

boolean outBounds(int x,int y){
return x<0||y<0||x>=gridW||y>=gridH;
}

int calcNear(int x, int y) {
if(outBounds(x,y))return 0;
int i=0;
for (int offsetX=-1; offsetX<=1; offsetX++) {
for (int offsetY=-1; offsetY<=1; offsetY++) {
if (outBounds(offsetX+x, offsetY+y))continue;
i+=mines[offsetX+x][offsetY+y];
}
}
return i;
}

//

Главная задача самой игры — раскрывать квадраты, начиная с точки х, у.

4//

void reveal(int x, int y){
if(outBounds(x,y))return;
if(revealed[x][y])return;
revealed[x][y]=true;
if(calcNear(x,y)!=0)return;
reveal(x-1,y-1);
reveal(x-1,y+1);
reveal(x+1,y-1);
reveal(x+1,y+1);
reveal(x-1,y);
reveal(x+1,y);
reveal(x,y-1);
reveal(x,y+1);
}

//

В итоге мы имеем следующий алгоритм:

  • Если позиция за пределами поля, end;
  • Если позиция раскрыта, end;
  • Раскрываем текущую позицию;
  • Если у нас бомба рядом с текущей позицией, end;
  • Если мы дошли до этого пункта во время выполнения функции, текущая позиция в пределах игрового поля была обнаружена и рядом с ней нет бомб, открываем смежные квадраты.

В принципе, вся остальная игра представляет собой то же самое.

Продолжение следует // Визуализация