1 11a5e2cf 2024-01-16 benni /* $NetBSD: tetris.c,v 1.34 2023/07/01 10:51:35 nia Exp $ */
4 11a5e2cf 2024-01-16 benni * Copyright (c) 1992, 1993
5 11a5e2cf 2024-01-16 benni * The Regents of the University of California. All rights reserved.
7 11a5e2cf 2024-01-16 benni * This code is derived from software contributed to Berkeley by
8 11a5e2cf 2024-01-16 benni * Chris Torek and Darren F. Provine.
10 11a5e2cf 2024-01-16 benni * Redistribution and use in source and binary forms, with or without
11 11a5e2cf 2024-01-16 benni * modification, are permitted provided that the following conditions
13 11a5e2cf 2024-01-16 benni * 1. Redistributions of source code must retain the above copyright
14 11a5e2cf 2024-01-16 benni * notice, this list of conditions and the following disclaimer.
15 11a5e2cf 2024-01-16 benni * 2. Redistributions in binary form must reproduce the above copyright
16 11a5e2cf 2024-01-16 benni * notice, this list of conditions and the following disclaimer in the
17 11a5e2cf 2024-01-16 benni * documentation and/or other materials provided with the distribution.
18 11a5e2cf 2024-01-16 benni * 3. Neither the name of the University nor the names of its contributors
19 11a5e2cf 2024-01-16 benni * may be used to endorse or promote products derived from this software
20 11a5e2cf 2024-01-16 benni * without specific prior written permission.
22 11a5e2cf 2024-01-16 benni * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 11a5e2cf 2024-01-16 benni * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 11a5e2cf 2024-01-16 benni * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 11a5e2cf 2024-01-16 benni * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 11a5e2cf 2024-01-16 benni * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 11a5e2cf 2024-01-16 benni * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 11a5e2cf 2024-01-16 benni * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 11a5e2cf 2024-01-16 benni * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 11a5e2cf 2024-01-16 benni * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 11a5e2cf 2024-01-16 benni * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 11a5e2cf 2024-01-16 benni * SUCH DAMAGE.
34 11a5e2cf 2024-01-16 benni * @(#)tetris.c 8.1 (Berkeley) 5/31/93
37 11a5e2cf 2024-01-16 benni #include <sys/cdefs.h>
38 60af9557 2024-01-16 benni #if !defined(lint) && !defined(__OpenBSD__)
39 11a5e2cf 2024-01-16 benni __COPYRIGHT("@(#) Copyright (c) 1992, 1993\
40 11a5e2cf 2024-01-16 benni The Regents of the University of California. All rights reserved.");
41 11a5e2cf 2024-01-16 benni #endif /* not lint */
44 11a5e2cf 2024-01-16 benni * Tetris (or however it is spelled).
47 11a5e2cf 2024-01-16 benni #include <sys/time.h>
49 11a5e2cf 2024-01-16 benni #include <err.h>
50 11a5e2cf 2024-01-16 benni #include <fcntl.h>
51 11a5e2cf 2024-01-16 benni #include <signal.h>
52 11a5e2cf 2024-01-16 benni #include <stdio.h>
53 11a5e2cf 2024-01-16 benni #include <stdlib.h>
54 11a5e2cf 2024-01-16 benni #include <string.h>
55 11a5e2cf 2024-01-16 benni #include <unistd.h>
57 11a5e2cf 2024-01-16 benni #include "input.h"
58 11a5e2cf 2024-01-16 benni #include "scores.h"
59 11a5e2cf 2024-01-16 benni #include "screen.h"
60 11a5e2cf 2024-01-16 benni #include "tetris.h"
62 11a5e2cf 2024-01-16 benni cell board[B_SIZE]; /* 1 => occupied, 0 => empty */
64 11a5e2cf 2024-01-16 benni int Rows, Cols; /* current screen size */
65 11a5e2cf 2024-01-16 benni int Offset; /* used to center board & shapes */
67 11a5e2cf 2024-01-16 benni static const struct shape *curshape;
68 11a5e2cf 2024-01-16 benni const struct shape *nextshape;
70 11a5e2cf 2024-01-16 benni long fallrate; /* less than 1 million; smaller => faster */
72 11a5e2cf 2024-01-16 benni int score; /* the obvious thing */
73 11a5e2cf 2024-01-16 benni gid_t gid, egid;
75 11a5e2cf 2024-01-16 benni char key_msg[100];
76 11a5e2cf 2024-01-16 benni int showpreview;
77 11a5e2cf 2024-01-16 benni int nocolor;
78 2e032d40 2024-03-01 benni int dofaster;
80 11a5e2cf 2024-01-16 benni static void elide(void);
81 11a5e2cf 2024-01-16 benni static void setup_board(void);
82 11a5e2cf 2024-01-16 benni static void onintr(int) __dead;
83 11a5e2cf 2024-01-16 benni static void usage(void) __dead;
86 11a5e2cf 2024-01-16 benni * Set up the initial board. The bottom display row is completely set,
87 11a5e2cf 2024-01-16 benni * along with another (hidden) row underneath that. Also, the left and
88 11a5e2cf 2024-01-16 benni * right edges are set.
90 11a5e2cf 2024-01-16 benni static void
91 11a5e2cf 2024-01-16 benni setup_board(void)
97 11a5e2cf 2024-01-16 benni for (i = B_SIZE; i; i--)
98 11a5e2cf 2024-01-16 benni *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 7 : 0;
102 11a5e2cf 2024-01-16 benni * Elide any full active rows.
104 11a5e2cf 2024-01-16 benni static void
105 11a5e2cf 2024-01-16 benni elide(void)
107 11a5e2cf 2024-01-16 benni int i, j, base;
110 11a5e2cf 2024-01-16 benni for (i = A_FIRST; i < A_LAST; i++) {
111 11a5e2cf 2024-01-16 benni base = i * B_COLS + 1;
112 11a5e2cf 2024-01-16 benni p = &board[base];
113 11a5e2cf 2024-01-16 benni for (j = B_COLS - 2; *p++ != 0;) {
114 11a5e2cf 2024-01-16 benni if (--j <= 0) {
115 11a5e2cf 2024-01-16 benni /* this row is to be elided */
116 11a5e2cf 2024-01-16 benni memset(&board[base], 0, B_COLS - 2);
117 11a5e2cf 2024-01-16 benni scr_update();
119 11a5e2cf 2024-01-16 benni while (--base != 0)
120 11a5e2cf 2024-01-16 benni board[base + B_COLS] = board[base];
121 11a5e2cf 2024-01-16 benni /* don't forget to clear 0th row */
122 11a5e2cf 2024-01-16 benni memset(&board[1], 0, B_COLS - 2);
123 11a5e2cf 2024-01-16 benni scr_update();
132 11a5e2cf 2024-01-16 benni main(int argc, char *argv[])
134 11a5e2cf 2024-01-16 benni int pos, c;
135 11a5e2cf 2024-01-16 benni const char *keys;
136 11a5e2cf 2024-01-16 benni int level = 2;
137 11a5e2cf 2024-01-16 benni #define NUMKEYS 7
138 11a5e2cf 2024-01-16 benni char key_write[NUMKEYS][10];
139 11a5e2cf 2024-01-16 benni char *nocolor_env;
140 11a5e2cf 2024-01-16 benni int ch, i, j;
143 11a5e2cf 2024-01-16 benni gid = getgid();
144 11a5e2cf 2024-01-16 benni egid = getegid();
145 11a5e2cf 2024-01-16 benni setegid(gid);
147 11a5e2cf 2024-01-16 benni fd = open("/dev/null", O_RDONLY);
148 11a5e2cf 2024-01-16 benni if (fd < 3)
150 11a5e2cf 2024-01-16 benni close(fd);
152 11a5e2cf 2024-01-16 benni keys = "jkl pqn";
154 2e032d40 2024-03-01 benni while ((ch = getopt(argc, argv, "bfk:l:ps")) != -1)
155 11a5e2cf 2024-01-16 benni switch(ch) {
157 11a5e2cf 2024-01-16 benni nocolor = 1;
160 2e032d40 2024-03-01 benni dofaster = 1;
163 11a5e2cf 2024-01-16 benni if (strlen(keys = optarg) != NUMKEYS)
167 11a5e2cf 2024-01-16 benni level = atoi(optarg);
168 11a5e2cf 2024-01-16 benni if (level < MINLEVEL || level > MAXLEVEL) {
169 11a5e2cf 2024-01-16 benni errx(1, "level must be from %d to %d",
170 11a5e2cf 2024-01-16 benni MINLEVEL, MAXLEVEL);
174 11a5e2cf 2024-01-16 benni showpreview = 1;
177 11a5e2cf 2024-01-16 benni showscores(0);
184 11a5e2cf 2024-01-16 benni argc -= optind;
185 11a5e2cf 2024-01-16 benni argv += optind;
190 11a5e2cf 2024-01-16 benni nocolor_env = getenv("NO_COLOR");
192 11a5e2cf 2024-01-16 benni if (nocolor_env != NULL && nocolor_env[0] != '\0')
193 11a5e2cf 2024-01-16 benni nocolor = 1;
195 11a5e2cf 2024-01-16 benni fallrate = 1000000 / level;
197 11a5e2cf 2024-01-16 benni for (i = 0; i <= (NUMKEYS-1); i++) {
198 11a5e2cf 2024-01-16 benni for (j = i+1; j <= (NUMKEYS-1); j++) {
199 11a5e2cf 2024-01-16 benni if (keys[i] == keys[j]) {
200 11a5e2cf 2024-01-16 benni errx(1, "duplicate command keys specified.");
203 11a5e2cf 2024-01-16 benni if (keys[i] == ' ')
204 11a5e2cf 2024-01-16 benni strcpy(key_write[i], "<space>");
206 11a5e2cf 2024-01-16 benni key_write[i][0] = keys[i];
207 11a5e2cf 2024-01-16 benni key_write[i][1] = '\0';
211 11a5e2cf 2024-01-16 benni snprintf(key_msg, sizeof(key_msg),
212 11a5e2cf 2024-01-16 benni "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit %s - down",
213 11a5e2cf 2024-01-16 benni key_write[0], key_write[1], key_write[2], key_write[3],
214 11a5e2cf 2024-01-16 benni key_write[4], key_write[5], key_write[6]);
216 11a5e2cf 2024-01-16 benni (void)signal(SIGINT, onintr);
217 11a5e2cf 2024-01-16 benni scr_init();
218 11a5e2cf 2024-01-16 benni setup_board();
220 11a5e2cf 2024-01-16 benni scr_set();
222 11a5e2cf 2024-01-16 benni pos = A_FIRST*B_COLS + (B_COLS/2)-1;
223 11a5e2cf 2024-01-16 benni nextshape = randshape();
224 11a5e2cf 2024-01-16 benni curshape = randshape();
226 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
228 11a5e2cf 2024-01-16 benni for (;;) {
229 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
230 11a5e2cf 2024-01-16 benni scr_update();
231 11a5e2cf 2024-01-16 benni place(curshape, pos, 0);
232 11a5e2cf 2024-01-16 benni c = tgetchar();
233 11a5e2cf 2024-01-16 benni if (c < 0) {
235 11a5e2cf 2024-01-16 benni * Timeout. Move down if possible.
237 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + B_COLS)) {
238 11a5e2cf 2024-01-16 benni pos += B_COLS;
243 11a5e2cf 2024-01-16 benni * Put up the current shape `permanently',
244 11a5e2cf 2024-01-16 benni * bump score, and elide any full rows.
246 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
251 11a5e2cf 2024-01-16 benni * Choose a new shape. If it does not fit,
252 11a5e2cf 2024-01-16 benni * the game is over.
254 11a5e2cf 2024-01-16 benni curshape = nextshape;
255 11a5e2cf 2024-01-16 benni nextshape = randshape();
256 11a5e2cf 2024-01-16 benni pos = A_FIRST*B_COLS + (B_COLS/2)-1;
257 11a5e2cf 2024-01-16 benni if (!fits_in(curshape, pos))
263 11a5e2cf 2024-01-16 benni * Handle command keys.
265 11a5e2cf 2024-01-16 benni if (c == keys[5]) {
266 11a5e2cf 2024-01-16 benni /* quit */
269 11a5e2cf 2024-01-16 benni if (c == keys[4]) {
270 11a5e2cf 2024-01-16 benni static char msg[] =
271 11a5e2cf 2024-01-16 benni "paused - press RETURN to continue";
273 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
275 11a5e2cf 2024-01-16 benni scr_update();
276 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 0);
277 11a5e2cf 2024-01-16 benni scr_msg(msg, 1);
278 11a5e2cf 2024-01-16 benni (void) fflush(stdout);
279 11a5e2cf 2024-01-16 benni } while (rwait(NULL) == -1);
280 11a5e2cf 2024-01-16 benni scr_msg(msg, 0);
281 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
282 11a5e2cf 2024-01-16 benni place(curshape, pos, 0);
285 11a5e2cf 2024-01-16 benni if (c == keys[0]) {
286 11a5e2cf 2024-01-16 benni /* move left */
287 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos - 1))
291 11a5e2cf 2024-01-16 benni if (c == keys[1]) {
292 11a5e2cf 2024-01-16 benni /* turn */
293 11a5e2cf 2024-01-16 benni const struct shape *new = &shapes[curshape->rot];
295 11a5e2cf 2024-01-16 benni if (fits_in(new, pos))
296 11a5e2cf 2024-01-16 benni curshape = new;
299 11a5e2cf 2024-01-16 benni if (c == keys[2]) {
300 11a5e2cf 2024-01-16 benni /* move right */
301 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + 1))
305 11a5e2cf 2024-01-16 benni if (c == keys[3]) {
306 11a5e2cf 2024-01-16 benni /* move to bottom */
307 11a5e2cf 2024-01-16 benni while (fits_in(curshape, pos + B_COLS)) {
308 11a5e2cf 2024-01-16 benni pos += B_COLS;
313 11a5e2cf 2024-01-16 benni if (c == keys[6]) {
314 11a5e2cf 2024-01-16 benni /* move down */
315 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + B_COLS)) {
316 11a5e2cf 2024-01-16 benni pos += B_COLS;
321 11a5e2cf 2024-01-16 benni if (c == '\f') {
322 11a5e2cf 2024-01-16 benni scr_clear();
323 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
327 11a5e2cf 2024-01-16 benni scr_clear();
328 11a5e2cf 2024-01-16 benni scr_end();
330 11a5e2cf 2024-01-16 benni (void)printf("Your score: %d point%s x level %d = %d\n",
331 11a5e2cf 2024-01-16 benni score, score == 1 ? "" : "s", level, score * level);
332 11a5e2cf 2024-01-16 benni savescore(level);
334 11a5e2cf 2024-01-16 benni printf("\nHit RETURN to see high scores, ^C to skip.\n");
336 11a5e2cf 2024-01-16 benni while ((i = getchar()) != '\n')
337 11a5e2cf 2024-01-16 benni if (i == EOF)
340 11a5e2cf 2024-01-16 benni showscores(level);
345 11a5e2cf 2024-01-16 benni static void
346 11a5e2cf 2024-01-16 benni onintr(int signo __unused)
348 11a5e2cf 2024-01-16 benni scr_clear();
349 11a5e2cf 2024-01-16 benni scr_end();
353 11a5e2cf 2024-01-16 benni static void
354 11a5e2cf 2024-01-16 benni usage(void)
356 11a5e2cf 2024-01-16 benni (void)fprintf(stderr, "usage: %s [-bps] [-k keys] [-l level]\n",
357 11a5e2cf 2024-01-16 benni getprogname());