Освой Processing играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Это перевод, ссылки на статью и на исходник внизу страницы. Код не оптимален, просто для изучения.
Напишем «Сапёр», в котором нужно просто нажимать на квадраты, надеясь, что под ними нет мины.
Первый шаг — определение состояния игры.
int gridW; // ширина сетки
int gridH; // высота сетки
int numMines; // число мин на поле
int[][] mines; // двумерный массив, 1 если есть мина, 0 если мины нет
boolean[][] flags; // entry is true if you have flagged that spot
boolean[][] revealed; // entry is true if that spot is revealed
Переменная int[][] mines позволяет легко подсчитать, сколько мин находится рядом с определённой позицией.
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;
}
После того, как мы уберём исключения, мы получим что-то похожее на это:
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;
}
Главная задача самой игры — раскрывать квадраты, начиная с точки х, у.
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);
}
В итоге мы имеем следующий алгоритм:
У нас есть переменная cellSize, определяющая количество пикселей в каждом квадрате.
void settings(){
size(gridW * cellSize, gridH * cellSize);
}
Таким образом мы создаём поле со сторонами gridW x gridH, где размеры каждого квадрата будут равняться значению cellSize.
Затем мы возвращаем переменные в изначальное состояние.
void setup(){
//initialize and clear the arrays
mines = new int[gridW][gridH];
flags = new boolean[gridW][gridH];
revealed = new boolean[gridW][gridH];
for(int x=0;x < gridW;x++){
for(int y = 0; y < gridH;y++){
mines[x][y]=0;
flags[x][y]=false;
revealed[x][y]=false;
}
}
}
Для инициализации поля:
//Place numMines mines on the grid
void placeMines(){
int i=0;
while(i < numMines){//We don't want mines to overlap, so while loop
int x=int(random(gridW));
int y=int(random(gridH));
if(mines[x][y]==1)continue;
mines[x][y]=1;
i++;
}
}
//Clear the mines
void clearMines() {
for (int x=0; x < gridW; x++) {
for (int y=0; y < gridH; y++) {
mines[x][y]=0;
}
}
}
Включаем обработку щелчков мыши.
//We don't want the first click to be a mine
boolean firstClick=true;
void mousePressed() {
int x=int(mouseX/cellSize);
int y=int(mouseY/cellSize);
//Right-click is flagging or de-flagging a square
if (mouseButton==RIGHT) {
flags[x][y]=!flags[x][y];
return;
} else {//left-click
//Avoid making the first click a mine
if (firstClick) {
firstClick=false;
do {
clearMines();
placeMines();
} while (calcNear(x,y)!=0);
}
//Check for game loss
if (mines[x][y]!=0) {
println("Dang!");
exit();
} else {//If game not lost, reveal starting from that square
reveal(x, y);
}
}
}
Отрисовка игры.
void draw() {
background(0);
//For each cell
for (int x=0; x0){
//fill(0,255,0);
//stroke(0,255,0);
//}
rect(x*cellSize, y*cellSize, cellSize, cellSize);
//If there is a mine near this spot and it is revealed
if (near>0&&revealed[x][y]) {
fill(txtColor);
noStroke();
textAlign(LEFT, TOP);
textSize(cellSize);
text(""+near, x*cellSize, y*cellSize);
}
}
}
}
На главную страницу Processing