forked from KolibriOS/kolibrios
2048: source files added
git-svn-id: svn://kolibrios.org@5229 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
c6b5941cbe
commit
9f16c89604
3
programs/games/2048/Makefile
Executable file
3
programs/games/2048/Makefile
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
OUTFILE = 2048
|
||||||
|
OBJS = main.o game.o board.o cell.o rect.o defines.o
|
||||||
|
include $(MENUETDEV)/makefiles/Makefile_for_program
|
6
programs/games/2048/Tupfile.lua
Normal file
6
programs/games/2048/Tupfile.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
if tup.getconfig('NO_GCC') ~= "" then return end
|
||||||
|
HELPERDIR = (tup.getconfig("HELPERDIR") == "") and "../../.." or tup.getconfig("HELPERDIR")
|
||||||
|
tup.include(HELPERDIR .. "/use_gcc.lua")
|
||||||
|
tup.include(HELPERDIR .. "/use_menuetlibc.lua")
|
||||||
|
compile_gcc{"main.c" "defines.c" "rect.c" "cell.c" "board.c" "game.c"}
|
||||||
|
link_gcc("2048")
|
476
programs/games/2048/board.c
Normal file
476
programs/games/2048/board.c
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
rect base_cell = {0};
|
||||||
|
tile null_tile = {0};
|
||||||
|
|
||||||
|
|
||||||
|
struct {
|
||||||
|
rect draw; // background rect
|
||||||
|
rect cell_map[BOARD_MAP_SIZE]; // background cells array
|
||||||
|
tile tile_map[BOARD_MAP_SIZE]; // tiles array
|
||||||
|
__u16 empty_index[BOARD_MAP_SIZE];// empty cells indexes
|
||||||
|
__u16 empty_count; // empty cells count
|
||||||
|
__u32 score;
|
||||||
|
} board = {0};
|
||||||
|
|
||||||
|
// Get tile index for row and column
|
||||||
|
__u16 board_index(__u16 row, __u16 column) {
|
||||||
|
return column + row * BOARD_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tile position (as point with eow and column) for index
|
||||||
|
point board_position(__u16 index) {
|
||||||
|
point p = {
|
||||||
|
.x = index % BOARD_COUNT,
|
||||||
|
.y = index / BOARD_COUNT
|
||||||
|
};
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate cell rect for row and column
|
||||||
|
rect position2cell(point p) {
|
||||||
|
rect c = {0};
|
||||||
|
c.width = base_cell.width;
|
||||||
|
c.height = base_cell.height;
|
||||||
|
c.x = board.draw.x + BOARD_SPACING + p.x * (c.width + BOARD_SPACING);
|
||||||
|
c.y = board.draw.y + BOARD_SPACING + p.y * (c.height + BOARD_SPACING);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update information about empty cells
|
||||||
|
void board_update_empty_info();
|
||||||
|
|
||||||
|
// Represent tile array as pointers array
|
||||||
|
void board_to_tempboard(tile* temp[]);
|
||||||
|
|
||||||
|
// Fill tile array with tiles from pointers array
|
||||||
|
void board_from_tempboard(tile* temp[], __u8 forward);
|
||||||
|
|
||||||
|
// Move tile inside a pointer array
|
||||||
|
void tempboard_move_tile(tile* temp[], __u16 from, __u16 to);
|
||||||
|
|
||||||
|
// Merge tiles inside a pointer array
|
||||||
|
void tempboard_merge_tile(tile* temp[], __u16 from, __u16 to);
|
||||||
|
|
||||||
|
// Random number generator
|
||||||
|
__u32 random_u32(__u32 max);
|
||||||
|
|
||||||
|
void board_init(rect* r)
|
||||||
|
{
|
||||||
|
// seed for random number generator
|
||||||
|
srand(__menuet__getsystemclock());
|
||||||
|
|
||||||
|
board.score = 0;
|
||||||
|
board.draw = *r;
|
||||||
|
|
||||||
|
__u16 cell_size = (r->width - BOARD_SPACING * (BOARD_COUNT + 1)) / BOARD_COUNT;
|
||||||
|
base_cell.width = cell_size;
|
||||||
|
base_cell.height = cell_size;
|
||||||
|
|
||||||
|
null_tile.value = 0;
|
||||||
|
null_tile.animate = false;
|
||||||
|
null_tile.ani_step = ANIM_STEP;
|
||||||
|
null_tile.merged = false;
|
||||||
|
|
||||||
|
__u16 i = 0;
|
||||||
|
for (i = 0; i < BOARD_MAP_SIZE; i++)
|
||||||
|
{
|
||||||
|
board.cell_map[i] = position2cell(board_position(i));
|
||||||
|
board.tile_map[i] = null_tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (i = 0; i < START_COUNT; i++)
|
||||||
|
{
|
||||||
|
board_add_random_tile();
|
||||||
|
}
|
||||||
|
|
||||||
|
board_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void board_redraw()
|
||||||
|
{
|
||||||
|
__u16 i = 0;
|
||||||
|
__u8 animate = false;
|
||||||
|
__u8 last_animate = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
vsync();
|
||||||
|
rect_draw(&board.draw,BOARD_BG_COLOR);
|
||||||
|
|
||||||
|
for (i = 0; i < BOARD_MAP_SIZE; i++)
|
||||||
|
{
|
||||||
|
rect_draw(&board.cell_map[i],CELL_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
animate = false;
|
||||||
|
last_animate = false;
|
||||||
|
for (i = 0; i < BOARD_MAP_SIZE; i++)
|
||||||
|
{
|
||||||
|
tile* t = &board.tile_map[i];
|
||||||
|
last_animate = tile_draw(t);
|
||||||
|
if (last_animate)
|
||||||
|
{
|
||||||
|
animate = last_animate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animate)
|
||||||
|
{
|
||||||
|
__menuet__delay100(ANIM_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_up()
|
||||||
|
{
|
||||||
|
__u8 moved = false;
|
||||||
|
|
||||||
|
__u16 row = 0;
|
||||||
|
__u16 column = 0;
|
||||||
|
__u16 ind = 0;
|
||||||
|
__u16 preind = 0;
|
||||||
|
tile* indtile = 0;
|
||||||
|
tile* pretile = 0;
|
||||||
|
|
||||||
|
tile* temp_board[BOARD_MAP_SIZE] = {0};
|
||||||
|
board_to_tempboard(temp_board);
|
||||||
|
|
||||||
|
for (column = 0; column < BOARD_COUNT; column++)
|
||||||
|
{
|
||||||
|
for (row = 0; row < BOARD_COUNT; row++)
|
||||||
|
{
|
||||||
|
if (row > 0)
|
||||||
|
{
|
||||||
|
ind = board_index(row,column);
|
||||||
|
indtile = temp_board[ind];
|
||||||
|
if (indtile)
|
||||||
|
{
|
||||||
|
preind = board_index(row - 1,column);
|
||||||
|
pretile = temp_board[preind];
|
||||||
|
if (!pretile)
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
tempboard_move_tile(temp_board,ind,preind);
|
||||||
|
row = 0;
|
||||||
|
}
|
||||||
|
else if (tile_mergeable(indtile,pretile))
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
board.score += indtile->value * 2;
|
||||||
|
tempboard_merge_tile(temp_board,ind,preind);
|
||||||
|
row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board_from_tempboard(temp_board,true);
|
||||||
|
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_down()
|
||||||
|
{
|
||||||
|
__u8 moved = false;
|
||||||
|
|
||||||
|
__u16 row = 0;
|
||||||
|
__u16 column = 0;
|
||||||
|
__u16 ind = 0;
|
||||||
|
__u16 preind = 0;
|
||||||
|
tile* indtile = 0;
|
||||||
|
tile* pretile = 0;
|
||||||
|
|
||||||
|
tile* temp_board[BOARD_MAP_SIZE] = {0};
|
||||||
|
board_to_tempboard(temp_board);
|
||||||
|
|
||||||
|
for (column = 0; column < BOARD_COUNT; column++)
|
||||||
|
{
|
||||||
|
row = BOARD_COUNT;
|
||||||
|
while (row--)
|
||||||
|
{
|
||||||
|
if ((BOARD_COUNT - row) > 1)
|
||||||
|
{
|
||||||
|
ind = board_index(row,column);
|
||||||
|
indtile = temp_board[ind];
|
||||||
|
if (indtile)
|
||||||
|
{
|
||||||
|
preind = board_index(row + 1,column);
|
||||||
|
pretile = temp_board[preind];
|
||||||
|
if (!pretile)
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
tempboard_move_tile(temp_board,ind,preind);
|
||||||
|
row = BOARD_COUNT;
|
||||||
|
}
|
||||||
|
else if (tile_mergeable(indtile,pretile))
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
board.score += indtile->value * 2;
|
||||||
|
tempboard_merge_tile(temp_board,ind,preind);
|
||||||
|
row = BOARD_COUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board_from_tempboard(temp_board,false);
|
||||||
|
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_left()
|
||||||
|
{
|
||||||
|
__u8 moved = false;
|
||||||
|
|
||||||
|
__u16 row = 0;
|
||||||
|
__u16 column = 0;
|
||||||
|
__u16 ind = 0;
|
||||||
|
__u16 preind = 0;
|
||||||
|
tile* indtile = 0;
|
||||||
|
tile* pretile = 0;
|
||||||
|
|
||||||
|
tile* temp_board[BOARD_MAP_SIZE] = {0};
|
||||||
|
board_to_tempboard(temp_board);
|
||||||
|
|
||||||
|
for (row = 0; row < BOARD_COUNT; row++)
|
||||||
|
{
|
||||||
|
for (column = 0; column < BOARD_COUNT; column++)
|
||||||
|
{
|
||||||
|
if (column > 0)
|
||||||
|
{
|
||||||
|
ind = board_index(row,column);
|
||||||
|
indtile = temp_board[ind];
|
||||||
|
if (indtile)
|
||||||
|
{
|
||||||
|
preind = board_index(row,column - 1);
|
||||||
|
pretile = temp_board[preind];
|
||||||
|
if (!pretile)
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
tempboard_move_tile(temp_board,ind,preind);
|
||||||
|
column = 0;
|
||||||
|
}
|
||||||
|
else if (tile_mergeable(indtile,pretile))
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
board.score += indtile->value * 2;
|
||||||
|
tempboard_merge_tile(temp_board,ind,preind);
|
||||||
|
column = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board_from_tempboard(temp_board,true);
|
||||||
|
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_right()
|
||||||
|
{
|
||||||
|
__u8 moved = false;
|
||||||
|
|
||||||
|
__u16 row = 0;
|
||||||
|
__u16 column = 0;
|
||||||
|
__u16 ind = 0;
|
||||||
|
__u16 preind = 0;
|
||||||
|
tile* indtile = 0;
|
||||||
|
tile* pretile = 0;
|
||||||
|
|
||||||
|
tile* temp_board[BOARD_MAP_SIZE] = {0};
|
||||||
|
board_to_tempboard(temp_board);
|
||||||
|
|
||||||
|
for (row = 0; row < BOARD_COUNT; row++)
|
||||||
|
{
|
||||||
|
column = BOARD_COUNT;
|
||||||
|
while (column--)
|
||||||
|
{
|
||||||
|
if ((BOARD_COUNT - column) > 1)
|
||||||
|
{
|
||||||
|
ind = board_index(row,column);
|
||||||
|
indtile = temp_board[ind];
|
||||||
|
if (indtile)
|
||||||
|
{
|
||||||
|
preind = board_index(row,column + 1);
|
||||||
|
pretile = temp_board[preind];
|
||||||
|
if (!pretile)
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
tempboard_move_tile(temp_board,ind,preind);
|
||||||
|
column = BOARD_COUNT;
|
||||||
|
}
|
||||||
|
else if (tile_mergeable(indtile,pretile))
|
||||||
|
{
|
||||||
|
moved = true;
|
||||||
|
board.score += indtile->value * 2;
|
||||||
|
tempboard_merge_tile(temp_board,ind,preind);
|
||||||
|
column = BOARD_COUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board_from_tempboard(temp_board,false);
|
||||||
|
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_add_random_tile()
|
||||||
|
{
|
||||||
|
board_update_empty_info();
|
||||||
|
if (board.empty_count)
|
||||||
|
{
|
||||||
|
__u16 rnd_av = random_u32(board.empty_count);
|
||||||
|
rnd_av = board.empty_index[rnd_av];
|
||||||
|
|
||||||
|
tile* av_tile = &board.tile_map[rnd_av];
|
||||||
|
av_tile->value = (random_u32(10) < 9) ? 2 : 4;
|
||||||
|
|
||||||
|
av_tile->animate = true;
|
||||||
|
av_tile->ani_step = 5;
|
||||||
|
av_tile->transition = position2cell(board_position(rnd_av));
|
||||||
|
av_tile->cell.x = av_tile->transition.x + base_cell.width / 2;
|
||||||
|
av_tile->cell.y = av_tile->transition.y + base_cell.height / 2;
|
||||||
|
av_tile->cell.width = 0;
|
||||||
|
av_tile->cell.height = 0;
|
||||||
|
}
|
||||||
|
return board.empty_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 board_has_moves()
|
||||||
|
{
|
||||||
|
__u16 ind = 0;
|
||||||
|
__u16 next = 0;
|
||||||
|
__u16 step = 0;
|
||||||
|
__u16 pos = 0;
|
||||||
|
for (step = 0; step < BOARD_COUNT; step++)
|
||||||
|
{
|
||||||
|
for (pos = 0; pos < BOARD_COUNT; pos++)
|
||||||
|
{
|
||||||
|
// check horizontal
|
||||||
|
ind = board_index(step,pos);
|
||||||
|
next = board_index(step,pos + 1);
|
||||||
|
|
||||||
|
if (!board.tile_map[ind].value ||
|
||||||
|
(((pos + 1) < BOARD_COUNT) &&
|
||||||
|
(!board.tile_map[next].value ||
|
||||||
|
(board.tile_map[ind].value == board.tile_map[next].value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// check vertical
|
||||||
|
ind = board_index(pos,step);
|
||||||
|
next = board_index(pos + 1,step);
|
||||||
|
|
||||||
|
if (!board.tile_map[ind].value ||
|
||||||
|
(((pos + 1) < BOARD_COUNT) &&
|
||||||
|
(!board.tile_map[next].value ||
|
||||||
|
(board.tile_map[ind].value == board.tile_map[next].value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 board_score()
|
||||||
|
{
|
||||||
|
return board.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
void board_update_empty_info()
|
||||||
|
{
|
||||||
|
board.empty_count = 0;
|
||||||
|
|
||||||
|
__u16 i = 0;
|
||||||
|
for (i = 0; i < BOARD_MAP_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (!board.tile_map[i].value)
|
||||||
|
{
|
||||||
|
board.empty_index[board.empty_count] = i;
|
||||||
|
board.empty_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void board_to_tempboard(tile* temp[])
|
||||||
|
{
|
||||||
|
__u16 ind = 0;
|
||||||
|
for (ind = 0; ind < BOARD_MAP_SIZE; ind++)
|
||||||
|
{
|
||||||
|
tile* bt = &board.tile_map[ind];
|
||||||
|
if (bt->value)
|
||||||
|
{
|
||||||
|
temp[ind] = bt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void board_from_tempboard(tile *temp[], __u8 forward)
|
||||||
|
{
|
||||||
|
__u16 ind = 0;
|
||||||
|
if (forward)
|
||||||
|
{
|
||||||
|
for (ind = 0; ind < BOARD_MAP_SIZE; ind++)
|
||||||
|
{
|
||||||
|
tile* bt = &board.tile_map[ind];
|
||||||
|
tile* tt = temp[ind];
|
||||||
|
if (tt)
|
||||||
|
{
|
||||||
|
*bt = *tt;
|
||||||
|
bt->transition = position2cell(board_position(ind));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*bt = null_tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ind = BOARD_MAP_SIZE;
|
||||||
|
while (ind--)
|
||||||
|
{
|
||||||
|
tile* bt = &board.tile_map[ind];
|
||||||
|
tile* tt = temp[ind];
|
||||||
|
if (tt)
|
||||||
|
{
|
||||||
|
*bt = *tt;
|
||||||
|
bt->transition = position2cell(board_position(ind));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*bt = null_tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tempboard_move_tile(tile* temp[], __u16 from, __u16 to)
|
||||||
|
{
|
||||||
|
temp[to] = temp[from];
|
||||||
|
temp[to]->animate = true;
|
||||||
|
temp[from] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tempboard_merge_tile(tile* temp[], __u16 from, __u16 to)
|
||||||
|
{
|
||||||
|
temp[from]->merged = true;
|
||||||
|
temp[from]->merged_rect = temp[to]->cell;
|
||||||
|
tempboard_move_tile(temp,from,to);
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 random_u32(__u32 max)
|
||||||
|
{
|
||||||
|
return ((rand() * 1.0) / RAND_MAX) * max;
|
||||||
|
}
|
40
programs/games/2048/board.h
Normal file
40
programs/games/2048/board.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef BOARD_H
|
||||||
|
#define BOARD_H
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "cell.h"
|
||||||
|
|
||||||
|
// Draw a new board
|
||||||
|
void board_init(rect* r);
|
||||||
|
|
||||||
|
// Redraw board and all content (animation will started if needed)
|
||||||
|
void board_redraw();
|
||||||
|
|
||||||
|
// Add one tile with 2 or 4 value in a random cell place
|
||||||
|
// Return true if tile added, false - if no more place for tile
|
||||||
|
__u8 board_add_random_tile();
|
||||||
|
|
||||||
|
// Check for available moves
|
||||||
|
// Return true if board has moves, false - if not
|
||||||
|
__u8 board_has_moves();
|
||||||
|
|
||||||
|
// Get score
|
||||||
|
__u32 board_score();
|
||||||
|
|
||||||
|
// Try to move all tiles up
|
||||||
|
// Will return true if something moved or false - if not
|
||||||
|
__u8 board_up();
|
||||||
|
|
||||||
|
// Try to move all tiles down
|
||||||
|
// Will return true if something moved or false - if not
|
||||||
|
__u8 board_down();
|
||||||
|
|
||||||
|
// Try to move all tiles left
|
||||||
|
// Will return true if something moved or false - if not
|
||||||
|
__u8 board_left();
|
||||||
|
|
||||||
|
// Try to move all tiles right
|
||||||
|
// Will return true if something moved or false - if not
|
||||||
|
__u8 board_right();
|
||||||
|
|
||||||
|
#endif // BOARD_H
|
58
programs/games/2048/cell.c
Normal file
58
programs/games/2048/cell.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "cell.h"
|
||||||
|
|
||||||
|
__u8 tile_draw(tile* t)
|
||||||
|
{
|
||||||
|
if (t->value)
|
||||||
|
{
|
||||||
|
__u32 bg_color = 0;
|
||||||
|
__u32 txt_color = 0;
|
||||||
|
switch (t->value)
|
||||||
|
{
|
||||||
|
case 0 : bg_color = CELL_COLOR; break;
|
||||||
|
case 2 : bg_color = 0xEEE4DA; txt_color = 0x776E65; break;
|
||||||
|
case 4 : bg_color = 0xEDE0C8; txt_color = 0x776E65; break;
|
||||||
|
case 8 : bg_color = 0xF2B179; txt_color = 0xF9F6F2; break;
|
||||||
|
case 16 : bg_color = 0xF59563; txt_color = 0xF9F6F2; break;
|
||||||
|
case 32 : bg_color = 0xF67C5F; txt_color = 0xF9F6F2; break;
|
||||||
|
case 64 : bg_color = 0xF65E3B; txt_color = 0xF9F6F2; break;
|
||||||
|
case 128 : bg_color = 0xEDCF72; txt_color = 0xF9F6F2; break;
|
||||||
|
case 256 : bg_color = 0xEDCC61; txt_color = 0xF9F6F2; break;
|
||||||
|
case 512 : bg_color = 0xEDC850; txt_color = 0xF9F6F2; break;
|
||||||
|
case 1024 : bg_color = 0xEDC53F; txt_color = 0xF9F6F2; break;
|
||||||
|
case 2048 : bg_color = 0xEDC22E; txt_color = 0xF9F6F2; break;
|
||||||
|
default : bg_color = 0x3C3A32; txt_color = 0xF9F6F2; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect* begin = &t->cell;
|
||||||
|
rect* end = &t->transition;
|
||||||
|
|
||||||
|
if (rect_transform(begin,end,t->ani_step))
|
||||||
|
t->animate = false;
|
||||||
|
|
||||||
|
rect_draw(begin,bg_color);
|
||||||
|
rect_draw_value(begin,t->value,txt_color);
|
||||||
|
|
||||||
|
if (t->merged)
|
||||||
|
{
|
||||||
|
if (rect_transform(&t->merged_rect,end,t->ani_step) &&
|
||||||
|
(t->animate == false))
|
||||||
|
{
|
||||||
|
t->animate = true;
|
||||||
|
t->merged = false;
|
||||||
|
t->value *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect_draw(&t->merged_rect,bg_color);
|
||||||
|
rect_draw_value(&t->merged_rect,t->value,txt_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t->animate;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 tile_mergeable(tile* from, tile* to)
|
||||||
|
{
|
||||||
|
return (from && !from->merged &&
|
||||||
|
to && !to->merged &&
|
||||||
|
(from->value == to->value));
|
||||||
|
}
|
23
programs/games/2048/cell.h
Normal file
23
programs/games/2048/cell.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef CELL_H
|
||||||
|
#define CELL_H
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rect cell; // current rect
|
||||||
|
__u32 value; // value, 0 - do not draw a tile
|
||||||
|
__u8 animate; // animation needed: true or false
|
||||||
|
__u16 ani_step; // step for animation
|
||||||
|
rect transition; // destination rect for animation
|
||||||
|
__u8 merged; // merge flag
|
||||||
|
rect merged_rect;// rect for drawing merged tile
|
||||||
|
} tile;
|
||||||
|
|
||||||
|
// Draw a tile (animation will started if needed)
|
||||||
|
__u8 tile_draw(tile* t);
|
||||||
|
|
||||||
|
// Check two tiles for merging
|
||||||
|
__u8 tile_mergeable(tile* from, tile* to);
|
||||||
|
|
||||||
|
#endif // CELL_H
|
15
programs/games/2048/defines.c
Normal file
15
programs/games/2048/defines.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
inline void enable_scancode() {
|
||||||
|
__asm__ __volatile__("int $0x40"::"a"(66),"b"(1),"c"(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear_key_buffer() {
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < 120; i++)
|
||||||
|
__menuet__getkey();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vsync() {
|
||||||
|
__asm__ __volatile__("int $0x40"::"a"(18),"b"(14));
|
||||||
|
}
|
39
programs/games/2048/defines.h
Normal file
39
programs/games/2048/defines.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef DEFINES_H
|
||||||
|
#define DEFINES_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <keys.h>
|
||||||
|
#include <menuet/gui.h>
|
||||||
|
|
||||||
|
inline void enable_scancode();
|
||||||
|
inline void clear_key_buffer();
|
||||||
|
inline void vsync();
|
||||||
|
|
||||||
|
#define false (0)
|
||||||
|
#define true (1)
|
||||||
|
|
||||||
|
#define FONT_WIDTH (5)
|
||||||
|
#define FONT_HEIGHT (9)
|
||||||
|
|
||||||
|
#define ANIM_DELAY (5) // time between animation redraw
|
||||||
|
#define ANIM_STEP (25) // default step for animation
|
||||||
|
|
||||||
|
#define START_COUNT (2) // tiles count for new game
|
||||||
|
|
||||||
|
#define WND_WIDTH (400) // main window width
|
||||||
|
#define WND_HEIGHT (400) // main window height
|
||||||
|
|
||||||
|
#define GAME_BORDER (30) // minimum border size around board
|
||||||
|
#define GAME_BG_COLOR (0x34FAF8EF) // main window background color
|
||||||
|
|
||||||
|
#define SCORE_HEIGHT (21) // minimum height for score text
|
||||||
|
|
||||||
|
#define BOARD_SPACING (10) // spacing between cells
|
||||||
|
#define BOARD_COUNT (4) // row and column count
|
||||||
|
#define BOARD_MAP_SIZE (16) // cells total count (row * column)
|
||||||
|
#define BOARD_BG_COLOR (0xBBADA0) // board color
|
||||||
|
|
||||||
|
#define CELL_COLOR (0xCDC0B4) // cell color
|
||||||
|
|
||||||
|
#endif // DEFINES_H
|
155
programs/games/2048/game.c
Normal file
155
programs/games/2048/game.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
rect new_game_button;// new game button place
|
||||||
|
rect score_rect; // score place
|
||||||
|
__u8 over; // flag for game over
|
||||||
|
} game;
|
||||||
|
|
||||||
|
void game_draw_top()
|
||||||
|
{
|
||||||
|
if (game.over)
|
||||||
|
{
|
||||||
|
__menuet__make_button(game.new_game_button.x,
|
||||||
|
game.new_game_button.y,
|
||||||
|
game.new_game_button.width,
|
||||||
|
game.new_game_button.height,
|
||||||
|
NEW_GAME_BUTTON,
|
||||||
|
BOARD_BG_COLOR);
|
||||||
|
rect_draw_text(&game.new_game_button,"NEW GAME",8,GAME_BG_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect_draw(&game.score_rect,BOARD_BG_COLOR);
|
||||||
|
rect_draw_value(&game.score_rect,board_score(),GAME_BG_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_init()
|
||||||
|
{
|
||||||
|
game.over = false;
|
||||||
|
// place window at the center of screen
|
||||||
|
__u16 screen_w = 0;
|
||||||
|
__u16 screen_h = 0;
|
||||||
|
__menuet__get_screen_max(&screen_w,&screen_h);
|
||||||
|
|
||||||
|
__menuet__window_redraw(1);
|
||||||
|
|
||||||
|
__menuet__define_window((screen_w - WND_WIDTH) / 2,
|
||||||
|
(screen_h - WND_HEIGHT) / 2,
|
||||||
|
WND_WIDTH,
|
||||||
|
WND_HEIGHT,
|
||||||
|
GAME_BG_COLOR,
|
||||||
|
0,
|
||||||
|
(__u32)header);
|
||||||
|
|
||||||
|
// find info about window client area
|
||||||
|
__menuet__get_process_table(&proc_info,PID_WHOAMI);
|
||||||
|
|
||||||
|
// calc board
|
||||||
|
rect av_area = {0};
|
||||||
|
av_area.x = GAME_BORDER;
|
||||||
|
av_area.y = (SCORE_HEIGHT > GAME_BORDER) ? SCORE_HEIGHT : GAME_BORDER;
|
||||||
|
av_area.width = proc_info.client_width - av_area.x * 2;
|
||||||
|
av_area.height = proc_info.client_height - av_area.y - GAME_BORDER;
|
||||||
|
// minimal square
|
||||||
|
if (av_area.width < av_area.height)
|
||||||
|
{
|
||||||
|
av_area.y += (av_area.height - av_area.width) / 2;
|
||||||
|
av_area.height = av_area.width;
|
||||||
|
}
|
||||||
|
else // if (av_area.height < av_area.width)
|
||||||
|
{
|
||||||
|
av_area.x += (av_area.width - av_area.height) / 2;
|
||||||
|
av_area.width = av_area.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
board_init(&av_area);
|
||||||
|
|
||||||
|
game.new_game_button.x = av_area.x;
|
||||||
|
game.new_game_button.y = (av_area.y - SCORE_HEIGHT) / 2;
|
||||||
|
game.new_game_button.width = (av_area.width - BOARD_SPACING) / 2;
|
||||||
|
game.new_game_button.height = SCORE_HEIGHT;
|
||||||
|
|
||||||
|
game.score_rect.x = av_area.x + (av_area.width + BOARD_SPACING) / 2;
|
||||||
|
game.score_rect.y = (av_area.y - SCORE_HEIGHT) / 2;
|
||||||
|
game.score_rect.width = (av_area.width - BOARD_SPACING) / 2;
|
||||||
|
game.score_rect.height = SCORE_HEIGHT;
|
||||||
|
|
||||||
|
game_draw_top();
|
||||||
|
|
||||||
|
__menuet__window_redraw(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_redraw()
|
||||||
|
{
|
||||||
|
__menuet__get_process_table(&proc_info,PID_WHOAMI);
|
||||||
|
|
||||||
|
// start redraw
|
||||||
|
__menuet__window_redraw(1);
|
||||||
|
|
||||||
|
vsync();
|
||||||
|
__menuet__define_window(0, // __u16 x1 : ignored
|
||||||
|
0, // __u16 y1 : ignored
|
||||||
|
0, // __u16 xsize : ignored
|
||||||
|
0, // __u16 ysize : ignored
|
||||||
|
GAME_BG_COLOR, // __u32 body_color
|
||||||
|
0, // __u32 grab_color
|
||||||
|
(__u32)header); // __u32 frame_color or header
|
||||||
|
|
||||||
|
game_draw_top();
|
||||||
|
board_redraw();
|
||||||
|
|
||||||
|
// end redraw
|
||||||
|
__menuet__window_redraw(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_move_up()
|
||||||
|
{
|
||||||
|
if (board_up())
|
||||||
|
{
|
||||||
|
board_redraw();
|
||||||
|
__u8 added = board_add_random_tile();
|
||||||
|
board_redraw();
|
||||||
|
|
||||||
|
game.over = !added || !board_has_moves();
|
||||||
|
game_draw_top();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_move_down()
|
||||||
|
{
|
||||||
|
if (board_down())
|
||||||
|
{
|
||||||
|
board_redraw();
|
||||||
|
__u8 added = board_add_random_tile();
|
||||||
|
board_redraw();
|
||||||
|
|
||||||
|
game.over = !added || !board_has_moves();
|
||||||
|
game_draw_top();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_move_left()
|
||||||
|
{
|
||||||
|
if (board_left())
|
||||||
|
{
|
||||||
|
board_redraw();
|
||||||
|
__u8 added = board_add_random_tile();
|
||||||
|
board_redraw();
|
||||||
|
|
||||||
|
game.over = !added || !board_has_moves();
|
||||||
|
game_draw_top();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_move_right()
|
||||||
|
{
|
||||||
|
if (board_right())
|
||||||
|
{
|
||||||
|
board_redraw();
|
||||||
|
__u8 added = board_add_random_tile();
|
||||||
|
board_redraw();
|
||||||
|
|
||||||
|
game.over = !added || !board_has_moves();
|
||||||
|
game_draw_top();
|
||||||
|
}
|
||||||
|
}
|
30
programs/games/2048/game.h
Normal file
30
programs/games/2048/game.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef GAME_H
|
||||||
|
#define GAME_H
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
static const char header[] = "2048";
|
||||||
|
static struct process_table_entry proc_info = {0};
|
||||||
|
|
||||||
|
#define NEW_GAME_BUTTON (0xFF)
|
||||||
|
|
||||||
|
// Start a new game
|
||||||
|
void game_init();
|
||||||
|
|
||||||
|
// Redraw game content
|
||||||
|
void game_redraw();
|
||||||
|
|
||||||
|
// Move Up
|
||||||
|
void game_move_up();
|
||||||
|
|
||||||
|
// Move Down
|
||||||
|
void game_move_down();
|
||||||
|
|
||||||
|
// Move Left
|
||||||
|
void game_move_left();
|
||||||
|
|
||||||
|
// Move Right
|
||||||
|
void game_move_right();
|
||||||
|
|
||||||
|
#endif // GAME_H
|
54
programs/games/2048/main.c
Normal file
54
programs/games/2048/main.c
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
#define KEY_RELEASED 0x80
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
enable_scancode();
|
||||||
|
game_init();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
int ev = __menuet__wait_for_event();
|
||||||
|
switch (ev)
|
||||||
|
{
|
||||||
|
case 1 : // EVENT_REDRAW:
|
||||||
|
game_redraw();
|
||||||
|
break;
|
||||||
|
case 2 : // EVENT_KEY:
|
||||||
|
{
|
||||||
|
ev = __menuet__getkey() & 0xFF;
|
||||||
|
switch (ev)
|
||||||
|
{
|
||||||
|
case ((K_Up & 0xFF) | KEY_RELEASED) : // key Up released
|
||||||
|
game_move_up();
|
||||||
|
clear_key_buffer();
|
||||||
|
break;
|
||||||
|
case ((K_Down & 0xFF) | KEY_RELEASED) : // key Down released
|
||||||
|
game_move_down();
|
||||||
|
clear_key_buffer();
|
||||||
|
break;
|
||||||
|
case ((K_Left & 0xFF) | KEY_RELEASED) : // key Left released
|
||||||
|
game_move_left();
|
||||||
|
clear_key_buffer();
|
||||||
|
break;
|
||||||
|
case ((K_Right & 0xFF) | KEY_RELEASED) : // key Right released
|
||||||
|
game_move_right();
|
||||||
|
clear_key_buffer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3 : // EVENT_BUTTON
|
||||||
|
ev = __menuet__get_button_id();
|
||||||
|
switch (ev)
|
||||||
|
{
|
||||||
|
case NEW_GAME_BUTTON :
|
||||||
|
game_init();
|
||||||
|
break;
|
||||||
|
default : // close
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
programs/games/2048/rect.c
Normal file
98
programs/games/2048/rect.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
void rect_draw(rect* r, __u32 color)
|
||||||
|
{
|
||||||
|
__menuet__bar(r->x,r->y,r->width,r->height,color);
|
||||||
|
}
|
||||||
|
|
||||||
|
__u8 rect_transform(rect* from, rect* to, __u16 step)
|
||||||
|
{
|
||||||
|
if (from->width < to->width)
|
||||||
|
{
|
||||||
|
from->width += (ANIM_STEP << 1);
|
||||||
|
if (from->width > to->width) from->width = to->width;
|
||||||
|
}
|
||||||
|
else if (from->width > to->width)
|
||||||
|
{
|
||||||
|
from->width -= (ANIM_STEP << 1);
|
||||||
|
if (from->width < to->width) from->width = to->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->height < to->height)
|
||||||
|
{
|
||||||
|
from->height += (ANIM_STEP << 1);
|
||||||
|
if (from->height > to->height) from->height = to->height;
|
||||||
|
}
|
||||||
|
else if (from->height > to->height)
|
||||||
|
{
|
||||||
|
from->height -= (ANIM_STEP << 1);
|
||||||
|
if (from->height < to->height) from->height = to->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->x < to->x)
|
||||||
|
{
|
||||||
|
from->x += ANIM_STEP;
|
||||||
|
if (from->x > to->x) from->x = to->x;
|
||||||
|
}
|
||||||
|
else if (from->x > to->x)
|
||||||
|
{
|
||||||
|
from->x -= ANIM_STEP;
|
||||||
|
if (from->x < to->x) from->x = to->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->y < to->y)
|
||||||
|
{
|
||||||
|
from->y += ANIM_STEP;
|
||||||
|
if (from->y > to->y) from->y = to->y;
|
||||||
|
}
|
||||||
|
else if (from->y > to->y)
|
||||||
|
{
|
||||||
|
from->y -= ANIM_STEP;
|
||||||
|
if (from->y < to->y) from->y = to->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (from->x == to->x) &&
|
||||||
|
(from->y == to->y) &&
|
||||||
|
(from->width == to->width) &&
|
||||||
|
(from->height == to->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rect_draw_text(rect *r, char *txt, __u32 len, __u32 color)
|
||||||
|
{
|
||||||
|
__menuet__write_text(r->x + 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x - 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y - 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x - 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x + 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y - 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
|
||||||
|
__menuet__write_text(r->x + 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x - 1 + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
__menuet__write_text(r->x + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y - 1 + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0xFFFFFF,txt,len);
|
||||||
|
|
||||||
|
__menuet__write_text(r->x + (r->width - len * FONT_WIDTH - len) / 2,
|
||||||
|
r->y + (r->height - FONT_HEIGHT) / 2,
|
||||||
|
0,txt,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rect_draw_value(rect *r, __u32 v, __u32 color)
|
||||||
|
{
|
||||||
|
char buffer[16] = {0};
|
||||||
|
__u32 length = strlen(itoa(v,buffer,10));
|
||||||
|
rect_draw_text(r,buffer,length,color);
|
||||||
|
}
|
32
programs/games/2048/rect.h
Normal file
32
programs/games/2048/rect.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef RECT_H
|
||||||
|
#define RECT_H
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
short width;
|
||||||
|
short height;
|
||||||
|
} rect;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
} point;
|
||||||
|
|
||||||
|
// Draw rect filled with color
|
||||||
|
void rect_draw(rect* r, __u32 color);
|
||||||
|
|
||||||
|
// Make transformation step
|
||||||
|
// Rect 'from' will be changed
|
||||||
|
// Return 'true' if transformation ends ('from' == 'to')
|
||||||
|
__u8 rect_transform(rect* from, rect* to, __u16 step);
|
||||||
|
|
||||||
|
// Draw text at the rect center
|
||||||
|
void rect_draw_text(rect* r, char* txt, __u32 len, __u32 color);
|
||||||
|
|
||||||
|
// Draw value as text at the rect center
|
||||||
|
void rect_draw_value(rect* r, __u32 v, __u32 color);
|
||||||
|
|
||||||
|
#endif // RECT_H
|
Loading…
Reference in New Issue
Block a user