北理工49. 【游戏】扫雷
49. 【游戏】扫雷
背景
你玩儿过扫雷游戏吧?有个操作系统中带了这个小游戏,那个系统叫什么来着?;-)在游戏中要想过关,就必须要在一个 NxM 的区域上找出所有的地雷。游戏过程中,计算机会在地图上显示一些数字从而帮助你确定哪里有地雷。例如,在下面这个有两颗地雷的 4x4 的地图(*表示地雷):
*...
....
.*..
....
根据上面的地图,可以计算出应该提供给游戏者的数字如下所示:
*100
2210
1*10
1110
每个数字表示了该方格周围到底有几个地雷,当然,一个方格周围最多的时候只会有八个。
输入
输入中将包括一系列的地图,每个地图的第一行有两个整数 n 和 m(0 <n,m <= 100),它们表示了地图的行数和列数。下面的 n 行每行都有 m 个字符,其中 "." 表示安全而 "*" 表示地雷。如果地图的 n 和 m 都为 0,则表示输入结束。
输出
针对每一个地图,首先输出一行:
Field #x:
其中 x 是当前地图的编号(从 1 开始)。下面的 n 行则将地图中的 "." 以数字表示,该数字表示该方格周围有多少颗地雷。
来源
http://acm.uva.es/problemset/v101/10189.html
| 测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
|---|---|---|---|---|---|
| 测试用例 1 | 以文本方式显示
|
以文本方式显示
|
1秒 | 64M | 0 |
| 测试用例 2 | 以文本方式显示
|
以文本方式显示
|
1秒 | 64M | 0 |
这道题很难,至少我做这题的感觉是这样。第一感觉是要用到二维数组,但是二维数组我忘记了!我还是太菜了……这题做的还是比较艰辛的,花了两天(流泪)
#include <stdio.h>
int row, col;
char landmine_number(const char point[][100], int x, int y);
int main(void)
{
/*首先创立一个大小为100*100的char数组读入row,col,还要有一个counter来记录次数
* 读入row,col
* 对于一个坐标x,y;它的周围 [x-1][y-1]~[x-1][y+1];[x][y-1]~[x][y+1];[x+1][y-1]~[x+1][y+1]
* landmine_counter来记录坐标周围地雷数量
*/
char table[100][100] = { '.'};
int counter = 0, landmine_counter = 0;
scanf("%d %d", &row, &col);
getchar();
do {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++)
table[i][j] = getchar();
getchar();
}
counter++;
putchar(counter > 1 ? '\n' : '\0');
printf("Field #%d:\n", counter);
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++)
printf("%c", landmine_number(table, i, j));
putchar('\n');
}
scanf("%d %d", &row, &col);
getchar();
} while (row != 0 && col != 0);
return 0;
}
char landmine_number(const char point[][100], int x, int y)
{
int landmine_counter = 0;
for (int i = x - 1; i <= x + 1 && i < row ; i++)
for (int j = y - 1; j <= y + 1 && j < col; j++)
if(j>=0 && i >= 0)
if (point[i][j] == '*' && (i != x || j != y)) landmine_counter++;
char ret[2] = {0};
if (point[x][y] == '*') ret[0] = '*';
else sprintf(ret, "%d", landmine_counter);
return ret[0];
}
原本这道题已经被我弃之脑后了,但是一次偶然与丁助教的聊天,又让我萌发了新的灵感,代码还可以改进!
1. 数据的读入可以采用字符串%s,或者一些专门的字符串读入函数。这样可以看上去更赏心悦目
2. 我采取的输出地雷方法是最容易想到的,但是还可以有另外一种想法。那就是把每个地雷周围的八个位置都++,然后输出
3. 关于边界问题,我自认为采取了一个很巧妙的方法,也就是下述代码!(我的脑子思考了两天才想出来)
for (int i = x - 1; i <= x + 1 && i < row ; i++)
for (int j = y - 1; j <= y + 1 && j < col; j++)
if(j>=0 && i >= 0)
if (point[i][j] == '*' && (i != x || j != y)) landmine_counter++;
但是还有一个新的想法就是,通过将数组扩大来避免边界问题。这样说很抽象,所以还是看代码
#include<stdio.h>
#include<string.h>
static int row, col;
void mark_mines(char table[][110], char mines[][110]);
int main(void) {
int counter = 0;
char table[110][110],mines[110][110];
scanf("%d %d", &row, &col);
getchar();
do {
memset(table, 0, sizeof(table));
memset(mines, '0', sizeof mines);
for (int i = 1; i < row + 1; i++)
gets(&table[i][1]);
/*only two rows, the whole data was read completely,wonderful*/
putchar(counter++ > 0 ? '\n' : '\0');
printf("Field #%d\n", counter);
mark_mines(table, mines);
for (int i = 1; i < row + 1; i++)
puts(&mines[i][1]);
scanf("%d %d", &row, &col);
getchar();
} while (row != 0 && col != 0);
return 0;
}
void mark_mines(char table[][110], char mines[][110])
{
for (int x = 1; x < row + 1; x++)
for (int y = 1; y < col + 1; y++)
if (table[x][y] == '*') {
for (int i = -1; i < 2; i++)
for (int j = -1; j < 2; j++)
if (mines[x + i][y + j] != '*') mines[x + i][y + j]++;
mines[x][y] = '*';
}
for (int i = 1; i < row + 1; i++)
mines[i][col + 1] = '\0';
}

浙公网安备 33010602011771号