Subversion Repositories Kolibri OS

Rev

Rev 5229 | Rev 5232 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5229 raandoom 1
#include "board.h"
2
 
3
rect base_cell = {0};
4
tile null_tile = {0};
5
 
6
struct {
7
    rect    draw;                       // background rect
8
    rect    cell_map[BOARD_MAP_SIZE];   // background cells array
9
    tile    tile_map[BOARD_MAP_SIZE];   // tiles array
10
    __u16   empty_index[BOARD_MAP_SIZE];// empty cells indexes
11
    __u16   empty_count;                // empty cells count
12
    __u32   score;
13
} board = {0};
14
 
15
// Get tile index for row and column
16
__u16 board_index(__u16 row, __u16 column) {
17
    return column + row * BOARD_COUNT;
18
}
19
 
20
// Get tile position (as point with eow and column) for index
21
point board_position(__u16 index) {
22
    point p = {
23
        .x = index % BOARD_COUNT,
24
        .y = index / BOARD_COUNT
25
    };
26
    return p;
27
}
28
 
29
// Calculate cell rect for row and column
30
rect position2cell(point p) {
31
    rect c = {0};
32
    c.width = base_cell.width;
33
    c.height = base_cell.height;
34
    c.x = board.draw.x + BOARD_SPACING + p.x * (c.width + BOARD_SPACING);
35
    c.y = board.draw.y + BOARD_SPACING + p.y * (c.height + BOARD_SPACING);
36
    return c;
37
}
38
 
39
// Update information about empty cells
40
void board_update_empty_info();
41
 
42
// Represent tile array as pointers array
43
void board_to_tempboard(tile* temp[]);
44
 
45
// Fill tile array with tiles from pointers array
46
void board_from_tempboard(tile* temp[], __u8 forward);
47
 
48
// Move tile inside a pointer array
49
void tempboard_move_tile(tile* temp[], __u16 from, __u16 to);
50
 
51
// Merge tiles inside a pointer array
52
void tempboard_merge_tile(tile* temp[], __u16 from, __u16 to);
53
 
54
// Random number generator
55
__u32 random_u32(__u32 max);
56
 
57
void board_init(rect* r)
58
{
59
    // seed for random number generator
60
    srand(__menuet__getsystemclock());
61
 
62
    __u16 cell_size = (r->width - BOARD_SPACING * (BOARD_COUNT + 1)) / BOARD_COUNT;
63
    base_cell.width = cell_size;
64
    base_cell.height = cell_size;
65
 
66
    null_tile.value = 0;
67
    null_tile.animate = false;
5231 raandoom 68
    null_tile.ani_step = ANI_APPEAR_STEP;
5229 raandoom 69
    null_tile.merged = false;
70
 
5231 raandoom 71
    board.score = 0;
72
    board.draw = *r;
73
 
74
    canvas_init(r);
75
    canvas_fill(BOARD_BG_COLOR);
76
 
5229 raandoom 77
    __u16 i = 0;
78
    for (i = 0; i < BOARD_MAP_SIZE; i++)
79
    {
80
        board.cell_map[i] = position2cell(board_position(i));
81
        board.tile_map[i] = null_tile;
82
    }
83
 
84
    i = 0;
85
    for (i = 0; i < START_COUNT; i++)
86
    {
87
        board_add_random_tile();
88
    }
89
 
90
    board_redraw();
91
}
92
 
5231 raandoom 93
void board_delete()
94
{
95
    canvas_delete();
96
}
97
 
5229 raandoom 98
void board_redraw()
99
{
100
    __u16 i = 0;
101
    __u8 animate = false;
102
    __u8 last_animate = false;
103
    do
104
    {
5231 raandoom 105
        canvas_fill(BOARD_BG_COLOR);
5229 raandoom 106
 
107
        for (i = 0; i < BOARD_MAP_SIZE; i++)
108
        {
5231 raandoom 109
            canvas_draw_rect(&board.cell_map[i],CELL_COLOR);
5229 raandoom 110
        }
111
 
112
        animate = false;
113
        last_animate = false;
114
        for (i = 0; i < BOARD_MAP_SIZE; i++)
115
        {
116
            tile* t = &board.tile_map[i];
117
            last_animate = tile_draw(t);
118
            if (last_animate)
119
            {
120
                animate = last_animate;
121
            }
122
        }
123
 
5231 raandoom 124
        canvas_paint();
125
 
5229 raandoom 126
        if (animate)
127
        {
5231 raandoom 128
            __menuet__delay100(ANI_DELAY);
5229 raandoom 129
        }
130
    }
131
    while (animate);
132
}
133
 
