diff --git a/F1-nolib/Tetris/TETRIS.bin b/F1-nolib/Tetris/TETRIS.bin index 5ba973d..4c9d506 100755 Binary files a/F1-nolib/Tetris/TETRIS.bin and b/F1-nolib/Tetris/TETRIS.bin differ diff --git a/F1-nolib/Tetris/debug.h b/F1-nolib/Tetris/debug.h new file mode 100644 index 0000000..994b878 --- /dev/null +++ b/F1-nolib/Tetris/debug.h @@ -0,0 +1,35 @@ +/* + * This file is part of the TETRIS project. + * Copyright 2021 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#ifndef DEBUG_H__ +#define DEBUG_H__ + +#ifdef EBUG +#include "usb.h" +#include "proto.h" +#define DBG(x) USB_send(x) +#define DBGU(x) USB_send(u2str(x)) +#define NL() USB_send("\n") +#else // EBUG +#define DBG(x) +#define DBGU(x) +#define NL() +#endif // EBUG + +#endif // DEBUG_H__ + diff --git a/F1-nolib/Tetris/fonts.c b/F1-nolib/Tetris/fonts.c index 6396688..2136cfa 100644 --- a/F1-nolib/Tetris/fonts.c +++ b/F1-nolib/Tetris/fonts.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ #include +#include "debug.h" #include "fonts.h" /* Bash-script to generate the symbols @@ -304,8 +305,6 @@ done static const afont FONTS[] = { [FONT14] = {font14_table, font14_encoding, FONT14HEIGHT, FONT14BYTES, FONT14BASELINE}, -// [FONTN16] = {fontNumb16_table, fontNumb16_encoding, FONTNUMB16HEIGHT, FONTNUMB16BYTES, FONTNUMB16BASELINE}, -// [FONTN10] = {fontNumb10_table, fontNumb10_encoding, FONTNUMB10HEIGHT, FONTNUMB10BYTES, FONTNUMB10BASELINE}, [FONTN8] = {fontNumb8_table, fontNumb8_encoding, FONTNUMB8HEIGHT, FONTNUMB8BYTES, FONTNUMB8BASELINE}, }; @@ -324,6 +323,7 @@ int choose_font(font_t newfont){ const uint8_t *font_char(uint8_t Char){ uint8_t idx = curfont->enctable[Char]; + //DBG("font_char("); DBGU(Char); DBG(")="); DBGU(idx); NL(); if(!idx) return NULL; // no this character in font return &(curfont->font[idx*(curfont->bytes+1)]); } diff --git a/F1-nolib/Tetris/screen.c b/F1-nolib/Tetris/screen.c index 10481f2..14bf718 100644 --- a/F1-nolib/Tetris/screen.c +++ b/F1-nolib/Tetris/screen.c @@ -18,10 +18,11 @@ #include // memset, memcpy #include +#include "debug.h" #include "fonts.h" #include "hardware.h" #include "screen.h" -//#include "usb.h" + // !!!FOR LITTLE-ENDIAN!!! @@ -106,6 +107,7 @@ uint8_t DrawCharAt(int16_t X, int16_t Y, uint8_t Char){ * @return - text width in pixels */ uint8_t PutStringAt(int16_t X, int16_t Y, const char *str){ + DBG("PutStringAt("); DBGU(X); DBG(", "); DBGU(Y); DBG(", \""); DBG(str); DBG("\"\n"); if(!str) return 0; int16_t Xold = X; while(*str){ @@ -169,22 +171,6 @@ void process_screen(){ } } break; - /*for(int i = 0; i < 32; ++i){ - DrawPix(0,i,0b11111111); - DrawPix(1,i,0b1001010); - DrawPix(2,i,0b00100101); - DrawPix(20,i,0b11100000); - DrawPix(21,i,0b10000000); - DrawPix(22,i,0b00100000); - DrawPix(30,i,0b00011100); - DrawPix(31,i,0b00010000); - DrawPix(32,i,0b00000100); - DrawPix(60,i,0b00000011); - DrawPix(61,i,0b00000010); - DrawPix(62,i,0b00000001); - }*/ - // memset -> halt - //memset(screenbuf, pattern, SCREENBUF_SZ); default: return; } diff --git a/F1-nolib/Tetris/snake.c b/F1-nolib/Tetris/snake.c index b98995b..f3df5cd 100644 --- a/F1-nolib/Tetris/snake.c +++ b/F1-nolib/Tetris/snake.c @@ -34,7 +34,7 @@ // cut - -1 to size #define CUT_COLOR (0b11100000) // chance of CUT appears when drawing food (/1000) -#define CUT_PROMILLE (33) +#define CUT_PROMILLE (80) // score - +10 to score #define SCORE_COLOR (0b00000001) // add this to score after each SCORE_COLOR eating @@ -176,6 +176,11 @@ static int move_snake(){ } // check borders: they could be broken when `balls` activated if(snake[0].x >= SCREEN_WIDTH || snake[0].y >= SCREEN_HEIGHT) return 0; + if(getRand() % 1000 < SCORE_PROMILLE){ // add ++score + point pt = RandCoords(); + if(pt.x && pt.y) + DrawPix(pt.x, pt.y, SCORE_COLOR); + } return 1; } diff --git a/F1-nolib/Tetris/tetris.c b/F1-nolib/Tetris/tetris.c index 951c876..92981f9 100644 --- a/F1-nolib/Tetris/tetris.c +++ b/F1-nolib/Tetris/tetris.c @@ -18,31 +18,31 @@ #include "adcrandom.h" #include "buttons.h" +#include "debug.h" +#include "fonts.h" #include "screen.h" #include "tetris.h" -#include "usb.h" -#include "proto.h" - // backround color #define BACKGROUND_COLOR (COLOR_BLACK) -#define CUP_COLOR (COLOR_LRED) +#define FOREGROUND_COLOR (COLOR_YELLOW) +#define CUP_COLOR (COLOR_CYAN) // height of cup #define CUPHEIGHT (30) #define CUPWIDTH (20) // screen coordinate of x=0 @ cup -#define CUPX0 (1) +#define CUPX0 (7) // screen coordinate of y=0 @ cup (Y grows upside down) #define CUPY0 (0) // coordinates of "NEXT figure" -#define NEXTX0 (30) -#define NEXTY0 (4) +#define NEXTX0 (-5) +#define NEXTY0 (SCREEN_HEIGHT/2-2) #define xmax (CUPWIDTH-1) #define ymax (CUPHEIGHT-1) // min speed -#define MAXSTEPMS (199) +#define MAXSTEPMS (299) // max speed / drop speed #define MINSTEPMS (19) // each NXTSPEEDSCORE of score the speed will be increased @@ -62,41 +62,41 @@ typedef struct{ // L: 00, 01, 02, 10 + 2 = 0x22, 0x23, 0x24, 0x32 static const figure L = { .f = {0x22, 0x23, 0x24, 0x32}, - .color = COLOR_LBLUE + .color = 0b00000001 }; // J: 00, 01, 02, -10 + 2 = 0x22, 0x23, 0x24, 0x12 static const figure J = { .f = {0x22, 0x23, 0x24, 0x12}, - .color = COLOR_BLUE + .color = 0b00000100 }; // O: 00, 01, 10, 11 + 2 = 0x22, 0x23, 0x32, 0x33 static const figure O = { .f = {0x22, 0x23, 0x32, 0x33}, - .color = COLOR_YELLOW + .color = 0b00000101 }; // I: 0-1, 00, 01, 02 + 2 = 0x21, 0x22, 0x23, 0x24 static const figure I = { .f = {0x21, 0x22, 0x23, 0x24}, - .color = COLOR_CYAN + .color = 0b00100000 }; // S: -10, 00, 01, 11 + 2 = 0x12, 0x22, 0x23, 0x33 static const figure S = { .f = {0x12, 0x22, 0x23, 0x33}, - .color = COLOR_LGREEN + .color = 0b00100001 }; -// Z: -11, 01, 00, 10 + 2 = 0x13, 0x23, 0x23, 0x32 +// Z: -11, 01, 00, 10 + 2 = 0x13, 0x23, 0x22, 0x32 static const figure Z = { - .f = {0x13, 0x23, 0x23, 0x32}, - .color = COLOR_GREEN + .f = {0x13, 0x23, 0x22, 0x32}, + .color = 0b00100100 }; // T: -10, 01, 00, 10 + 2 = 0x12, 0x23, 0x22, 0x32 static const figure T = { .f = {0x12, 0x23, 0x22, 0x32}, - .color = COLOR_PURPLE + .color = 0b00100101 }; #define FIGURESNUM (7) @@ -111,34 +111,51 @@ static uint32_t nextSpeedScore = 0; // chk if figure can be put to (x,y); @return 1 if empty static int chkfigure(int x, int y, const figure *F){ - if(x < 0 || x > xmax) return 0; - if(y < 0 || y > ymax) return 0; + DBG("CHKFIG: x="); DBGU(x); DBG(", y="); DBGU(y); DBG(" ... "); + if(x < 0 || x > xmax){ + DBG("x<0 || >xmax\n"); + return 0; + } + if(y < 0 || y > ymax){ + DBG("y<0 || > ymax\n"); + return 0; + } for(int i = 0; i < 4; ++i){ int xn = x + GETX(F->f[i]), yn = y + GETY(F->f[i]); - if(yn > ymax || yn < 0) return 0; - if(xn < 0 || xn > xmax || yn < 0) return 0; // border - if(GetPix(xn ,yn) != BACKGROUND_COLOR) return 0; // occupied + if(yn > ymax){ + DBG("y > ymax\n"); + return 0; + } + if(xn < 0 || xn > xmax){ // border + DBG("x out of borders\n"); + return 0; + } + if(GetPix(CUPX0 + xn, CUPY0 + yn) != BACKGROUND_COLOR){ // occupied + DBG("occupied\n"); + return 0; + } } + DBG("good\n"); return 1; } // clear figure from old location static void clearfigure(int x, int y){ - USB_send("Clear @ "); USB_send(u2str(x)); USB_send(", "); USB_send(u2str(y)); USB_send("\n"); + DBG("Clear @ "); DBGU(x); DBG(", "); DBGU(y); NL(); for(int i = 0; i < 4; ++i){ int xn = x + GETX(curfigure.f[i]), yn = y + GETY(curfigure.f[i]); - if(xn < 0 || xn > xmax || yn < 0 || yn > ymax) continue; // out of cup - DrawPix(xn, yn, BACKGROUND_COLOR); + //if(xn < 0 || xn > xmax || yn < 0 || yn > ymax) continue; // out of cup + DrawPix(CUPX0 + xn, CUPY0 + yn, BACKGROUND_COLOR); } } // put figure into new location static void putfigure(int x, int y, figure *F){ - USB_send("Put @ "); USB_send(u2str(x)); USB_send(", "); USB_send(u2str(y)); USB_send("\n"); + DBG("Put @ "); DBGU(x); DBG(", "); DBGU(y); NL(); for(int i = 0; i < 4; ++i){ int xn = x + GETX(F->f[i]), yn = y + GETY(F->f[i]); - if(xn < 0 || xn > xmax || yn < 0 || yn > ymax) continue; // out of cup - DrawPix(xn, yn, F->color); + //if(xn < 0 || xn > xmax || yn < 0 || yn > ymax) continue; // out of cup + DrawPix(CUPX0 + xn, CUPY0 + yn, F->color); } } @@ -149,10 +166,10 @@ static void rotatefigure(int dir, figure *F){ int x = GETX(F->f[i]), y = GETY(F->f[i]), xn, yn; if(dir > 0){ // CW xn = y; yn = -x; - USB_send("Rotate CW\n"); + DBG("Rotate CW\n"); }else if(dir < 0){ // CCW xn = -y; yn = x; - USB_send("Rotate CCW\n"); + DBG("Rotate CCW\n"); } nF.f[i] = ((xn + 2) << 4) | (yn + 2); } @@ -165,19 +182,20 @@ static int checkandroll(){ for(int y = 0; y < CUPHEIGHT; ++y){ int N = 0; for(int x = 0; x < CUPWIDTH; ++x) - if(GetPix(x, y) != BACKGROUND_COLOR) ++N; + if(GetPix(CUPX0 + x, CUPY0 + y) != BACKGROUND_COLOR) ++N; if(N == 0) upper = y; else if(N == CUPWIDTH){ // full line - roll all upper + DBG("========= Full row! ========= "); DBG("y="); DBGU(y); DBG(", upper="); DBGU(upper); NL(); ++ret; - for(int yy = y; yy <= upper; --yy){ + for(int yy = y; yy > upper; --yy){ uint8_t *ptr = &screenbuf[(yy+CUPY0)*SCREEN_WIDTH + CUPX0]; for(int x = 0; x < CUPWIDTH; ++x, ++ptr) - *ptr = ptr[-CUPWIDTH]; // copy upper row into the current + *ptr = ptr[-SCREEN_WIDTH]; // copy upper row into the current } ++upper; } } - USB_send("Roll="); USB_send(u2str(ret)); USB_send("\n"); + DBG("Roll="); DBGU(ret); NL(); return ret; } @@ -195,11 +213,17 @@ static int getrand(){ // return 0 if cannot move static int mvfig(int *x, int *y, int dx){ register int xx = *x, yy = *y; - int xnew = xx+dx, ynew = yy+1, ret = 1; + DBG("MVFIG: x="); DBGU(*x); DBG(", y="); DBGU(*y); DBG(", dx="); DBGU(dx); NL(); + int ret = 1; clearfigure(xx, yy); - if(chkfigure(xnew, ynew, &curfigure)){ - xx = xnew; yy = ynew; - *x = xx; *y = yy; + // check dx: + if(dx){ + if(chkfigure(xx+dx, yy, &curfigure)){ + xx = xx + dx; *x = xx; + }else ret = 0; + } + if(chkfigure(xx, yy+1, &curfigure)){ + ++yy; *y = yy; }else ret = 0; putfigure(xx, yy, &curfigure); return ret; @@ -208,6 +232,7 @@ static int mvfig(int *x, int *y, int dx){ // dir == -1 - left, 1 - right static void rotfig(int x, int y, int dir){ if(!dir) return; + DBG("Rotate "); DBGU(dir); NL(); figure newF = curfigure; rotatefigure(dir, &newF); clearfigure(x, y); @@ -219,95 +244,117 @@ static void rotfig(int x, int y, int dir){ // draw current & next figures; return 0 if can't static int drawnext(){ + DBG("\n\nDraw next figure\n"); curfigure = nextfigure; clearfigure(NEXTX0, NEXTY0); // clear NEXT nextfigure = *figures[getrand()]; putfigure(NEXTX0, NEXTY0, &nextfigure); - xf = xmax/2; yf = ymax/2; + xf = xmax/2; yf = 1; if(!chkfigure(xf, yf, &curfigure)) return 0; // can't draw next putfigure(xf, yf, &curfigure); + Tlast = Tms; + incSpd = StepMS; return 1; } void tetris_init(){ setBGcolor(BACKGROUND_COLOR); + setFGcolor(FOREGROUND_COLOR); + choose_font(FONT14); ClearScreen(); ScreenON(); - StepMS = MAXSTEPMS; - Tlast = Tms; - incSpd = StepMS; score = 0; nextSpeedScore = NXTSPEEDSCORE; + StepMS = MAXSTEPMS; // draw cup for(int y = 0; y < CUPHEIGHT; ++y){ - DrawPix(CUPX0, CUPY0 + y, CUP_COLOR); + DrawPix(CUPX0-1, CUPY0 + y, CUP_COLOR); DrawPix(CUPX0 + CUPWIDTH, CUPY0 + y, CUP_COLOR); } - for(int x = 0; x < CUPWIDTH; ++x) - DrawPix(CUPX0 + x, CUPY0 + CUPHEIGHT, CUP_COLOR); + for(int x = 0; x < CUPWIDTH + 2; ++x) + DrawPix(CUPX0 - 1 + x, CUPY0 + CUPHEIGHT, CUP_COLOR); nextfigure = *figures[getrand()]; + PutStringAt(CUPX0 + CUPWIDTH + 5, CUPY0 + 5 + curfont->height, "0 "); drawnext(); } // process tetris game; @return 0 if game is over int tetris_process(){ - uint8_t moveX = 0, rot = 0; - keyevent evt; + static int moveX = 0, rot = 0; static uint8_t paused = 0; + keyevent evt; + if(Tms == Tlast) return 1; +#define EVENT(x) ((keystate(x, &evt) && evt == EVT_PRESS) || keyevt(x) == EVT_HOLD) // change moving direction if(keystate(KEY_U, &evt) && (evt == EVT_PRESS || evt == EVT_HOLD)){ // UP - pause if(paused){ - USB_send("Tetris resume\n"); + DBG("----> Tetris resume\n"); paused = 0; }else{ - USB_send("Tetris paused\n"); + DBG("----> Tetris paused\n"); paused = 1; } } - if(keystate(KEY_D, &evt) && evt == EVT_PRESS){ // Down - drop - incSpd = MINSTEPMS; - } - if(keystate(KEY_L, &evt) && evt == EVT_PRESS){ // L - left - moveX = -1; - } - if(keystate(KEY_R, &evt) && evt == EVT_PRESS){ // Right - moveX = 1; - } - if(keystate(KEY_M, &evt) && evt == EVT_PRESS){ // Menu - rotate CCW - rot = -1; - } - if(keystate(KEY_S, &evt) && evt == EVT_PRESS){ // Set - rotate CW - rot = 1; + if(!paused){ + if(keystate(KEY_D, &evt) && evt == EVT_PRESS){ // Down - drop + incSpd = MINSTEPMS; + } + if(EVENT(KEY_L)){ // L - left + moveX = -1; + } + if(EVENT(KEY_R)){ // Right + moveX = 1; + } + if(EVENT(KEY_M)){ // Menu - rotate CCW + rot = 1; + } + if(EVENT(KEY_S)){ // Set - rotate CW + rot = -1; + } } +#undef EVENT clear_events(); if(Tms - Tlast > incSpd){ Tlast = Tms; if(paused) return 1; int xnew = xf, ynew = yf; - if(rot) rotfig(xf, yf, rot); + if(rot){ + rotfig(xf, yf, rot); + rot = 0; + } + DBG("Move down 1px\n"); if(!mvfig(&xnew, &ynew, moveX) && ynew == yf){ // can't move: end of moving? + moveX = 0; int s = checkandroll(); switch(s){ // add score case 1: score += 1; + DBG("One line!\n"); break; case 2: score += 3; + DBG("Two lines!\n"); break; case 3: score += 7; + DBG("Three lines!\n"); break; case 4: score += 15; + DBG("Four lines!\n"); break; default: break; } + PutStringAt(CUPX0 + CUPWIDTH + 5, CUPY0 + 5 + curfont->height, u2str(score)); if(StepMS > MINSTEPMS && score > nextSpeedScore){ // increase speed --StepMS; nextSpeedScore += NXTSPEEDSCORE; } if(!drawnext()) return 0; + }else{ + moveX = 0; + xf = xnew; yf = ynew; } } return 1;