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 }
array
Definition: minesweeper.c:29
block
Definition: minesweeper.c:20
sprite
Definition: lcd.c:40