Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15 7u83 1
#include <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <keyboard.h>
5
#include <event.h>
6
 
7
// 2048.
8
// y increases down, x increases right.
9
 
10
// square board of this size
11
#define BOARDSIZE 4
12
 
13
// square boarder
14
#define BORDER 4
15
 
16
typedef struct Tile Tile;
17
 
18
struct Tile {
19
	int value;
20
	Image *color;
21
};
22
 
23
Tile grid[BOARDSIZE][BOARDSIZE];
24
Tile *grid1 = &grid[0][0];
25
int score = 0;
26
int gameover = 0;
27
 
28
Font *bigfont;
29
 
30
Image *colors[13];
31
 
32
Image *
33
val2col(int val)
34
{
35
	int i;
36
 
37
	if(val == 0)
38
		return colors[0];
39
 
40
	for(i = 32; (val & (1<<i)) == 0; i--)
41
		;
42
 
43
	if(i < nelem(colors))
44
		return colors[i];
45
 
46
	return colors[nelem(colors)-1];
47
}
48
 
49
 
50
void
51
initcolors(void)
52
{
53
	int i;
54
 
55
	int cols[] = {
56
		0xcdc0b4ff, 0xeee4daff, 0xede0c8ff, 0xf2b179ff, 0xf59563ff,
57
		0xf67c5fff, 0xf65e36ff, 0xedcf72ff, 0xedcc61ff,
58
		0xedc850ff, 0xedc53fff, 0xedc22eff, 0x3c3a32ff };
59
 
60
	for(i = 0; i < nelem(cols); i++) {
61
		colors[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, cols[i]);
62
	}
63
}
64
 
65
void
66
initboard(void)
67
{
68
	int x, y, x2, y2;
69
 
70
	for(y = 0; y < BOARDSIZE; y++) {
71
		for(x = 0; x < BOARDSIZE; x++) {
72
			grid[y][x].value = 0;
73
			grid[y][x].color = val2col(0);
74
		}
75
	}
76
 
77
	y = nrand(BOARDSIZE);
78
	x = nrand(BOARDSIZE);
79
 
80
	grid[y][x].value = 2;
81
	grid[y][x].color = val2col(2);;
82
 
83
	y2 = nrand(BOARDSIZE);
84
	x2 = nrand(BOARDSIZE);
85
 
86
	while(y == y2 || x == x2) {
87
		y2 = nrand(BOARDSIZE);
88
		x2 = nrand(BOARDSIZE);
89
	}
90
 
91
	grid[y2][x2].value = 2;
92
	grid[y2][x2].color = val2col(2);;
93
 
94
	score = 0;
95
}
96
 
97
void
98
redraw(void)
99
{
100
	Rectangle r;
101
	Point p, sp;
102
	int x, y; // grid indexes
103
	int width, height; // of each tile
104
	char buf[64];
105
 
106
	Point strp;
107
	int strwid;
108
 
109
	r = insetrect(screen->r, BORDER);
110
	sp = r.min;
111
	r.min.y += font->height;
112
	p = r.min;
113
 
114
	width = Dx(r) / BOARDSIZE;
115
	height = Dy(r) / BOARDSIZE;
116
 
117
	draw(screen, screen->r, display->black, nil, ZP);
118
 
119
	snprint(buf, sizeof buf, "Score: %d", score);
120
	string(screen, sp, display->white, ZP, font, buf);
121
 
122
	for(y = 0; y < BOARDSIZE; y++) {
123
		for(x = 0; x < BOARDSIZE; x++) {
124
			r = Rect(p.x + (x * width), p.y + (y * height), p.x + (x * width) + width, p.y + (y * height) + height);
125
			r = insetrect(r, BORDER);
126
			draw(screen, r, grid[y][x].color, nil, ZP);
127
 
128
			if(grid[y][x].value == 0)
129
				continue;
130
 
131
			snprint(buf, sizeof buf, "%d", grid[y][x].value);
132
			strwid = stringwidth(bigfont, buf);
133
			strp = Pt(Dx(r)/2, Dy(r)/2);
134
			strp.x -= strwid / 2;
135
			string(screen, addpt(r.min, strp), display->black, ZP, bigfont, buf);
136
		}
137
	}
138
}
139
 
