mine sweeper(マインスイーパー)作成
マインスイーパー作りました。課題です。めんどいなあ。。。再帰を使ってかけって言われて書いたけど、再帰は必須だね。使わない縛りPlayは誰もしないと思うよ。うん。
こうやって見えても500行でほぼすべての機能を入れました。メモをしておきましょう。まずいくつかの制約事項があったのでそこから。まずFieldの配列に入れるものが決まっていて、それ道理に設計すること、再帰を使って周辺を開くこと。(当たり前なんだがそうしないとクッソ実装が大変)で、フラグも考慮してあっていると仮定して周りを開けます。まあ当たり前なんだけどフラグミスると死にます。
まずプログラムが始まると、フィールドを動的に作成します。まあ当たり前なんだけどこうしないとFieldの大きさが固定になってしまいますのでね。で、フィールドを0で埋めておいてカーソルから3*3以外のところを候補の配列にぶっこんで、シャッフルして、先頭からn個取り出します。
取り出したn個を設置する際、同時にヒントも生成します。そうすると無駄なカウントがなく、処理が早いです。生成は考えて作らないと体感速度が大幅に変わります。何よりも最初に開いたときに設置するので、その時に時間がかかると嫌ですよね(よくあるけど)。
こうしないともし80*150のフィールドで11900個の爆弾を置くと間違いなくフリーズしますというか減点されますのでね。で、こうしたら準備は完了したので周りを開きます。
周りを開く関数はフィールドと位置を引数とすると良いでしょう。もし自分が0だったら(フラグを考慮しても同様)周りを開いていきます。と言っても8方向再帰で開きましょう。これはループを使って実装すると良いでしょう。
後は飾りを実装すれば完成です。
コード例ですが、まあまあ作りこみました。
[c]
include <stdio.h>
include <stdlib.h>
include <assert.h>
include <ctype.h>
include <stdbool.h>
/ * field discription * 0-8 .....numOfBomb * 9 .....bombInHere * 10-18 .....OpenedBlock(NumOfBomb-10) * 20-29 .....flaged here(0-9) / typedef struct{ int width; int height; int numOfBombs; int **field; } field_t;
typedef struct{ int x; int y; } vector_t;
vector_t add(vector_t a,vector_t b);/add two vectors/ int distSq(vector_t a,vector_t b);/distance from 2 points/ vector_t calcMotion(char ch);/calcMotion/ void calcCursor(field_t field,char ch,vector_t cursor);/cursor motion/
int initGame(field_t field);/initialize game/ void exitGame(field_t field);/deinitialize game/ int setBombs(field_t field,vector_t cursor);/set bombs(cursor requred)/ int newField(field_t field);/make new field/ void freeField(field_t field);/free field/ int numOfFlags(field_t field,vector_t p);
void dispMessage(field_t *field);
void dispElement(int num);/display Element of map/ void dispField(field_t field,vector_t cursor);/disp map/
void open(field_t field,vector_t p);/open tile/ void putFlag(field_t field,vector_t p); bool isGameClear(field_t field); bool isGameOver(field_t *field);
void gameOverEvent(field_t field,vector_t cursor); void gameClearEvent(field_t field,vector_t cursor);
define COL_RED 1
define COL_GREEN 2
define COL_YELLOW 3
define COL_BLUE 4
define COL_PINK 5
define COL_CYAN 6
define COL_WHITE 7
define COL_RESET 9
define SET_BACKGROUND_COL(col) printf("\033[4%dm",col)
define SET_FRONTGROUND_COL(col) printf("\033[3%dm",col)
define REVERCE_BACKGROUND_FRONTGROUND_COL() printf("\033[7m")
define RESET_SETTING() printf("\033[0m")
define CLR_SCREEN() printf("\033[2J")
define SET_CURSOR(x,y) printf("\033[%d;%dH",y+1,x+1)
const struct{ char key; vector_t move; } KEYS[]={ {'4',{-1,0}}, {'8',{0,-1}}, {'6',{1,0}}, {'2',{0,1}}, {'7',{-1,-1}}, {'9',{1,-1}}, {'1',{-1,1}}, {'3',{1,1}}, };
int numOfFlagsinField;
int main(int argc,char **argv){ char ch; field_t field; vector_t cursor={0,0}; bool isStarted = false;
if(argc == 1){ field.width = 15; field.height = 15; field.numOfBombs = 30; } else if(argc == 4){ field.width = atoi(argv[1]); field.height = atoi(argv[2]); field.numOfBombs = atoi(argv[3]); } else{ printf("Num of args must be 0 or 3.\n[width] [height] [num of bombs]\n"); return EXIT_FAILURE; }
dispMessage(&field);
assert(initGame(&field)==EXIT_SUCCESS);
CLR_SCREEN(); dispField(&field,&cursor); while(1){ ch = getchar(); if(isdigit(ch)&&ch!='0'&&ch!='5'){ calcCursor(&field,ch,&cursor); }
if(ch == '\n'){
if(!isStarted){
isStarted = true;
if(setBombs(&field,&cursor) == EXIT_FAILURE){
printf("cannot put bombs\n");
break;
}
}
if(field.field[cursor.y][cursor.x]<19) open(&field,cursor); if(isGameOver(&field)){ gameOverEvent(&field,&cursor); break; } } else if(ch == 'e')break; else if(ch == 'f'&&isStarted)putFlag(&field,&cursor); CLR_SCREEN(); dispField(&field,&cursor); if(isGameClear(&field)&&isStarted){ gameClearEvent(&field,&cursor); break; } } exitGame(&field); return EXIT_SUCCESS; } void dispMessage(field_t *field){ printf("===Mine Sweeper===\n"); printf(" __\n"); printf(" / \\n"); printf("|/▼ ▼ \ |\n"); printf("| ヽ_/ |\n"); printf(" \___/ \n"); printf("\nPlz confirm configulation...\n"); printf("[%-*s]:%d\n",15,"width of field",field->width);
printf("[%-s]:%d\n",15,"height of field",field->height); printf("[%-s]:%d\n",15,"number of bombs",field->numOfBombs); printf("If you will edit these elements, you must put the argument!\n"); printf("[width] [height] [numOfBomb]\n\n"); printf("Enter to continue..."); while(getchar()!='\n');
printf("Plz confirm key settings...\n"); printf("[%-s]...%s.\n",5,"Enter","Dig (if put flag, dig around)"); printf("[%-s]...%s.\n",5,"F","Put flag"); printf("[%-s]...%s.\n",5,"4","Move cursor to the left"); printf("[%-s]...%s.\n",5,"8","Move cursor to the up"); printf("[%-s]...%s.\n",5,"6","Move cursor to the right"); printf("[%-s]...%s.\n",5,"2","Move cursor to the down"); printf("[%-s]...%s.\n",5,"7","Move cursor to the upper left"); printf("[%-s]...%s.\n",5,"9","Move cursor to the upper right"); printf("[%-s]...%s.\n",5,"1","Move cursor to the lower left"); printf("[%-s]...%s.\n",5,"3","Move cursor to the lower right"); printf("[%-*s]...%s.\n",5,"E","Exit game");
printf("\ That it! Have fun!\n\ Enter to continue..."); while(getchar()!='\n'); }
bool isGameOver(field_t *field){ int x,y; for(x=0;x<field->width;x++){ for(y=0;y<field->height;y++){ if(field->field[y][x]==19) return true; } } return false; }
bool isGameClear(field_t *field){ int x,y; for(x=0;x<field->width;x++){ for(y=0;y<field->height;y++){ if*1 return false; } } return true; }
vector_t calcMotion(char ch){ unsigned int i; for(i=0;i<sizeof(KEYS)/sizeof(KEYS[0]);i++){ if(KEYS[i].key == ch){ return KEYS[i].move; } } assert(0); return KEYS[0].move; } void calcCursor(field_t field,char ch,vector_t cursor){ cursor = add(cursor,calcMotion(ch)); if(field->width <= cursor->x){ cursor -> x = field->width-1; } else if(0 > cursor->x)cursor->x = 0; if(field->height <= cursor->y){ cursor -> y = field->height-1; } else if(0 > cursor->y)cursor->y = 0; }
bool isInField(field_t field,vector_t p){ return field->width > p->x && 0 <= p->x&& field->height > p->y && 0 <= p->y; }
int initGame(field_t *field){ int res;
assert(field->width); assert(field->height); assert(field->numOfBombs);
numOfFlagsinField = 0;
res = newField(field); if(res == EXIT_FAILURE){ return EXIT_FAILURE; }
if(system("stty -echo -icanon min 1 time 0")<0){ printf("echo setting failed\n"); return EXIT_FAILURE; }
return EXIT_SUCCESS; }
void exitGame(field_t *field){ freeField(field); if(system("stty echo -icanon min 1 time 0")<0){ printf("echo setting failed\n"); } }
void gameClearEvent(field_t field,vector_t cursor){ int x,y; for(x=0;x<field->width;x++){ for(y=0;y<field->height;y++){ if(field->field[y][x]==9) field->field[y][x]+=20; else if(field->field[y][x]<9){ field->field[y][x]+=10; } } } dispField(field,cursor); printf("Game cleard\nThank you for playing!\n"); }
void gameOverEvent(field_t field,vector_t cursor){ int x,y; for(x=0;x<field->width;x++){ for(y=0;y<field->height;y++){ if(field->field[y][x]<=9) field->field[y][x]+=10; } } dispField(field,cursor); printf("Bomb exploded!!\nYou dead。。。\n"); }
int setBombs(field_t field,vector_t cursor){ vector_t *candidi; size_t numofcandidi;
unsigned int i = 0;
numofcandidi = field->heightfield->width-4;/widthheight-4が最大数/
candidi = (vector_t)malloc(sizeof(vector_t)numofcandidi); if(candidi == NULL)return EXIT_FAILURE; { vector_t p;
for(p.y=0;p.y<field->height;p.y++){
for(p.x=0;p.x<field->width;p.x++){
if(distSq(p,*cursor)>2){
candidi[i++]=p;
}
}
}
}
numofcandidi = (size_t)i; { vector_t tmp; int randnum; for(i=0;i<numofcandidi;i++){ randnum = rand()%numofcandidi; tmp = candidi[i]; candidi[i] = candidi[randnum]; candidi[randnum] = tmp; } }
if(numofcandidi < (unsigned int)field->numOfBombs){ printf("candidi:%lu\n",numofcandidi); return EXIT_FAILURE; } { int j; vector_t tmp; for(i = 0;i < (unsigned int)field->numOfBombs;i++){ field->field[candidi[i].y][candidi[i].x] = 9; for(j=0;j<(int)(sizeof(KEYS)/sizeof(KEYS[0]));j++){ tmp = add(KEYS[j].move,candidi[i]); if(isInField(field,&tmp)){ if(field->field[tmp.y][tmp.x]!=9){ field->field[tmp.y][tmp.x]++; } } } } } free(candidi);
return EXIT_SUCCESS; }
void putFlag(field_t field,vector_t p){ if(field->field[p->y][p->x] < 10){ field->field[p->y][p->x]+=20; numOfFlagsinField++; } else if(field->field[p->y][p->x] >= 20&&field->field[p->y][p->x] < 30) { field->field[p->y][p->x]-=20; numOfFlagsinField--; } }
void open(field_t field,vector_t p){ vector_t tmp; int i; if(field->field[p.y][p.x] < 10) field->field[p.y][p.x] += 10;/open tile/ if(field->field[p.y][p.x]==0+10|| numOfFlags(field,&p)==field->field[p.y][p.x]-10){ for(i=0;i<(int)(sizeof(KEYS)/sizeof(KEYS[0]));i++){/open around/ tmp = add(p,KEYS[i].move); if(isInField(field,&tmp)){ if(field->field[tmp.y][tmp.x]<10)/have not opended yet*/ open(field,tmp); // if(field->field[tmp.y][tmp.x] } } } }
int newField(field_t *field){ unsigned int height = field->height;
field->field = calloc(sizeof(int*),field->height);
int **fld = field->field;
if(fld==NULL)return EXIT_FAILURE;
do{ fld = calloc(sizeof(int),field->width); if(fld++==NULL)return EXIT_FAILURE; }while(--height);
return EXIT_SUCCESS; }
void freeField(field_t *field){ unsigned int height = field->height; int **fld = field->field;
do{ free(*(fld++)); }while(--height);
free(field->field); }
int numOfFlags(field_t field,vector_t p){ int i; int numOfFlags=0; vector_t tmp;
for(i=0;i<(int)(sizeof(KEYS)/sizeof(KEYS[0]));i++){ tmp = add(*p,KEYS[i].move); if(isInField(field,&tmp)){ if(field->field[tmp.y][tmp.x]>=20){ numOfFlags++; } } } return numOfFlags; }
void dispElement(int num){ assert(num>=0); if(num < 10){ printf("#"); } else if(num < 20){ if(num == 10){printf(" ");} else if(num <= 18){ printf("%d",num-10); } else if(num == 19){ SET_BACKGROUND_COL(COL_RED); printf("B"); SET_BACKGROUND_COL(COL_RESET); } } else if(num < 30){ SET_BACKGROUND_COL(COL_GREEN); printf("F"); SET_BACKGROUND_COL(COL_RESET); } else assert(0); } void dispField(field_t field,vector_t cursor){ int x,y; int **fld = field->field;
for(x=0;x<field->width;x++){ printf("+-"); } printf("+\n"); for(y=0;y<field->height;y++){ for(x=0;x<field->width;x++){ if(cursor->x==x&&y==cursor->y){ printf("["); REVERCE_BACKGROUND_FRONTGROUND_COL(); } else if(cursor->x==x-1&&y==cursor->y)printf("]"); else printf("|"); dispElement(fld[y][x]); RESET_SETTING(); } if(cursor->x==x-1&&y==cursor->y)printf("]\n"); else printf("|\n"); } for(x=0;x<field->width;x++){ printf("+-"); } printf("+\n"); printf("num of flags %d/%d\n",numOfFlagsinField,field->numOfBombs); }
vector_t add(vector_t a,vector_t b){ vector_t res;
res.x = a.x+b.x; res.y = a.y+b.y;
return res; }
int distSq(vector_t a,vector_t b){ return (a.x-b.x)(a.x-b.x)+(a.y-b.y)(a.y-b.y); }
[/c]
*1:field->field[y][x]>=20&&field->field[y][x]<=28)|| (field->field[y][x]>=0 &&field->field[y][x]<=8