January 2002 Programmer's Challenge
TriMinesweeper
Mail solutions to:
progchallenge@mactech.com
Due Date: 11:59pm ET, Sunday, 6 January 2002
Those of you that spend time on the Dark Side have certainly encountered that enemy of time well spent packaged with the OS for the masses, the game MineSweeper. For those of you who havent wasted hours on this pastime, the object of the game is to discover which cells in a rectangular grid contain bombs and which do not. You find the bombs by selecting one cell after another and specifying whether you think the cell contains a bomb. If you guess the cell to be safe and it actually contains a bomb, well, as they say, "game over". If the cell is safe, the game tells you how many of the 8 adjacent cells contain bombs. The skilled player uses this information to guess intelligently the next time.
Now, the standard MineSweeper game is probably too familiar to make an interesting Challenge. However, there are a couple of variants that are less well known. One of these variants is played on a board of hexagonal cells, where each cell has six neighbors instead of the standard eight. The variant for this Challenge uses triangular cells, with twelve neighbors for each cell, as depicted below.

The prototype for the code you should write is:
typedef void (*MinesweeperMoveProc) (
int row,
int col,
/* row and column to be checked or marked */
/* MinesweeperMoveProc updates contents of board variable provided to PlayMinesweeper */
int *bombsRemaining,
/* number of bombs remaining to be discovered */
Boolean checkOrMark,
/* FALSE to play the triangle (row,col), TRUE to mark it as a bomb */
Boolean *youLose,
/* returns TRUE if the location you played is a bomb */
Boolean *youWin
/* returns TRUE if you have marked all positions without losing */
);
#define kUnknown ((char)0x80)
#define kBomb ((char)0xFF)
void PlayMinesweeper (
int boardSize,
/* number of rows/columns in board */
int numberOfBombs,
/* number of bombs in board */
const char *board,
/* board[row*boardSize + col] is board element (row,col) */
MinesweeperMoveProc MakeMove
/* procedure for reporting moves */
/* MakeMove updates elements of board */
);
Your PlayMinesweeper routine will be called with four parameters: the size of the game being played (boardSize), the number of bombs on the board (numberOfBombs), a pointer to the game board, and a callback procedure that you must use for each move. The board will be square, and boardSize indicates both the number of triangles in each row and the number of rows in the board. The example above shows a board with 4 rows and 10 columns in the Challenge those values will be the same. Initially, you dont know anything about the values of the board cells, so they will all be marked as kUnknown.
The third parameter is the MakeMove callback procedure. To make a move, you must call the MakeMove procedure with the location of a cell (row, col). If you think the cell is safe, you should set checkOrMark to FALSE. To mark the cell as a bomb, set checkOrMark to TRUE. MakeMove will update the values in the board originally provided to PlayMinesweeper. If the cell is a bomb, the corresponding board value will be set to kBomb. If the cell is empty, its value will be set to the number of bombs in the 12 neighboring cells. If you move to a cell containing a bomb without marking it as such, youLose will be set to TRUE and the game is over. If you mark a cell as a bomb that does not actually contain a bomb, you will also lose. And if you correctly mark all cells in the board, youWin will be set to TRUE, and you win the game.
Many versions of the minesweeper game will reveal more than one board cell when logic indicates that multiple cells are safe, as when the cell played has no neighbors that contain bombs. The Challenge callback updates only one board value for each move, allowing you the privilege of marking each cell yourself. Other versions of the game also allow you to tentatively mark a cell as a bomb, possibly changing your mind later. In the Challenge, you have only one chance to mark a cell correctly mark a cell as a bomb incorrectly and it is Game Over.
The winner will be the player that wins the most games, weighted by size, in the minimum amount of time. You will earn one point per board cell for every game you win. One point will be deducted for each millisecond of execution time used in all games, including both games won and games lost. The execution time used by the callback procedure will be included.
This Challenge will use the CodeWarrior Pro 7 development environment. Solutions may be coded in C, C++, or Pascal (using the available-but-no-longer-supported Pascal compiler).
Oh, and just one more thing. ;-) Someone interested in the theory of computation is certain to write and tell me that MineSweeper is NP-complete. I know. If you are interested in this sort of thing, you can check out this link for some interesting work done by Richard Kaye.
|