#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <helianthus.h>
#define CELLSIZE 128
#define MAPSIZE 4
typedef struct {
Group group;
int value;
} Cell;
Animation grid;
Animation numbers[11];
Cell map[MAPSIZE][MAPSIZE];
double speed = 8;
void setSprite(Cell *cell, double x, double y) {
if (cell->group)
groupDestroyEach(cell->group);
else
cell->group = createGroup();
Sprite sprite = createSpriteEx(x, y, 1, 1, numbers[cell->value]);
groupAdd(cell->group, sprite);
}
int add(int dr, int dc) {
int count = 0;
for(int r = 0; r < MAPSIZE; ++r)
for(int c = 0; c < MAPSIZE; ++c)
if (map[r][c].value < 0)
++count;
if (count == 0) return 0;
int i = randomNumber(0, count-1);
for(int r = 0; r < MAPSIZE; ++r)
for(int c = 0; c < MAPSIZE; ++c)
if (map[r][c].value < 0)
if (i-- == 0) {
map[r][c].value = 0;
int cc = dc > 0 ? -1 : (dc < 0 ? MAPSIZE : c);
int rr = dr > 0 ? -1 : (dr < 0 ? MAPSIZE : r);
setSprite(&map[r][c], cc + 0.5, rr + 0.5);
return 1;
}
return 0;
}
void fallStep(int *moves, Cell **prev, int *skip, Cell *curr, Cell *empty) {
if (curr->value < 0) {
++(*skip);
} else
if (*prev && (*prev)->value == curr->value && curr->value < 10) {
for(int i = 0; i < groupGetCount(curr->group); ++i)
groupAdd((*prev)->group, groupGet(curr->group, i));
groupDestroy(curr->group);
curr->group = NULL;
curr->value = -1;
++((*prev)->value);
++(*skip);
++(*moves);
*prev = NULL;
} else {
if (empty != curr) {
empty->group = curr->group;
empty->value = curr->value;
curr->group = NULL;
curr->value = -1;
++(*moves);
}
*prev = empty;
}
}
void fall(int dr, int dc) {
Cell *prev;
int skip;
int moves = 0;
if (dr == 0) {
for(int r = 0; r < MAPSIZE; ++r) {
prev = NULL; skip = 0;
if (dc < 0)
for(int c = 0; c < MAPSIZE; ++c)
fallStep(&moves, &prev, &skip, &map[r][c], &map[r][c-skip]);
else
if (dc > 0)
for(int c = MAPSIZE-1; c >= 0; --c)
fallStep(&moves, &prev, &skip, &map[r][c], &map[r][c+skip]);
}
} else
if (dc == 0) {
for(int c = 0; c < MAPSIZE; ++c) {
prev = NULL; skip = 0;
if (dr < 0)
for(int r = 0; r < MAPSIZE; ++r)
fallStep(&moves, &prev, &skip, &map[r][c], &map[r-skip][c]);
else
if (dr > 0)
for(int r = MAPSIZE-1; r >= 0; --r)
fallStep(&moves, &prev, &skip, &map[r][c], &map[r+skip][c]);
}
}
if (moves > 0) add(dr, dc);
}
void init() {
for(int r = 0; r < MAPSIZE; ++r) {
for(int c = 0; c < MAPSIZE; ++c) {
map[r][c].group = NULL;
map[r][c].value = -1;
}
}
grid = createAnimationEx("data/sprite/2048/frame.png", TRUE, TRUE, TRUE);
numbers[ 0] = createAnimation("data/sprite/2048/2.png");
numbers[ 1] = createAnimation("data/sprite/2048/4.png");
numbers[ 2] = createAnimation("data/sprite/2048/8.png");
numbers[ 3] = createAnimation("data/sprite/2048/16.png");
numbers[ 4] = createAnimation("data/sprite/2048/32.png");
numbers[ 5] = createAnimation("data/sprite/2048/64.png");
numbers[ 6] = createAnimation("data/sprite/2048/128.png");
numbers[ 7] = createAnimation("data/sprite/2048/256.png");
numbers[ 8] = createAnimation("data/sprite/2048/512.png");
numbers[ 9] = createAnimation("data/sprite/2048/1024.png");
numbers[10] = createAnimation("data/sprite/2048/2048.png");
add(0, 0);
add(0, 0);
}
void draw() {
saveState();
zoom(CELLSIZE);
saveState();
noStroke();
fillTexture(grid, 0, 0, 1, 1, FALSE);
rect(0, 0, MAPSIZE, MAPSIZE);
restoreState();
if (keyWentDown("left")) fall(0, -1);
if (keyWentDown("right")) fall(0, 1);
if (keyWentDown("up")) fall(-1, 0);
if (keyWentDown("down")) fall( 1, 0);
double dp = speed * windowGetFrameTime();
int score = 0;
for(int r = 0; r < MAPSIZE; ++r) {
for(int c = 0; c < MAPSIZE; ++c) {
Cell *cell = &map[r][c];
if (cell->group) {
score += (1 << (cell->value + 1));
int count = groupGetCount(cell->group);
int ready = count > 1;
double prevX = 0, prevY = 0;
double cx = c + 0.5;
double cy = r + 0.5;
for(int i = 0; i < count; ++i) {
Sprite sprite = groupGet(cell->group, i);
double x = spriteGetX(sprite);
double y = spriteGetY(sprite);
x = fabs(x - cx) <= dp ? cx : (x < cx ? x + dp : x - dp);
y = fabs(y - cy) <= dp ? cy : (y < cy ? y + dp : y - dp);
spriteSetXY(sprite, x, y);
if (i > 0 && (fabs(prevX - x) > 0.01 || fabs(prevY - y) > 0.01))
ready = 0;
prevX = x;
prevY = y;
}
if (ready)
setSprite(cell, prevX, prevY);
}
}
}
char buf[20];
sprintf(buf, "%d", score);
windowSetTitle(buf);
drawSprites();
restoreState();
}
int main() {
windowSetTitle("2048");
windowSetSize(MAPSIZE*CELLSIZE, MAPSIZE*CELLSIZE);
windowSetVariableFrameRate();
windowSetInit(&init);
windowSetDraw(&draw);
windowRun();
return 0;
}