-
Notifications
You must be signed in to change notification settings - Fork 0
/
minesweeper.c
346 lines (255 loc) · 9.71 KB
/
minesweeper.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*
* Jefferson E. M. Bueno
*
* Campo Minado
*
*/
#include <stdio.h>
#include <stdlib.h>
#define DEBUG 1
//Abertura do arquivo que contém o campo,
//a partir do nome contido em "nome_arquivo".
FILE* abre_arquivo(FILE* arquivo){
char nome_arquivo[8]; //nome do arquivo (x.board)
scanf("%s", nome_arquivo);
arquivo = fopen(nome_arquivo, "r");
return arquivo;
}
//Descobre o número de linhas e colunas na matriz presente no arquivo
//Após isso, volta o ponteiro ao começo do arquivo.
void descobre_lin_col(FILE* arquivo, int* lin, int* col){
char prov; //Variavel provisória para armazenar os caracteres da matriz.
int cont = 0; //Variavel para contar o número total de caracteres.
while(fscanf(arquivo, "%c", &prov) != EOF){
cont++;
if(prov == '\n'){ //Caso encontre um '\n', soma uma linha.
(*lin)++;
}
}
*col = cont / *lin; //O numero de colunas é igual ao total de valores dividido pelas linhas
fseek(arquivo, 0, SEEK_SET);
}
//Aloca dinamicamente a matriz a partir do tamanho das linhas e colunas
//obtido pela função "descobre_lin_col".
char** aloca_matriz(int lin, int col){
char** mat = (char**)malloc(lin * sizeof(char*));
for(int i = 0; i < lin; i++){
mat[i] = (char*)malloc(col * sizeof(char));
}
return mat;
}
//Lê a matriz do campo minado presente no arquivo
//E a armazena em "mat_campo".
void le_matriz_campo(FILE* arquivo, char** mat_campo, int lin, int col){
for(int i = 0; i < lin; i++){
for(int j = 0; j < col; j++){
fscanf(arquivo, "%c", &mat_campo[i][j]);
}
}
}
//Printa a matriz iterativamente.
void printa_matriz(char** mat, int lin, int col){
for(int i = 0; i < lin; i++){
for(int j = 0; j < col-1; j++){
printf("%c", mat[i][j]);
}
printf("\n");
}
}
//Retorna verdadeiro caso a coordenada (x, y)
//seja valida, ou seja, esta dentro da matriz
int cord_valida(int x, int y, int lin, int col){
return (x >= 0) && (x < lin) && (y >= 0) && (y < col-1);
}
//Retorna verdadeiro caso a coordenada (x, y)
//tenha uma bomba (*).
int tem_bomba(int x, int y, char** mat){
if (mat[x][y] == '*')return 1;
else return 0;
}
//Conta o numero de bombas nas posicoes vizinhas a coordenada atual (x, y)
//Inicialmente testa se a coordenada está dentro da matriz com cord_valida
//Apos isso, checa se cada uma das 8 posicoes adjacentes contem bombas
//e soma cada uma encontrada a variavel cont.
char conta_bombas_adjacentes(char** mat_campo, int x, int y, int lin, int col){
int cont = 0;
//Checa a coordenada para cima
if (cord_valida(x-1, y, lin, col) == 1){
if (tem_bomba(x-1, y, mat_campo) == 1)cont++;
}
//Checa a coordenada para baixo
if (cord_valida(x+1, y, lin, col) == 1){
if (tem_bomba(x+1, y, mat_campo) == 1)cont++;
}
//Checa a coordenada para a direita
if (cord_valida(x, y+1, lin, col) == 1){
if (tem_bomba(x, y+1, mat_campo) == 1)cont++;
}
//Checa a coordenada para a esquerda
if (cord_valida(x, y-1, lin, col) == 1){
if (tem_bomba(x, y-1, mat_campo) == 1)cont++;
}
//Checa a coordenada para cima-direita
if (cord_valida(x-1, y+1, lin, col) == 1){
if (tem_bomba(x-1, y+1, mat_campo) == 1)cont++;
}
//Checa a coordenada para cima-esquerda
if (cord_valida(x-1, y-1, lin, col) == 1){
if (tem_bomba(x-1, y-1, mat_campo) == 1)cont++;
}
//Checa a coordenada para baixo-direita
if (cord_valida(x+1, y+1, lin, col) == 1){
if (tem_bomba(x+1, y+1, mat_campo) == 1)cont++;
}
//Checa a coordenada para baixo-esquerda
if (cord_valida(x+1, y-1, lin, col) == 1){
if (tem_bomba(x+1, y-1, mat_campo) == 1)cont++;
}
//converter o número de bombas (em inteiro)
//para o valor correspondente em char
cont = cont + '0';
return cont;
}
//Percorre a matriz do campo minado iterativamente, preenchendo
//as posicoes que correspondem a vizinhanca com o numero de bombas
//adjacentes, utilizando a funcao conta_combas_adjacentes
void preenche_matriz_dicas(char** mat_campo, int lin, int col){
for(int i = 0; i < lin; i++){
for(int j = 0; j < col; j++){
char cont = conta_bombas_adjacentes(mat_campo, i, j, lin, col);
if((cont != '0') && (mat_campo[i][j] != '*')){ //caso existam bombas, adiciona seu valor.
mat_campo[i][j] = cont;
}
}
}
}
//Preenche a matriz do usuario com "X"
//Posteriormente, alguns "X" serão substituidos por outros valores
void preenche_matriz_user(char** mat_user, int lin, int col){
for(int i = 0; i < lin; i++){
for(int j = 0; j < col; j++){
if(j == col-1){
mat_user[i][j] = '\n';
}else{
mat_user[i][j] = 'X';
}
}
}
}
//Percorre recursivamente a matriz do campo minado, adicionando os valores a matriz do usuario
//Caso a coordenada atual na matriz do usuario nao seja um valor "X", entao retorna, pois ja foi percorrido.
//Se nao, vai para cada uma das coordenadas adjacentes, apos testar se estao dentro da matriz e sao espacos vazios.
void percorre_matriz(char** mat_campo, char** mat_user, int x, int y, int lin, int col){
//Caso base: se ja foi percorrido, retorna
if(mat_user[x][y] != 'X') return;
//Copiar o valor do campo para a matriz do usuario
mat_user[x][y] = mat_campo[x][y];
//Caso o valor no campo ainda seja um lugar vazio, percorre os 8 adjacentes
if(mat_campo[x][y] == '.'){
//Testa para cima
if (cord_valida(x-1, y, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x-1, y, lin, col);
}
//Testa para baixo
if (cord_valida(x+1, y, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x+1, y, lin, col);
}
//Testa para a direita
if (cord_valida(x, y+1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x, y+1, lin, col);
}
//Testa para a esquerda
if (cord_valida(x, y-1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x, y-1, lin, col);
}
//Testa para cima-direita
if (cord_valida(x-1, y+1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x-1, y+1, lin, col);
}
//Testa para cima-esquerda
if (cord_valida(x-1, y-1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x-1, y-1, lin, col);
}
//Testa para baixo-direita
if (cord_valida(x+1, y+1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x+1, y+1, lin, col);
}
//Testa para baixo-esquerda
if (cord_valida(x+1, y-1, lin, col) == 1){
percorre_matriz(mat_campo, mat_user, x+1, y-1, lin, col);
}
}
}
//Lida com a interacao do usuario com o modo de jogo 3
//e printa o resultado de acordo com as coordenadas selecionadas
void interacao_usuario(char** mat_campo, char** mat_user, int x, int y, int lin, int col){
//Caso o usuario selecione uma bomba, todo o campo é printado, mostrando que o jogo foi perdido.
if(mat_campo[x][y] == '*'){
printa_matriz(mat_campo, lin, col);
return;
}
//Caso o usuario selecione uma dica, a matriz preenchida por "X" é printada,
//exceto pela posicao da dica, mostrando a quantidade de bombas adjacentes
if((mat_campo[x][y] != '.') && (mat_campo[x][y] != '*')){
mat_user[x][y] = mat_campo[x][y]; //Adiciona a dica a matriz de "X"
printa_matriz(mat_user, lin, col);
return;
}
//Caso um espaco vazio seja selecionado, a matriz é percorrida recursivamente
//para mostrar a vizinhanca da area vazia selecionada.
if(mat_campo[x][y] == '.'){
percorre_matriz(mat_campo, mat_user, x, y, lin, col);
printa_matriz(mat_user, lin, col);
}
}
int main(void){
//Declaraçao de variáveis.
short int modo; //modo de jogo (1-3)
FILE* arquivo = NULL; //arquivo a ser lido
int lin = 0, col = 0; //linhas e colunas da matriz
char** mat_campo = NULL; //matriz que recebe o campo
char** mat_user = NULL; //matriz que será mostrada após interação
int x, y; //coordenadas inseridas pelo usuario
//Leitura do modo do jogo.
scanf("%hd", &modo);
//Abre o arquivo e trata de um possível erro
arquivo = abre_arquivo(arquivo);
if(arquivo == NULL){
printf("Erro na abertura do arquivo.");
return -1;
}
//Descobrir o número de linhas e colunas
descobre_lin_col(arquivo, &lin, &col);
//Alocação e leitura da matriz do campo minado
mat_campo = aloca_matriz(lin, col);
le_matriz_campo(arquivo, mat_campo, lin, col);
//Escolha do de jogo (1-3) a partir da variavel "modo"
switch(modo){
case 1:
//Exibir o campo inalterado
printa_matriz(mat_campo, lin, col);
break;
case 2:
//Criar dicas.
preenche_matriz_dicas(mat_campo, lin, col);
//Exibir campo com as dicas
printa_matriz(mat_campo, lin, col);
break;
case 3:
//Recebe as coordenadas a partir do usuario
scanf("%d %d", &x, &y);
//Aloca a matriz que seja exibida ao usuario
//E a preenche com "X"
mat_user = aloca_matriz(lin, col);
preenche_matriz_user(mat_user, lin, col);
//Cria dicas no campo
preenche_matriz_dicas(mat_campo, lin, col);
//Percorrer a matriz a partir das coordenadas
interacao_usuario(mat_campo, mat_user, x, y, lin, col);
break;
}
fclose(arquivo);
free(mat_user);
free(mat_campo);
return 0;
}