2015年1月19日 星期一

[專題] 第八組 - 踩地雷

main.cpp
/*   ** 遊戲設計說明:
     1. 踩地雷有9*9的格子,共10顆地雷
     2. 顯示數字為那一格附近的八個地區共有幾顆地雷
        未顯示數字則表示附近的八個地區沒地雷 

     ** 程式設計說明:
     1. 將格子宣告成int cells[9][9]的陣列,存放資訊之用
            0  代表安全的地區,且附近沒地雷 
         1~ 8  代表安全的地區,但附近有地雷,數字為地雷數 
           -1  代表尚未被踩到的地雷區
        10~18  代表已被選取的安全地區
           -2  代表已被踩到的地雷區,遊戲結束
           
     2. 在螢幕上印出格子
     3. 請使用者輸入第一個要打開的位置(x, y) 
     2. 利用亂數放置地雷十顆,在不重複的位置且不是使用者輸入的位址
     4. 在安全地區計算其資訊(附近幾顆地雷)
     5. 將剛被選取到的安全地區值加10(代表已選取) 
     6. 清除螢幕
     7. 顯示cells陣列中,值>10的資訊(>10代表已經選取)
     8. 請使用者輸入接下來要打開的位置(x2, y2)
     9. 計算(x2, y2)的值 (安全-> cells[x2][y2] += 10;地雷-> cells[x2][y2] = -2,遊戲結束)
    10. 如果cells[x2, y2]的值為10,則打開附近的格子
    10. 若未結束則重複step 6 ~ 9,直到贏(全部都>10 or ==-1 )就跳出 
    11. 詢問是否再玩一次,若再玩一次則重複2~10 
*/

#include
#include
#include

void assign_initial(int cells[][11]);                                           //將格子內資訊初始化為0
void print_blanks(void);                                                        //印出遊戲初始的格子 
void open_cell(int *op_x, int *op_y);                                           //請使用者輸入要打開的位置
void put_mine(int cells[][11], int op_x, int op_y);                             //放置地雷
void calculate_num_of_cells(int cells[][11]);                                   //計算非地雷區附近有幾顆地雷 
void assign_inf_after_open(int cells[][11], int op_x, int op_y);                //改變使用者打開的位置之資訊
void open_surrounding(int cells[][11], int p_x, int op_y);                      //打開附近的區域(當格子附近無地雷時) 
void check_no_mine(int cells[][11], int op_x, int op_y);                        //檢查附近的區域有沒有地雷 
int  check_over(int cells[][11], int op_x, int op_y);                           //檢查遊戲是否結束(輸或贏)
void print_cells(int cells[][11], int op_x, int op_y, int over);                //印出目前的狀況
void print_condition_playing(int cells[][11]);                                  //印出尚未結束的狀況
void print_condition_over(int cells[][11], int over);                           //印出遊戲結束的狀況(每個格子之資訊) 
char play_again(void);                                                          //詢問是否再玩一次

int main(void) {
    int  cells[11][11],
         open_x, open_y,
         over;
    char again;

    do {
       system("cls");
       assign_initial(cells);                                                   //將格子內資訊初始化為0
       print_blanks();                                                          //印出遊戲初始的格子 
       open_cell(&open_x, &open_y);                                             //請使用者輸入要打開的位置
       put_mine(cells, open_x, open_y);                                         //放置地雷
       calculate_num_of_cells(cells);                                           //計算非地雷區附近有幾彈地雷
       assign_inf_after_open(cells, open_x, open_y);                            //改變使用者打開的位置之資訊
       check_no_mine(cells, open_x, open_y);                                    //檢查附近的區域有沒有地雷,並將無地雷的區域打開
       over = check_over(cells, open_x, open_y);                                //檢查遊戲是否結束(輸或贏)
       print_cells(cells, open_x, open_y, over);                                //印出目前的狀況
       while (over == 0) {
             open_cell(&open_x, &open_y);
             assign_inf_after_open(cells, open_x, open_y);                      //請使用者輸入要打開的位置
             check_no_mine(cells, open_x, open_y);                              //檢查附近的區域有沒有地雷,並將無地雷的區域打開
             over = check_over(cells, open_x, open_y);                          //檢查遊戲是否結束(輸或贏)
             print_cells(cells, open_x, open_y, over);                          //印出目前的狀況
       }
       again = play_again();                                                    //詢問是否再玩一次
    } while (again == 'Y' || again == 'y');

    return(0);
}

void assign_initial(int cells[][11]) {                                          //將格子內資訊初始化為0 
     int i, j;
     for (i = 0; i < 11; i++)
         for (j = 0; j < 11; j++)
             cells[i][j] = 0;
}

void print_blanks(void) {                                                       //印出遊戲初始的格子 
     int i, j;
     printf("              遊戲說明:\n");
     printf("---------------------------------------\n");
     printf("※ 要開啟最左上角那格請輸入1 1\n");
     printf("   往下一格則左邊的值+1(輸入:2 1)\n");
     printf("   往右一格則右邊的值+1(輸入:1 2)\n");
     printf("   其餘以此類推,從1 1 ~ 9 9\n");
     printf("   輸入格式為:數字空格數字,如:8 2\n\n");
     printf("※ 可一次輸入多格座標,\n");
     printf("   座標間只需以非數字符號隔開就可以了!\n");
     printf("   祝您遊戲愉快!:)\n");
     printf("---------------------------------------\n\n");
     printf("    ");
     for (i = 1; i <= 9; i++)
         printf("%2d", i);
     printf("\n");
     for (i = 1; i <= 9; i++) {
         for (j = 0; j <= 9; j++) {
             if (j == 0)
                printf("%4d", i); 
             else
                 printf("口");
         }
         printf("\n");
     }
}

