-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathgame.c
128 lines (107 loc) · 3.17 KB
/
game.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "nalloc.h"
#include "tetris.h"
/* FIXME: inaccurate */
#define SECOND 1e5
typedef enum { MOVE_LEFT, MOVE_RIGHT, DROP, ROTCW, ROTCCW, NONE } ui_move_t;
static ui_move_t move_next(grid_t *g, block_t *b, shape_stream_t *ss, float *w)
{
static move_t *move = NULL;
if (!move) {
/* New block. just display it. */
move = best_move(g, b, ss, w);
return NONE;
}
/* Make moves one at a time. rotations first */
if (b->rot != move->rot) {
int inc = (move->rot - b->rot + 4) % 4;
return inc < 3 ? ROTCW : ROTCCW;
}
if (b->offset.x != move->col)
return move->col > b->offset.x ? MOVE_RIGHT : MOVE_LEFT;
/* No further action. just drop */
move = NULL;
return DROP;
}
void auto_play(float *w)
{
grid_t *g = grid_new(GRID_HEIGHT, GRID_WIDTH);
block_t *b = block_new();
tui_setup(g);
bool dropped = true;
shape_stream_t *ss = shape_stream_new();
while (1) {
switch (tui_scankey()) {
case INPUT_PAUSE: {
tui_prompt(g, "Paused");
while (tui_scankey() != INPUT_PAUSE)
usleep(0.1 * SECOND);
tui_prompt(g, " ");
break;
}
case INPUT_QUIT:
goto cleanup;
case INPUT_INVALID:
break;
}
if (dropped) {
/* Generate a new block */
shape_stream_pop(ss);
block_init(b, shape_stream_peek(ss, 0));
grid_block_center_elevate(g, b);
/* If we can not place a new block, game over */
if (grid_block_intersects(g, b))
break;
tui_block_print_shadow(b, 1 + 1, g);
/* Simulate "wait! computer is thinking" */
usleep(0.3 * SECOND);
dropped = false;
} else {
ui_move_t move = move_next(g, b, ss, w);
/* Simulate "wait! computer is thinking" */
usleep(0.5 * SECOND);
/* Unpaint old block */
tui_block_print_shadow(b, 0, g);
switch (move) {
case MOVE_LEFT:
case MOVE_RIGHT:
grid_block_move(g, b, move == MOVE_LEFT ? LEFT : RIGHT, 1);
break;
case DROP:
dropped = true;
break;
case ROTCW:
case ROTCCW:
grid_block_rotate(g, b, 1 + 2 * (move == ROTCCW));
break;
case NONE:
break;
}
int cleared = 0;
if (dropped) {
grid_block_drop(g, b);
grid_block_add(g, b);
cleared = grid_clear_lines(g);
}
if (cleared) {
/* Have to repaint the whole grid */
tui_grid_print(g);
} else {
/* repaint in new location */
tui_block_print_shadow(b, 1 + (int) (!dropped), g);
}
}
tui_refresh();
}
tui_prompt(g, "Game Over!");
sleep(3);
cleanup:
tui_quit();
nfree(ss);
nfree(g);
nfree(b);
free_shape();
}