forked from taylorconor/tinytetris
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tinytetris-commented.cpp
161 lines (150 loc) · 3.52 KB
/
tinytetris-commented.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <ctime>
#include <curses.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
// block layout is: {w-1,h-1}{x0,y0}{x1,y1}{x2,y2}{x3,y3} (two bits each)
int x = 431424, y = 598356, r = 427089, px = 247872, py = 799248, pr,
c = 348480, p = 615696, tick, board[20][10],
block[7][4] = {{x, y, x, y},
{r, p, r, p},
{c, c, c, c},
{599636, 431376, 598336, 432192},
{411985, 610832, 415808, 595540},
{px, py, px, py},
{614928, 399424, 615744, 428369}},
score = 0;
// extract a 2-bit number from a block entry
int NUM(int x, int y) { return 3 & block[p][x] >> y; }
// create a new piece, don't remove old one (it has landed and should stick)
void new_piece() {
y = py = 0;
p = rand() % 7;
r = pr = rand() % 4;
x = px = rand() % (10 - NUM(r, 16));
}
// draw the board and score
void frame() {
for (int i = 0; i < 20; i++) {
move(1 + i, 1); // otherwise the box won't draw
for (int j = 0; j < 10; j++) {
board[i][j] && attron(262176 | board[i][j] << 8);
printw(" ");
attroff(262176 | board[i][j] << 8);
}
}
move(21, 1);
printw("Score: %d", score);
refresh();
}
// set the value fo the board for a particular (x,y,r) piece
void set_piece(int x, int y, int r, int v) {
for (int i = 0; i < 8; i += 2) {
board[NUM(r, i * 2) + y][NUM(r, (i * 2) + 2) + x] = v;
}
}
// move a piece from old (p*) coords to new
int update_piece() {
set_piece(px, py, pr, 0);
set_piece(px = x, py = y, pr = r, p + 1);
}
// remove line(s) from the board if they're full
void remove_line() {
for (int row = y; row <= y + NUM(r, 18); row++) {
c = 1;
for (int i = 0; i < 10; i++) {
c *= board[row][i];
}
if (!c) {
continue;
}
for (int i = row - 1; i > 0; i--) {
memcpy(&board[i + 1][0], &board[i][0], 40);
}
memset(&board[0][0], 0, 10);
score++;
}
}
// check if placing p at (x,y,r) will be a collision
int check_hit(int x, int y, int r) {
if (y + NUM(r, 18) > 19) {
return 1;
}
set_piece(px, py, pr, 0);
c = 0;
for (int i = 0; i < 8; i += 2) {
board[y + NUM(r, i * 2)][x + NUM(r, (i * 2) + 2)] && c++;
}
set_piece(px, py, pr, p + 1);
return c;
}
// slowly tick the piece y position down so the piece falls
int do_tick() {
if (++tick > 30) {
tick = 0;
if (check_hit(x, y + 1, r)) {
if (!y) {
return 0;
}
remove_line();
new_piece();
} else {
y++;
update_piece();
}
}
return 1;
}
// main game loop with wasd input checking
void runloop() {
while (do_tick()) {
usleep(10000);
if ((c = getch()) == 'a' && x > 0 && !check_hit(x - 1, y, r)) {
x--;
}
if (c == 'd' && x + NUM(r, 16) < 9 && !check_hit(x + 1, y, r)) {
x++;
}
if (c == 's') {
while (!check_hit(x, y + 1, r)) {
y++;
update_piece();
}
remove_line();
new_piece();
}
if (c == 'w') {
++r %= 4;
while (x + NUM(r, 16) > 9) {
x--;
}
if (check_hit(x, y, r)) {
x = px;
r = pr;
}
}
if (c == 'q') {
return;
}
update_piece();
frame();
}
}
// init curses and start runloop
int main() {
srand(time(0));
initscr();
start_color();
// colours indexed by their position in the block
for (int i = 1; i < 8; i++) {
init_pair(i, i, 0);
}
new_piece();
resizeterm(22, 22);
noecho();
timeout(0);
curs_set(0);
box(stdscr, 0, 0);
runloop();
endwin();
}