Subversion Repositories Kolibri OS

Rev

Rev 5232 | Details | Compare with Previous | Last modification | View Log | RSS feed

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