134
__u8 board_up()
135
{
136
    __u8 moved = false;
137
 
138
    __u16 row = 0;
139
    __u16 column = 0;
140
    __u16 ind = 0;
141
    __u16 preind = 0;
142
    tile* indtile = 0;
143
    tile* pretile = 0;
144
 
145
    tile* temp_board[BOARD_MAP_SIZE] = {0};
146
    board_to_tempboard(temp_board);
147
 
148
    for (column = 0; column < BOARD_COUNT; column++)
149
    {
150
        for (row = 0; row < BOARD_COUNT; row++)
151
        {
152
            if (row > 0)
153
            {
154
                ind = board_index(row,column);
155
                indtile = temp_board[ind];
156
                if (indtile)
157
                {
158
                    preind = board_index(row - 1,column);
159
                    pretile = temp_board[preind];
160
                    if (!pretile)
161
                    {
162
                        moved = true;
163
                        tempboard_move_tile(temp_board,ind,preind);
164
                        row = 0;
165
                    }
166
                    else if (tile_mergeable(indtile,pretile))
167
                    {
168
                        moved = true;
169
                        board.score += indtile->value * 2;
170
                        tempboard_merge_tile(temp_board,ind,preind);
171
                        row = 0;
172
                    }
173
                }
174
            }
175
        }
176
    }
177
 
178
    board_from_tempboard(temp_board,true);
179
 
180
    return moved;
181
}
182
 
183
__u8 board_down()
184
{
185
    __u8 moved = false;
186
 
187
    __u16 row = 0;
188
    __u16 column = 0;
189
    __u16 ind = 0;
190
    __u16 preind = 0;
191
    tile* indtile = 0;
192
    tile* pretile = 0;
193
 
194
    tile* temp_board[BOARD_MAP_SIZE] = {0};
195
    board_to_tempboard(temp_board);
196
 
197
    for (column = 0; column < BOARD_COUNT; column++)
198
    {
199
        row = BOARD_COUNT;
200
        while (row--)
201
        {
202
            if ((BOARD_COUNT - row) > 1)
203
            {
204
                ind = board_index(row,column);
205
                indtile = temp_board[ind];
206
                if (indtile)
207
                {
208
                    preind = board_index(row + 1,column);
209
                    pretile = temp_board[preind];
210
                    if (!pretile)
211
                    {
212
                        moved = true;
213
                        tempboard_move_tile(temp_board,ind,preind);
214
                        row = BOARD_COUNT;
215
                    }
216
                    else if (tile_mergeable(indtile,pretile))
217
                    {
218
                        moved = true;
219
                        board.score += indtile->value * 2;
220
                        tempboard_merge_tile(temp_board,ind,preind);
221
                        row = BOARD_COUNT;
222
                    }
223
                }
224
            }
225
        }
226
    }
227
 
228
    board_from_tempboard(temp_board,false);
229
 
230
    return moved;
231
}
232
 
233
__u8 board_left()
234
{
235
    __u8 moved = false;
236
 
237
    __u16 row = 0;
238
    __u16 column = 0;
239
    __u16 ind = 0;
240
    __u16 preind = 0;
241
    tile* indtile = 0;
242
    tile* pretile = 0;
243
 
244
    tile* temp_board[BOARD_MAP_SIZE] = {0};
245
    board_to_tempboard(temp_board);
246
 
247
    for (row = 0; row < BOARD_COUNT; row++)
248
    {
249
        for (column = 0; column < BOARD_COUNT; column++)
250
        {
251
            if (column > 0)
252
            {
253
                ind = board_index(row,column);
254
                indtile = temp_board[ind];
255
                if (indtile)
256
                {
257
                    preind = board_index(row,column - 1);
258
                    pretile = temp_board[preind];
259
                    if (!pretile)
260
                    {
261
                        moved = true;
262
                        tempboard_move_tile(temp_board,ind,preind);
263
                        column = 0;
264
                    }
265
                    else if (tile_mergeable(indtile,pretile))
266
                    {
267
                        moved = true;
268
                        board.score += indtile->value * 2;
269
                        tempboard_merge_tile(temp_board,ind,preind);
270
                        column = 0;
271
                    }
272
                }
273
            }
274
        }
275
    }
276
 
277
    board_from_tempboard(temp_board,true);
278
 
279
    return moved;
280
}
281
 
282
__u8 board_right()
283
{
284
    __u8 moved = false;
285
 
286
    __u16 row = 0;
287
    __u16 column = 0;
288
    __u16 ind = 0;
289
    __u16 preind = 0;
290
    tile* indtile = 0;
291
    tile* pretile = 0;
292
 
293
    tile* temp_board[BOARD_MAP_SIZE] = {0};
294
    board_to_tempboard(temp_board);
295
 
296
    for (row = 0; row < BOARD_COUNT; row++)
297
    {
298
        column = BOARD_COUNT;
299
        while (column--)
300
        {
301
            if ((BOARD_COUNT - column) > 1)
302
            {
303
                ind = board_index(row,column);
304
                indtile = temp_board[ind];
305
                if (indtile)
306
                {
307
                    preind = board_index(row,column + 1);
308
                    pretile = temp_board[preind];
309
                    if (!pretile)
310
                    {
311
                        moved = true;
312
                        tempboard_move_tile(temp_board,ind,preind);
313
                        column = BOARD_COUNT;
314
                    }
315
                    else if (tile_mergeable(indtile,pretile))
316
                    {
317
                        moved = true;
318
                        board.score += indtile->value * 2;
319
                        tempboard_merge_tile(temp_board,ind,preind);
320
                        column = BOARD_COUNT;
321
                    }
322
                }
323
            }
324
        }
325
    }
326
 
327
    board_from_tempboard(temp_board,false);
328
 
329
    return moved;
330
}
331
 
