Compare commits
4
Commits
e4a2fef052
...
9deb40d080
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9deb40d080 | ||
|
|
87559e409f | ||
|
|
a6da01d4ac | ||
|
|
4fffad5540 |
@@ -3,3 +3,4 @@
|
||||
build/
|
||||
src/engine/CMakeFiles
|
||||
examples/CMakeFiles
|
||||
*.xopp
|
||||
|
||||
+451
-7
@@ -1,7 +1,252 @@
|
||||
#include "dangerzone/render/rect.h"
|
||||
#include <dangerzone/engine.h>
|
||||
#include <dangerzone/render/misc.h>
|
||||
#include <dangerzone/render/text.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define SIZE 4
|
||||
|
||||
typedef enum {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
UP,
|
||||
DOWN
|
||||
} dir_e;
|
||||
|
||||
typedef struct {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
} v2_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t area[SIZE][SIZE];
|
||||
dir_e direction;
|
||||
uint32_t score;
|
||||
} game_t;
|
||||
|
||||
static game_t game;
|
||||
|
||||
void
|
||||
print_area()
|
||||
{
|
||||
printf("AREA:\n");
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
printf("[");
|
||||
for (int j = 0; j < SIZE - 1; j++) {
|
||||
printf("%d, ", game.area[i][j]);
|
||||
}
|
||||
printf("%d]\n", game.area[i][SIZE - 1]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
bool
|
||||
move()
|
||||
{
|
||||
bool retval = false;
|
||||
switch (game.direction) {
|
||||
case LEFT:
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
for (int k = 0; k < SIZE - 1; k++) {
|
||||
if (game.area[i][k] == 0 && game.area[i][k + 1] != 0) {
|
||||
game.area[i][k] = game.area[i][k + 1];
|
||||
game.area[i][k + 1] = 0;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
uint32_t *row = game.area[i];
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
for (int k = SIZE - 1; k > 0; k--) {
|
||||
if (game.area[i][k] == 0 && game.area[i][k - 1] != 0) {
|
||||
game.area[i][k] = game.area[i][k - 1];
|
||||
game.area[i][k - 1] = 0;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UP:
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
for (int k = 0; k < SIZE - 1; k++) {
|
||||
if (game.area[k][i] == 0 && game.area[k + 1][i] != 0) {
|
||||
game.area[k][i] = game.area[k + 1][i];
|
||||
game.area[k + 1][i] = 0;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DOWN:
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
for (int k = SIZE - 1; k > 0; k--) {
|
||||
if (game.area[k][i] == 0 && game.area[k - 1][i] != 0) {
|
||||
game.area[k][i] = game.area[k - 1][i];
|
||||
game.area[k - 1][i] = 0;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
combine_horizontal(
|
||||
bool has_moved
|
||||
) {
|
||||
bool retval = has_moved;
|
||||
int8_t direction;
|
||||
uint32_t start, end;
|
||||
switch (game.direction) {
|
||||
case LEFT:
|
||||
// combine left
|
||||
direction = -1;
|
||||
start = 0;
|
||||
end = SIZE - 1;
|
||||
break;
|
||||
case RIGHT:
|
||||
// combine right
|
||||
direction = 1;
|
||||
start = SIZE - 1;
|
||||
end = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int row_index = 0; row_index < SIZE; row_index++) {
|
||||
uint32_t *row = game.area[row_index];
|
||||
|
||||
for (int i = start; (game.direction == LEFT) ? i < end : i > end; i -= direction) {
|
||||
if (row[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
if (row[i] == row[i - direction]) {
|
||||
retval = true;
|
||||
row[i] *= 2;
|
||||
game.score += row[i];
|
||||
row[i - direction] = 0;
|
||||
for (int j = i - direction; (game.direction == LEFT) ? j < end : j > end; j -= direction) {
|
||||
row[j] = row[j - direction];
|
||||
}
|
||||
row[end] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
combine_vertical(
|
||||
bool has_moved
|
||||
) {
|
||||
bool retval = has_moved;
|
||||
int8_t direction;
|
||||
uint32_t start, end;
|
||||
switch (game.direction) {
|
||||
case UP:
|
||||
// combine up
|
||||
direction = -1;
|
||||
start = 0;
|
||||
end = SIZE - 1;
|
||||
break;
|
||||
case DOWN:
|
||||
// combine down
|
||||
direction = 1;
|
||||
start = SIZE - 1;
|
||||
end = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int col_index = 0; col_index < SIZE; col_index++) {
|
||||
for (int i = start; (game.direction == UP) ? i < end : i > end; i -= direction) {
|
||||
if (game.area[i][col_index] == 0) {
|
||||
continue;
|
||||
}
|
||||
if (game.area[i][col_index] == game.area[i - direction][col_index]) {
|
||||
retval = true;
|
||||
game.area[i][col_index] *= 2;
|
||||
game.score += game.area[i][col_index];
|
||||
game.area[i - direction][col_index] = 0;
|
||||
for (int j = i - direction; (game.direction == UP) ? j < end : j > end; j -= direction) {
|
||||
game.area[j][col_index] = game.area[j - direction][col_index];
|
||||
}
|
||||
game.area[end][col_index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
combine(
|
||||
bool has_moved
|
||||
) {
|
||||
if (game.direction == LEFT || game.direction == RIGHT) {
|
||||
return combine_horizontal(has_moved);
|
||||
} else {
|
||||
return combine_vertical(has_moved);
|
||||
}
|
||||
}
|
||||
|
||||
// finds a random empty position and puts a two there
|
||||
void
|
||||
new_2()
|
||||
{
|
||||
uint32_t row = rand() % SIZE;
|
||||
uint32_t col = rand() % SIZE;
|
||||
while (game.area[row][col] != 0) {
|
||||
row = rand() % SIZE;
|
||||
col = rand() % SIZE;
|
||||
}
|
||||
|
||||
game.area[row][col] = 2;
|
||||
}
|
||||
|
||||
void
|
||||
slide()
|
||||
{
|
||||
// 1. move all squares in one direction
|
||||
bool has_moved = move();
|
||||
|
||||
// 2. then combine them and shift the potential rest by one in the given direction
|
||||
bool has_combined = combine(has_moved);
|
||||
|
||||
// printf("moved? %s, combined? %s\n", (has_moved) ? "true" : "false", (has_combined) ? "true" : "false");
|
||||
|
||||
// 3. generate a new 2
|
||||
if (has_moved || has_combined) {
|
||||
new_2();
|
||||
}
|
||||
|
||||
// printf("score: %d\n", game.score);
|
||||
|
||||
// print_area();
|
||||
}
|
||||
|
||||
// polling events every frame
|
||||
void
|
||||
client_poll_event()
|
||||
@@ -17,31 +262,230 @@ client_poll_event()
|
||||
case SDLK_Q:
|
||||
game_state->is_running = false;
|
||||
break;
|
||||
case SDLK_W:
|
||||
game.direction = UP;
|
||||
slide();
|
||||
break;
|
||||
case SDLK_S:
|
||||
game.direction = DOWN;
|
||||
slide();
|
||||
break;
|
||||
case SDLK_A:
|
||||
game.direction = LEFT;
|
||||
slide();
|
||||
break;
|
||||
case SDLK_D:
|
||||
game.direction = RIGHT;
|
||||
slide();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CHR(ord) ((ord) + 48)
|
||||
#define ORD(chr) ((chr) - 48)
|
||||
|
||||
uint32_t
|
||||
colors(
|
||||
uint32_t number
|
||||
) {
|
||||
switch (number) {
|
||||
case 0:
|
||||
return 0xFFFFFF;
|
||||
case 2:
|
||||
return 0x00FF00;
|
||||
case 4:
|
||||
return 0xFF0000;
|
||||
case 8:
|
||||
return 0x0000FF;
|
||||
default:
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
numlen(
|
||||
uint32_t n
|
||||
) {
|
||||
uint32_t len = 0;
|
||||
|
||||
while (n > 0) {
|
||||
len++;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
power(
|
||||
uint32_t x,
|
||||
uint32_t n
|
||||
) {
|
||||
// x ^ n
|
||||
uint32_t acc = 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
acc *= x;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
numrev(
|
||||
uint32_t n
|
||||
) {
|
||||
uint32_t len = numlen(n);
|
||||
uint32_t new = 0;
|
||||
int i = 0;
|
||||
|
||||
while (n > 0) {
|
||||
new += (n % 10) * power(10, len - (++i));
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
// performed every frame
|
||||
void
|
||||
client_update_framebuffer()
|
||||
{
|
||||
// single green demo pixel
|
||||
game_state->framebuffer[0] = 0x00FF00;
|
||||
// clear_framebuffer(0xFFFF00);
|
||||
// put_string("Welcome to the most\n*DANGEROUS* 2048 game!",
|
||||
// 20, 20, 2, 2, 3, 0x000000, 0xFFFF00
|
||||
// );
|
||||
|
||||
clear_framebuffer(0xFFFF00);
|
||||
put_string("Welcome to the most\n*DANGEROUS* 2048 game!",
|
||||
20, 20, 2, 2, 3, 0x000000, 0xFFFF00
|
||||
);
|
||||
clear_framebuffer(0x000000);
|
||||
|
||||
uint32_t tile_size = game_state->width / SIZE;
|
||||
uint8_t border_width = 10;
|
||||
char *n_str;
|
||||
bool alloced = false;
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
for (int j = 0; j < SIZE; j++) {
|
||||
alloced = true;
|
||||
// background
|
||||
uint32_t x = (border_width / 2) + i * tile_size;
|
||||
uint32_t y = (border_width / 2) + j * tile_size;
|
||||
uint32_t w = tile_size - border_width;
|
||||
uint32_t h = tile_size - border_width;
|
||||
uint32_t background_color = colors(game.area[j][i]);
|
||||
put_rect(x, y, w, h, background_color);
|
||||
|
||||
// number in foreground
|
||||
uint32_t foreground_color = 0x000000;
|
||||
uint8_t font_size = 3;
|
||||
|
||||
uint32_t n = game.area[j][i];
|
||||
uint32_t n_len = numlen(n);
|
||||
n_str = calloc(n_len, sizeof(char));
|
||||
if (n_str == NULL) {
|
||||
game_state->is_running = false;
|
||||
}
|
||||
sprintf(n_str, "%d", n);
|
||||
uint32_t n_rev = numrev(n);
|
||||
uint32_t digit_offset = 1;
|
||||
if (n != 0) {
|
||||
put_string(n_str, x + border_width, y + border_width, font_size, digit_offset, 12, foreground_color, background_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// score display line (single line)
|
||||
char *score_text = calloc(numlen(game.score), sizeof(char));
|
||||
if (score_text == NULL) {
|
||||
game_state->is_running = false;
|
||||
}
|
||||
alloced = true;
|
||||
|
||||
sprintf(score_text, "score: %6d", game.score);
|
||||
put_string(score_text, border_width / 2, tile_size * SIZE + border_width / 2, 6, 1, 12, 0xFFFFFF, 0x000000);
|
||||
|
||||
if (alloced) {
|
||||
free(n_str);
|
||||
free(score_text);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
v2_eq(v2_t a, v2_t b)
|
||||
{
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
bool
|
||||
v2_contains(v2_t v[], size_t size, v2_t elem)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (v2_eq(v[i], elem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
game_init()
|
||||
{
|
||||
srand(time(NULL));
|
||||
|
||||
// generate MAX_NUMBER_OF_4 + MAX_NUMBER_OF_2 random indices in range 0..15 (row in 0..3, col in 0..3)
|
||||
// this means that there will be at least MAX_NUMBER_OF_2 of 2s and MAX_NUMBER_OF_4 <= MAX_NUMBER_OF_2 4s
|
||||
// => usually less 4s than 2s because the indices can get replaced
|
||||
#define MAX_NUMBER_OF_4 1
|
||||
#define MAX_NUMBER_OF_2 2
|
||||
|
||||
uint8_t row, col;
|
||||
v2_t elem;
|
||||
v2_t fours[MAX_NUMBER_OF_4], twos[MAX_NUMBER_OF_2];
|
||||
|
||||
int i = 0;
|
||||
while (i < MAX_NUMBER_OF_4) {
|
||||
row = rand() % SIZE;
|
||||
col = rand() % SIZE;
|
||||
elem = (v2_t){ .x = col, .y = row };
|
||||
if (!v2_contains(twos, MAX_NUMBER_OF_4, elem)) {
|
||||
fours[i++] = elem;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_NUMBER_OF_2) {
|
||||
row = rand() % SIZE;
|
||||
col = rand() % SIZE;
|
||||
elem = (v2_t){ .x = col, .y = row };
|
||||
if (!v2_contains(twos, MAX_NUMBER_OF_2, elem)) {
|
||||
twos[i++] = elem;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUMBER_OF_4; i++) {
|
||||
game.area[fours[i].y][fours[i].x] = 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUMBER_OF_2; i++) {
|
||||
game.area[twos[i].y][twos[i].x] = 2;
|
||||
}
|
||||
|
||||
game.direction = RIGHT;
|
||||
game.score = 0;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
uint32_t window_width = 500;
|
||||
uint32_t window_height = window_width * 1.12f;
|
||||
|
||||
game_init();
|
||||
|
||||
// initialize the engine
|
||||
if (engine_init(
|
||||
500, 500,
|
||||
window_width, window_height,
|
||||
"Dangerous 2048",
|
||||
client_poll_event,
|
||||
client_update_framebuffer
|
||||
|
||||
@@ -46,3 +46,4 @@ void
|
||||
engine_sdl_destroy(
|
||||
engine_sdl_state_t *state
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user