2021-11-15 08:57:27 +00:00
|
|
|
#include "2048.h"
|
2021-12-14 20:26:10 +00:00
|
|
|
#include <stdbool.h>
|
2021-11-15 10:00:37 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2021-12-14 18:24:51 +00:00
|
|
|
void game_add_block(Game *game) {
|
2021-12-14 17:56:37 +00:00
|
|
|
|
|
|
|
bool is_full = true;
|
2021-12-14 23:58:48 +00:00
|
|
|
for (int i = 0; i < game->field_size_x; i++) {
|
|
|
|
for (int j = 0; j < game->field_size_y; j++) {
|
2021-12-14 18:24:51 +00:00
|
|
|
if (game->field[j][i] == 0) {
|
2021-12-14 17:56:37 +00:00
|
|
|
is_full = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_full) {
|
2021-12-14 18:24:51 +00:00
|
|
|
game->game_over = true;
|
|
|
|
return;
|
2021-12-14 17:56:37 +00:00
|
|
|
}
|
|
|
|
|
2021-11-15 10:00:37 +00:00
|
|
|
size_t x, y;
|
|
|
|
int value;
|
2021-11-15 15:33:31 +00:00
|
|
|
do {
|
2021-12-14 20:26:10 +00:00
|
|
|
x = rand() % game->field_size_x;
|
2021-12-14 18:24:51 +00:00
|
|
|
y = rand() % game->field_size_y;
|
2021-11-15 15:33:31 +00:00
|
|
|
value = (rand() % 2) + 1;
|
2021-12-14 23:58:48 +00:00
|
|
|
} while (game->field[y][x] != 0);
|
|
|
|
game->field[y][x] = value * 2;
|
2021-11-15 10:00:37 +00:00
|
|
|
}
|
2021-11-15 08:57:27 +00:00
|
|
|
|
2021-11-15 21:20:16 +00:00
|
|
|
Game game_init(size_t field_size_x, size_t field_size_y) {
|
2021-11-15 08:57:27 +00:00
|
|
|
Game game;
|
2021-12-14 17:56:37 +00:00
|
|
|
game.game_over = false;
|
2021-12-14 20:06:42 +00:00
|
|
|
game.won = false;
|
2021-11-15 21:20:16 +00:00
|
|
|
game.field_size_x = field_size_x;
|
|
|
|
game.field_size_y = field_size_y;
|
2021-11-15 08:57:27 +00:00
|
|
|
game.score = 0;
|
2021-11-15 21:20:16 +00:00
|
|
|
game.field = malloc(sizeof(uint16_t *) * field_size_y);
|
2021-12-14 23:58:48 +00:00
|
|
|
for (size_t i = 0; i < field_size_x; i++) {
|
|
|
|
game.field[i] = calloc(field_size_y, sizeof(uint16_t) * field_size_y);
|
2021-11-15 08:57:27 +00:00
|
|
|
}
|
2021-11-15 10:00:37 +00:00
|
|
|
|
|
|
|
time_t t;
|
2021-12-14 20:26:10 +00:00
|
|
|
srand((unsigned)time(&t));
|
2021-12-14 18:24:51 +00:00
|
|
|
game_add_block(&game);
|
2021-11-15 15:33:31 +00:00
|
|
|
|
2021-11-15 08:57:27 +00:00
|
|
|
return game;
|
|
|
|
}
|
|
|
|
|
2021-12-24 13:02:00 +00:00
|
|
|
void game_destroy(Game *game) {
|
|
|
|
for (size_t i = 0; i < game->field_size_x; i++) {
|
|
|
|
free(game->field[i]);
|
2021-11-15 08:57:27 +00:00
|
|
|
}
|
2021-12-24 13:02:00 +00:00
|
|
|
free(game->field);
|
|
|
|
game->field = NULL;
|
2021-11-15 08:57:27 +00:00
|
|
|
}
|
|
|
|
|
2021-12-14 17:56:37 +00:00
|
|
|
void game_move(Game *game, Direction direction) {
|
2021-12-14 20:06:42 +00:00
|
|
|
if (game->game_over || game->won) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-14 21:36:44 +00:00
|
|
|
// I have few chained for loops that do a lot of similar stuff so I call them in a for loop for better clarity and readability
|
|
|
|
for (int u = 0; u < 3; u++) {
|
2021-12-14 23:58:48 +00:00
|
|
|
for (int i = 0; i < game->field_size_x; i++) {
|
2021-12-14 21:36:44 +00:00
|
|
|
uint16_t **field = game->field;
|
|
|
|
// move everything on one side
|
2021-12-14 23:58:48 +00:00
|
|
|
for (int j = 0; j < game->field_size_y - 1; j++) {
|
2021-12-14 21:36:44 +00:00
|
|
|
// a, b is the same as i and j. It is just flipped when
|
|
|
|
// it does not go horizontally so I can access stuff vertically
|
|
|
|
int a = i;
|
|
|
|
int b = j;
|
|
|
|
if (direction == Up || direction == Down) {
|
|
|
|
a = j;
|
|
|
|
b = i;
|
2021-11-24 09:05:59 +00:00
|
|
|
}
|
2021-11-18 17:08:33 +00:00
|
|
|
|
2021-12-14 21:36:44 +00:00
|
|
|
// make it so it can work with different directions
|
2021-12-14 22:08:08 +00:00
|
|
|
int directionality = b;
|
2021-12-14 21:36:44 +00:00
|
|
|
if (direction == Down) {
|
|
|
|
directionality = a;
|
2021-12-14 20:26:10 +00:00
|
|
|
}
|
2021-12-14 21:36:44 +00:00
|
|
|
int movement = 1;
|
|
|
|
if (direction == Left || direction == Up) {
|
|
|
|
if (direction == Left) {
|
|
|
|
directionality = game->field_size_x - b - 1;
|
2021-12-14 20:06:42 +00:00
|
|
|
}
|
2021-12-14 21:36:44 +00:00
|
|
|
else {
|
|
|
|
directionality = game->field_size_y - a - 1;
|
2021-12-14 20:06:42 +00:00
|
|
|
}
|
2021-12-14 21:36:44 +00:00
|
|
|
movement = -1;
|
2021-12-14 20:26:10 +00:00
|
|
|
}
|
2021-12-14 21:36:44 +00:00
|
|
|
// the similar stuff
|
|
|
|
switch (u) {
|
|
|
|
case 0:
|
|
|
|
case 2:
|
|
|
|
if (direction == Left || direction == Right) {
|
|
|
|
if (field[a][directionality + movement] == 0) {
|
|
|
|
field[a][directionality + movement] = field[a][directionality];
|
|
|
|
field[a][directionality] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (field[directionality + movement][b] == 0) {
|
|
|
|
field[directionality + movement][b] = field[directionality][b];
|
|
|
|
field[directionality][b] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
// TODO: fix 444 <- 48, should be 84
|
|
|
|
if (direction == Left || direction == Right) {
|
|
|
|
if (field[a][directionality + movement] == field[a][directionality]) {
|
|
|
|
field[a][directionality + movement] = field[a][directionality] * 2;
|
|
|
|
game->score += field[a][directionality + movement];
|
|
|
|
if (field[a][directionality + movement] == 2048) {
|
|
|
|
game->won = true;
|
|
|
|
}
|
|
|
|
field[a][directionality] = 0;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (field[directionality + movement][b] == field[directionality][b]) {
|
|
|
|
field[directionality + movement][b] = field[directionality][b] * 2;
|
|
|
|
game->score += field[directionality + movement][b];
|
|
|
|
if (field[directionality + movement][b] == 2048) {
|
|
|
|
game->won = true;
|
|
|
|
}
|
|
|
|
field[directionality][b] = 0;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2021-11-24 09:05:59 +00:00
|
|
|
}
|
2021-11-18 17:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-15 15:33:31 +00:00
|
|
|
|
2021-12-14 18:24:51 +00:00
|
|
|
game_add_block(game);
|
2021-11-15 08:57:27 +00:00
|
|
|
}
|