sbin/hammer2: Fix usage()
[dragonfly.git] / games / tetris / tetris.c
blobca7581133a491a1b190967eba42fdcd820981183
1 /* $OpenBSD: tetris.c,v 1.32 2017/08/13 02:12:16 tedu Exp $ */
2 /* $NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $ */
4 /*-
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Chris Torek and Darren F. Provine.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * @(#)tetris.c 8.1 (Berkeley) 5/31/93
39 * Tetris (or however it is spelled).
42 #include <err.h>
43 #include <limits.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
50 #include "input.h"
51 #include "scores.h"
52 #include "screen.h"
53 #include "tetris.h"
55 cell board[B_SIZE];
56 int Rows, Cols;
57 const struct shape *curshape;
58 const struct shape *nextshape;
59 long fallrate;
60 int score;
61 char key_msg[120];
62 int showpreview, classic;
64 static void elide(void);
65 __dead2 void onintr(int __unused);
66 const struct shape *randshape(void);
67 static void setup_board(void);
68 __dead2 void usage(void);
71 * Set up the initial board. The bottom display row is completely set,
72 * along with another (hidden) row underneath that. Also, the left and
73 * right edges are set.
75 static void
76 setup_board(void)
78 int i;
79 cell *p;
81 p = board;
82 for (i = B_SIZE; i; i--)
83 *p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2;
87 * Elide any full active rows.
89 static void
90 elide(void)
92 int rows = 0;
93 int i, j, base;
94 cell *p;
96 for (i = A_FIRST; i < A_LAST; i++) {
97 base = i * B_COLS + 1;
98 p = &board[base];
99 for (j = B_COLS - 2; *p++ != 0;) {
100 if (--j <= 0) {
101 /* this row is to be elided */
102 rows++;
103 memset(&board[base], 0, B_COLS - 2);
104 scr_update();
105 tsleep();
106 while (--base != 0)
107 board[base + B_COLS] = board[base];
108 memset(&board[1], 0, B_COLS - 2);
109 scr_update();
110 tsleep();
111 break;
115 switch (rows) {
116 case 1:
117 score += 10;
118 break;
119 case 2:
120 score += 30;
121 break;
122 case 3:
123 score += 70;
124 break;
125 case 4:
126 score += 150;
127 break;
128 default:
129 break;
133 const struct shape *
134 randshape(void)
136 const struct shape *tmp;
137 int i, j;
139 tmp = &shapes[arc4random_uniform(7)];
140 j = arc4random_uniform(4);
141 for (i = 0; i < j; i++)
142 tmp = &shapes[classic? tmp->rotc : tmp->rot];
143 return (tmp);
146 #define NUMKEYS 6
149 main(int argc, char *argv[])
151 int pos, c;
152 const char *keys;
153 int level = 2;
154 char key_write[NUMKEYS][10];
155 const char *errstr;
156 int ch, i, j;
158 keys = "jkl pq";
160 classic = showpreview = 0;
161 while ((ch = getopt(argc, argv, "ck:l:ps")) != -1)
162 switch(ch) {
163 case 'c':
165 * this means:
166 * - rotate the other way;
167 * - no reverse video.
169 classic = 1;
170 break;
171 case 'k':
172 if (strlen(keys = optarg) != NUMKEYS)
173 usage();
174 break;
175 case 'l':
176 level = (int)strtonum(optarg, MINLEVEL, MAXLEVEL,
177 &errstr);
178 if (errstr)
179 errx(1, "level must be from %d to %d",
180 MINLEVEL, MAXLEVEL);
181 break;
182 case 'p':
183 showpreview = 1;
184 break;
185 case 's':
186 showscores(0);
187 return 0;
188 default:
189 usage();
192 argc -= optind;
193 argv += optind;
195 if (argc)
196 usage();
198 fallrate = 1000000000L / level;
200 for (i = 0; i <= (NUMKEYS-1); i++) {
201 for (j = i+1; j <= (NUMKEYS-1); j++) {
202 if (keys[i] == keys[j])
203 errx(1, "duplicate command keys specified.");
205 if (keys[i] == ' ')
206 strlcpy(key_write[i], "<space>", sizeof key_write[i]);
207 else {
208 key_write[i][0] = keys[i];
209 key_write[i][1] = '\0';
213 snprintf(key_msg, sizeof(key_msg),
214 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
215 key_write[0], key_write[1], key_write[2], key_write[3],
216 key_write[4], key_write[5]);
218 signal(SIGINT, onintr);
219 scr_init();
220 setup_board();
222 scr_set();
224 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
225 nextshape = randshape();
226 curshape = randshape();
228 scr_msg(key_msg, 1);
230 for (;;) {
231 place(curshape, pos, 1);
232 scr_update();
233 place(curshape, pos, 0);
234 c = tgetchar();
235 if (c < 0) {
237 * Timeout. Move down if possible.
239 if (fits_in(curshape, pos + B_COLS)) {
240 pos += B_COLS;
241 continue;
245 * Put up the current shape `permanently',
246 * bump score, and elide any full rows.
248 place(curshape, pos, 1);
249 score++;
250 elide();
253 * Choose a new shape. If it does not fit,
254 * the game is over.
256 curshape = nextshape;
257 nextshape = randshape();
258 pos = A_FIRST*B_COLS + (B_COLS/2)-1;
259 if (!fits_in(curshape, pos))
260 break;
261 continue;
265 * Handle command keys.
267 if (c == keys[5]) {
268 /* quit */
269 break;
271 if (c == keys[4]) {
272 static char msg[] =
273 "paused - press RETURN to continue";
275 place(curshape, pos, 1);
276 do {
277 scr_update();
278 scr_msg(key_msg, 0);
279 scr_msg(msg, 1);
280 fflush(stdout);
281 } while (rwait(NULL) == -1);
282 scr_msg(msg, 0);
283 scr_msg(key_msg, 1);
284 place(curshape, pos, 0);
285 continue;
287 if (c == keys[0]) {
288 /* move left */
289 if (fits_in(curshape, pos - 1))
290 pos--;
291 continue;
293 if (c == keys[1]) {
294 /* turn */
295 const struct shape *new = &shapes[
296 classic? curshape->rotc : curshape->rot];
298 if (fits_in(new, pos))
299 curshape = new;
300 continue;
302 if (c == keys[2]) {
303 /* move right */
304 if (fits_in(curshape, pos + 1))
305 pos++;
306 continue;
308 if (c == keys[3]) {
309 /* move to bottom */
310 while (fits_in(curshape, pos + B_COLS)) {
311 pos += B_COLS;
312 score++;
314 continue;
316 if (c == '\f') {
317 scr_clear();
318 scr_msg(key_msg, 1);
322 scr_clear();
323 scr_end();
325 if (showpreview == 0)
326 printf("Your score: %d point%s x level %d = %d\n",
327 score, score == 1 ? "" : "s", level, score * level);
328 else {
329 printf("Your score: %d point%s x level %d x preview penalty %0.3f = %d\n",
330 score, score == 1 ? "" : "s", level, (double)PRE_PENALTY,
331 (int)(score * level * PRE_PENALTY));
332 score = score * PRE_PENALTY;
334 savescore(level);
336 printf("\nHit RETURN to see high scores, ^C to skip.\n");
338 while ((i = getchar()) != '\n')
339 if (i == EOF)
340 break;
342 showscores(level);
344 return 0;
347 void
348 onintr(int signo __unused)
350 scr_clear(); /* XXX signal race */
351 scr_end(); /* XXX signal race */
352 _exit(0);
355 void
356 usage(void)
358 fprintf(stderr, "usage: %s [-cps] [-k keys] "
359 "[-l level]\n", getprogname());
360 exit(1);