332
__u8 board_add_random_tile()
333
{
334
    board_update_empty_info();
335
    if (board.empty_count)
336
    {
337
        __u16 rnd_av = random_u32(board.empty_count);
338
        rnd_av = board.empty_index[rnd_av];
339
 
340
        tile* av_tile = &board.tile_map[rnd_av];
341
        av_tile->value = (random_u32(10) < 9) ? 2 : 4;
342
 
343
        av_tile->animate = true;
5231 raandoom 344
        av_tile->ani_step = ANI_APPEAR_STEP;
5229 raandoom 345
        av_tile->transition = position2cell(board_position(rnd_av));
346
        av_tile->cell.x = av_tile->transition.x + base_cell.width / 2;
347
        av_tile->cell.y = av_tile->transition.y + base_cell.height / 2;
348
        av_tile->cell.width = 0;
349
        av_tile->cell.height = 0;
350
    }
351
    return board.empty_count;
352
}
353
 
354
__u8 board_has_moves()
355
{
356
    __u16 ind = 0;
357
    __u16 next = 0;
358
    __u16 step = 0;
359
    __u16 pos = 0;
360
    for (step = 0; step < BOARD_COUNT; step++)
361
    {
362
        for (pos = 0; pos < BOARD_COUNT; pos++)
363
        {
364
            // check horizontal
365
            ind = board_index(step,pos);
366
            next = board_index(step,pos + 1);
367
 
368
            if (!board.tile_map[ind].value ||
369
                    (((pos + 1) < BOARD_COUNT) &&
370
                     (!board.tile_map[next].value ||
371
                      (board.tile_map[ind].value == board.tile_map[next].value)
372
                      )
373
                     )
374
                    )
375
                return true;
376
 
377
            // check vertical
378
            ind = board_index(pos,step);
379
            next = board_index(pos + 1,step);
380
 
381
            if (!board.tile_map[ind].value ||
382
                    (((pos + 1) < BOARD_COUNT) &&
383
                     (!board.tile_map[next].value ||
384
                      (board.tile_map[ind].value == board.tile_map[next].value)
385
                      )
386
                     )
387
                    )
388
                return true;
389
        }
390
    }
391
    return false;
392
}
393
 
394
__u32 board_score()
395
{
396
    return board.score;
397
}
398
 
399
void board_update_empty_info()
400
{
401
    board.empty_count = 0;
402
 
403
    __u16 i = 0;
404
    for (i = 0; i < BOARD_MAP_SIZE; i++)
405
    {
406
        if (!board.tile_map[i].value)
407
        {
408
            board.empty_index[board.empty_count] = i;
409
            board.empty_count++;
410
        }
411
    }
412
}
413
 
414
void board_to_tempboard(tile* temp[])
415
{
416
    __u16 ind = 0;
417
    for (ind = 0; ind < BOARD_MAP_SIZE; ind++)
418
    {
419
        tile* bt = &board.tile_map[ind];
420
        if (bt->value)
421
        {
422
            temp[ind] = bt;
423
        }
424
    }
425
}
426
 
427
void board_from_tempboard(tile *temp[], __u8 forward)
428
{
429
    __u16 ind = 0;
430
    if (forward)
431
    {
432
        for (ind = 0; ind < BOARD_MAP_SIZE; ind++)
433
        {
434
            tile* bt = &board.tile_map[ind];
435
            tile* tt = temp[ind];
436
            if (tt)
437
            {
438
                *bt = *tt;
439
                bt->transition = position2cell(board_position(ind));
440
            }
441
            else
442
            {
443
                *bt = null_tile;
444
            }
445
        }
446
    }
447
    else
448
    {
449
        ind = BOARD_MAP_SIZE;
450
        while (ind--)
451
        {
452
            tile* bt = &board.tile_map[ind];
453
            tile* tt = temp[ind];
454
            if (tt)
455
            {
456
                *bt = *tt;
457
                bt->transition = position2cell(board_position(ind));
458
            }
459
            else
460
            {
461
                *bt = null_tile;
462
            }
463
        }
464
    }
465
}
466
 
467
void tempboard_move_tile(tile* temp[], __u16 from, __u16 to)
468
{
469
    temp[to] = temp[from];
470
    temp[to]->animate = true;
5231 raandoom 471
    temp[to]->ani_step = ANI_MOVE_STEP;
5229 raandoom 472
    temp[from] = 0;
473
}
474
 
475
void tempboard_merge_tile(tile* temp[], __u16 from, __u16 to)
476
{
477
    temp[from]->merged = true;
478
    temp[from]->merged_rect = temp[to]->cell;
479
    tempboard_move_tile(temp,from,to);
480
}
481
 
482
__u32 random_u32(__u32 max)
483
{
484
    return ((rand() * 1.0) / RAND_MAX) * max;
485
}