//■マインスイーパー(Mine Sweeper) // 右クリックで旗表示を切り替えるようにすることで、 // 左クリックで開く、旗を表示できるように改良しました。 #include "myWin.h" #include "stdlib.h" #include "math.h" #include "time.h" #define frand() ((double)rand()/(RAND_MAX+1)) #define SZ 20 // セルサイズ #define S9 19 // (枠線表示用)セルサイズ-1 #define S8 18 // (枠線表示用)セルサイズ-2 #define Bomb -100 // 爆弾を示す定数 #define Hiden0 -50 // 隠された個数0を示す定数 #define numX 20 // X方向の数 #define numY 20 // Y方向の数 #define numB 50 // 爆弾の個数 static int exeMode = true; // 実行中フラグ static int AX, AY; // 爆発場所(0のとき static int DT[numX+2][numY+2]; // 状態を示す配列 static int Flag[numX+2][numY+2]; // 状態を示す配列 int X, Y; // クリックしたときのマウスの位置 static LOGFONT lfF; // 表示用フォント void fontIni(){ // フォント初期設定 lfF.lfHeight = 18; lfF.lfWidth = lfF.lfEscapement = lfF.lfOrientation = 0; lfF.lfWeight = FW_BOLD; lfF.lfItalic = lfF.lfUnderline = lfF.lfStrikeOut = FALSE; lfF.lfCharSet = SHIFTJIS_CHARSET; lfF.lfOutPrecision = OUT_DEFAULT_PRECIS; lfF.lfClipPrecision = CLIP_DEFAULT_PRECIS; lfF.lfQuality = DEFAULT_QUALITY; lfF.lfPitchAndFamily = 0; lfF.lfFaceName[0] = '\0'; } void setBomb(){ // 爆弾の生成 int X, Y; do { X = (int)(frand()*numX) + 1; Y = (int)(frand()*numY) + 1; } while (DT[X][Y] == Bomb); DT[X][Y] = Bomb; } int countB(int count, int X, int Y){// 爆弾の個数カウント if (DT[X][Y] == Bomb) return count + 1; else return count; } void countSetNum(int X, int Y){ //爆弾の数をカウントしてセットする。 int count = 0; for (int i = X - 1; i <= X + 1; i++) for (int j = Y - 1; j <= Y + 1; j++) if (i != X || j != Y) count = countB(count, i, j); if (count > 0) DT[X][Y] = -count; } void DrawLine(HDC hdc, int Col,int X1, int Y1, int X2,int Y2){//直線 HPEN hpen=CreatePen(PS_SOLID,1,Col); SelectObject(hdc,hpen); MoveToEx(hdc,X1,Y1,NULL);LineTo(hdc, X2,Y2); DeleteObject(hpen); } void FillRectangle(HDC hdc, int Col,int X, int Y, int Wd, int Ht){//矩形塗り潰し HBRUSH hbrush=CreateSolidBrush(Col); HPEN hpen=CreatePen(PS_SOLID,1,0x777777); SelectObject(hdc,hpen); SelectObject(hdc,hbrush); Rectangle(hdc, X,Y, X+Wd, Y+Ht); DeleteObject(hbrush);DeleteObject(hpen); } void DrawRectangle(HDC hdc, int Col,int X, int Y, int Wd, int Ht){//矩形 HPEN hpen=CreatePen(PS_SOLID,1,Col); SelectObject(hdc,hpen); MoveToEx(hdc,X,Y,NULL); LineTo(hdc, X+Wd,Y); LineTo(hdc, X+Wd,Y+Ht); LineTo(hdc, X ,Y+Ht) ; LineTo(hdc, X,Y); DeleteObject(hpen); } void FillEllipse(HDC hdc, int Col,int X, int Y, int Rx, int Ry){//楕円塗り潰し HBRUSH hbrush=CreateSolidBrush(Col); SelectObject(hdc,hbrush); Ellipse(hdc, X-Rx,Y-Ry, X+Rx, Y+Ry); DeleteObject(hbrush); } void DrawString(HDC hdc, TCHAR str[], int Col,int X1, int Y1){ HFONT hF=CreateFontIndirect(&lfF); SelectObject(hdc,hF); SetBkMode(hdc,TRANSPARENT); TextOut(hdc,X1,Y1, str,lstrlen(str)); SelectObject(hdc,GetStockObject(SYSTEM_FONT)); DeleteObject(hF); } void drawFlag(HDC hdc, int X, int Y){//旗を表示する。 int SX=SZ/3, SY=SZ/4, XX = SZ * X + SX, YY = SZ * Y + SY; FillRectangle(hdc, 0xFF,XX, YY, SX, SY); DrawLine(hdc,0x4488,XX,YY,XX,YY+SY*2); } void drawHide(HDC hdc, int X, int Y){// 隠された状態の表示 int XX = X * SZ, YY = Y * SZ; FillRectangle(hdc, 0xCCCCCC, XX, YY, SZ, SZ); DrawLine(hdc, 0xFFFFFF, XX , YY , XX + SZ, YY ); DrawLine(hdc, 0xFFFFFF, XX , YY , XX , YY + SZ); DrawLine(hdc, 0x000000, XX , YY + SZ, XX + SZ, YY + SZ); DrawLine(hdc, 0x000000, XX + SZ, YY , XX + SZ, YY + SZ); DrawLine(hdc, 0x777777, XX , YY + S9, XX + S9, YY + S9); DrawLine(hdc, 0x777777, XX + S9, YY , XX + S9, YY + S9); DrawLine(hdc, 0x777777, XX + 1, YY + S8, XX + S8, YY + S8); DrawLine(hdc, 0x777777, XX + S8, YY + 1, XX + S8, YY + S8); if(Flag[X][Y]) drawFlag(hdc, X,Y);//旗表示 } void drawFlat(HDC hdc,int Col, int X, int Y){// フラット塗り潰し int XX = X * SZ, YY = Y * SZ; FillRectangle(hdc, Col , XX, YY, SZ, SZ); DrawRectangle(hdc, 0x7777777, XX, YY, SZ, SZ); } void drawNum(HDC hdc,int V, int X, int Y){// 爆弾個数の表示 TCHAR str[10]; int XX = X * SZ, YY = Y * SZ; drawFlat(hdc, 0x337733, X, Y); wsprintf(str,TEXT("%d"),V); DrawString(hdc, str, 0x00000, XX + 4, YY + 1); } void drawSpace(HDC hdc, int X, int Y){// 空白の表示 int XX = X * SZ, YY = Y * SZ; FillRectangle(hdc, 0x77FFFF, XX, YY, SZ, SZ); DrawRectangle(hdc, 0x000000, XX, YY, SZ, SZ); DrawLine(hdc, 0x777777, XX + 1, YY + 1, XX + S9, YY + 1); DrawLine(hdc, 0x777777, XX + 2, YY + 2, XX + S8, YY + 2); DrawLine(hdc, 0x444444, XX + 1, YY + 1, XX + 1, YY + S9); DrawLine(hdc, 0x444444, XX + 2, YY + 2, XX + 2, YY + S8); DrawLine(hdc, 0xFFFFFF, XX + 1, YY + S9, XX + S9, YY + S9); DrawLine(hdc, 0xFFFFFF, XX + 2, YY + S8, XX + S8, YY + S8); DrawLine(hdc, 0xFFFFFF, XX + S9, YY + 1, XX + S9, YY + S9); DrawLine(hdc, 0xFFFFFF, XX + S8, YY + 2, XX + S8, YY + S8); } void drawBomb(HDC hdc, int X, int Y){// 爆弾の表示 if ((AX == X) && (AY == Y)) drawFlat(hdc, 0x0000FF, X, Y); else drawFlat(hdc, 0x4488FF, X, Y); int XX = X * SZ, YY = Y * SZ; FillEllipse(hdc, 0x0000000, XX + SZ/2, YY + SZ/2, SZ/4, SZ/4); DrawLine(hdc,0x222222, XX + SZ/2, YY + SZ/2, XX + SZ/2+5, YY + 2); } void endDisplay(HDC hdc){// 終了時の表示 for (int X = 1; X <= numX; X++) for (int Y = 1; Y <= numY; Y++) if (DT[X][Y] == Bomb) drawBomb(hdc, X, Y); else if (DT[X][Y] == Hiden0 || DT[X][Y] == 0) drawSpace(hdc, X, Y); else drawNum(hdc, abs(DT[X][Y]), X, Y); } void display(HDC hdc){ // ゲーム時の表示 for (int X = 1; X <= numX; X++) for (int Y = 1; Y <= numY; Y++) if (DT[X][Y] < 0) drawHide(hdc, X, Y); else if (DT[X][Y] > 0) drawNum(hdc, DT[X][Y], X, Y); else drawSpace(hdc, X, Y); } void Initialize() { // 初期化 AX = 0; exeMode = true; for (int X = 0; X < numX + 2; X++)// 初期値は隠された0とする for (int Y = 0; Y < numY + 2; Y++) DT[X][Y] = Hiden0; for (int i = 0; i < numB; i++) setBomb(); // 爆弾の生成 for (int X = 1; X <= numX; X++)// 周囲の爆弾の個数カウント for (int Y = 1; Y <= numY; Y++) if (DT[X][Y] != Bomb) countSetNum(X, Y); for (int X = 0; X < numX + 2; X++)// 初期値は旗なしとする for (int Y = 0; Y < numY + 2; Y++) Flag[X][Y] = 0; } int openCheck(int sw, int X, int Y){// 隠された0を開かれた0にする(開かれた0にしたらtrue) if (DT[X][Y] == Hiden0) { DT[X][Y] = 0; return true; } else if (DT[X][Y] != Bomb && DT[X][Y]<0) DT[X][Y] = -DT[X][Y]; return sw; } int UDLR(int sw, int X, int Y){// 上下左右を検査 if (DT[X][Y] == 0) return openCheck(openCheck(openCheck(openCheck (sw, X, Y + 1), X, Y - 1), X - 1, Y), X + 1, Y); else return sw; } void sweep(){//掃き出し int sw = true; int X, Y; while (sw){ sw = false; for (X = 1; X <= numX; X++) for (Y = 1; Y <= numY; Y++) sw = UDLR(sw, X, Y); for (Y = numY; Y >= 1; Y--) for (X = 1; X <= numX; X++) sw = UDLR(sw, X, Y); for (X = numX; X >= 1; X--) for (Y = 1; Y <= numY; Y++) sw = UDLR(sw, X, Y); for (Y = 1; Y <= numY; Y++) for (X = numX; X >= 1; X--) sw = UDLR(sw, X, Y); for (X = 1; X <= numX; X++) for (Y = 1; Y <= numY; Y++) if (DT[X][Y] == 0) sw=openCheck(openCheck(openCheck(openCheck (sw, X-1, Y - 1), X -1, Y + 1), X + 1, Y-1), X + 1, Y+1); } } int continueCheck(){// 終了のチェック for (int X = 1; X <= numX; X++) for (int Y = 1; Y <= numY; Y++) if ((DT[X][Y] < 0) && (DT[X][Y] != Bomb)) return true; return false; } void procCreate(HWND hw, WPARAM wp, LPARAM lp){ SetWindowText(hw,TEXT("Mine Sweeper")); srand((int)time(NULL)); fontIni(); Initialize(); InvalidateRect(hw,NULL,TRUE); } void procPaint(HWND hw, WPARAM wp, LPARAM lp){//画面に表示 PAINTSTRUCT ps; HDC hdc=BeginPaint(hw,&ps); if (exeMode) display(hdc); else endDisplay(hdc); EndPaint(hw, &ps); } void cellSelect(int X, int Y){// セルが選択されたときの処理 if (X < 1 || X > numX || Y < 1 || Y >numY) return; if (DT[X][Y] == 0) return; if (DT[X][Y] == Bomb){// 爆弾位置が選択されたとき AX = X; AY = Y; exeMode = false; } else { // 爆弾位置でないセルが選択されたとき if (DT[X][Y] == Hiden0) { DT[X][Y] = 0; sweep(); } else if (DT[X][Y] <0) DT[X][Y] = -DT[X][Y]; exeMode = continueCheck(); } } void procLButtonUp(HWND hw, WPARAM wp, LPARAM lp){//左ボタンクリック X=LOWORD(lp); Y=HIWORD(lp); if (exeMode) cellSelect(X / SZ, Y / SZ); else Initialize(); InvalidateRect(hw,NULL,TRUE); if(AX!=0) MessageBox(NULL,TEXT("残念!そこは爆弾です"),TEXT("Mine Sweeper"),MB_OK); else if (!exeMode) MessageBox(NULL,TEXT("終了です"),TEXT("Mine Sweeper"),MB_OK); } void procRButtonUp(HWND hw, WPARAM wp, LPARAM lp){//右ボタンクリック int i, j; X=LOWORD(lp); Y=HIWORD(lp); if (exeMode) { i = X / SZ; j = Y / SZ; // 旗表示のOn/Offを反転させる。 if(DT[i][j]<0) Flag[i][j] = !Flag[i][j]; } else Initialize(); InvalidateRect(hw,NULL,TRUE); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){ switch(msg){ case WM_DESTROY : PostQuitMessage(0) ; return 0; case WM_CREATE : procCreate (hw, wp, lp); return 0; case WM_PAINT : procPaint (hw, wp, lp); return 0; case WM_LBUTTONUP : procLButtonUp(hw, wp, lp); case WM_RBUTTONUP : procRButtonUp(hw, wp, lp); } return DefWindowProc(hw, msg, wp, lp); }