📄 landmine.c
字号:
printline(6, "1-leg games:%3d\n", games1[index]);
printline(7, "Lost games: %3d\n", games0[index]);
if (games) {
printline(9, "Legs/game: %3d.%03d\n", score / games,
((score * 1000) / games) % 1000);
printline(10, "Steps/game:%3d.%03d\n", allsteps / games,
((allsteps * 1000) / games) % 1000);
}
}
/*
* Printf routine for windows, which can print at particular lines.
* A negative line number means continue printing at the previous location.
* Assumes the status window for output.
*/
static void printline(GR_COORD row, char * fmt, ...)
{
va_list ap;
GR_COUNT cc;
GR_SIZE width;
char *cp;
char buf[256];
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
if (row >= 0) {
charxpos = 0;
charypos = charheight * row + charheight - 1;
}
cp = buf;
for (;;) {
cc = 0;
width = 0;
while (*cp >= ' ') {
width += fi.widths[(int)*cp++];
cc++;
}
if (width) {
GrText(statwid, statgc, charxpos, charypos,
cp - cc, cc, GR_TFBOTTOM);
charxpos += width;
}
switch (*cp++) {
case '\0':
return;
case '\n':
newline();
break;
case '\r':
charxpos = 0;
break;
}
}
}
/*
* Clear the remainder of the line and move to the next line.
* This assumes output is in the status window.
*/
static void
newline()
{
GrFillRect(statwid, blackgc, charxpos, charypos - charheight + 1,
statwidth - charxpos, charheight);
charxpos = 0;
charypos += charheight;
}
/*
* Translate a board window coordinate into a cell position.
* If the coordinate is outside of the window, or exactly on one
* of the interior lines, then a coordinate of 0 is returned.
*/
static POS
findcell(x, y)
GR_COORD x;
GR_COORD y;
{
GR_COORD row;
GR_COORD col;
if (((x % xp) == 0) || ((y % yp) == 0))
return 0;
row = (y / yp) + 1;
col = (x / xp) + 1;
if ((row <= 0) || (row > size) || (col <= 0) || (col > size))
return 0;
return boardpos(row, col);
}
/*
* Initialize the board for playing
*/
static void
newgame()
{
GR_COORD row;
GR_COORD col;
GR_COUNT count;
CELL cell;
POS pos;
for (row = 0; row < FULLSIZE; row++) {
for (col = 0; col < FULLSIZE; col++) {
cell = F_EMPTY;
if (badsquare(row) || badsquare(col))
cell |= F_EDGE;
board[boardpos(row, col)] = cell;
}
}
playing = GR_TRUE;
count = 0;
legs = 2;
steps = 0;
drawstatus();
setcursor();
while (count < mines) {
do {
row = (rand() / 16) % (size * size + 1);
} while (row == (size * size));
col = (row % size) + 1;
row = (row / size) + 1;
pos = boardpos(row, col);
if ((pos == boardpos(1,1)) || (pos == boardpos(1,2)) ||
(pos == boardpos(2,1)) || (pos == boardpos(2,2)) ||
(pos == boardpos(size,size)))
continue;
if (!ismine(board[pos]) && checkpath(pos))
count++;
}
board[boardpos(1,1)] = (F_OLD | '0');
GrClearWindow(boardwid, GR_TRUE);
}
/*
* Check to see if there is still a path from the top left corner to the
* bottom right corner, if a new mine is placed at the indicated position.
* Returns GR_TRUE if mine was successfully placed.
*/
static GR_BOOL
checkpath(pos)
POS pos; /* position to place mine at */
{
CELL *bp; /* current board position */
CELL *endbp; /* ending position */
POS endpos; /* ending position */
GR_COUNT count; /* number of neighbors */
GR_COUNT i; /* loop counter */
GR_BOOL more; /* GR_TRUE if new square reached */
/*
* Begin by assuming there is a mine at the specified location,
* and then count neighbors. If there are less than two other
* mines or edge squares, then there must still be a path.
*/
board[pos] |= F_MINE;
count = 0;
for (i = 7; i >= 0; i--) {
if (board[pos + steptable[i]] & (F_MINE | F_EDGE))
count++;
}
if (count < 2)
return GR_TRUE;
/*
* Two or more neighbors, so we must do the full check.
* First clear the reach flag, except for the top left corner.
*/
endpos = boardpos(size, size);
bp = &board[endpos];
endbp = bp;
while (bp != board)
*bp-- &= ~F_REACH;
board[boardpos(1,1)] |= F_REACH;
/*
* Now loop looking for new squares next to already reached squares.
* Stop when no more changes are found, or when the lower right
* corner is reached.
*/
do {
more = GR_FALSE;
for (bp = &board[boardpos(1,1)]; bp != endbp; bp++) {
if (*bp & F_REACH) {
for (i = 7; i >= 0; i--) {
if ((bp[steptable[i]] & (F_MINE | F_REACH | F_EDGE)) == 0) {
bp[steptable[i]] |= F_REACH;
more = GR_TRUE;
}
}
}
}
if (board[endpos] & F_REACH)
return GR_TRUE;
} while (more);
/*
* Cannot reach the lower right corner, so remove the mine and fail.
*/
board[pos] &= ~F_MINE;
return GR_FALSE;
}
/*
* Move to a particular position and see if we hit a mine.
* If not, then count the number of mines adjacent to us so it can be seen.
* If we are stepping onto a location where we remembered a mine is at,
* then don't do it. Moving is only allowed to old locations, or to
* locations adjacent to old ones.
*/
static void
movetopos(newpos)
POS newpos; /* position to move to */
{
POS fixpos; /* position to fix up */
CELL cell; /* current cell */
GR_COUNT count; /* count of cells */
GR_COUNT i; /* index for neighbors */
if ((newpos < 0) || (newpos >= (FULLSIZE * FULLSIZE)) || !playing)
return;
cell = board[newpos];
if (isedge(cell) || (isseen(cell)) || isold(cell))
return;
count = isold(cell);
for (i = 0; i < 8; i++)
if (isold(board[newpos + steptable[i]]))
count++;
if (count <= 0)
return;
cell = (cell & F_FLAGS) | F_OLD;
steps++;
PRINTSTEPS;
if (ismine(cell)) { /* we hit a mine */
legs--;
board[newpos] = (F_REMEMBER | F_MINE);
cell = (F_EMPTY | F_OLD);
board[newpos] = cell;
drawbomb(newpos, redgc, GR_TRUE);
clearcell(newpos);
setcursor();
for (i = 0; i < 8; i++) {
fixpos = newpos + steptable[i];
if (isold(board[fixpos])) {
board[fixpos]--;
drawcell(fixpos);
}
}
drawstatus();
}
count = 0;
for (i = 0; i < 8; i++)
if (ismine(board[newpos + steptable[i]]))
count++;
board[newpos] = cell | (count + '0');
drawcell(newpos);
if ((legs <= 0) || (newpos == boardpos(size,size)))
gameover();
}
/*
* Remember or forget the location of a mine.
* This is for informational purposes only and does not affect anything.
*/
static void
togglecell(pos)
POS pos; /* position to toggle */
{
CELL cell;
if ((pos <= 0) || !playing)
return;
cell = board[pos];
if (isknown(cell)) {
if (!isseen(cell))
return;
board[pos] = (board[pos] & F_FLAGS) | F_EMPTY;
clearcell(pos);
return;
}
board[pos] = (board[pos] & F_FLAGS) | F_REMEMBER;
drawcell(pos);
}
/*
* Here when the game is over.
* Show where the mines are, and give the results.
*/
static void
gameover()
{
POS pos;
CELL cell;
playing = GR_FALSE;
switch (legs) {
case 0:
games0[index]++;
steps0[index] += steps;
break;
case 1:
games1[index]++;
steps1[index] += steps;
break;
case 2:
games2[index]++;
steps2[index] += steps;
break;
}
for (pos = 0; pos < (FULLSIZE * FULLSIZE); pos++) {
cell = board[pos];
if (isseen(cell))
cell = (cell & F_FLAGS) | F_WRONG;
if (ismine(cell))
cell = (cell & F_FLAGS) | F_REMEMBER;
board[pos] = cell;
}
drawboard();
drawstatus();
}
/*
* Search the game parameter table for the current board size and
* number of mines, and set the index for those parameters so that
* the statistics can be accessed. Allocates a new index if necessary.
*/
static void
findindex()
{
for (index = 0; index < MAXPARAMS; index++) {
if ((sizeparam[index] == size) && (mineparam[index] == mines))
return;
}
for (index = 0; index < MAXPARAMS; index++) {
if (sizeparam[index] == 0) {
sizeparam[index] = size;
mineparam[index] = mines;
return;
}
}
fprintf(stderr, "Too many parameters in save file\n");
exit(1);
}
/*
* Read in a saved game if available, otherwise start from scratch.
* Exits if an error is encountered.
*/
static void
readgame(name)
char *name; /* filename */
{
int fd;
fd = -1;
if (name)
fd = open(name, 0);
if (fd < 0) {
magic = MAGIC;
size = SIZE;
mines = (size * size * MINEPERCENT) / 100;
playing = GR_FALSE;
return;
}
if (read(fd, &st, sizeof(st)) != sizeof(st))
magic = 0;
close(fd);
if ((magic != MAGIC) || (size > MAXSIZE)) {
fprintf(stderr, "Save file format is incorrect\n");
exit(1);
}
}
/*
* Write the current game to a file.
* Returns nonzero on an error.
*/
static GR_BOOL
writegame(name)
char *name; /* filename */
{
int fd;
if (name == NULL)
return GR_TRUE;
fd = creat(name, 0666);
if (fd < 0)
return GR_TRUE;
if (write(fd, &st, sizeof(st)) != sizeof(st)) {
close(fd);
return GR_TRUE;
}
close(fd);
return GR_FALSE;
}
/* END CODE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -