Blob Blame Raw

#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;
}