~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to uspace/app/tetris/tetris.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray Exp $ */
 
2
/*      $NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $   */
 
3
 
 
4
/*-
 
5
 * Copyright (c) 1992, 1993
 
6
 *      The Regents of the University of California.  All rights reserved.
 
7
 *
 
8
 * This code is derived from software contributed to Berkeley by
 
9
 * Chris Torek and Darren F. Provine.
 
10
 *
 
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.
 
22
 *
 
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.
 
34
 *
 
35
 *      @(#)tetris.c    8.1 (Berkeley) 5/31/93
 
36
 */
 
37
 
 
38
/** @addtogroup tetris Tetris
 
39
 * @brief Tetris ported from OpenBSD
 
40
 * @{
 
41
 */
 
42
/** @file
 
43
 */
 
44
 
 
45
static const char copyright[] =
 
46
        "@(#) Copyright (c) 1992, 1993\n"
 
47
        "\tThe Regents of the University of California.  All rights reserved.\n";
 
48
 
 
49
#include <sys/time.h>
 
50
#include <sys/types.h>
 
51
#include <err.h>
 
52
#include <errno.h>
 
53
#include <stdio.h>
 
54
#include <stdlib.h>
 
55
#include <string.h>
 
56
#include <unistd.h>
 
57
#include <getopt.h>
 
58
 
 
59
#include "input.h"
 
60
#include "scores.h"
 
61
#include "screen.h"
 
62
#include "tetris.h"
 
63
 
 
64
cell board[B_SIZE];
 
65
 
 
66
int Rows;
 
67
int Cols;
 
68
 
 
69
const struct shape *curshape;
 
70
const struct shape *nextshape;
 
71
 
 
72
long fallrate;
 
73
int score;
 
74
char key_msg[100];
 
75
int showpreview;
 
76
int classic;
 
77
 
 
78
static void elide(void);
 
79
static void setup_board(void);
 
80
static const struct shape *randshape(void);
 
81
 
 
82
static void usage(void);
 
83
 
 
84
static int firstgame = 1;
 
85
 
 
86
/*
 
87
 * Set up the initial board. The bottom display row is completely set,
 
88
 * along with another (hidden) row underneath that. Also, the left and
 
89
 * right edges are set.
 
90
 */
 
91
static void setup_board(void)
 
92
{
 
93
        int i;
 
94
        cell *p = board;
 
95
        
 
96
        for (i = B_SIZE; i; i--)
 
97
                *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
 
98
}
 
99
 
 
100
/*
 
101
 * Elide any full active rows.
 
102
 */
 
103
static void elide(void)
 
104
{
 
105
        int rows = 0;
 
106
        int i;
 
107
        int j;
 
108
        int base;
 
109
        cell *p;
 
110
        
 
111
        for (i = A_FIRST; i < A_LAST; i++) {
 
112
                base = i * B_COLS + 1;
 
113
                p = &board[base];
 
114
                for (j = B_COLS - 2; *p++ != 0;) {
 
115
                        if (--j <= 0) {
 
116
                                /* This row is to be elided */
 
117
                                rows++;
 
118
                                memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
 
119
                                
 
120
                                scr_update();
 
121
                                tsleep();
 
122
                                
 
123
                                while (--base != 0)
 
124
                                        board[base + B_COLS] = board[base];
 
125
                                
 
126
                                scr_update();
 
127
                                tsleep();
 
128
                                
 
129
                                break;
 
130
                        }
 
131
                }
 
132
        }
 
133
        
 
134
        switch (rows) {
 
135
        case 1:
 
136
                score += 10;
 
137
                break;
 
138
        case 2:
 
139
                score += 30;
 
140
                break;
 
141
        case 3:
 
142
                score += 70;
 
143
                break;
 
144
        case 4:
 
145
                score += 150;
 
146
                break;
 
147
        default:
 
148
                break;
 
149
        }
 
150
}
 
151
 
 
152
const struct shape *randshape(void)
 
153
{
 
154
        const struct shape *tmp = &shapes[random() % 7];
 
155
        int i;
 
156
        int j = random() % 4;
 
157
        
 
158
        for (i = 0; i < j; i++)
 
159
                tmp = &shapes[classic ? tmp->rotc : tmp->rot];
 
160
        
 
161
        return (tmp);
 
162
}
 
163
 
 
164
static void srandomdev(void)
 