140
void
141
addrandom(void)
142
{
143
	int x, y, nfree;
144
	Tile **tfree;
145
 
146
	nfree = 0;
147
 
148
	for(x = 0; x < BOARDSIZE; x++) {
149
		for(y = 0; y < BOARDSIZE; y++) {
150
			if(grid[x][y].value == 0)
151
				nfree++;
152
		}
153
	}
154
 
155
	if(nfree > 0) {
156
		tfree = mallocz(sizeof(Tile*) * nfree, 1);
157
		nfree = 0;
158
		for(x = 0; x < BOARDSIZE; x++) {
159
			for(y = 0; y < BOARDSIZE; y++) {
160
				if(grid[x][y].value == 0)
161
					tfree[nfree++] = &grid[x][y];
162
			}
163
		}
164
 
165
		// 10% chance of 4.
166
		if(nrand(10) == 0)
167
			x = 4;
168
		else
169
			x = 2;
170
 
171
		nfree = nrand(nfree);
172
 
173
		tfree[nfree]->value = x;
174
		tfree[nfree]->color = val2col(x);
175
 
176
		free(tfree);
177
	}
178
}
179
 
180
void
181
buildrow(Tile *out[BOARDSIZE], int n, int dir)
182
{
183
	int i, start, add;
184
	add = start = 0;
185
 
186
	switch(dir) {
187
	case Kright:
188
		add = 1;
189
		start = n*BOARDSIZE;
190
		break;
191
	case Kleft:
192
		add = -1;
193
		start = n*BOARDSIZE + (BOARDSIZE-1);
194
		break;
195
	case Kdown:
196
		add = BOARDSIZE;
197
		start = n;
198
		break;
199
	case Kup:
200
		add = -BOARDSIZE;
201
		start = (BOARDSIZE-1)*BOARDSIZE + n;
202
		break;
203
	}
204
 
205
	for(i = 0; i < BOARDSIZE; i++) {
206
		out[i] = &grid1[add*i + start];
207
	}
208
}
209
 
210
int
211
merge(Tile *row[BOARDSIZE])
212
{
213
	int i, j, moved;
214
	Tile nrow[BOARDSIZE];
215
 
216
	for(i = 0; i < BOARDSIZE; i++) {
217
		nrow[i].value = 0;
218
		nrow[i].color = val2col(0);
219
	}
220
 
221
	j = BOARDSIZE-1;
222
	for(i = j; i >= 0; i--) {
223
		if(row[i]->value == 0) {
224
			;
225
		} else if(nrow[j].value == 0) {
226
			nrow[j] = *row[i];
227
		} else if(nrow[j].value == row[i]->value) {
228
			score += nrow[j].value *= 2;
229
			nrow[j].color = val2col(nrow[j].value);
230
			j--;
231
		} else {
232
			nrow[--j] = *row[i];
233
		}
234
	}
235
 
236
	moved = 0;
237
	for(i = 0; i < BOARDSIZE; i++) {
238
		if(nrow[i].value != row[i]->value)
239
			moved = 1;
240
 
241
		*row[i] = nrow[i];
242
	}
243
 
244
	return moved;
245
}
246
 
247
void
248
shift(int dir)
249
{
250
	Tile *cur[BOARDSIZE];
251
	int i;
252
	int moved = 0;
253
 
254
	for(i = 0; i < BOARDSIZE; i++) {
255
		//print("%d\n", i);
256
		buildrow(cur, i, dir);
257
		moved = merge(cur) || moved;
258
	}
259
 
260
	if(moved) {
261
		addrandom();
262
		// check gameover here
263
	}
264
}
265
 
266
void
267
main(int argc, char **argv)
268
{
269
	char *fontname;
270
 
271
	USED(argc);
272
	USED(argv);
273
 
274
	if(initdraw(0, 0, "2048") < 0)
275
		sysfatal("initdraw: %r");
276
 
277
	fontname = "/lib/font/bit/fixed/unicode.10x20.font";
278
	if((bigfont = openfont(display, fontname)) == nil)
279
		sysfatal("can't open font %s: %r", fontname);
280
 
281
	einit(Ekeyboard|Emouse);
282
	srand(time(0));
283
 
284
	initcolors();
285
	initboard();
286
 
287
	redraw();
288
 
289
	while(1) {
290
		int key;
291
		redraw();
292
		flushimage(display, 1);
293
 
294
		switch(key = ekbd()) {
295
		case 0x7f: // p9p lacks Kdel
296
		case 'q':
297
			// quit
298
			exits(0);
299
			break;
300
		case ' ':
301
			// reset board
302
			initboard();
303
		case Kup:
304
		case Kdown:
305
		case Kleft:
306
		case Kright:
307
			shift(key);
308
			break;
309
		}
310
	}
311
}
312
 
313
void
314
eresized(int new)
315
{
316
	if(new && getwindow(display, Refnone) < 0)
317
		sysfatal("getwindow: %r");
318
 
319
	redraw();
320
}