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 7b083439 2024-06-06 benni #if !defined(lint) && !defined(__OpenBSD__) && !defined(__linux__)
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 b600ed35 2024-07-25 benni #ifdef __linux__
58 b600ed35 2024-07-25 benni # include <bsd/stdlib.h>
61 11a5e2cf 2024-01-16 benni #include "input.h"
62 11a5e2cf 2024-01-16 benni #include "scores.h"
63 11a5e2cf 2024-01-16 benni #include "screen.h"
64 11a5e2cf 2024-01-16 benni #include "tetris.h"
66 11a5e2cf 2024-01-16 benni cell board[B_SIZE]; /* 1 => occupied, 0 => empty */
68 11a5e2cf 2024-01-16 benni int Rows, Cols; /* current screen size */
69 11a5e2cf 2024-01-16 benni int Offset; /* used to center board & shapes */
71 11a5e2cf 2024-01-16 benni static const struct shape *curshape;
72 11a5e2cf 2024-01-16 benni const struct shape *nextshape;
74 11a5e2cf 2024-01-16 benni long fallrate; /* less than 1 million; smaller => faster */
76 11a5e2cf 2024-01-16 benni int score; /* the obvious thing */
77 11a5e2cf 2024-01-16 benni gid_t gid, egid;
79 11a5e2cf 2024-01-16 benni char key_msg[100];
80 11a5e2cf 2024-01-16 benni int showpreview;
81 11a5e2cf 2024-01-16 benni int nocolor;
82 2e032d40 2024-03-01 benni int dofaster;
84 11a5e2cf 2024-01-16 benni static void elide(void);
85 11a5e2cf 2024-01-16 benni static void setup_board(void);
86 11a5e2cf 2024-01-16 benni static void onintr(int) __dead;
87 11a5e2cf 2024-01-16 benni static void usage(void) __dead;
90 11a5e2cf 2024-01-16 benni * Set up the initial board. The bottom display row is completely set,
91 11a5e2cf 2024-01-16 benni * along with another (hidden) row underneath that. Also, the left and
92 11a5e2cf 2024-01-16 benni * right edges are set.
94 11a5e2cf 2024-01-16 benni static void
95 11a5e2cf 2024-01-16 benni setup_board(void)
100 11a5e2cf 2024-01-16 benni p = board;
101 11a5e2cf 2024-01-16 benni for (i = B_SIZE; i; i--)
102 11a5e2cf 2024-01-16 benni *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 7 : 0;
106 11a5e2cf 2024-01-16 benni * Elide any full active rows.
108 11a5e2cf 2024-01-16 benni static void
109 11a5e2cf 2024-01-16 benni elide(void)
111 11a5e2cf 2024-01-16 benni int i, j, base;
114 11a5e2cf 2024-01-16 benni for (i = A_FIRST; i < A_LAST; i++) {
115 11a5e2cf 2024-01-16 benni base = i * B_COLS + 1;
116 11a5e2cf 2024-01-16 benni p = &board[base];
117 11a5e2cf 2024-01-16 benni for (j = B_COLS - 2; *p++ != 0;) {
118 11a5e2cf 2024-01-16 benni if (--j <= 0) {
119 11a5e2cf 2024-01-16 benni /* this row is to be elided */
120 11a5e2cf 2024-01-16 benni memset(&board[base], 0, B_COLS - 2);
121 11a5e2cf 2024-01-16 benni scr_update();
123 11a5e2cf 2024-01-16 benni while (--base != 0)
124 11a5e2cf 2024-01-16 benni board[base + B_COLS] = board[base];
125 11a5e2cf 2024-01-16 benni /* don't forget to clear 0th row */
126 11a5e2cf 2024-01-16 benni memset(&board[1], 0, B_COLS - 2);
127 11a5e2cf 2024-01-16 benni scr_update();
136 11a5e2cf 2024-01-16 benni main(int argc, char *argv[])
138 11a5e2cf 2024-01-16 benni int pos, c;
139 11a5e2cf 2024-01-16 benni const char *keys;
140 11a5e2cf 2024-01-16 benni int level = 2;
141 11a5e2cf 2024-01-16 benni #define NUMKEYS 7
142 11a5e2cf 2024-01-16 benni char key_write[NUMKEYS][10];
143 11a5e2cf 2024-01-16 benni char *nocolor_env;
144 11a5e2cf 2024-01-16 benni int ch, i, j;
147 11a5e2cf 2024-01-16 benni gid = getgid();
148 11a5e2cf 2024-01-16 benni egid = getegid();
149 11a5e2cf 2024-01-16 benni setegid(gid);
151 11a5e2cf 2024-01-16 benni fd = open("/dev/null", O_RDONLY);
152 11a5e2cf 2024-01-16 benni if (fd < 3)
154 11a5e2cf 2024-01-16 benni close(fd);
156 11a5e2cf 2024-01-16 benni keys = "jkl pqn";
158 2e032d40 2024-03-01 benni while ((ch = getopt(argc, argv, "bfk:l:ps")) != -1)
159 11a5e2cf 2024-01-16 benni switch(ch) {
161 11a5e2cf 2024-01-16 benni nocolor = 1;
164 2e032d40 2024-03-01 benni dofaster = 1;
167 11a5e2cf 2024-01-16 benni if (strlen(keys = optarg) != NUMKEYS)
171 11a5e2cf 2024-01-16 benni level = atoi(optarg);
172 11a5e2cf 2024-01-16 benni if (level < MINLEVEL || level > MAXLEVEL) {
173 11a5e2cf 2024-01-16 benni errx(1, "level must be from %d to %d",
174 11a5e2cf 2024-01-16 benni MINLEVEL, MAXLEVEL);
178 11a5e2cf 2024-01-16 benni showpreview = 1;
181 11a5e2cf 2024-01-16 benni showscores(0);
188 11a5e2cf 2024-01-16 benni argc -= optind;
189 11a5e2cf 2024-01-16 benni argv += optind;
194 11a5e2cf 2024-01-16 benni nocolor_env = getenv("NO_COLOR");
196 11a5e2cf 2024-01-16 benni if (nocolor_env != NULL && nocolor_env[0] != '\0')
197 11a5e2cf 2024-01-16 benni nocolor = 1;
199 11a5e2cf 2024-01-16 benni fallrate = 1000000 / level;
201 11a5e2cf 2024-01-16 benni for (i = 0; i <= (NUMKEYS-1); i++) {
202 11a5e2cf 2024-01-16 benni for (j = i+1; j <= (NUMKEYS-1); j++) {
203 11a5e2cf 2024-01-16 benni if (keys[i] == keys[j]) {
204 11a5e2cf 2024-01-16 benni errx(1, "duplicate command keys specified.");
207 11a5e2cf 2024-01-16 benni if (keys[i] == ' ')
208 11a5e2cf 2024-01-16 benni strcpy(key_write[i], "<space>");
210 11a5e2cf 2024-01-16 benni key_write[i][0] = keys[i];
211 11a5e2cf 2024-01-16 benni key_write[i][1] = '\0';
215 11a5e2cf 2024-01-16 benni snprintf(key_msg, sizeof(key_msg),
216 11a5e2cf 2024-01-16 benni "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit %s - down",
217 11a5e2cf 2024-01-16 benni key_write[0], key_write[1], key_write[2], key_write[3],
218 11a5e2cf 2024-01-16 benni key_write[4], key_write[5], key_write[6]);
220 11a5e2cf 2024-01-16 benni (void)signal(SIGINT, onintr);
221 11a5e2cf 2024-01-16 benni scr_init();
222 11a5e2cf 2024-01-16 benni setup_board();
224 11a5e2cf 2024-01-16 benni scr_set();
226 11a5e2cf 2024-01-16 benni pos = A_FIRST*B_COLS + (B_COLS/2)-1;
227 11a5e2cf 2024-01-16 benni nextshape = randshape();
228 11a5e2cf 2024-01-16 benni curshape = randshape();
230 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
232 11a5e2cf 2024-01-16 benni for (;;) {
233 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
234 11a5e2cf 2024-01-16 benni scr_update();
235 11a5e2cf 2024-01-16 benni place(curshape, pos, 0);
236 11a5e2cf 2024-01-16 benni c = tgetchar();
237 11a5e2cf 2024-01-16 benni if (c < 0) {
239 11a5e2cf 2024-01-16 benni * Timeout. Move down if possible.
241 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + B_COLS)) {
242 11a5e2cf 2024-01-16 benni pos += B_COLS;
247 11a5e2cf 2024-01-16 benni * Put up the current shape `permanently',
248 11a5e2cf 2024-01-16 benni * bump score, and elide any full rows.
250 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
255 11a5e2cf 2024-01-16 benni * Choose a new shape. If it does not fit,
256 11a5e2cf 2024-01-16 benni * the game is over.
258 11a5e2cf 2024-01-16 benni curshape = nextshape;
259 11a5e2cf 2024-01-16 benni nextshape = randshape();
260 11a5e2cf 2024-01-16 benni pos = A_FIRST*B_COLS + (B_COLS/2)-1;
261 11a5e2cf 2024-01-16 benni if (!fits_in(curshape, pos))
267 11a5e2cf 2024-01-16 benni * Handle command keys.
269 11a5e2cf 2024-01-16 benni if (c == keys[5]) {
270 11a5e2cf 2024-01-16 benni /* quit */
273 11a5e2cf 2024-01-16 benni if (c == keys[4]) {
274 11a5e2cf 2024-01-16 benni static char msg[] =
275 11a5e2cf 2024-01-16 benni "paused - press RETURN to continue";
277 11a5e2cf 2024-01-16 benni place(curshape, pos, 1);
279 11a5e2cf 2024-01-16 benni scr_update();
280 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 0);
281 11a5e2cf 2024-01-16 benni scr_msg(msg, 1);
282 11a5e2cf 2024-01-16 benni (void) fflush(stdout);
283 11a5e2cf 2024-01-16 benni } while (rwait(NULL) == -1);
284 11a5e2cf 2024-01-16 benni scr_msg(msg, 0);
285 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
286 11a5e2cf 2024-01-16 benni place(curshape, pos, 0);
289 11a5e2cf 2024-01-16 benni if (c == keys[0]) {
290 11a5e2cf 2024-01-16 benni /* move left */
291 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos - 1))
295 11a5e2cf 2024-01-16 benni if (c == keys[1]) {
296 11a5e2cf 2024-01-16 benni /* turn */
297 11a5e2cf 2024-01-16 benni const struct shape *new = &shapes[curshape->rot];
299 11a5e2cf 2024-01-16 benni if (fits_in(new, pos))
300 11a5e2cf 2024-01-16 benni curshape = new;
303 11a5e2cf 2024-01-16 benni if (c == keys[2]) {
304 11a5e2cf 2024-01-16 benni /* move right */
305 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + 1))
309 11a5e2cf 2024-01-16 benni if (c == keys[3]) {
310 11a5e2cf 2024-01-16 benni /* move to bottom */
311 11a5e2cf 2024-01-16 benni while (fits_in(curshape, pos + B_COLS)) {
312 11a5e2cf 2024-01-16 benni pos += B_COLS;
317 11a5e2cf 2024-01-16 benni if (c == keys[6]) {
318 11a5e2cf 2024-01-16 benni /* move down */
319 11a5e2cf 2024-01-16 benni if (fits_in(curshape, pos + B_COLS)) {
320 11a5e2cf 2024-01-16 benni pos += B_COLS;
325 11a5e2cf 2024-01-16 benni if (c == '\f') {
326 11a5e2cf 2024-01-16 benni scr_clear();
327 11a5e2cf 2024-01-16 benni scr_msg(key_msg, 1);
331 11a5e2cf 2024-01-16 benni scr_clear();
332 11a5e2cf 2024-01-16 benni scr_end();
334 11a5e2cf 2024-01-16 benni (void)printf("Your score: %d point%s x level %d = %d\n",
335 11a5e2cf 2024-01-16 benni score, score == 1 ? "" : "s", level, score * level);
336 11a5e2cf 2024-01-16 benni savescore(level);
338 11a5e2cf 2024-01-16 benni printf("\nHit RETURN to see high scores, ^C to skip.\n");
340 11a5e2cf 2024-01-16 benni while ((i = getchar()) != '\n')
341 11a5e2cf 2024-01-16 benni if (i == EOF)
344 11a5e2cf 2024-01-16 benni showscores(level);
349 11a5e2cf 2024-01-16 benni static void
350 7b083439 2024-06-06 benni onintr(int signo)
352 7b083439 2024-06-06 benni (void)signo;
353 11a5e2cf 2024-01-16 benni scr_clear();
354 11a5e2cf 2024-01-16 benni scr_end();
358 11a5e2cf 2024-01-16 benni static void
359 11a5e2cf 2024-01-16 benni usage(void)
361 7b083439 2024-06-06 benni (void)fprintf(stderr, "usage: tetris [-bps] [-k keys] [-l level]\n");