165
{
 
166
        struct timeval tv;
 
167
        
 
168
        gettimeofday(&tv, NULL);
 
169
        srandom(tv.tv_sec + tv.tv_usec / 100000);
 
170
}
 
171
 
 
172
static void tetris_menu_draw(int level) 
 
173
{
 
174
        clear_screen();
 
175
        moveto(5, 10);
 
176
        puts("Tetris\n\n");
 
177
        
 
178
        moveto(8, 10);
 
179
        printf("Level = %d (press keys 1 - 9 to change)", level);
 
180
        moveto(9, 10);
 
181
        printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
 
182
        moveto(12, 10);
 
183
        printf("Press 'h' to show hiscore table.");
 
184
        moveto(13, 10);
 
185
        printf("Press 's' to start game.");
 
186
        moveto(14, 10);
 
187
        printf("Press 'q' to quit game.");
 
188
        moveto(20, 10);
 
189
        printf("In game controls:");
 
190
        moveto(21, 0);
 
191
        puts(key_msg);
 
192
}
 
193
 
 
194
static int tetris_menu(int *level)
 
195
{
 
196
        tetris_menu_draw(*level);
 
197
        while (1) {
 
198
                int i = getchar();
 
199
                
 
200
                switch(i) {
 
201
                        case 'p':
 
202
                                showpreview = !showpreview;
 
203
                                moveto(9, 21);
 
204
                                if (showpreview)
 
205
                                        printf("on ");
 
206
                                else
 
207
                                        printf("off");
 
208
                                break;
 
209
                        case 'h':
 
210
                                loadscores();
 
211
                                showscores(firstgame);
 
212
                                tetris_menu_draw(*level);
 
213
                                break;
 
214
                        case 's':
 
215
                                firstgame = 0;
 
216
                                return 1;
 
217
                        case 'q':
 
218
                                return 0;
 
219
                        case '1':
 
220
                        case '2':
 
221
                        case '3':
 
222
                        case '4':
 
223
                        case '5':
 
224
                        case '6':
 
225
                        case '7':
 
226
                        case '8':
 
227
                        case '9':
 
228
                                *level = i - '0';
 
229
                                moveto(8, 18);
 
230
                                printf("%d", *level);
 
231
                                break;
 
232
                }
 
233
        }
 
234
}
 
235
 
 
236
int main(int argc, char *argv[])
 
