Subversion Repositories Kolibri OS

Rev

Rev 5231 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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