Skip to content

Instantly share code, notes, and snippets.

@Siguza
Last active March 8, 2022 08:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Siguza/2ef468405d97c559fc88154585d63cf0 to your computer and use it in GitHub Desktop.
Save Siguza/2ef468405d97c559fc88154585d63cf0 to your computer and use it in GitHub Desktop.
2048 for your calculator! :D
/*
* t2048.c - 2048 for some TI calculators
*
* Copyright (c) 2014 Siguza
*
* Tested on TI-89 Titanium only. According to headers, it should work on TI-92 and Voyage 200 as well, but no promises.
* To be compiled with ti-gcc - as far as I remember, TI's own C compiler can't handle this.
*
* Licensed under MIT, i.e. feel free to use and redistribute at will, but I'd appreciate some credit. :)
*/
#define USE_TI89
#define USE_TI92PLUS
#define USE_V200
#define OPTIMIZE_ROM_CALLS
#define MIN_AMS 100
#define SAVE_SCREEN
#include <alloc.h>
#include <estack.h>
#include <graph.h>
#include <gray.h>
#include <kbd.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <system.h>
const SCR_RECT *TILE_AREA = &(SCR_RECT){{0, 0, 103, 99}};
void *screen;
unsigned char *field;
unsigned char *tmp;
unsigned char *tmp2;
unsigned char *fdir;
char *str;
unsigned long score;
unsigned long highscore;
unsigned char gameover;
unsigned char animate;
unsigned char gmode;
int round(float);
void init();
void draw();
void drawTile(unsigned int, unsigned int, unsigned int);
void drawBox(unsigned int, unsigned int);
void fillBox(unsigned int, unsigned int);
unsigned char load();
void save();
void move(signed int, signed int, signed int);
unsigned char nextTileIndex();
void newTile(unsigned char);
void intToStr(unsigned long);
void _main()
{
ClrScr();
DrawStr(35, 1, "TI-2048, v1.1.1", A_NORMAL);
DrawStr(20, 11, "(Unofficial/Fanmade)", A_NORMAL);
DrawStr(44, 21, "by Siguza", A_NORMAL);
DrawStr(23, 36, "Arrows - Move tiles", A_NORMAL);
DrawStr(32, 46, "Clear - New game", A_NORMAL);
DrawStr(35, 56, "Home/Esc - Exit", A_NORMAL);
DrawStr(11, 66, "Mode - Toggle animation", A_NORMAL);
DrawStr(5, 76, "2nd Mode - Change shading", A_NORMAL);
DrawStr(5, 91, "Press any key to continue", A_NORMAL);
switch(ngetchx())
{
case 264: // Esc
case 277: // Home
return;
}
randomize();
field = malloc(16);
tmp = malloc(16);
tmp2 = malloc(16);
fdir = malloc(16);
str = malloc(10);
screen = malloc(LCD_SIZE);
if(!screen)
{
free(field);
free(tmp);
free(tmp2);
free(fdir);
free(str);
return;
}
if(load())
{
highscore = 0;
animate = 1;
gmode = 0;
init();
}
if(gmode < 2)
{
PortSet(screen, 239, 127);
}
else
{
GrayOn();
}
draw();
while(1)
{
idle();
switch(ngetchx())
{
case 18: // 2nd + Mode
gmode = (gmode + 1) % 3;
if(gmode == 0)
{
GrayOff();
PortSet(screen, 239, 127);
}
else if(gmode == 2)
{
PortRestore();
GrayOn();
}
draw();
break;
case 263: // Clear
init();
draw();
break;
case 264: // Esc
case 277: // Home
save();
if(GrayCheckRunning())
{
GrayOff();
}
else
{
PortRestore();
}
free(field);
free(tmp);
free(tmp2);
free(fdir);
free(str);
free(screen);
return;
case 266: // Mode
animate = !animate;
break;
case 272: // F5
PortRestore();
if(gmode < 2)
{
PortSet(screen, 239, 127);
}
draw();
break;
case 337: // Up
move(1, 0, 4);
break;
case 340: // Down
move(1, 12, -4);
break;
case 338: // Left
move(4, 0, 1);
break;
case 344: // Right
move(4, 3, -1);
break;
}
}
}
int round(float x)
{
return (int)(x + 0.5);
}
void init()
{
unsigned char i, r;
for(i = 0; i < 16; i++)
{
field[i] = 0;
}
i = random(16);
r = random(15);
if(r >= i)
{
r++;
}
newTile(i);
newTile(r);
score = 0;
gameover = 0;
}
// Screen is 160x100
void draw()
{
unsigned int i, x, y;
if(gmode >= 2)
{
GraySetAMSPlane(LIGHT_PLANE);
ClrScr();
GraySetAMSPlane(DARK_PLANE);
}
ClrScr();
DrawLine(104, 0, 104, 99, A_NORMAL);
DrawLine(104, 32, 159, 32, A_NORMAL);
DrawLine(104, 67, 159, 67, A_NORMAL);
DrawStr(120, 12, "2048", A_NORMAL);
DrawStr(117, 40, "Score", A_NORMAL);
DrawStr(105, 74, "Highscore", A_NORMAL);
intToStr(score);
DrawStr(132 - strlen(str) * 3, 52, str, A_NORMAL);
intToStr(highscore);
DrawStr(132 - strlen(str) * 3, 86, str, A_NORMAL);
for(y = 0; y < 4; y++)
{
for(x = 0; x < 4; x++)
{
i = field[4 * y + x];
if(i > 0)
{
drawTile(x * 26, y * 25, i);
}
}
}
if(gameover)
{
if(gmode >= 2)
{
GraySetAMSPlane(LIGHT_PLANE);
ScrRectFill(&(SCR_RECT){{24, 45, 79, 53}}, TILE_AREA, A_REVERSE);
GraySetAMSPlane(DARK_PLANE);
}
ScrRectFill(&(SCR_RECT){{24, 45, 79, 53}}, TILE_AREA, A_REVERSE);
DrawLine(23, 44, 80, 44, A_NORMAL);
DrawLine(23, 54, 80, 54, A_NORMAL);
DrawLine(23, 45, 23, 53, A_NORMAL);
DrawLine(80, 45, 80, 53, A_NORMAL);
DrawStr(25, 46, "Game Over", A_NORMAL);
}
if(gmode < 2)
{
LCD_restore(screen);
}
}
void drawTile(unsigned int x, unsigned int y, unsigned int i)
{
intToStr((long)pow(2, i));
switch(gmode)
{
case 2:
if(i <= 4)
{
DrawStr(x + 12 - strlen(str) * 3, y + 8, str, A_NORMAL);
break;
}
if(i <= 8)
{
GraySetAMSPlane(LIGHT_PLANE);
}
fillBox(x, y);
DrawStr(x + 12 - strlen(str) * 3, y + 8, str, A_REVERSE);
if(i <= 8)
{
GraySetAMSPlane(DARK_PLANE);
}
break;
case 1:
if(i > 6)
{
fillBox(x, y);
DrawStr(x + 12 - strlen(str) * 3, y + 8, str, A_REVERSE);
break;
}
case 0:
DrawStr(x + 12 - strlen(str) * 3, y + 8, str, A_NORMAL);
break;
}
drawBox(x, y);
}
void drawBox(unsigned int x, unsigned int y)
{
DrawLine(x + 2, y, x + 22, y, A_NORMAL);
DrawLine(x + 2, y + 23, x + 22, y + 23, A_NORMAL);
DrawLine(x, y + 2, x, y + 21, A_NORMAL);
DrawLine(x + 24, y + 2, x + 24, y + 21, A_NORMAL);
DrawPix(x + 1, y + 1, A_NORMAL);
DrawPix(x + 1, y + 22, A_NORMAL);
DrawPix(x + 23, y + 1, A_NORMAL);
DrawPix(x + 23, y + 22, A_NORMAL);
}
void fillBox(unsigned int x, unsigned int y)
{
ScrRectFill(&(SCR_RECT){{x + 1, y + 1, x + 23, y + 22}}, &(SCR_RECT){{0, 0, 103, 99}}, A_NORMAL);
}
unsigned char load()
{
unsigned char c;
FILE *file = fopen("t2048dat", "rb");
if(file == NULL)
{
return 1;
}
if(fgetc(file) != 1)
{
fclose(file);
return 1;
}
fread(field, 16, 1, file);
c = (unsigned char)fgetc(file);
gameover = c & 1;
animate = (c & 2) >> 1;
gmode = (c & 12) >> 2;
fread(&score, sizeof(unsigned long), 1, file);
fread(&highscore, sizeof(unsigned long), 1, file);
fclose(file);
return 0;
}
void save()
{
FILE *file = fopen("t2048dat", "wb");
if(file == NULL)
{
return;
}
fputc(1, file);
fwrite(field, 16, 1, file);
fputc(gameover + (animate << 1) + (gmode << 2), file);
fwrite(&score, sizeof(unsigned long), 1, file);
fwrite(&highscore, sizeof(unsigned long), 1, file);
fputc(DATA_TAG, file);
fclose(file);
}
void move(signed int fu, signed int v0, signed int dv)
{
signed int c, i, u, v;
float x, y;
unsigned char j, moved = 0;
for(c = 0; c < 16; c++)
{
tmp[c] = field[c];
fdir[c] = 4;
}
for(u = 0; u < 4 * fu; u += fu)
{
c = 0;
for(v = 0; v < 4; v++)
{
i = u + v0 + (v * dv);
if(field[i] > 0)
{
if(v != c)
{
field[u + v0 + (c * dv)] = field[i];
fdir[i] += (v - c) * ((dv > 0) ? 1 : -1);
moved |= 1;
}
c++;
}
}
if(c > 0)
{
for(; c < 4; c++)
{
field[u + v0 + (c * dv)] = 0;
}
}
for(v = 0; v < 3; v++)
{
i = u + v0 + (v * dv);
if((field[i] != 0) && (field[i] == field[i + dv]))
{
score += pow(2, ++field[i]);
fdir[i + dv] += (dv > 0) ? 1 : -1;
for(c = v + 1; c < 3; c++)
{
i = u + v0 + (c * dv);
field[i] = field[i + dv];
fdir[i + dv] += (dv > 0) ? 1 : -1;
}
field[u + v0 + (3 * dv)] = 0;
moved |= 1;
}
}
}
if(!moved)
{
return;
}
j = nextTileIndex();
if(animate)
{
OSFreeTimer(6);
OSRegisterTimer(6, 8);
for(c = 1; c < 8; c++)
{
if(GrayCheckRunning())
{
GraySetAMSPlane(LIGHT_PLANE);
ScrRectFill(&(SCR_RECT){{0, 0, 103, 99}}, &(SCR_RECT){{0, 0, 103, 99}}, A_REVERSE);
GraySetAMSPlane(DARK_PLANE);
}
ScrRectFill(&(SCR_RECT){{0, 0, 103, 99}}, &(SCR_RECT){{0, 0, 103, 99}}, A_REVERSE);
v = (j % 4) * 26;
u = (j / 4) * 25;
i = round(1.5 * ((float)c));
DrawClipRect(&(WIN_RECT){v + 12 - i, u + 12 - i, v + 13 + i, u + 12 + i}, TILE_AREA, A_NORMAL | B_NORMAL);
for(u = 0; u < 4; u++)
{
for(v = 0; v < 4; v++)
{
i = tmp[(4 * u) + v];
if(i > 0)
{
x = v;
y = u;
if(fu == 1)
{
y -= ((float)(fdir[(4 * u) + v] - 4)) * (((float)c) / 8.0);
}
else
{
x -= ((float)(fdir[(4 * u) + v] - 4)) * (((float)c) / 8.0);
}
drawTile(round(x * 26), round(y * 25), i);
}
}
}
i = 7 - OSTimerCurVal(6);
if(i > c)
{
c = i + 1;
}
if(gmode < 2)
{
LCD_restore(screen);
}
}
OSFreeTimer(6);
}
if(score > highscore)
{
highscore = score;
}
newTile(j);
for(c = 0; c < 16; c++)
{
if(field[c] == 0)
{
goto okai;
}
}
for(c = 0; c < 16; c++)
{
if(((c % 4 != 3) && (field[c] == field[c + 1])) || ((c < 12) && (field[c] == field[c + 4])))
{
goto okai;
}
}
gameover = 1;
okai:
draw();
}
unsigned char nextTileIndex()
{
unsigned char i;
unsigned char c = 0;
for(i = 0; i < 16; i++)
{
if(field[i] == 0)
{
tmp2[c++] = i;
}
}
return tmp2[random(c)];
}
void newTile(unsigned char i)
{
field[i] = random(10) == 0 ? 2 : 1;
}
void intToStr(unsigned long x)
{
unsigned char c, i;
for(c = 1; c < 9; c++)
{
if((x / ((long)pow(10, c))) == 0)
{
break;
}
}
for(i = 0; i < c; i++)
{
str[c - i - 1] = '0' + (x % 10);
x /= 10;
}
str[c] = '\0';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment