Skip to content

Commit 0cd6dab

Browse files
committed
Tetris.
1 parent 10664c3 commit 0cd6dab

File tree

6 files changed

+748
-0
lines changed

6 files changed

+748
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.svn
2+
*~

CTetris.cpp

+289
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
2+
/* Arduino Tetris library, particularly suitable for low-resolution matrix displays.
3+
* Adapted from Tetris in the bsdgames package, see licence below.
4+
* - Daniel Swann 15/01/2015
5+
*/
6+
7+
8+
/*-
9+
* Copyright (c) 1992, 1993
10+
* The Regents of the University of California. All rights reserved.
11+
*
12+
* This code is derived from software contributed to Berkeley by
13+
* Chris Torek and Darren F. Provine.
14+
*
15+
* Redistribution and use in source and binary forms, with or without
16+
* modification, are permitted provided that the following conditions
17+
* are met:
18+
* 1. Redistributions of source code must retain the above copyright
19+
* notice, this list of conditions and the following disclaimer.
20+
* 2. Redistributions in binary form must reproduce the above copyright
21+
* notice, this list of conditions and the following disclaimer in the
22+
* documentation and/or other materials provided with the distribution.
23+
* 3. Neither the name of the University nor the names of its contributors
24+
* may be used to endorse or promote products derived from this software
25+
* without specific prior written permission.
26+
*
27+
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30+
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37+
* SUCH DAMAGE.
38+
*
39+
* @(#)tetris.c 8.1 (Berkeley) 5/31/93
40+
*/
41+
42+
#include <stdlib.h>
43+
#include <string.h>
44+
45+
#include "Arduino.h" // for micros()
46+
#include "CTetris.h"
47+
48+
const struct shape *curshape;
49+
const struct shape *nextshape;
50+
struct shape shapes[19];
51+
52+
53+
CTetris::CTetris(set_xy_fuct set_xy, int rows, int cols, int level)
54+
{
55+
_set_xy = set_xy;
56+
57+
__b_cols = cols;
58+
__b_rows = rows;
59+
_board = (cell*)malloc(__b_cols*__b_rows);
60+
_a_first = 1;
61+
_a_last = rows-2;
62+
63+
init_shapes();
64+
setup_board();
65+
66+
srandom(2); /* FIXME */
67+
68+
_pos = _a_first*__b_cols + (__b_cols/2)-1;
69+
_nextshape = randshape();
70+
_curshape = randshape();
71+
_score = 0;
72+
_game_over = false;
73+
_last_update = 0;
74+
_level = level;
75+
76+
77+
_fallrate = 500000 / _level;
78+
}
79+
80+
CTetris::~CTetris()
81+
{
82+
if (_board != NULL)
83+
{
84+
free(_board);
85+
_board = NULL;
86+
}
87+
}
88+
89+
bool CTetris::loop()
90+
{
91+
bool timeout_reached = false;
92+
bool redraw_screen = false;
93+
94+
// Assume loop() is called more often than required, i.e. don't advance game state on each call.
95+
if ((micros() - _last_update) > _fallrate)
96+
{
97+
timeout_reached = true;
98+
_last_update = micros();
99+
}
100+
101+
if (!timeout_reached)
102+
return false;
103+
104+
if (_game_over)
105+
return false;
106+
107+
faster();
108+
place(_curshape, _pos, 1);
109+
update_display();
110+
place(_curshape, _pos, 0);
111+
112+
113+
if (fits_in(_curshape, _pos + __b_cols))
114+
{
115+
_pos += __b_cols;
116+
return true;
117+
}
118+
119+
/*
120+
* Put up the current shape `permanently',
121+
* bump score, and elide any full rows.
122+
*/
123+
place(_curshape, _pos, 1);
124+
_score++;
125+
elide();
126+
127+
/*
128+
* Choose a new shape. If it does not fit,
129+
* the game is over.
130+
*/
131+
_curshape = _nextshape;
132+
_nextshape = randshape();
133+
_pos = _a_first*__b_cols + (__b_cols/2)-1;
134+
if (!fits_in(_curshape, _pos))
135+
_game_over = true;
136+
137+
return true;
138+
}
139+
140+
void CTetris::left()
141+
{
142+
if (fits_in(_curshape, _pos - 1))
143+
_pos--;
144+
}
145+
146+
void CTetris::right()
147+
{
148+
if (fits_in(_curshape, _pos + 1))
149+
_pos++;
150+
}
151+
152+
void CTetris::rotate()
153+
{
154+
/* turn */
155+
const struct shape *newshape = &shapes[_curshape->rot];
156+
157+
if (fits_in(newshape, _pos))
158+
_curshape = newshape;
159+
}
160+
161+
void CTetris::drop()
162+
{
163+
/* move to bottom */
164+
while (fits_in(_curshape, _pos + __b_cols))
165+
{
166+
_pos += __b_cols;
167+
_score++;
168+
}
169+
}
170+
171+
void CTetris::update_display()
172+
{
173+
for (int y=0; y < __b_rows; y++)
174+
for (int x=0; x < __b_cols; x++)
175+
_set_xy(x, y, _board[(__b_cols*y)+x] ? 1 : 0);
176+
}
177+
178+
/*
179+
* Set up the initial board. The bottom display row is completely set,
180+
* along with another (hidden) row underneath that. Also, the left and
181+
* right edges are set.
182+
*/
183+
void CTetris::setup_board()
184+
{
185+
int i;
186+
cell *p;
187+
188+
p = _board;
189+
for (i = (__b_cols * __b_rows); i; i--)
190+
*p++ = i <= (2 * __b_cols) || (i % __b_cols) < 2;
191+
}
192+
193+
194+
/*
195+
* Elide any full active rows.
196+
*/
197+
void CTetris::elide()
198+
{
199+
int i, j, base;
200+
cell *p;
201+
202+
for (i = _a_first; i < _a_last; i++) {
203+
base = i * __b_cols + 1;
204+
p = _board+base;
205+
for (j = __b_cols - 2; *p++ != 0;) {
206+
if (--j <= 0) {
207+
/* this row is to be elided */
208+
memset(_board+base, 0, __b_cols - 2);
209+
update_display();
210+
// tsleep(); FIXME
211+
while (--base != 0)
212+
_board[base + __b_cols] = _board[base];
213+
update_display();
214+
// tsleep(); FIXME
215+
break;
216+
}
217+
}
218+
}
219+
}
220+
221+
void CTetris::init_shapes()
222+
{
223+
int tl = (-1*__b_cols) - 1; /* top left */
224+
int tc = (-1*__b_cols); /* top center */
225+
int tr = (-1*__b_cols) + 1; /* top right */
226+
int ml = -1; /* middle left */
227+
int mr = 1; /* middle right */
228+
int bl = (__b_cols) - 1; /* bottom left */
229+
int bc = (__b_cols); /* bottom center */
230+
int br = (__b_cols) + 1; /* bottom right */
231+
232+
shapes[ 0].rot = 7; shapes[ 0].off[0] = tl; shapes[ 0].off[1] = tc; shapes[ 0].off[2] = mr;
233+
shapes[ 1].rot = 8; shapes[ 1].off[0] = tc; shapes[ 1].off[1] = tr; shapes[ 1].off[2] = ml;
234+
shapes[ 2].rot = 9; shapes[ 2].off[0] = ml; shapes[ 2].off[1] = mr; shapes[ 2].off[2] = bc;
235+
shapes[ 3].rot = 3; shapes[ 3].off[0] = tl; shapes[ 3].off[1] = tc; shapes[ 3].off[2] = ml;
236+
shapes[ 4].rot = 12; shapes[ 4].off[0] = ml; shapes[ 4].off[1] = bl; shapes[ 4].off[2] = mr;
237+
shapes[ 5].rot = 15; shapes[ 5].off[0] = ml; shapes[ 5].off[1] = br; shapes[ 5].off[2] = mr;
238+
shapes[ 6].rot = 18; shapes[ 6].off[0] = ml; shapes[ 6].off[1] = mr; shapes[ 6].off[2] = 2 ; /* sticks out */
239+
shapes[ 7].rot = 0; shapes[ 7].off[0] = tc; shapes[ 7].off[1] = ml; shapes[ 7].off[2] = bl;
240+
shapes[ 8].rot = 1; shapes[ 8].off[0] = tc; shapes[ 8].off[1] = mr; shapes[ 8].off[2] = br;
241+
shapes[ 9].rot = 10; shapes[ 9].off[0] = tc; shapes[ 9].off[1] = mr; shapes[ 9].off[2] = bc;
242+
shapes[10].rot = 11; shapes[10].off[0] = tc; shapes[10].off[1] = ml; shapes[10].off[2] = mr;
243+
shapes[11].rot = 2; shapes[11].off[0] = tc; shapes[11].off[1] = ml; shapes[11].off[2] = bc;
244+
shapes[12].rot = 13; shapes[12].off[0] = tc; shapes[12].off[1] = bc; shapes[12].off[2] = br;
245+
shapes[13].rot = 14; shapes[13].off[0] = tr; shapes[13].off[1] = ml; shapes[13].off[2] = mr;
246+
shapes[14].rot = 4; shapes[14].off[0] = tl; shapes[14].off[1] = tc; shapes[14].off[2] = bc;
247+
shapes[15].rot = 16; shapes[15].off[0] = tr; shapes[15].off[1] = tc; shapes[15].off[2] = bc;
248+
shapes[16].rot = 17; shapes[16].off[0] = tl; shapes[16].off[1] = mr; shapes[16].off[2] = ml;
249+
shapes[17].rot = 5; shapes[17].off[0] = tc; shapes[17].off[1] = bc; shapes[17].off[2] = bl;
250+
shapes[18].rot = 6; shapes[18].off[0] = tc; shapes[18].off[1] = bc; shapes[18].off[2] = 2*__b_cols; /* sticks out */
251+
}
252+
253+
/*
254+
* Return true iff the given shape fits in the given position,
255+
* taking the current board into account.
256+
*/
257+
int CTetris::fits_in(const struct shape *shape, int pos)
258+
{
259+
const int *o = shape->off;
260+
261+
if (_board[pos] || _board[pos + *o++] || _board[pos + *o++] ||
262+
_board[pos + *o])
263+
return 0;
264+
return 1;
265+
}
266+
267+
/*
268+
* Write the given shape into the current board, turning it on
269+
* if `onoff' is 1, and off if `onoff' is 0.
270+
*/
271+
void CTetris::place(const struct shape *shape, int pos, int onoff)
272+
{
273+
const int *o = shape->off;
274+
275+
_board[pos] = onoff;
276+
_board[pos + *o++] = onoff;
277+
_board[pos + *o++] = onoff;
278+
_board[pos + *o] = onoff;
279+
}
280+
281+
int CTetris::get_score()
282+
{
283+
return _score;
284+
}
285+
286+
void CTetris::faster()
287+
{
288+
_fallrate -= _fallrate / 3000;
289+
}

0 commit comments

Comments
 (0)