Code:
/* Blocks by Joseph Larson ver 7 April 2008*/
#include <curses.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#define WIDTH 10
#define HEIGHT 20
#define PIECES 8
#define CLEARBLOCKS c = 0; while (!clip(piece, rot, y + c, x)) c++; c--; \
drawpiece (pwin, piece, rot, level, y + c, x); \
drawpiece (nwin, next, rot, (level + 1) % 8, 1, 2); \
drawpiece (pwin, piece, rot, level % 8, y, x);
#define DRAWBLOCKS c = 0; while (!clip(piece, rot, y + c, x)) c++; c--;\
d = (piece % 8 == level % 8) ? (piece + 1) % 8 : piece % 8; \
if (sop) drawpiece (pwin, piece, rot, d, y + c, x); \
if (nop) drawpiece (nwin, next, rot, next % 8 + 8, 1, 2);\
drawpiece (pwin, piece, rot, piece % 8 + 8, y, x);
#define REF wrefresh (pwin); wrefresh (nwin);
char blocks[4][PIECES][4] = /* [line][shape][col] */
{{".X..",".X..",".XX.","..X.",".X..",".X..","....",".XX."},
{".XX.",".X..",".X..",".XX.",".XX.",".X..",".XX.",".X.."},
{".X..",".XX.",".X..",".X..","..X.",".X..",".XX.",".XX."},
{"....","....","....","....","....",".X..","....","...."}};
int buf[HEIGHT + 1][WIDTH + 2];
WINDOW *pwin, *nwin, *iwin, *bwin;
int wfillrect(WINDOW *w, int sy, int sx, int height, int width){
int x, y;
for (x = sx; x < (sx+width); x++) for (y = sy; y < (sy+height); y++)
mvwaddch (w, y, x, ' ');
}
int rx (int r, int y, int x) {
int n;
n = (r % 2 ? y : x);
if(r / 2) n = 3 - n;
return n;
}
int clip (int p, int r, int y, int x) {
int c, d;
for (d = 0; d < 4; d++) for (c = 0; c < 4; c++)
if (blocks[rx(r, d, c)][p][rx((r + 1) % 4, d, c)] != '.')
if (buf[d + y][c + x - 1]) return 1;
return 0;
}
void drawpiece (WINDOW *w, int p, int r, int col, int y, int x) {
int c, d;
wattrset (w, COLOR_PAIR(col));
for (d = 0; d < 4; d++) for (c = 0; c < 4; c++)
if (blocks[rx(r, d, c)][p][rx((r + 1) % 4, d, c)] != '.')
mvwaddstr(w, d + y, (c + x - 1) * 2 - 1, " "); /* 2 spaces */
}
void init() { /* Setup Curses the way we want it. */
int c, x, y;
srand (time(NULL));
initscr ();
raw (); nodelay(stdscr,1); noecho(); curs_set(0); nonl(); keypad(stdscr,1);
start_color();
for (c = 0; c < COLORS; c++) init_pair(c, COLOR_WHITE, c);
x = (COLS - WIDTH * 2) / 2 - 1; y = (LINES - HEIGHT) / 2;
clear ();
refresh ();
pwin = newwin(HEIGHT + 1, WIDTH * 2 + 2, y, x);
nwin = newwin(6, 10, y + 1, x - 14);
iwin = newwin(12, 15, y + 8, x - 16);
wattrset (iwin, COLOR_PAIR (8));
box (iwin,0,0);
wfillrect (iwin, 1, 1, 10, 13);
mvwaddstr (iwin, 5, 3, "Use arrow");
mvwaddstr (iwin, 6, 2, "keys to play");
mvwaddstr (iwin, 7, 2, "UP = Rotate");
mvwaddstr (iwin, 8, 2, "'N' Next");
mvwaddstr (iwin, 9, 2, "'S' Shadow");
mvwaddstr (iwin, 10, 2, "'Q' to Quit");
bwin = newwin(LINES - 1, 10, 0, x + WIDTH * 2 + 6);
for (y = 0; y < LINES - 3; y += 2) { /* Decorate a bit */
c = rand () % PIECES; drawpiece (bwin, c, rand () % 4, c % 8 + 1, y, 2);
}
wrefresh (bwin);
}
void drawplay (int lvl) {
int x, y;
lvl %= 8;
wattrset (pwin, COLOR_PAIR (lvl));
wborder(pwin, 0, 0, ' ', 0, ACS_VLINE, ACS_VLINE, 0, 0);
for (y = 0; y < HEIGHT; y++) for (x = 1; x <= WIDTH; x++) {
wattrset (pwin, COLOR_PAIR((buf[y][x]) ? buf[y][x] % 8 + 8 : lvl));
mvwaddstr (pwin, y, x * 2 - 1, " ");
}
wattrset (nwin, COLOR_PAIR ((lvl + 1) % 8));
box (nwin,0,0);
wfillrect (nwin, 1, 1, 4, 8);
mvwaddstr (nwin, 0, 3, "NEXT");
}
int clearedlines (int lvl) {
int x, y, c, d, ret;
ret = 0;
for (y = 0; y < HEIGHT; y++) {
c = 0;
for (x = 1; x <= WIDTH; x++) if (buf[y][x]) c++;
if (c == WIDTH) {
ret++;
for (d = y; d > 0; d--) for (x = 1; x <= WIDTH; x++)
buf[d][x] = buf[d - 1][x];
drawplay (lvl); REF; beep (); napms(75);
}
}
return ret;
}
int play () {
int piece, rot, x, y, next, level, lines, in, c, d, nop, sop;
double delay;
clock_t start, check;
for (y = 0; y < HEIGHT + 1; y ++) for (x = 0; x < WIDTH + 2; x++)
buf[y][x] = (y < HEIGHT && x > 0 && x < WIDTH + 1) ? 0 : 1;
level = 1; nop = sop = 1; lines = 0; rot = 0;
x = WIDTH / 2; y = 0; next = rand () % PIECES;
do {
delay = 1.0 - level * .05; if (delay < .2) delay = 0.2;
piece = next; next = rand () % PIECES;
drawplay (level);
do {
mvwprintw (iwin, 1, 2, "Level : %d", level);
mvwprintw (iwin, 3, 2, "Lines : %d", lines);
wrefresh (iwin);
CLEARBLOCKS; y++;
DRAWBLOCKS; REF;
start = clock ();
do {
in = getch();
switch (in) {
case KEY_RIGHT : if (!clip(piece, rot, y, x + 1)) {
CLEARBLOCKS; x++; DRAWBLOCKS; REF;
} break;
case KEY_LEFT : if (!clip(piece, rot, y, x - 1)) {
CLEARBLOCKS; x--; DRAWBLOCKS; REF;
} break;
case KEY_DOWN : CLEARBLOCKS;
while (!clip(piece, rot, y + 1, x)) y++;
DRAWBLOCKS; REF; start = clock (); break;
case KEY_UP : if (!clip(piece, (rot + 1) % 4, y, x)) {
CLEARBLOCKS; rot++; rot %= 4; DRAWBLOCKS; REF;
delay = 1.0 - level * .05;
if (delay < .2) delay = 0.2;
start = clock ();
} break;
case 'n' :
case 'N' : nop = !nop; break;
case 's' :
case 'S' : sop = !sop; break;
case 'q' :
case 'Q' : return (lines);
}
check = clock ();
} while ((double)(check - start) / CLOCKS_PER_SEC < delay);
delay = 1.0 - level * .05; if (delay < .05) delay = 0.05;
} while (!clip (piece, rot, y + 1, x));
for (d = 0; d < 4; d++) for (c = 0; c < 4; c++) /* commit piece to buffer */
if (blocks[rx(rot, d, c)][piece][rx((rot + 1) % 4, d, c)] != '.')
buf[d + y][c + x - 1] = piece + 8;
drawplay (level);
REF;
lines += clearedlines(level);
level = lines / 10 + 1;
x = WIDTH / 2; y = 0;
} while (!clip (next, rot, y, x));
drawpiece (pwin, next, rot, next % 8 + 8, y, x);
return (lines);
}
int again (int hs) {
int x, y, ch;
wattrset (pwin, COLOR_PAIR (9));
y = (HEIGHT - 11) / 2; x = (WIDTH - 6);
wfillrect (pwin, y, x, 11, 13);
mvwprintw (pwin, y + 1, x + 1, "High Score:");
mvwprintw (pwin, y + 3, x + 3, " %d lines", hs);
mvwprintw (pwin, y + 6, x + 1, "Do you want");
mvwprintw (pwin, y + 7, x + 3, "to play");
mvwprintw (pwin, y + 8, x + 4, "again");
mvwprintw (pwin, y + 9, x + 4, "(Y/N)");
wrefresh (pwin);
do {ch = getch();}
while ((tolower(ch) != 'q')&&(tolower(ch) != 'n')&&(tolower(ch) != 'y'));
if (tolower(ch) == 'y') return 1;
else return 0;
}
int main () {
int highscore;
init();
do {highscore = play ();} while (again (highscore));
endwin();
}
I'm probably going to post a stripped down version that shaved more than 1k off the code on the site to avoid a too-long program.