diff options
Diffstat (limited to 'demos/applications/justget10/jg10.c')
-rw-r--r-- | demos/applications/justget10/jg10.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/demos/applications/justget10/jg10.c b/demos/applications/justget10/jg10.c new file mode 100644 index 00000000..6ea4e951 --- /dev/null +++ b/demos/applications/justget10/jg10.c @@ -0,0 +1,501 @@ +#include "gfx.h" +#include "src/gwin/gwin_class.h" +#include "stdlib.h" +#include "string.h" +#include "jg10.h" + +GEventMouse ev; +GHandle mainWin, Jg10SelectWidget; + +typedef struct jg10WidgetObject_t { + GWidgetObject w; // Base Class +} jg10WidgetObject; + +GHandle jg10SelectionWidgetGCreate(GDisplay* g, jg10WidgetObject* wo, GWidgetInit* pInit); +#define jg10SelectionWidgetCreate(wo, pInit) jg10SelectionWidgetGCreate(GDISP, wo, pInit) + + +typedef struct { // Node properties + uint8_t num; // Node number + bool_t check; // Node needs to be checked or not + bool_t sel; // Node selected or not +} nodeProps; + +nodeProps jg10Field[JG10_FIELD_WIDTH][JG10_FIELD_HEIGHT]; // jg10 field array +bool_t jg10GameOver = FALSE; +const char *jg10Graph[] = {"background.bmp", "1.bmp","2.bmp","3.bmp","4.bmp","5.bmp","6.bmp","7.bmp","8.bmp", "9.bmp", "10.bmp", "11.bmp", "12.bmp", "13.bmp", "14.bmp", "15.bmp", "16.bmp", "17.bmp", "18.bmp", "19.bmp", "20.bmp"}; // 21 elements (0-20) +gdispImage jg10Image[JG10_MAX_COUNT]; +#define JG10_ANIM_IMAGES 5 +#define JG10_ANIM_DELAY 60 +const char *jg10GraphAnim[] = {"a1.bmp","a2.bmp","a3.bmp","a4.bmp","background.bmp"}; // 5 elements (0-4) +gdispImage jg10ImageAnim[JG10_ANIM_IMAGES]; +uint8_t jg10MaxVal=4; // Max value in field... +font_t font; +#if JG10_SHOW_SPLASH +GTimer jg10SplashBlink; +bool_t jg10SplashTxtVisible = FALSE; +gdispImage jg10SplashImage; +#endif + + +static void initRng(void) { + srand(gfxSystemTicks()); +} + +static uint32_t randomInt(uint32_t max) { + return rand() % max; +} + +static int uitoa(unsigned int value, char * buf, int max) { + int n = 0; + int i = 0; + int tmp = 0; + + if (!buf) return -3; + if (2 > max) return -4; + i=1; + tmp = value; + if (0 > tmp) { + tmp *= -1; + i++; + } + for (;;) { + tmp /= 10; + if (0 >= tmp) break; + i++; + } + if (i >= max) { + buf[0] = '?'; + buf[1] = 0x0; + return 2; + } + n = i; + tmp = value; + if (0 > tmp) { + tmp *= -1; + } + buf[i--] = 0x0; + for (;;) { + buf[i--] = (tmp % 10) + '0'; + tmp /= 10; + if (0 >= tmp) break; + } + if (-1 != i) { + buf[i--] = '-'; + } + return n; +} + +static bool_t inRange(int16_t x, int16_t y) { + if ((x >= 0) && (x < JG10_FIELD_WIDTH) && (y >= 0) && (y < JG10_FIELD_HEIGHT)) return TRUE; else return FALSE; +} + +static void clean_SelCheck(void) { + uint16_t i ,j; + for (i = 0; i < JG10_FIELD_WIDTH; i++) { + for (j = 0; j < JG10_FIELD_HEIGHT; j++) { + jg10Field[i][j].check = FALSE; + jg10Field[i][j].sel = FALSE; + } + } +} + +static void remove_Selected(void) { + uint16_t i ,j, step; + systemticks_t delay_start = 0; + systemticks_t delay=0; + for (step = 0; step < JG10_ANIM_IMAGES; step++) { + delay_start = gfxSystemTicks(); + for (i = 0; i < JG10_FIELD_WIDTH; i++) { + for (j = 0; j < JG10_FIELD_HEIGHT; j++) { + if (jg10Field[i][j].sel) { + gdispImageDraw(&jg10ImageAnim[step], (i*JG10_CELL_HEIGHT)+1, (j*JG10_CELL_WIDTH)+1, JG10_CELL_WIDTH, JG10_CELL_HEIGHT, 0, 0); + } + } + } + delay = gfxSystemTicks()-delay_start; + if (delay <= JG10_ANIM_DELAY) { + gfxSleepMilliseconds(JG10_ANIM_DELAY-delay); + } + } + for (i = 0; i < JG10_FIELD_WIDTH; i++) { + for (j = 0; j < JG10_FIELD_HEIGHT; j++) { + if (jg10Field[i][j].sel) { + jg10Field[i][j].sel = FALSE; + jg10Field[i][j].num = 0; + } + } + } +// gwinRedraw(mainWin); +} + +static uint8_t jg10_randomer(uint8_t max, uint8_t th) { + uint32_t r = randomInt((1<<max)-1); + + if (r != 0) { + for (int8_t i = max; i >= 0; i--) { + if (r >= (uint32_t)(1<<i)) { + if ((max-i) >= th) { + return randomInt(max-i)+1; + } else { + return randomInt(th)+1; + } + } + } + } + return randomInt(max-1)+1; +} + +static void movePiecesDown(void) { + uint8_t tmp = 0; + bool_t needToCheck = TRUE; + while (needToCheck) { + needToCheck = FALSE; + for (int8_t y = (JG10_FIELD_HEIGHT-1); y >= 0; y--) { + for (uint8_t x = 0; x < JG10_FIELD_WIDTH; x++) { + if (jg10Field[x][y].num == 0) { + // check if there is at least single none empty piece + tmp = 0; + for (int8_t tmpy = y; tmpy >= 0; tmpy--) { + if (jg10Field[x][tmpy].num != 0) tmp++; + } + if (tmp != 0) { + for (int8_t tmpy = y; tmpy > 0; tmpy--) { + jg10Field[x][tmpy].num = jg10Field[x][tmpy-1].num; + } + jg10Field[x][0].num = 0; + needToCheck = TRUE; + } + } + } + } + } + gwinRedraw(mainWin); + // Add new pieces + needToCheck = TRUE; + while (needToCheck) { + needToCheck = FALSE; + for (int8_t y = (JG10_FIELD_HEIGHT-1); y >= 0; y--) { + for (uint8_t x = 0; x < JG10_FIELD_WIDTH; x++) { + if (jg10Field[x][y].num == 0) { + for (int8_t tmpy = y; tmpy > 0; tmpy--) { + jg10Field[x][tmpy].num = jg10Field[x][tmpy-1].num; + } + jg10Field[x][0].num = jg10_randomer(jg10MaxVal, 3); + needToCheck = TRUE; + } + } + } + gwinRedraw(mainWin); + gfxSleepMilliseconds(50); + } +} + +static bool_t checkForPossibleMove(void) { + bool_t canMove = FALSE; + uint16_t i ,j; + for (i = 0; i < JG10_FIELD_WIDTH; i++) { + for (j = 0; j < JG10_FIELD_HEIGHT; j++) { + if ((inRange(i,j-1) && jg10Field[i][j-1].num == jg10Field[i][j].num) || + (inRange(i-1,j) && jg10Field[i-1][j].num == jg10Field[i][j].num) || + (inRange(i,j+1) && jg10Field[i][j+1].num == jg10Field[i][j].num) || + (inRange(i+1,j) && jg10Field[i+1][j].num == jg10Field[i][j].num)) { + canMove = TRUE; + return canMove; + } + } + } + return canMove; +} + +static void printGameOver(void) { + gdispFillArea(JG10_TOTAL_FIELD_WIDTH, (gdispGetHeight()/2)-10, gdispGetWidth()-JG10_TOTAL_FIELD_WIDTH, 80, Black); + if (jg10GameOver) { + gdispDrawString(JG10_TOTAL_FIELD_WIDTH+((gdispGetWidth()-JG10_TOTAL_FIELD_WIDTH)/2)-(gdispGetStringWidth("Game Over", font)/2), gdispGetHeight()/2, "Game Over", font, White); + } +} + +static void printCongrats(void) { + char pps_str[3]; + gdispFillArea(JG10_TOTAL_FIELD_WIDTH, (gdispGetHeight()/2)-10, gdispGetWidth()-JG10_TOTAL_FIELD_WIDTH, 80, Black); + gdispDrawString(JG10_TOTAL_FIELD_WIDTH+((gdispGetWidth()-JG10_TOTAL_FIELD_WIDTH)/2)-(gdispGetStringWidth("Congrats, now try to get", font)/2), gdispGetHeight()/2, "Congrats, now try to get", font, White); + uitoa(jg10MaxVal+1, pps_str, sizeof(pps_str)); + gdispDrawString(JG10_TOTAL_FIELD_WIDTH+((gdispGetWidth()-JG10_TOTAL_FIELD_WIDTH)/2)-(gdispGetStringWidth(pps_str, font)/2), (gdispGetHeight()/2)+20, pps_str, font, Red); +} + +static DECLARE_THREAD_FUNCTION(thdJg10, msg) { + (void)msg; + uint16_t x,y; + while (!jg10GameOver) { + srand(gfxSystemTicks()); + ginputGetMouseStatus(0, &ev); + if (ev.buttons & GINPUT_MOUSE_BTN_LEFT) { + x = ev.x/JG10_CELL_WIDTH; + y = ev.y/JG10_CELL_HEIGHT; + if (x < JG10_FIELD_WIDTH && y < JG10_FIELD_HEIGHT) { + while (ev.buttons & GINPUT_MOUSE_BTN_LEFT) { // Wait until release + ginputGetMouseStatus(0, &ev); + } + if (!jg10Field[x][y].sel) { + // Check if we have at least two + if ((inRange(x,y-1) && jg10Field[x][y-1].num == jg10Field[x][y].num) || + (inRange(x-1,y) && jg10Field[x-1][y].num == jg10Field[x][y].num) || + (inRange(x,y+1) && jg10Field[x][y+1].num == jg10Field[x][y].num) || + (inRange(x+1,y) && jg10Field[x+1][y].num == jg10Field[x][y].num)) { + gwinSetVisible(Jg10SelectWidget, FALSE); + clean_SelCheck(); + jg10Field[x][y].check = TRUE; + gwinSetVisible(Jg10SelectWidget, TRUE); + } + } else { + // already selected section clicked... + jg10Field[x][y].num++; + if (jg10Field[x][y].num > jg10MaxVal) { + jg10MaxVal = jg10Field[x][y].num; + if (jg10MaxVal >= 10) printCongrats(); + if (jg10MaxVal == 20) { // Just in case someone got so far :D I cannot imaginge though + jg10GameOver = TRUE; + printGameOver(); + } + } + jg10Field[x][y].sel = FALSE; + gwinSetVisible(Jg10SelectWidget, FALSE); + remove_Selected(); + movePiecesDown(); + if (checkForPossibleMove()) { + clean_SelCheck(); + //gwinRedraw(mainWin); + } else { + jg10GameOver = TRUE; + printGameOver(); + } + } + } + } + } + THREAD_RETURN(0); +} + +static void initField(void) { + jg10MaxVal = 4; + for (uint8_t x = 0; x < JG10_FIELD_WIDTH; x++) { + for (uint8_t y = 0; y < JG10_FIELD_HEIGHT; y++) { + jg10Field[x][y].num = randomInt(jg10MaxVal)+1; + //jg10Field[x][y].num = 1; // good for animation testing + //jg10Field[x][y].num = x+x+5; // good to get high score fast + //jg10Field[x][y].num = x+y+5; // good demo to check out pieces :D + jg10Field[x][y].check = FALSE; + jg10Field[x][y].sel = FALSE; + } + } + jg10GameOver = FALSE; + printGameOver(); +} + +static void mainWinDraw(GWidgetObject* gw, void* param) { + (void)param; + + for (uint8_t x = 0; x < JG10_FIELD_WIDTH; x++) { + for (uint8_t y = 0; y < JG10_FIELD_HEIGHT; y++) { + gdispGImageDraw(gw->g.display, &jg10Image[jg10Field[x][y].num], (x*JG10_CELL_HEIGHT)+1, (y*JG10_CELL_WIDTH)+1, JG10_CELL_WIDTH, JG10_CELL_HEIGHT, 0, 0); + } + } +} + +static void jg10SelectionWidget_Draw(GWidgetObject* gw, void* param) { + int16_t x, y; + bool_t needToCheck = TRUE; + + (void)param; + + while (needToCheck) { + needToCheck = FALSE; + for (x = 0; x < JG10_FIELD_WIDTH; x++) { + for (y = 0; y < JG10_FIELD_HEIGHT; y++) { + if (jg10Field[x][y].check && !jg10Field[x][y].sel) { + jg10Field[x][y].sel = TRUE; + jg10Field[x][y].check = FALSE; + // Up + if (inRange(x, y-1) && !jg10Field[x][y-1].sel && (jg10Field[x][y-1].num == jg10Field[x][y].num)) { + jg10Field[x][y-1].check = TRUE; + needToCheck = TRUE; + } else if (!inRange(x, y-1) || (inRange(x, y-1) && !jg10Field[x][y-1].sel)) { + // We need longer line if this is wide corner inside shape + if (inRange(x+1, y) && inRange(x+1, y-1) && (jg10Field[x][y].num == jg10Field[x+1][y].num) && (jg10Field[x][y].num == jg10Field[x+1][y-1].num)) { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)+1, (y*JG10_CELL_HEIGHT)+1, JG10_CELL_WIDTH+2, 2, JG10_SEL_COLOR); + } else { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)+1, (y*JG10_CELL_HEIGHT)+1, JG10_CELL_WIDTH, 2, JG10_SEL_COLOR); + } + } + // Down + if (inRange(x, y+1) && !jg10Field[x][y+1].sel && (jg10Field[x][y+1].num == jg10Field[x][y].num)) { + jg10Field[x][y+1].check = TRUE; + needToCheck = TRUE; + } else if (!inRange(x, y+1) || (inRange(x, y+1) && !jg10Field[x][y+1].sel)) { + // We need longer line if this is wide corner inside shape + if (inRange(x-1, y) && inRange(x-1, y+1) && (jg10Field[x][y].num == jg10Field[x-1][y].num) && (jg10Field[x][y].num == jg10Field[x-1][y+1].num)) { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)-1, ((y+1)*JG10_CELL_HEIGHT)-1, JG10_CELL_WIDTH+2, 2, JG10_SEL_COLOR); + } else { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)+1, ((y+1)*JG10_CELL_HEIGHT)-1, JG10_CELL_WIDTH, 2, JG10_SEL_COLOR); + } + } + // Left + if (inRange(x-1, y) && !jg10Field[x-1][y].sel && (jg10Field[x-1][y].num == jg10Field[x][y].num)) { + jg10Field[x-1][y].check = TRUE; + needToCheck = TRUE; + } else if (!inRange(x-1, y) || (inRange(x-1, y) && !jg10Field[x-1][y].sel)) { + // We need longer line if this is wide corner inside shape + if (inRange(x, y-1) && inRange(x-1, y-1) && (jg10Field[x][y].num == jg10Field[x][y-1].num) && (jg10Field[x][y].num == jg10Field[x-1][y-1].num)) { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)+1, (y*JG10_CELL_HEIGHT)-1, 2, JG10_CELL_HEIGHT+2, JG10_SEL_COLOR); + } else { + gdispGFillArea(gw->g.display, (x*JG10_CELL_WIDTH)+1, (y*JG10_CELL_HEIGHT)+1, 2, JG10_CELL_HEIGHT, JG10_SEL_COLOR); + } + } + // Right + if (inRange(x+1, y) && !jg10Field[x+1][y].sel && (jg10Field[x+1][y].num == jg10Field[x][y].num)) { + jg10Field[x+1][y].check = TRUE; + needToCheck = TRUE; + } else if (!inRange(x+1, y) || (inRange(x+1, y) && !jg10Field[x+1][y].sel)) { + // We need longer line if this is wide corner inside shape + if (inRange(x, y+1) && inRange(x+1, y+1) && (jg10Field[x][y].num == jg10Field[x][y+1].num) && (jg10Field[x][y].num == jg10Field[x+1][y+1].num)) { + gdispGFillArea(gw->g.display, ((x+1)*JG10_CELL_WIDTH)-1, (y*JG10_CELL_HEIGHT)+1, 2, JG10_CELL_HEIGHT+2, JG10_SEL_COLOR); + } else { + gdispGFillArea(gw->g.display, ((x+1)*JG10_CELL_WIDTH)-1, (y*JG10_CELL_HEIGHT)+1, 2, JG10_CELL_HEIGHT, JG10_SEL_COLOR); + } + } + } + } + } + } +} + +static const gwidgetVMT jg10SelectionWidgetVMT = { + { + "jg10SelectionWidget", // The classname + sizeof(jg10WidgetObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + jg10SelectionWidget_Draw, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + 0, // Process mouse down events + 0, // Process mouse up events + 0, // Process mouse move events + }, + #endif + #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD + { + 0 // Process keyboard events + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, // Toggle role + 0, // Assign Toggles + 0, // Get Toggles + 0, // Process toggle off events + 0, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials + 0, // Get Dials + 0, // Process dial move events + }, + #endif +}; + +GHandle jg10SelectionWidgetGCreate(GDisplay* g, jg10WidgetObject* wo, GWidgetInit* pInit) { + if (!(wo = (jg10WidgetObject*)_gwidgetCreate(g, &wo->w, pInit, &jg10SelectionWidgetVMT))) { + return 0; + } + gwinSetVisible((GHandle)wo, pInit->g.show); + return (GHandle)wo; +} + + +static void createMainWin(void) { + GWidgetInit wi; + gwinWidgetClearInit(&wi); + // Container - mainWin + wi.g.show = FALSE; + wi.g.x = 0; + wi.g.y = 0; + wi.g.width = gdispGetWidth(); + wi.g.height = gdispGetHeight(); + wi.g.parent = 0; + wi.text = "Container"; + wi.customDraw = mainWinDraw; + wi.customParam = 0; + wi.customStyle = 0; + mainWin = gwinContainerCreate(0, &wi, 0); + + // create selection widget + wi.g.show = FALSE; + wi.g.x = 0; + wi.g.y = 0; + wi.g.width = 272; + wi.g.height = 480; + wi.g.parent = mainWin; + wi.customDraw = jg10SelectionWidget_Draw; + Jg10SelectWidget = jg10SelectionWidgetCreate(0, &wi); +} + +void guiCreate(void) { + GWidgetInit wi; + gwinWidgetClearInit(&wi); + createMainWin(); + gwinHide(mainWin); + gwinShow(mainWin); +} + +void jg10Start(void) { +#if JG10_SHOW_SPLASH + gtimerStop(&jg10SplashBlink); + gdispClear(Black); +#endif + initField(); + guiCreate(); + gfxThreadCreate(0, 1024, NORMAL_PRIORITY, thdJg10, 0); + while (!jg10GameOver) { + gfxSleepMilliseconds(100); + } +} + +void jg10Init(void) { + initRng(); + for (uint8_t i = 0; i < JG10_MAX_COUNT; i++) { + gdispImageOpenFile(&jg10Image[i], jg10Graph[i]); + gdispImageCache(&jg10Image[i]); + } + for (uint8_t i = 0; i < JG10_ANIM_IMAGES; i++) { + gdispImageOpenFile(&jg10ImageAnim[i], jg10GraphAnim[i]); + gdispImageCache(&jg10ImageAnim[i]); + } + font = gdispOpenFont("DejaVuSans16_aa"); +} + +#if JG10_SHOW_SPLASH +static void jg10SplashBlinker(void* arg) { + (void)arg; + jg10SplashTxtVisible = !jg10SplashTxtVisible; + if (jg10SplashTxtVisible) { + gdispImageOpenFile(&jg10SplashImage, "splashtxt.bmp"); + } else { + gdispImageOpenFile(&jg10SplashImage, "splashclr.bmp"); + } + gdispImageDraw(&jg10SplashImage, (gdispGetWidth()/2)-150+106, (gdispGetHeight()/2)-100+168, 89, 9, 0, 0); + gdispImageClose(&jg10SplashImage); +} + +void jg10ShowSplash(void) { + gdispImageOpenFile(&jg10SplashImage, "splash.bmp"); + gdispImageDraw(&jg10SplashImage, (gdispGetWidth()/2)-150, (gdispGetHeight()/2)-100, 300, 200, 0, 0); + gdispImageClose(&jg10SplashImage); + gtimerStart(&jg10SplashBlink, jg10SplashBlinker, 0, TRUE, 400); +} +#endif
\ No newline at end of file |