見出し画像

マインスイーパー作ってみた【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;
}

一応これで動きますが、バグがあるかもしれません。

一番上のROWCOLUMNBOMBの値を調整するとマス目の数や地雷の数を調整できます。

動作している様子


  • □:開けたマス

  • ■:開けてないマス

  • 数字:周囲の地雷の数

  • *:地雷

  • F:旗

何かアドバイス等あればコメントをよろしくお願いいたします。

この記事が気に入ったらサポートをしてみませんか?