source: mainline/uspace/app/tetris/tetris.c@ 3bacee1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3bacee1 was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 8.5 KB
RevLine 
[79ae36dd]1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
[e9a3c52]4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
[79ae36dd]9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** Attributations
30 *
31 * tetris.c 8.1 (Berkeley) 5/31/93
32 * NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd
33 * OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray
34 *
35 * Based upon BSD Tetris
36 *
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California.
39 * Distributed under BSD license.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * Chris Torek and Darren F. Provine.
[e9a3c52]43 *
44 */
45
[b2951e2]46/** @addtogroup tetris Tetris
[ebe70f1]47 * @brief Tetris ported from OpenBSD
48 * @{
[b2951e2]49 */
50/** @file
51 */
52
[9260102]53static volatile const char copyright[] =
[3bacee1]54 "@(#) Copyright (c) 1992, 1993\n"
55 "\tThe Regents of the University of California. All rights reserved.\n";
[e9a3c52]56
57#include <sys/time.h>
[d4b9d28]58#include <errno.h>
[76d0981d]59#include <stdbool.h>
[e9a3c52]60#include <stdio.h>
61#include <stdlib.h>
[582a0b8]62#include <stdint.h>
[19f857a]63#include <str.h>
[ebe70f1]64#include <getopt.h>
[e9a3c52]65#include "scores.h"
66#include "screen.h"
67#include "tetris.h"
68
[ebe70f1]69cell board[B_SIZE];
70
71int Rows;
72int Cols;
73
[e9a3c52]74const struct shape *curshape;
75const struct shape *nextshape;
76
[ebe70f1]77long fallrate;
78int score;
79char key_msg[100];
80int showpreview;
81int classic;
82
83static void elide(void);
84static void setup_board(void);
85static const struct shape *randshape(void);
86
87static void usage(void);
88
89static int firstgame = 1;
[e9a3c52]90
91/*
[ebe70f1]92 * Set up the initial board. The bottom display row is completely set,
93 * along with another (hidden) row underneath that. Also, the left and
[e9a3c52]94 * right edges are set.
95 */
[ebe70f1]96static void setup_board(void)
[e9a3c52]97{
98 int i;
[ebe70f1]99 cell *p = board;
[a35b458]100
[e9a3c52]101 for (i = B_SIZE; i; i--)
[ebe70f1]102 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
[e9a3c52]103}
104
105/*
106 * Elide any full active rows.
107 */
[ebe70f1]108static void elide(void)
[e9a3c52]109{
110 int rows = 0;
[ebe70f1]111 int i;
112 int j;
113 int base;
[e9a3c52]114 cell *p;
[a35b458]115
[e9a3c52]116 for (i = A_FIRST; i < A_LAST; i++) {
117 base = i * B_COLS + 1;
118 p = &board[base];
[84239b1]119 j = B_COLS - 2;
120 while (*p++ != 0) {
[e9a3c52]121 if (--j <= 0) {
[ebe70f1]122 /* This row is to be elided */
[e9a3c52]123 rows++;
[ebe70f1]124 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
[a35b458]125
[e9a3c52]126 scr_update();
127 tsleep();
[a35b458]128
[e9a3c52]129 while (--base != 0)
130 board[base + B_COLS] = board[base];
[a35b458]131
[e9a3c52]132 scr_update();
133 tsleep();
[a35b458]134
[e9a3c52]135 break;
136 }
137 }
138 }
[a35b458]139
[e9a3c52]140 switch (rows) {
141 case 1:
142 score += 10;
143 break;
144 case 2:
145 score += 30;
146 break;
147 case 3:
148 score += 70;
149 break;
150 case 4:
151 score += 150;
152 break;
153 default:
154 break;
155 }
156}
157
[ebe70f1]158const struct shape *randshape(void)
[e9a3c52]159{
[c718bda]160 const struct shape *tmp = &shapes[rand() % 7];
[ebe70f1]161 int i;
[c718bda]162 int j = rand() % 4;
[a35b458]163
[e9a3c52]164 for (i = 0; i < j; i++)
[ebe70f1]165 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
[a35b458]166
[e9a3c52]167 return (tmp);
168}
[c594489]169
170static void srandomdev(void)
171{
172 struct timeval tv;
[a35b458]173
[c594489]174 gettimeofday(&tv, NULL);
[c718bda]175 srand(tv.tv_sec + tv.tv_usec / 100000);
[c594489]176}
[e9a3c52]177
[1b20da0]178static void tetris_menu_draw(int level)
[9996ed5]179{
[ebe70f1]180 clear_screen();
181 moveto(5, 10);
[1abcf1d]182 puts("Tetris\n");
[a35b458]183
[ebe70f1]184 moveto(8, 10);
185 printf("Level = %d (press keys 1 - 9 to change)", level);
186 moveto(9, 10);
[3bacee1]187 printf("Preview is %s (press 'p' to change)", (showpreview ? "on " : "off"));
[ebe70f1]188 moveto(12, 10);
189 printf("Press 'h' to show hiscore table.");
190 moveto(13, 10);
191 printf("Press 's' to start game.");
192 moveto(14, 10);
193 printf("Press 'q' to quit game.");
194 moveto(20, 10);
195 printf("In game controls:");
196 moveto(21, 0);
[1abcf1d]197 printf("%s", key_msg);
[9996ed5]198}
199
[ebe70f1]200static int tetris_menu(int *level)
[9996ed5]201{
202 tetris_menu_draw(*level);
[76d0981d]203 while (true) {
[ebe70f1]204 int i = getchar();
[a35b458]205
[3bacee1]206 switch (i) {
207 case 'p':
208 showpreview = !showpreview;
209 moveto(9, 21);
210 if (showpreview)
211 printf("on ");
212 else
213 printf("off");
214 break;
215 case 'h':
216 loadscores();
217 showscores(firstgame);
218 tetris_menu_draw(*level);
219 break;
220 case 's':
221 firstgame = 0;
222 return 1;
223 case 'q':
224 return 0;
225 case '1':
226 case '2':
227 case '3':
228 case '4':
229 case '5':
230 case '6':
231 case '7':
232 case '8':
233 case '9':
234 *level = i - '0';
235 moveto(8, 18);
236 printf("%d", *level);
237 break;
[9996ed5]238 }
239 }
240}
241
[ebe70f1]242int main(int argc, char *argv[])
[e9a3c52]243{
[ebe70f1]244 int pos;
245 int c;
[a405563]246 const char *keys;
[e9a3c52]247 int level = 2;
248 char key_write[6][10];
[ebe70f1]249 int i;
250 int j;
251 int ch;
[a35b458]252
[79ae36dd]253 console = console_init(stdin, stdout);
[a35b458]254
[e9a3c52]255 keys = "jkl pq";
[a35b458]256
[9996ed5]257 classic = 0;
[79ae36dd]258 showpreview = 1;
[a35b458]259
[ebe70f1]260 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
[3bacee1]261 switch (ch) {
[ebe70f1]262 case 'c':
263 /*
264 * this means:
265 * - rotate the other way
266 * - no reverse video
267 */
268 classic = 1;
269 break;
270 case 'k':
271 if (str_size(keys = optarg) != 6)
272 usage();
273 break;
274 case 'p':
275 showpreview = 1;
276 break;
277 case 's':
278 showscores(0);
279 exit(0);
280 default:
281 usage();
282 }
[a35b458]283
[ebe70f1]284 argc -= optind;
285 argv += optind;
[a35b458]286
[ebe70f1]287 if (argc)
288 usage();
[a35b458]289
[e9a3c52]290 for (i = 0; i <= 5; i++) {
[ebe70f1]291 for (j = i + 1; j <= 5; j++) {
[f538ef3]292 if (keys[i] == keys[j]) {
293 fprintf(stderr, "duplicate command keys specified.");
294 abort();
295 }
[e9a3c52]296 }
[a35b458]297
[e9a3c52]298 if (keys[i] == ' ')
[ebe70f1]299 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
[e9a3c52]300 else {
301 key_write[i][0] = keys[i];
302 key_write[i][1] = '\0';
303 }
304 }
[a35b458]305
[ebe70f1]306 snprintf(key_msg, sizeof(key_msg),
307 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
308 key_write[0], key_write[1], key_write[2], key_write[3],
309 key_write[4], key_write[5]);
[a35b458]310
[9996ed5]311 scr_init();
[d4b9d28]312 if (loadscores() != EOK)
313 initscores();
314
[9996ed5]315 while (tetris_menu(&level)) {
[237867d]316 fallrate = 1000000 / level;
[a35b458]317
[9996ed5]318 scr_clear();
319 setup_board();
[a35b458]320
[9996ed5]321 srandomdev();
322 scr_set();
[a35b458]323
[ebe70f1]324 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
[9996ed5]325 nextshape = randshape();
326 curshape = randshape();
[a35b458]327
[9996ed5]328 scr_msg(key_msg, 1);
[a35b458]329
[76d0981d]330 while (true) {
[9996ed5]331 place(curshape, pos, 1);
332 scr_update();
333 place(curshape, pos, 0);
334 c = tgetchar();
335 if (c < 0) {
336 /*
337 * Timeout. Move down if possible.
338 */
339 if (fits_in(curshape, pos + B_COLS)) {
340 pos += B_COLS;
341 continue;
342 }
[a35b458]343
[9996ed5]344 /*
345 * Put up the current shape `permanently',
346 * bump score, and elide any full rows.
347 */
348 place(curshape, pos, 1);
349 score++;
350 elide();
[a35b458]351
[9996ed5]352 /*
353 * Choose a new shape. If it does not fit,
354 * the game is over.
355 */
356 curshape = nextshape;
357 nextshape = randshape();
[ebe70f1]358 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
[a35b458]359
[9996ed5]360 if (!fits_in(curshape, pos))
361 break;
[a35b458]362
[e9a3c52]363 continue;
364 }
[a35b458]365
[e9a3c52]366 /*
[9996ed5]367 * Handle command keys.
[e9a3c52]368 */
[9996ed5]369 if (c == keys[5]) {
370 /* quit */
[e9a3c52]371 break;
372 }
[a35b458]373
[9996ed5]374 if (c == keys[4]) {
375 static char msg[] =
376 "paused - press RETURN to continue";
[a35b458]377
[9996ed5]378 place(curshape, pos, 1);
379 do {
380 scr_update();
381 scr_msg(key_msg, 0);
382 scr_msg(msg, 1);
[79ae36dd]383 console_flush(console);
384 } while (!twait());
[a35b458]385
[9996ed5]386 scr_msg(msg, 0);
387 scr_msg(key_msg, 1);
388 place(curshape, pos, 0);
389 continue;
390 }
[a35b458]391
[9996ed5]392 if (c == keys[0]) {
393 /* move left */
394 if (fits_in(curshape, pos - 1))
395 pos--;
396 continue;
397 }
[a35b458]398
[9996ed5]399 if (c == keys[1]) {
400 /* turn */
[ebe70f1]401 const struct shape *new =
402 &shapes[classic ? curshape->rotc : curshape->rot];
[a35b458]403
[9996ed5]404 if (fits_in(new, pos))
405 curshape = new;
406 continue;
407 }
[a35b458]408
[9996ed5]409 if (c == keys[2]) {
410 /* move right */
411 if (fits_in(curshape, pos + 1))
412 pos++;
413 continue;
414 }
[a35b458]415
[9996ed5]416 if (c == keys[3]) {
417 /* move to bottom */
418 while (fits_in(curshape, pos + B_COLS)) {
419 pos += B_COLS;
420 score++;
421 }
422 continue;
423 }
[a35b458]424
[9996ed5]425 if (c == '\f') {
426 scr_clear();
427 scr_msg(key_msg, 1);
428 }
429 }
[a35b458]430
[9996ed5]431 scr_clear();
[d4b9d28]432 loadscores();
[9996ed5]433 insertscore(score, level);
[d4b9d28]434 savescores();
[ebe70f1]435 score = 0;
[0aa024b1]436 }
[a35b458]437
[0aa024b1]438 scr_clear();
[ebe70f1]439 printf("\nGame over.\n");
[9996ed5]440 scr_end();
[a35b458]441
[501a8ba]442 return 0;
[e9a3c52]443}
444
[ebe70f1]445void usage(void)
[e9a3c52]446{
[0b2d369]447 fprintf(stderr, "%s", copyright);
[ebe70f1]448 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
[e9a3c52]449 exit(1);
450}
[b2951e2]451
452/** @}
453 */
Note: See TracBrowser for help on using the repository browser.