Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* code from mark huckvale: http://www.phon.ucl.ac.uk/home/mark/sudoku/ */
2
 
3
#include <u.h>
4
#include <libc.h>
5
#include <draw.h>
6
#include <event.h>
7
 
8
#include "sudoku.h"
9
 
10
char *imgdir = "/sys/games/lib/sudoku/images";
11
char *lvldir = "/sys/games/lib/sudoku/boards";	/* level library dir */
12
 
13
int selected;	/* which digit do we have selected? */
14
 
15
Image *background;	/* DPaleyellow */
16
Image *backselect;	/* DPalebluegreen */
17
Image *blink;		/* DDarkyellow */
18
Image *brdr;		/* 0x55555555 */
19
Image *fixed;		/* DBlue */
20
Image *wrong;		/* DRed */
21
Image *dig[10];		/* digit masks */
22
 
23
Dir *dir;
24
int numlevels;
25
int curlevel;
26
 
27
char *buttons[] = 
28
{
29
	"new",
30
	"check",
31
	"solve",
32
	"clear",
33
	"save",
34
	"load",
35
	"print",
36
	"offline",
37
	"exit",
38
 
39
};
40
 
41
Menu menu = 
42
{
43
	buttons
44
};
45
 
46
Menu lmenu =
47
{
48
	nil,
49
	genlevels,
50
	0,
51
};
52
 
53
int
54
readlevels(char *leveldir)
55
{
56
	int fd, n;
57
 
58
	if((fd = open(leveldir, OREAD)) < 0)
59
		return -1;
60
 
61
	n = dirreadall(fd, &dir);
62
	close(fd);
63
 
64
	return n;	
65
}
66
 
67
char *
68
genlevels(int i)
69
{
70
	if(numlevels == 0)
71
		numlevels = readlevels(lvldir);
72
 
73
	if(numlevels > 0 && i < numlevels)
74
		return (dir+i)->name;
75
 
76
	return nil;
77
}
78
 
79
void
80
convert(Cell *brd, int *board)
81
{
82
	int i;
83
 
84
	for(i = 0; i < Psize; i++) {
85
		brd[i].digit = board[i] & Digit;
86
		if(brd[i].digit < 0 || brd[i].digit > 9)
87
			brd[i].digit = -1;
88
		brd[i].solve = (board[i] & Solve) >> 4;
89
		brd[i].locked = board[i] & MLock;
90
	}
91
	memcpy(obrd, brd, Psize * sizeof(Cell));
92
}
93
 
94
Image *
95
eallocimage(Rectangle r, int repl, uint color)
96
{
97
	Image *tmp;
98
 
99
	tmp = allocimage(display, r, screen->chan, repl, color);
100
	if(tmp == nil)
101
		sysfatal("cannot allocate buffer image: %r");
102
 
103
	return tmp;
104
}
105
 
106
Image *
107
eloadfile(char *path)
108
{
109
	Image *img;
110
	int fd;
111
 
112
	fd = open(path, OREAD);
113
	if(fd < 0) {
114
		fprint(2, "cannot open image file %s: %r\n", path);
115
		exits("image");
116
	}
117
	img = readimage(display, fd, 0);
118
	if(img == nil)
119
		sysfatal("cannot load image: %r");
120
	close(fd);
121
 
122
	return img;
123
}
124
 
125
 
126
void
127
clearboard(Cell *board)
128
{
129
	int i;
130
 
131
	for(i = 0; i < Psize; i++) {
132
		board[i].digit = -1;
133
		board[i].solve = 0;
134
		board[i].locked = 0;
135
	}
136
}
137
 
138
void
139
solveboard(Cell *board)
140
{
141
	int i;
142
 
143
	for(i = 0; i < Psize; i++) {
144
		board[i].digit = board[i].solve;
145
	}
146
}
147
 
148
 
149
int
150
checkpossible(Cell *board, int x, int y, int num)
151
{
152
	int i, j;
153
 
154
	for(i = 0; i < Brdsize; i++) {
155
		if(board[i*Brdsize + y].digit == num && i != x)
156
			return 0;
157
		if(board[x*Brdsize + i].digit == num && i != y)	
158
			return 0;
159
	}
160
 
161
	for(i = x - (x%3); i < x - (x%3) + 3; i++)
162
		for(j = y - (y%3); j < y - (y%3) + 3; j++)
163
			if((i != x && j != y) && board[i*Brdsize + j].digit == num)
164
				return 0;
165
 
166
	return 1;
167
}
168
 