void open_cell(int *op_x, int *op_y) {                                          //請使用者輸入要打開的位置
     int x, y;
     printf("\n輸入您要開啟的座標 >> ");
     scanf("%d%d", op_x, op_y);
}

void put_mine(int cells[][11], int op_x, int op_y) {                            //放置地雷
     srand(time(NULL));          //  亂數種子 
     int  n = 0,
          rand_num,
          cell_x,
          cell_y;

     do {
         rand_num = rand() % 81;     // ( rand() % (最大值-最小值+1)) + 最小值
         cell_x = (rand_num % 9) + 1;
         cell_y = ((rand_num - cell_x) / 9) + 1;
         if (cells[cell_x][cell_y] != -1 && !(cell_x == op_x && cell_y == op_y)) {
             cells[cell_x][cell_y] = -1;
             n++;
         }
     } while (n < 10);
}

void calculate_num_of_cells(int cells[][11]) {                                  //計算非地雷區附近有幾彈地雷 
     int i, j, u, v;
     for (i = 1; i <= 9; i++)
         for (j = 1; j <= 9; j++)
             if (cells[i][j] == 0)
                for (u = i - 1; u <= i + 1; u++)
                    for (v = j - 1; v <= j + 1; v++)
                        if (cells[u][v] == -1)
                           cells[i][j]++;
}

void assign_inf_after_open(int cells[][11], int op_x, int op_y) {               //改變使用者打開的位置之資訊 
     if (cells[op_x][op_y] == -1)
        cells[op_x][op_y] = -2;
     if (cells[op_x][op_y] >= 0 && cells[op_x][op_y] <= 8)
        cells[op_x][op_y] += 10;
}

void open_surrounding(int cells[][11], int op_x, int op_y) {                    //打開附近的區域(當格子附近無地雷時) 
     int i, j;
     for (i = op_x - 1; i <= op_x + 1; i++) {
         for (j = op_y - 1; j <= op_y + 1; j++) {
             if (cells[i][j] >= 0 && cells[i][j] <=8 && i % 10 != 0 && j %10 != 0) {
                cells[i][j] += 10;
                check_no_mine(cells, i, j);
             }
         }
     }
}

void check_no_mine(int cells[][11], int op_x, int op_y) {                       //檢查附近的區域有沒有地雷
     if (cells[op_x][op_y] == 10)        //附近沒地雷 
        open_surrounding(cells, op_x, op_y);
}

void print_condition_playing(int cells[][11]) {                                 //印出尚未結束的狀況
     int i, j;
     printf("      ");
     for (i = 1; i <= 9; i++)
         printf("%2d", i);
     printf("\n    ┌---------┐\n");
     for (i = 1; i <= 9; i++) {
             for (j = 0; j <= 9; j++) { 
                 if (j == 0)
                    printf("%4d|", i); 
                 else if (cells[i][j] < 10)
                      printf("口");
                 else if (cells[i][j] == 10)
                      printf(" 0");
                 else if (cells[i][j] > 10 && cells[i][j] <= 18)
                      printf(" %d", cells[i][j] - 10);
                 if (j == 9)
                    printf("|%d", i); 
         }
         printf("\n");
     }
     printf("    └---------┘\n");
     printf("      ");
     for (i = 1; i <= 9; i++)
         printf("%2d", i);
     printf("\n");
}
     
     
void print_condition_over(int cells[][11], int over) {                          //印出遊戲結束的狀況(每個格子之資訊) 
     int i, j;
     printf("  ┌---------┐\n");
     for (i = 1; i <= 9; i++) {
         for (j = 0; j <= 10; j++) {
             if (j  == 0)
                printf("  |");
             else if (j == 10)
                  printf("|"); 
             else if(cells[i][j] % 10 == 0)
                  printf(".");
             else if (cells[i][j] == -1)
                  printf(" *");
             else if (cells[i][j] == -2)
                  printf("⊕");
             else
                 printf("%2d", cells[i][j] % 10);
         }
         printf("\n");
     }
     printf("  └---------┘\n");
     if (over == 1)
        printf(".ˇ.恭喜你~~贏了!\n\n");
     else
         printf("ˊ_ˋ爆了…… \n\n");
     printf("數字代表周圍八格地雷總數量\n");
     printf("*代表地雷\n");
     printf(".代表周圍沒地雷\n");
     printf("⊕代表爆掉的地雷。\n");
     printf("感謝您的賞光~~~\n");
}
     
void print_cells(int cells[][11], int op_x, int op_y, int over) {               //印出目前的狀況
     system("cls");
     printf("\n");
     int i, j;
     if (over == 0) {
        print_condition_playing(cells);
     } else
           print_condition_over(cells, over);
}

int  check_over(int cells[][11], int op_x, int op_y) {                          //檢查遊戲是否結束(輸或贏)
    //result == 0 ->尚未結束,result == 1 ->贏,result == -1 ->輸
    int i, j, result = 1;
    if (cells[op_x][op_y] == -2) {
       result = -1;
    } else {
           for (i = 1; i <= 9 && result == 1; i++)
               for (j = 1; j <= 9 && result == 1; j++)
                   if ((cells[i][j] >= 0 && cells[i][j] <= 8))
                      result = 0;
    }
    return(result);
}

char play_again(void) {                                                         //詢問是否再玩一次
     char again;
     printf("\n還要再玩一次嗎?");
     do {
        printf("\n要再玩一次的話請輸入Y,\n");
        printf("或輸入N關閉程式。 >>");
        scanf(" %c", &again);
     } while (again != 'Y' && again != 'y' && again != 'N' && again != 'n');
     return(again);
}

沒有留言:

張貼留言