マインスイーパー作ってみた【C言語】
こんにちは、とりすてぃっくです。
なんとなくゲーム作りたいなと思って
マインスイーパーを作りました。
言語は C言語 です。
大体の仕様
ターミナル上で動く
9x9マス
地雷は12個
旗を立てられる
最初に指定したマスとその周囲1マスには、地雷は生成されないようにする
そのマスの周囲に地雷がなければ、周囲のマスも自動的に開けるようにする。
ソースコード
かなり汚いコードかもしれません。
行数は256行です。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COLUMN 9
#define BOMB 12
typedef struct {
int bomb;
int flag;
int opened;
int surround;
int checking;
}block;
block block_state[ROW][COLUMN];
int remain = 0;
int get_random(int min, int max);
void init_game();
int draw_block();
int generate_bomb(int bomb);
void enter_address(int* row, int* column);
int check_address();
int check_bomb(int row, int column);
int search_checking();
int main(void){
srand((unsigned int)time(NULL));
while(1) {
int flag_generate = 0;
int flag_bomb = 0;
int retry = 0;
int row = 0;
int column = 0;
init_game();
while(1){
if(draw_block() == -1){
printf("error!\n");
return -1;
}
if(flag_generate == 0){
if(generate_bomb(BOMB) == -1){
printf("\n");
}
flag_generate++;
}else{
enter_address(&row, &column);
if(check_address(row, column) == 1){
flag_bomb = 1;
break;
}
if(remain <= BOMB){
break;
}
}
}
for(int i = 0; i < ROW; i++){
for(int j = 0; j < COLUMN; j++){
block_state[i][j].opened = 1;
}
}
draw_block();
if(flag_bomb == 1){
printf("GameOver\n");
}else{
printf("Clear!\n");
}
printf("Do you wanna retry?\n Yes->1, No->Others\n>");
scanf("%d", &retry);
if(retry != 1){
printf("See you!\n");
break;
}
}
return 0;
}
int get_random(int min, int max){
return min + (int)(rand() * (max - min + 1.0) / (1.0 + RAND_MAX));
}
void init_game() {
for(int i=0; i<ROW; i++) {
for(int j=0; j<COLUMN; j++){
block_state[i][j].bomb = 0;
block_state[i][j].flag = 0;
block_state[i][j].opened = 0;
block_state[i][j].surround = 0;
block_state[i][j].checking = 0;
remain = ROW*COLUMN;
}
}
return;
}
int draw_block() {
for(int i=-1; i<ROW; i++) {
for(int j=-1; j<COLUMN; j++){
if(i == -1){
if(j == -1){
printf(" ");
j++;
}
printf("%2d",j);
}else{
if(j == -1){
printf("%2d ",i);
j++;
}
switch (block_state[i][j].opened){
case 0:
switch(block_state[i][j].flag){
case 0:
printf("■ ");
break;
case 1:
printf("F ");
break;
default:
return -1;
}
break;
case 1:
if(block_state[i][j].bomb == 1){
printf("* ");
}else if(block_state[i][j].surround == 0){
printf("□ ");
}else if(block_state[i][j].surround <= 8){
printf("%d ",block_state[i][j].surround);
}else{
return -1;
}
break;
default:
return -1;
}
}
}
printf("\n");
}
return 0;
}
int generate_bomb(int bomb) {
static int i, j;
int row = 0;
int column = 0;
enter_address(&row, &column);
while(i != BOMB){
int r = get_random(0, ROW-1);
int c = get_random(0, COLUMN);
if(block_state[r][c].bomb == 0 && (row + 1 < r || row - 1 > r) && (column + 1 < c || column > c)){
block_state[r][c].bomb = 1;
i++;
}else{
j++;
if(j > 1000){
return -1;
}
}
}
block_state[row][column].checking = 1;
search_checking();
return 0;
}
void enter_address(int* row, int* column){
do{
printf("enter the block address.\n");
printf("(row)>");
scanf("%d", &*row);
printf("(column)>");
scanf("%d", &*column);
}while(*row < 0 || *row >= ROW || *column < 0 || *column >= COLUMN);
return;
}
int check_address(int row, int column){
int num = -1;
if(block_state[row][column].opened == 0){
if(block_state[row][column].flag == 0){
printf("open = 0, flag = 1\n");
scanf("%d", &num);
switch(num){
case 0:
block_state[row][column].checking = 1;
if(check_bomb(row, column) == 1){
return 1;
}
search_checking();
break;
case 1:
block_state[row][column].flag = 1;
break;
default:
break;
}
}else{
block_state[row][column].flag = 0;
}
}else{
printf("This block is already opened\n");
}
return 0;
}
int check_bomb(int row, int column){
if(block_state[row][column].bomb == 1){
block_state[row][column].opened = 1;
return 1;
}else{
for(int i = -1; i <= 1; i++){
for(int j = -1; j <= 1; j++){
if(row + i >= 0 && row + i < ROW && column + j >= 0 && column + j < COLUMN){
if(block_state[row + i][column + j].bomb == 1){
block_state[row][column].surround += 1;
}
}
}
}
}
if(block_state[row][column].surround == 0){
for(int i = -1; i <= 1; i++){
for(int j = -1; j <= 1; j++){
if(row + i >= 0 && row + i < ROW && column + j >= 0 && column + j < COLUMN){
if(block_state[row + i][column + j].checking == 0){
block_state[row + i][column+ j].checking = 1;
}
}
}
}
}
block_state[row][column].checking = 2;
block_state[row][column].opened = 1;
remain -= 1;
return 0;
}
int search_checking(){
int re_check = 0;
do{
re_check = 0;
for(int i = 0; i < ROW; i++){
for(int j = 0; j < COLUMN; j++){
if(block_state[i][j].checking == 1){
check_bomb(i, j);
re_check = 1;
}
}
}
}while(re_check == 1);
return 0;
}
一応これで動きますが、バグがあるかもしれません。
一番上のROWとCOLUMNとBOMBの値を調整するとマス目の数や地雷の数を調整できます。
動作している様子
□:開けたマス
■:開けてないマス
数字:周囲の地雷の数
*:地雷
F:旗
何かアドバイス等あればコメントをよろしくお願いいたします。
この記事が気に入ったらサポートをしてみませんか?