169
void
170
resize(void)
171
{
172
	int fd;
173
 
174
	fd = open("/dev/wctl", OWRITE);
175
	if(fd >= 0){
176
		fprint(fd, "resize -dx %d -dy %d", Maxx, Maxy);
177
		close(fd);
178
	}
179
 
180
}
181
 
182
void
183
drawcell(int x, int y, int num, Image *col)
184
{
185
	Rectangle r = Rect(x*Square, y*Square, (x+1)*Square, (y+1)*Square);
186
 
187
	if(num < 0 || num > 9)
188
		return;
189
 
190
	r = insetrect(r, Border);
191
	r = rectaddpt(r, Pt(0, Square));
192
	r.max = addpt(r.max, Pt(2, 2));
193
 
194
	draw(screen, rectaddpt(r, screen->r.min), col, dig[num], ZP);
195
}
196
 
197
void
198
drawboard(void)
199
{
200
	int i;
201
 
202
	for(i = 0; i < Psize; i++) {
203
		drawcell(i / Brdsize, i % Brdsize, brd[i].digit, brd[i].locked ? fixed : display->black);
204
	}
205
}
206
 
207
void
208
drawchecked(Cell *brd)
209
{
210
	int i;
211
 
212
	for(i = 0; i < Psize; i++) {
213
		if(brd[i].locked)
214
			drawcell(i / Brdsize, i % Brdsize, brd[i].digit, fixed);
215
		else 
216
			drawcell(i / Brdsize, i % Brdsize, brd[i].digit, 
217
					checkpossible(brd, i / Brdsize, i % Brdsize, brd[i].digit) ? display->black : wrong);
218
	}
219
}
220
 
221
void
222
drawscreen(void)
223
{
224
	Point l1, l2;
225
	int i;
226
 
227
	draw(screen, screen->r, brdr, nil, ZP);
228
	draw(screen, insetrect(screen->r, Border), background, nil, ZP);
229
	for(i = 0; i < Brdsize; i++) {
230
		l1 = addpt(screen->r.min, Pt(i*Square, Square));
231
		l2 = addpt(screen->r.min, Pt(i*Square, Maxy));
232
		line(screen, l1, l2, Endsquare, Endsquare, (i%3) == 0 ? Thickline : Line, brdr, ZP); 
233
		l1 = addpt(screen->r.min, Pt(0, (i+1)*Square));
234
		l2 = addpt(screen->r.min, Pt(Maxx, (i+1)*Square));
235
		line(screen, l1, l2, Endsquare, Endsquare, (i%3) == 0 ? Thickline : Line, brdr, ZP); 
236
	}
237
	for(i = 1; i < 10; i++) {
238
		drawbar(i, (selected == i) ? 1 : 0);
239
	}
240
	drawboard();
241
	flushimage(display, 1);
242
}
243
 
244
 
245
void
246
drawbar(int digit, int selected)
247
{
248
	Rectangle r = Rect((digit - 1)*Square, 0, digit*Square, Square);
249
 
250
	if(digit < 1 || digit > 9)
251
		return;
252
 
253
	r = insetrect(r, Border);
254
	r.max = addpt(r.max, Pt(2, 2));
255
	draw(screen, rectaddpt(r, screen->r.min), selected ? backselect : background, nil, ZP);
256
	draw(screen, rectaddpt(r, screen->r.min), display->black, dig[digit-1], ZP);
257
}
258
 
259
void
260
eresized(int new)
261
{
262
	Point p;
263
	char path[256];
264
	int i;
265
 
266
	if(new && getwindow(display, Refnone) < 0)
267
		sysfatal("can't reattach to window");
268
 
269
	if(background == nil) 
270
		background = eallocimage(Rect(0, 0, 1, 1), 1, DPaleyellow);
271
	if(backselect == nil) 
272
		backselect = eallocimage(Rect(0, 0, 1, 1), 1, DPalebluegreen);
273
	if(blink == nil) 
274
		blink = eallocimage(Rect(0, 0, 1, 1), 1, DDarkyellow);
275
	if(brdr == nil)
276
		brdr = eallocimage(Rect(0, 0, 1, 1), 1, 0x55555555);
277
	if(fixed == nil)
278
		fixed = eallocimage(Rect(0, 0, 1, 1), 1, DBlue);
279
	if(wrong == nil)
280
		wrong = eallocimage(Rect(0, 0, 1, 1), 1, DRed);
281
	if(dig[0] == nil) {
282
		for(i = 0; i < 9; i++) {
283
			snprint(path, 256, "%s/%d.bit", imgdir, i+1);
284
			dig[i] = eloadfile(path);
285
		}
286
	}
287
 
288
	p = Pt(Dx(screen->r), Dy(screen->r));
289
	if(!new || !eqpt(p, Pt(Maxx - 8, Maxy - 8)))
290
		resize();
291
 
292
	drawscreen();
293
}
294
 
