SayoriOS  0.3.3
minesweeper.c
1 // Minesweeper by Sal1r
2 // Partial fixes by NDRAEY
3 
4 #include <kernel.h>
5 #include <gui/basics.h>
6 #include <gui/circle.h>
7 #include <drv/input/keyboard.h>
8 #include <drv/input/mouse.h>
9 #include <lib/rand.h>
10 #include "./minesweeper_sprites.h"
11 
12 #define BLOCK_SIZE 32
13 #define FIELD_WIDTH 9
14 #define FIELD_HEIGHT 9
15 
16 // Баг с выходом чинить надо
17 
18 // Убрать поля позиции. Сделать метод для получения координат.
19 // Вообще, много говнокода. Можно многое уменьшить.
20 typedef struct block { // Переписать
21  int32_t fx, fy; // Позиция на поле
22  int32_t sx, sy; // Позиция на экране
23  uint8_t has_mine; // 0 - без мины, 1 - с миной
24  uint8_t closed; // 0 - открыт, 1 - закрыт
25  uint8_t checked; // 0 - не помечен, 1 - помечен
26  uint8_t count; // Кол-во мин вокруг. Для has_mine == 0
27 } block;
28 
29 typedef struct array {
30  block** arr;
31  size_t size;
32 } array;
33 
34 void init_array(array* arr) {
35  arr->arr = NULL;
36  arr->size = 0;
37 }
38 
39 void array_append(array* arr, block* item) {
40  arr->arr = krealloc(arr->arr, (arr->size + 1) * sizeof(block*));
41  ++(arr->size);
42  arr->arr[arr->size - 1] = item;
43 }
44 
45 block* array_get(array* arr, size_t index) {
46  return arr->arr[index];
47 }
48 
49 void array_clear(array* arr) {
50  kfree(arr->arr);
51  arr->arr = NULL;
52  arr->size = 0;
53 }
54 
55 void move_array(array* from, array* to) {
56  kfree(to->arr);
57  to->arr = from->arr;
58  to->size = from->size;
59  from->arr = NULL;
60  from->size = 0;
61 }
62 
63 block field[FIELD_WIDTH * FIELD_HEIGHT] = {0};
64 uint8_t running = 1;
65 uint8_t mb1 = 0;
66 uint8_t mb2 = 0;
67 
68 void draw_sprite(const uint32_t* sprite, const uint32_t sprite_size, int32_t sx, int32_t sy) {
69  for (int x = 0; x < sprite_size; ++x) {
70  for (int y = 0; y < sprite_size; ++y) {
71  uint32_t pix = sprite[sprite_size * y + x];
72  if (pix >> 24 == 0) continue;
73  set_pixel(sx + x, sy + y,
74  ((pix & 0xFF0000) >> 16) + (pix & 0x00FF00) + ((pix & 0x0000FF) << 16));
75  }
76  }
77 }
78 
79 void init_field(int32_t sx, int32_t sy) {
80  for (int x = 0; x < 9; ++x) {
81  for (int y = 0; y < 9; ++y) {
82  block* b = &field[FIELD_HEIGHT * x + y]; // Переписать
83  b->fx = x;
84  b->fy = y;
85  b->sx = sx + x * BLOCK_SIZE + x * 2;
86  b->sy = sy + y * BLOCK_SIZE + y * 2;
87  b->has_mine = 0;
88  b->closed = 1;
89  b->checked = 0;
90  b->count = 0;
91  }
92  }
93  // Переписать
94  for (int i = 0; i < 10; ++i) {
95  int r = (uint32_t)rand() % 81;
96  block* b = &field[r];
97  b->has_mine = 1;
98  }
99 
100  for (int i = 0; i < 81; ++i) {
101  block* b = &field[i];
102 
103  if (!b->has_mine) { // Переписать
104  uint8_t count = 0;
105 
106  for (int x = -1; x < 2; ++x) {
107  for (int y = -1; y < 2; ++y) {
108  int xx = b->fx + x;
109  int yy = b->fy + y;
110  if (xx < 0 || yy < 0 || xx >= FIELD_WIDTH ||
111  yy >= FIELD_HEIGHT || (xx == b->fx && yy == b->fy)) continue; // Переписать
112  block* bb = &field[FIELD_HEIGHT * xx + yy]; // Переписать
113  if (bb->has_mine) ++count;
114  }
115  }
116 
117  b->count = count;
118  }
119  }
120 }
121 
122 void draw_field() { // Переписать
123  for (int i = 0; i < 81; ++i) {
124  block* b = &field[i];
125 
126  if (b->closed) {
127  // Закрытая
128  draw_filled_rectangle(b->sx, b->sy, BLOCK_SIZE, BLOCK_SIZE, 0xAAAAAA);
129  if (b -> checked)
130  // С флажком
131  draw_sprite(flag_sprite, FLAG_FRAME_SIZE, b->sx, b->sy);
132  } else {
133  // Открытая
134  draw_filled_rectangle(b->sx, b->sy, BLOCK_SIZE, BLOCK_SIZE, 0x777777);
135  // С числом мин
136  if (b->count > 0) {
137  // char* count_str;
138  // itoa(b->count, count_str);
139  // draw_vga_str(count_str, 1, b->sx, b->sy, 0xFFFFFF);
140  uint32_t* num = nums_sprites[b->count - 1];
141  draw_sprite(num, NUMS_FRAME_SIZE, b->sx, b->sy);
142  }
143  // С миной
144  if (b->has_mine) {
145  draw_sprite(mine_sprite, MINE_FRAME_SIZE, b->sx, b->sy);
146  }
147  }
148  }
149 }
150 
151 void input() {
152  if (getCharRaw() == 1) running = 0;
153 
154  // Открытие клетки
155  if (mouse_get_b1()) {
156  if (!mb1) {
157  mb1 = 1;
158  int32_t mx = mouse_get_x();
159  int32_t my = mouse_get_y();
160 
161  for (int i = 0; i < FIELD_WIDTH * FIELD_HEIGHT; ++i) {
162  block* b = &field[i];
163 
164  if (mx >= b->sx && mx <= b->sx + BLOCK_SIZE &&
165  my >= b->sy && my <= b->sy + BLOCK_SIZE) {
166  if (!b->checked && b->closed) {
167  b->closed = 0;
168 
169  array arr = {0};
170  init_array(&arr);
171  array_append(&arr, b);
172 
173  array second_arr = {0};
174  init_array(&second_arr);
175 
176  do {
177  for (size_t i = 0; i < arr.size; ++i) {
178  b = array_get(&arr, i);
179 
180  for (int x = -1; x < 2; ++x) {
181  int xx = b->fx + x;
182  int yy = b->fy;
183  if (xx < 0 || yy < 0 || xx >= FIELD_WIDTH ||
184  yy >= FIELD_HEIGHT || (xx == b->fx && yy == b->fy)) continue; // Переписать
185  block* bb = &field[FIELD_HEIGHT * xx + yy]; // Переписать
186  if (!bb->checked && bb->closed && !bb->has_mine) {
187  bb->closed = 0;
188  if (bb->count == 0) array_append(&second_arr, bb);
189  }
190  }
191 
192  for (int y = -1; y < 2; ++y) {
193  int xx = b->fx;
194  int yy = b->fy + y;
195  if (xx < 0 || yy < 0 || xx >= FIELD_WIDTH ||
196  yy >= FIELD_HEIGHT || (xx == b->fx && yy == b->fy)) continue; // Переписать
197  block* bb = &field[FIELD_HEIGHT * xx + yy]; // Переписать
198  if (!bb->checked && bb->closed && !bb->has_mine) {
199  bb->closed = 0;
200  if (bb->count == 0) array_append(&second_arr, bb);
201  }
202  }
203 
204  }
205  move_array(&second_arr, &arr);
206 
207  } while (arr.size != 0);
208 
209  array_clear(&arr);
210  array_clear(&second_arr);
211 
212  break;
213  }
214  if (b->has_mine) running = 0;
215  }
216  }
217  }
218  } else {
219  mb1 = 0;
220  }
221 
222  // Флажок
223  if (mouse_get_b2()) {
224  if (!mb2) {
225  mb2 = 1;
226  int32_t mx = mouse_get_x();
227  int32_t my = mouse_get_y();
228 
229  for (int i = 0; i < 81; ++i) {
230  block* b = &field[i];
231  if (mx >= b->sx && mx <= b->sx + BLOCK_SIZE &&
232  my >= b->sy && my <= b->sy + BLOCK_SIZE) {
233  b->checked = !b->checked;
234  }
235  }
236  }
237  } else {
238  mb2 = 0;
239  }
240 }
241 
242 void minesweeper() {
243  clean_screen();
244  set_cursor_enabled(false);
245  keyboardctl(KEYBOARD_ECHO, false);
246 
247  init_field(10, 10);
248 
249  int lmx = 0;
250  int lmy = 0;
251 
252  running = 1;
253 
254  while (running) {
255  input();
256 
257  draw_field();
258 
259  draw_circle(lmx, lmy, 3, 0x000000);
260 
261  int32_t mx = mouse_get_x();
262  int32_t my = mouse_get_y();
263  draw_circle(mx, my, 3, 0xFFFFFF);
264  lmx = mx;
265  lmy = my; // По-красивше сделать курсор
266  punch();
267  }
268 
269  while (1) {
270  if (getCharRaw() == 1) break;
271  }
272 
273  clean_screen();
274  set_cursor_enabled(true);
275 
276  keyboardctl(KEYBOARD_ECHO, true);
277 }
Definition: lcd.c:40