Subversion Repositories planix.SVN

Rev

Rev 15 | Details | Compare with Previous | 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;
16 7u83 135
			strp.y -= font->height / 2;
136
 
15 7u83 137
			string(screen, addpt(r.min, strp), display->black, ZP, bigfont, buf);
138
		}
139
	}
140
}
141
 
142
void
143
addrandom(void)
144
{
145
	int x, y, nfree;
146
	Tile **tfree;
147
 
148
	nfree = 0;
149
 
150
	for(x = 0; x < BOARDSIZE; x++) {
151
		for(y = 0; y < BOARDSIZE; y++) {
152
			if(grid[x][y].value == 0)
153
				nfree++;
154
		}
155
	}
156
 
157
	if(nfree > 0) {
158
		tfree = mallocz(sizeof(Tile*) * nfree, 1);
159
		nfree = 0;
160
		for(x = 0; x < BOARDSIZE; x++) {
161
			for(y = 0; y < BOARDSIZE; y++) {
162
				if(grid[x][y].value == 0)
163
					tfree[nfree++] = &grid[x][y];
164
			}
165
		}
166
 
167
		// 10% chance of 4.
168
		if(nrand(10) == 0)
169
			x = 4;
170
		else
171
			x = 2;
172
 
173
		nfree = nrand(nfree);
174
 
175
		tfree[nfree]->value = x;
176
		tfree[nfree]->color = val2col(x);
177
 
178
		free(tfree);
179
	}
180
}
181
 
182
void
183
buildrow(Tile *out[BOARDSIZE], int n, int dir)
184
{
185
	int i, start, add;
186
	add = start = 0;
187
 
188
	switch(dir) {
189
	case Kright:
190
		add = 1;
191
		start = n*BOARDSIZE;
192
		break;
193
	case Kleft:
194
		add = -1;
195
		start = n*BOARDSIZE + (BOARDSIZE-1);
196
		break;
197
	case Kdown:
198
		add = BOARDSIZE;
199
		start = n;
200
		break;
201
	case Kup:
202
		add = -BOARDSIZE;
203
		start = (BOARDSIZE-1)*BOARDSIZE + n;
204
		break;
205
	}
206
 
207
	for(i = 0; i < BOARDSIZE; i++) {
208
		out[i] = &grid1[add*i + start];
209
	}
210
}
211
 
212
int
213
merge(Tile *row[BOARDSIZE])
214
{
215
	int i, j, moved;
216
	Tile nrow[BOARDSIZE];
217
 
218
	for(i = 0; i < BOARDSIZE; i++) {
219
		nrow[i].value = 0;
220
		nrow[i].color = val2col(0);
221
	}
222
 
223
	j = BOARDSIZE-1;
224
	for(i = j; i >= 0; i--) {
225
		if(row[i]->value == 0) {
226
			;
227
		} else if(nrow[j].value == 0) {
228
			nrow[j] = *row[i];
229
		} else if(nrow[j].value == row[i]->value) {
230
			score += nrow[j].value *= 2;
231
			nrow[j].color = val2col(nrow[j].value);
232
			j--;
233
		} else {
234
			nrow[--j] = *row[i];
235
		}
236
	}
237
 
238
	moved = 0;
239
	for(i = 0; i < BOARDSIZE; i++) {
240
		if(nrow[i].value != row[i]->value)
241
			moved = 1;
242
 
243
		*row[i] = nrow[i];
244
	}
245
 
246
	return moved;
247
}
248
 
249
void
250
shift(int dir)
251
{
252
	Tile *cur[BOARDSIZE];
253
	int i;
254
	int moved = 0;
255
 
256
	for(i = 0; i < BOARDSIZE; i++) {
257
		//print("%d\n", i);
258
		buildrow(cur, i, dir);
259
		moved = merge(cur) || moved;
260
	}
261
 
262
	if(moved) {
263
		addrandom();
264
		// check gameover here
265
	}
266
}
267
 
268
void
269
main(int argc, char **argv)
270
{
271
	char *fontname;
272
 
273
	USED(argc);
274
	USED(argv);
275
 
276
	if(initdraw(0, 0, "2048") < 0)
277
		sysfatal("initdraw: %r");
278
 
279
	fontname = "/lib/font/bit/fixed/unicode.10x20.font";
280
	if((bigfont = openfont(display, fontname)) == nil)
281
		sysfatal("can't open font %s: %r", fontname);
282
 
283
	einit(Ekeyboard|Emouse);
284
	srand(time(0));
285
 
286
	initcolors();
287
	initboard();
288
 
289
	redraw();
290
 
291
	while(1) {
292
		int key;
293
		redraw();
294
		flushimage(display, 1);
295
 
296
		switch(key = ekbd()) {
297
		case 0x7f: // p9p lacks Kdel
298
		case 'q':
299
			// quit
300
			exits(0);
301
			break;
302
		case ' ':
303
			// reset board
304
			initboard();
305
		case Kup:
306
		case Kdown:
307
		case Kleft:
308
		case Kright:
309
			shift(key);
310
			break;
311
		}
312
	}
313
}
314
 
315
void
316
eresized(int new)
317
{
318
	if(new && getwindow(display, Refnone) < 0)
319
		sysfatal("getwindow: %r");
320
 
321
	redraw();
322
}