Minesweeper done in main() using SDL2

I was having fun time challenging myself to do minesweeper game yesterday and today with SDL2 and having every piece of code in main(). Here is result.
(OK; There is no game over state or any actual play again programmed in. Just idea of minesweeper created)

Any feedback is appreciated

Goofy texture used: https://imgur.com/a/4VKLc

And; well code (use "-lSDL2" flag to compile on Linux. On Windows, dunno):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <iostream>
#include <SDL2/SDL.h>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>

int main(int argc, char const *argv[]) {
  SDL_Window * window;
  SDL_Renderer * renderer;
  SDL_Surface * img; // Surface is used as temp place for bmp's
  SDL_Texture * tex; // Full tile sheet
  int w=32; // img and boad size
  int minesCount = 10;
  bool isRunning=true;
  srand(time(NULL));

  // Init SDL
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    std::cout << "We f'd up: " << SDL_GetError() << '\n';
    return -1;
  }

  // Create window ready to be drawn
  if (SDL_CreateWindowAndRenderer(320, 320,SDL_WINDOW_OPENGL, &window, &renderer)<0) {
    std::cout << "We did f again: " << SDL_GetError() << '\n';
    SDL_DestroyRenderer(renderer); // Just to be safe...
    SDL_DestroyWindow(window); // Just to be safe...
    SDL_Quit();
    return -2;
  }

  // LOAD TEXTURE
  // "Sheet" explained later
  img = SDL_LoadBMP("gfx.bmp");
  tex = SDL_CreateTextureFromSurface(renderer, img);
  SDL_FreeSurface(img); // Use img later if needed for more textures

  // Basic struct for nodes of tiles in display
  struct Tile {
    bool isMine;
    int n;  // Neighbors
    bool isRevealed=false;
  };

  // init board
  Tile board[10][10];
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
      board[i][j].isMine=false;
      board[i][j].n=0;
    }
  }

  // Fill board with minesCount of mines.
  int m=0;
  while(m<minesCount) {
    int x=rand()%10;
    int y=rand()%10;
    if (board[x][y].isMine)
    continue;
    board[x][y].isMine=true;
    m++;
  }

  // Calculate neighbors
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
      // If this is mine, skip it
      if (board[i][j].isMine) {
        board[i][j].n=9; // Choose correct texture from sheet tho
        continue;
      }
      int n=0;
      // Calculate all neighbors on 3x3 grid around tile
      for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= 1; y++) {
          int xoff=i+x;
          int yoff=j+y;
          // Do not count outside array
          if (xoff<0 || xoff>9 || yoff<0 || yoff>9)
            continue;
          if (board[xoff][yoff].isMine)
            n++;
        }
        // Update neighbor count to the struct
        board[i][j].n=n;
      }
    }
  }

  // Main loop
  while (isRunning) {
    // We want to use black background
    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
    // Clear the screen with current background color
    SDL_RenderClear(renderer);

    // DO DRAW
    SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    for (int i = 0; i < 10; i++) {
      for (int j= 0; j < 10; j++) {
        // for showing grid at start
        SDL_Rect rect;
        rect.x=i*w;
        rect.y=j*w;
        rect.w=w;
        rect.h=w;
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);
        SDL_RenderFillRect(renderer, &rect);
        // outline
        SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
        SDL_RenderDrawRect(renderer, &rect);

        // Player has clicked on tile and we want to show tilesheet graphics
        // Continue loop since current tile has not yet been revealed
        if (!board[i][j].isRevealed)
          continue;

        // Make sure we display correct texture within spritesheet
        // spritesheet is divided in 10 sprites from 0 to 8 mines
        // and of course the mine itself.
        SDL_Rect n;
        n.w=w;
        n.h=w;
        n.y=0;
        // Selecting correct tile
        n.x=board[i][j].n*w;

        // Copy correct texture from textures sheet
        SDL_RenderCopy(renderer, tex,&n,&rect);
      }
    }

    // Handle inputs
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
      if (e.type == SDL_QUIT) {
        isRunning=false;
      }

      if (e.type == SDL_MOUSEBUTTONDOWN) {
        int mouseX, mouseY;
        Uint32 buttons; // NOTE: button_state is 32 bit integer
        buttons = SDL_GetMouseState(&mouseX, &mouseY); // getting state
        // Make sure mouse pointer is in field (and window)
        if (mouseX<0 || mouseX>320 || mouseY<0 || mouseY>320)
          continue;
        if (buttons & SDL_BUTTON(SDL_BUTTON_LEFT) ){ // Left mouse button
          // calculate which tile we are in and reveal it
          int i,j;
          i=mouseX/w;
          j=mouseY/w;
          board[i][j].isRevealed=true;

          // Crap.. We actually hit cell without neighboring mines
          // TODO: Reveal only horizontal/vertical neigbors; not diagonal?
          if (board[i][j].n==0) {
            // Flood fill time!!
            std::vector <std::pair<int,int>> pairs;
            auto pair = std::make_pair(i,j);
            pairs.push_back(pair);

            // Loop until all 0's are filled.
            while (!pairs.empty()) {
              // Get last pair out of que
              auto current = pairs.back();
              pairs.pop_back();

              for (int x = -1; x <= 1; x++) {
                for (int y = -1; y <= 1; y++) {
                  int xoff=current.first+x;
                  int yoff=current.second+y;
                  // Do not count outside array
                  if (xoff<0 || xoff>9 || yoff<0 || yoff>9)
                    continue;
                  // skip if revealed
                  if (board[xoff][yoff].isRevealed)
                    continue;

                  // finally reveal neigbor
                  board[xoff][yoff].isRevealed=true;
                  // if revealed tile is 0 also. push it back to be checked
                  if (board[xoff][yoff].n==0) {
                    auto newpair = std::make_pair(xoff, yoff);
                    pairs.push_back(newpair);
                  }
                }
              }
            }
          }
        }
      }
    }

    // Show currrent frame
    SDL_RenderPresent(renderer);
    // Sleep a bit TODO: fps gapping?
    SDL_Delay(20);

  }
  SDL_Delay(200);

  // Be kind and clean afterwards
  SDL_DestroyTexture(tex);
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}




Last edited on
Topic archived. No new replies allowed.