Subversion Repositories Kolibri OS

Rev

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

  1. #include "board.h"
  2. #include "config.h"
  3.  
  4. __u8 board_need_config = true;
  5.  
  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;
  16.     __u32   highscore;
  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;
  72.     null_tile.ani_step = ANI_APPEAR_STEP;
  73.     null_tile.merged = false;
  74.  
  75.     board.score = 0;
  76.     board.draw = *r;
  77.  
  78.     canvas_init(r);
  79.     canvas_fill(BOARD_BG_COLOR);
  80.  
  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.  
  88.     __u8 loaded = false;
  89.     __u8 empty_config = true;
  90.     if (board_need_config)
  91.     {
  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.         }
  110.     }
  111.  
  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.  
  121.     board_redraw();
  122. }
  123.  
  124. void board_delete()
  125. {
  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.  
  134.     canvas_delete();
  135. }
  136.  
  137. void board_redraw()
  138. {
  139.     __u16 i = 0;
  140.     __u8 animate = false;
  141.     __u8 last_animate = false;
  142.     do
  143.     {
  144.         canvas_fill(BOARD_BG_COLOR);
  145.  
  146.         for (i = 0; i < BOARD_MAP_SIZE; i++)
  147.         {
  148.             canvas_draw_rect(&board.cell_map[i],CELL_COLOR);
  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.  
  163.         canvas_paint();
  164.  
  165.         if (animate)
  166.         {
  167.             __menuet__delay100(ANI_DELAY);
  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;
  209.                         if (board.score > board.highscore)
  210.                             board.highscore = board.score;
  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;
  261.                         if (board.score > board.highscore)
  262.                             board.highscore = board.score;
  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;
  312.                         if (board.score > board.highscore)
  313.                             board.highscore = board.score;
  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;
  364.                         if (board.score > board.highscore)
  365.                             board.highscore = board.score;
  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];
  386.         __u32 rnd_value = (random_u32(10) < 9) ? 2 : 4;
  387.  
  388.         board_add_tile(rnd_value,rnd_av);
  389.     }
  390.     return board.empty_count;
  391. }
  392.  
  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.  
  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.  
  452. __u32 board_highscore()
  453. {
  454.     return board.highscore;
  455. }
  456.  
  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;
  529.     temp[to]->ani_step = ANI_MOVE_STEP;
  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. }
  544.