13 febrero 2008

El "algoritmo" del buscaminas

Hace una semana o dos programé un pequeño buscaminas para la Nintendo DS. Hoy me ha dado por añadirle la opción de poner banderitas pero... ¡en el lápiz no hay botón derecho!

En su día me bajé 3 versiones distintas del buscaminas para la DS (creo que todo aquél que ha programado algo para la DS su primer programa ha sido un buscaminas). En todos esos juegos para poner banderas se usaba L+click. Esta forma es buena para los diestros pero muy incomoda para los zurdos como yo. Los buscaminas más currados que se han hecho no discriminan a los zurdos y permiten también R+click para poner banderas. Al final he utilizado estos 2 botones también.

Tras programar lo de las banderitas me he encontrado con que la función que se llama al hacer click en un cuadrado empezó siendo super simple y ahora ya no hay quien la entienda. Cada vez que surgía un fallo añadía un nuevo if y después de corregir varios fallos ya se nota el caos.

Algún día la reescribiré mejor (por lo tanto crearé nuevos fallos) o le pondré comentarios...


void checkPosition(int y, int x, int action) {
if (y >= ROWS || x >= COLS)
return;

if (estate == VICTORY || estate == DEAD)
return;

lastX = x;
lastY = y;

if (action == FLAG && opened[y][x] != OPENED) {
if (opened[y][x] == FLAGGED)
opened[y][x] = HIDDEN;
else
opened[y][x] = FLAGGED;
} else if (opened[y][x] == FLAGGED) {
// nada
} else if (map[y][x] == MINE) {
estate = DEAD;
opened[y][x] = OPENED;
} else if (opened[y][x] == HIDDEN){

opened[y][x] = OPENED;
numOpened++;

if (map[y][x] == 0)
dfsOpen(y, x);

if (numOpened == (COLS*ROWS - NMINES)) {
estate = VICTORY;
}
}

printMap();
}


Por si a alguien le interesa:
action: vale FLAGGED si se ha puesto una bandera y DISCOVER si es para abrir una casilla.
lastX, lastY: Guarda la posición del último click. No recuerdo ahora para qué...
estate: Indica en que estado se encuentra el juego: PLAYING, DEAD, VICTORY, CREATING_GAME, etc.
map[y][x]: puede valer 0,1,2,...,8 o MINE.
openen[y][x]: puede valer HIDDEN si aun no se ha abierto esa casilla, FLAGGED si se le ha puesto bandero u OPENED.

Ocurren 2 cosas:
opened se usaba para indicar si una casilla habia sido abierta o no. Ahora que también sirve para indicar si tiene bandera el nombre no es muy acertado. Esto me ocurre en 2 o 3 sitios más del código.

Cada vez que añado alguna cosa al programa, aunque sea una gilipollez añado también varios fallos. Por ejemplo con lo de las banderas me pasaba que a una casilla descubierta le podias poner la bandera y después al quitársela pasaba a estar tapada de nuevo. Como yo cuento el número de casillas destapadas (numOpened) para calcular cuando ha ganado se podría estar abriendo todo el rato la misma casilla con este método y ganar.