237
{
 
238
        int pos;
 
239
        int c;
 
240
        const char *keys;
 
241
        int level = 2;
 
242
        char key_write[6][10];
 
243
        int i;
 
244
        int j;
 
245
        int ch;
 
246
        
 
247
        keys = "jkl pq";
 
248
        
 
249
        classic = 0;
 
250
        showpreview = 1; 
 
251
        
 
252
        while ((ch = getopt(argc, argv, "ck:ps")) != -1)
 
253
                switch(ch) {
 
254
                case 'c':
 
255
                        /*
 
256
                         * this means:
 
257
                         *  - rotate the other way
 
258
                         *  - no reverse video
 
259
                         */
 
260
                        classic = 1;
 
261
                        break;
 
262
                case 'k':
 
263
                        if (str_size(keys = optarg) != 6)
 
264
                                usage();
 
265
                        break;
 
266
                case 'p':
 
267
                        showpreview = 1;
 
268
                        break;
 
269
                case 's':
 
270
                        showscores(0);
 
271
                        exit(0);
 
272
                default:
 
273
                        usage();
 
274
                }
 
275
        
 
276
        argc -= optind;
 
277
        argv += optind;
 
278
        
 
279
        if (argc)
 
280
                usage();
 
281
        
 
282
        for (i = 0; i <= 5; i++) {
 
283
                for (j = i + 1; j <= 5; j++) {
 
284
                        if (keys[i] == keys[j])
 
285
                                errx(1, "duplicate command keys specified.");
 
286
                }
 
287
                
 
288
                if (keys[i] == ' ')
 
289
                        str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
 
290
                else {
 
291
                        key_write[i][0] = keys[i];
 
292
                        key_write[i][1] = '\0';
 
293
                }
 
294
        }
 
295
        
 
296
        snprintf(key_msg, sizeof(key_msg),
 
297
            "%s - left   %s - rotate   %s - right   %s - drop   %s - pause   %s - quit",
 
298
            key_write[0], key_write[1], key_write[2], key_write[3],
 
299
            key_write[4], key_write[5]);
 
300
        
 
301
        scr_init();
 
302
        if (loadscores() != EOK)
 
303
                initscores();
 
304
 
 
305
        while (tetris_menu(&level)) {
 
306
                fallrate = 1000000 / level;
 
307
                
 
308
                scr_clear();
 
309
                setup_board();
 
310
                
 
311
                srandomdev();
 
312
                scr_set();
 
313
                
 
314
                pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
 
315
                nextshape = randshape();
 
316
                curshape = randshape();
 
317
                
 
318
                scr_msg(key_msg, 1);
 
319
                
 
320
                while (1) {
 
321
                        place(curshape, pos, 1);
 
322
                        scr_update();
 
323
                        place(curshape, pos, 0);
 
324
                        c = tgetchar();
 
325
                        if (c < 0) {
 
326
                                /*
 
327
                                 * Timeout.  Move down if possible.
 
328
                                 */
 
329
                                if (fits_in(curshape, pos + B_COLS)) {
 
330
                                        pos += B_COLS;
 
331
                                        continue;
 
332
                                }
 
333
                                
 
334
                                /*
 
335
                                 * Put up the current shape `permanently',
 
336
                                 * bump score, and elide any full rows.
 
337
                                 */
 
338
                                place(curshape, pos, 1);
 
339
                                score++;
 
340
                                elide();
 
341
                                
 
342
                                /*
 
343
                                 * Choose a new shape.  If it does not fit,
 
344
                                 * the game is over.
 
345
                                 */
 
346
                                curshape = nextshape;
 
347
                                nextshape = randshape();
 
348
                                pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
 
349
                                
 
350
                                if (!fits_in(curshape, pos))
 
351
                                        break;
 
352
                                
 
353
                                continue;
 
354
                        }
 
355
                        
 
356
                        /*
 
357
                         * Handle command keys.
 
358
                         */
 
359
                        if (c == keys[5]) {
 
360
                                /* quit */
 
361
                                break;
 
362
                        }
 
363
                        
 
364
                        if (c == keys[4]) {
 
365
                                static char msg[] =
 
366
                                    "paused - press RETURN to continue";
 
367
                                
 
368
                                place(curshape, pos, 1);
 
369
                                do {
 
370
                                        scr_update();
 
371
                                        scr_msg(key_msg, 0);
 
372
                                        scr_msg(msg, 1);
 
373
                                        (void) fflush(stdout);
 
374
                                } while (rwait((struct timeval *) NULL) == -1);
 
375
                                
 
376
                                scr_msg(msg, 0);
 
377
                                scr_msg(key_msg, 1);
 
378
                                place(curshape, pos, 0);
 
379
                                continue;
 
380
                        }
 
381
                        
 
382
                        if (c == keys[0]) {
 
383
                                /* move left */
 
384
                                if (fits_in(curshape, pos - 1))
 
385
                                        pos--;
 
386
                                continue;
 
387
                        }
 
388
                        
 
389
                        if (c == keys[1]) {
 
390
                                /* turn */
 
391
                                const struct shape *new =
 
392
                                    &shapes[classic ? curshape->rotc : curshape->rot];
 
393
                                
 
394
                                if (fits_in(new, pos))
 
395
                                        curshape = new;
 
396
                                continue;
 
397
                        }
 
398
                        
 
399
                        if (c == keys[2]) {
 
400
                                /* move right */
 
401
                                if (fits_in(curshape, pos + 1))
 
402
                                        pos++;
 
403
                                continue;
 
404
                        }
 
405
                        
 
406
                        if (c == keys[3]) {
 
407
                                /* move to bottom */
 
408
                                while (fits_in(curshape, pos + B_COLS)) {
 
409
                                        pos += B_COLS;
 
410
                                        score++;
 
411
                                }
 
412
                                continue;
 
413
                        }
 
414
                        
 
415
                        if (c == '\f') {
 
416
                                scr_clear();
 
417
                                scr_msg(key_msg, 1);
 
418
                        }
 
419
                }
 
420
                
 
421
                scr_clear();
 
422
                loadscores();
 
423
                insertscore(score, level);
 
424
                savescores();
 
425
                score = 0;
 
426
        }
 
427
        
 
428
        scr_clear();
 
429
        printf("\nGame over.\n");
 
430
        scr_end();
 
431
        
 
432
        return 0;
 
433
}
 
434
 
 
435
void usage(void)
 
436
{
 
437
        fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
 
438
        exit(1);
 
439
}
 
440
 
 
441
/** @}
 
442
 */