295
void
296
main(int argc, char *argv[])
297
{
298
	Mouse m;
299
	Event e;
300
	Point p;
301
	int last1 = 0;	/* was the button clicked last time? */
302
 
303
	USED(argc, argv);
304
 
305
	if(initdraw(nil, nil, "sudoku") < 0)
306
		sysfatal("initdraw failed: %r");
307
 
308
	einit(Emouse|Ekeyboard);
309
 
310
 
311
	clearboard(brd);
312
	eresized(0);
313
 
314
	srand(time(0)*getpid());
315
	makep();
316
	convert(brd, board);
317
 
318
	drawscreen();
319
	for(;;) {
320
		switch(event(&e)) {
321
		case Emouse:
322
			m = e.mouse;
323
			if(m.buttons&1) {
324
				if(last1 == 0) {
325
					last1 = 1;
326
					p = subpt(m.xy, screen->r.min);
327
					if(ptinrect(p, Rect(0, 0, Maxx, Square+Border))) {
328
						if(p.x/Square == selected - 1) {
329
							drawbar(selected, 0);
330
							selected = 0;
331
						} else {
332
							selected = p.x/Square + 1;
333
						}
334
					} else {
335
						Point lp = divpt(p, Square);
336
						lp.y--;
337
 
338
						if(brd[lp.x * Brdsize + lp.y].locked)
339
							break;
340
 
341
						if(selected) {
342
							brd[lp.x * Brdsize + lp.y].digit = selected - 1;
343
						} else {
344
							brd[lp.x * Brdsize + lp.y].digit = -1;
345
						}			
346
					}
347
					drawscreen();
348
				}
349
			} else {
350
				last1 = 0;
351
			}
352
 
353
			if(m.buttons&2) {
354
				char *str;
355
				int l;
356
				/* levels start from 1 */
357
				lmenu.lasthit = curlevel;
358
				l = emenuhit(2, &m, &lmenu);
359
				if(l >= 0){
360
					curlevel = l;
361
					str = smprint("%s/%s", lvldir, (dir+curlevel)->name);
362
					if(loadlevel(str, brd) < 0)
363
						clearboard(brd);
364
					memcpy(obrd, brd, Psize * sizeof(Cell));
365
					free(str);
366
				}
367
				drawscreen();
368
			}
369
			if(m.buttons&4) {
370
				switch(emenuhit(3, &m, &menu)) {
371
				case 0: 	/* new */
372
					makep();
373
					convert(brd, board);
374
					drawscreen();
375
					break;
376
				case 1:		/* solve */
377
					drawchecked(brd);
378
					break;
379
				case 2:		/* solve */
380
					solveboard(brd);
381
					drawscreen();
382
					break;
383
				case 3:		/* clear */
384
					memcpy(brd, obrd, Psize * sizeof(Cell));
385
					drawscreen();
386
					break;
387
				case 4:		/* save */
388
					savegame(brd);
389
					drawscreen();
390
					break;
391
				case 5:		/* load */
392
					if(loadgame(brd) < 0) {
393
						clearboard(brd);
394
					}
395
					memcpy(obrd, brd, Psize * sizeof(Cell));
396
					drawscreen();
397
					break;
398
				case 6:		/* print */
399
					printboard(brd);
400
					break;
401
				case 7:		/* offline */
402
					fprettyprintbrd(brd);
403
					break;
404
				case 8:		/* exit */
405
					exits(nil);
406
				}
407
			}
408
			break;
409
 
410
		case Ekeyboard:
411
			switch(e.kbdc) {
412
			case 127:
413
			case 'q':
414
			case 'Q':
415
				exits(nil);
416
			default:
417
				break;
418
			}
419
			break;
420
		}
421
	}
422
}