changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/games/glendy.c

changeset 4350: 1f9d7811d546
parent: 79a8cc0be6ed
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 
6 enum{
7  /* difficulty levels (how many circles are initially occupied) */
8  DEasy, /* 10≤x<15 */
9  DMed, /* 5≤x<10 */
10  DHard, /* 0≤x<5 */
11 
12  /* dynamic? original game has a fixed grid size, but we don't need to abide by it */
13  SzX = 11,
14  SzY = 11,
15 
16  Border = 10,
17  /* movement directions */
18  NE,
19  E,
20  SE,
21  SW,
22  W,
23  NW,
24 
25  Won = 1, /* game-ending states */
26  Lost = 2,
27 };
28 
29 Font *font;
30 
31 int difficulty = DMed;
32 int finished;
33 
34 int grid[SzX][SzY];
35 int ogrid[SzX][SzY]; /* so we can restart levels */
36 
37 Image *gl; /* glenda */
38 Image *glm; /* glenda's mask */
39 Image *cc; /* clicked */
40 Image *ec; /* empty; not clicked */
41 Image *bg;
42 Image *lost;
43 Image *won;
44 
45 
46 char *mbuttons[] =
47 {
48  "easy",
49  "medium",
50  "hard",
51  0
52 };
53 
54 char *rbuttons[] =
55 {
56  "new",
57  "reset",
58  "exit",
59  0
60 };
61 
62 Menu mmenu =
63 {
64  mbuttons,
65 };
66 
67 Menu rmenu =
68 {
69  rbuttons,
70 };
71 
72 Image *
73 eallocimage(Rectangle r, int repl, uint color)
74 {
75  Image *tmp;
76 
77  tmp = allocimage(display, r, screen->chan, repl, color);
78  if(tmp == nil)
79  sysfatal("cannot allocate buffer image: %r");
80 
81  return tmp;
82 }
83 
84 Image *
85 eloadfile(char *path)
86 {
87  Image *img;
88  int fd;
89 
90  fd = open(path, OREAD);
91  if(fd < 0) {
92  fprint(2, "cannot open image file %s: %r\n", path);
93  exits("image");
94  }
95  img = readimage(display, fd, 0);
96  if(img == nil)
97  sysfatal("cannot load image: %r");
98  close(fd);
99 
100  return img;
101 }
102 
103 
104 void
105 allocimages(void)
106 {
107  Rectangle one = Rect(0, 0, 1, 1);
108 
109  cc = eallocimage(one, 1, 0x777777FF);
110  ec = eallocimage(one, 1, DPalegreen);
111  bg = eallocimage(one, 1, DPurpleblue);
112  lost = eallocimage(one, 1, DRed);
113  won = eallocimage(one, 1, DGreen);
114  gl = eloadfile("/lib/face/48x48x4/g/glenda.1");
115 
116  glm = allocimage(display, Rect(0, 0, 48, 48), gl->chan, 1, DCyan);
117  if(glm == nil)
118  sysfatal("cannot allocate mask: %r");
119 
120  draw(glm, glm->r, display->white, nil, ZP);
121  gendraw(glm, glm->r, display->black, ZP, gl, gl->r.min);
122  freeimage(gl);
123  gl = display->black;
124 
125 
126 }
127 
128 /* unnecessary calculations here, but it's fine */
129 Point
130 board2pix(int x, int y)
131 {
132  float d, rx, ry, yh;
133  int nx, ny;
134 
135  d = (float)(Dx(screen->r) > Dy(screen->r)) ? Dy(screen->r) -20 : Dx(screen->r) -20;
136  rx = d/(float)SzX;
137  rx = rx/2.0;
138  ry = d/(float)SzY;
139  ry = ry/2.0;
140 
141  yh = ry/3.73205082;
142 
143  nx = (int)((float)x*rx*2.0+rx +(y%2?rx:0.0)); /* nx = x*(2rx) + rx + rx (conditional) */
144  ny = (int)((float)y*(ry*2.0-(y>0?yh:0.0)) + ry); /* ny = y*(2ry-yh) +ry */
145  return Pt(nx, ny);
146 }
147 
148 Point
149 pix2board(int x, int y)
150 {
151  float d, rx, ry, yh;
152  int ny, nx;
153 
154  /* XXX: float→int causes small rounding errors */
155 
156  d = (float)(Dx(screen->r) > Dy(screen->r)) ? Dy(screen->r) -20: Dx(screen->r)-20;
157  rx = d/(float)SzX;
158  rx = rx/2.0;
159  ry =d/(float)SzY;
160  ry = ry/2.0;
161 
162  yh = ry/3.73205082;
163 
164  /* reverse board2pix() */
165  ny = (int)(((float)y - ry)/(2*ry - ((y>2*ry)?yh:0.0)) + 0.5); /* ny = (y - ry)/(2ry-yh) */
166  nx = (int)(((float)x - rx - (ny%2?rx:0.0))/(rx*2.0) + 0.5); /* nx = (x - rx - rx)/2rx */
167 
168  if (nx >= SzX)
169  nx = SzX-1;
170  if (ny >=SzY)
171  ny = SzY-1;
172 
173  return Pt(nx, ny);
174 }
175 
176 void
177 initlevel(void)
178 {
179  int i, cnt = 10, x, y;
180 
181  for(x = 0; x < SzX; x++)
182  for(y = 0; y < SzY; y++)
183  ogrid[x][y] = 100;
184 
185  switch(difficulty){
186  case DEasy:
187  cnt = 10 + nrand(5);
188  break;
189  case DMed:
190  cnt = 5 + nrand(5);
191  break;
192  case DHard:
193  cnt = nrand(5);
194  break;
195  }
196  for(i = 0; i < cnt; i++) {
197  do {
198  x = nrand(SzX);
199  y = nrand(SzY);
200  } while(ogrid[x][y] != 100);
201  ogrid[x][y] = 999;
202  }
203 
204  ogrid[SzX/2][SzY/2] = 1000;
205 
206  memcpy(grid, ogrid, sizeof grid);
207 
208  finished = 0;
209 
210 }
211 
212 void
213 drawlevel(void)
214 {
215  Point p;
216  int x, y, rx, ry, d;
217  char *s = nil;
218 
219  if(finished)
220  draw(screen, screen->r, finished==Won?won:lost, nil, ZP);
221  else
222  draw(screen, screen->r, bg, nil, ZP);
223 
224  d = (Dx(screen->r) > Dy(screen->r)) ? Dy(screen->r) -20: Dx(screen->r) -20;
225  rx = (int)ceil((float)(d-2*Border)/(float)SzX)/2;
226  ry = (int)ceil((float)(d-2*Border)/(float)SzY)/2;
227 
228  for(x = 0; x < SzX; x++) {
229  for(y = 0; y < SzY; y++) {
230  p = board2pix(x, y);
231  switch(grid[x][y]){
232  case 999:
233  fillellipse(screen, addpt(screen->r.min, p), rx, ry, cc, ZP);
234  break;
235  case 1000:
236  p = addpt(screen->r.min, p);
237  fillellipse(screen, p, rx, ry, ec, ZP);
238  p = subpt(p, Pt(24, 24));
239  draw(screen, Rpt(p, addpt(p, Pt(48, 48))), gl, glm, ZP);
240  break;
241  default:
242  fillellipse(screen, addpt(screen->r.min, p), rx, ry, ec, ZP);
243  USED(s);
244  /* uncomment the following to see game state and field scores */
245  /*s = smprint("%d", grid[x][y]);
246  string(screen, addpt(screen->r.min, p), display->black, ZP, font, s);
247  free(s);
248  */
249  break;
250  }
251  }
252  }
253  flushimage(display, 1);
254 }
255 
256 void
257 domove(int dir, int x, int y)
258 {
259  if(x == 0 || x == SzX-1 || y == 0 || y == SzY-1)
260  goto done;
261 
262  switch(dir){
263  case NE:
264  if(y%2)
265  grid[x+1][y-1] = 1000;
266  else
267  grid[x][y-1] = 1000;
268  break;
269  case E:
270  grid[x+1][y] = 1000;
271  break;
272  case SE:
273  if(y%2)
274  grid[x+1][y+1] = 1000;
275  else
276  grid[x][y+1] = 1000;
277  break;
278  case SW:
279  if(y%2)
280  grid[x][y+1] = 1000;
281  else
282  grid[x-1][y+1] = 1000;
283  break;
284  case W:
285  grid[x-1][y] = 1000;
286  break;
287  case NW:
288  if(y%2)
289  grid[x][y-1] = 1000;
290  else
291  grid[x-1][y-1] = 1000;
292  break;
293  }
294 done:
295  grid[x][y] = 100;
296 }
297 
298 Point
299 findglenda(void)
300 {
301  int x, y;
302  for(x = 0; x < SzX; x++)
303  for(y = 0; y < SzY; y++)
304  if(grid[x][y] == 1000)
305  return Pt(x, y);
306  return Pt(-1, -1);
307 }
308 
309 int
310 checknext(int dir, int x, int y)
311 {
312  switch(dir){
313  case NE:
314  return grid[x+(y%2?1:0)][y-1];
315  case E:
316  return grid[x+1][y];
317  case SE:
318  return grid[x+(y%2?1:0)][y+1];
319  case SW:
320  return grid[x+(y%2?0:-1)][y+1];
321  case W:
322  return grid[x-1][y];
323  case NW:
324  return grid[x+(y%2?0:-1)][y-1];
325  default:
326  sysfatal("andrey messed up big time");
327  }
328  return 1000;
329 }
330 /* the following two routines constitute the "game AI"
331 * they score the field based on the number of moves
332 * required to reach the edge from a particular point
333 * scores > 100 are "dead spots" (this assumes the field
334 * is not larger than ~100*2
335 *
336 * routines need to run at least twice to ensure a field is properly
337 * scored: there are errors that creep up due to the nature of
338 * traversing the board
339 */
340 int
341 score1(int x, int y) {
342  int dir, min = 999, next;
343 
344  if(x == 0 || x == SzX-1 || y == 0 || y == SzY-1)
345  return 1; /* we can always escape from the edges */
346 
347  for(dir = NE; dir <= NW; dir++) {
348  next = checknext(dir, x, y);
349  if(next < min)
350  min = next;
351  }
352  if(min == 999) return 998;
353  return 1+min;
354 }
355 
356 void
357 calc(void)
358 {
359  int i, x, y;
360  for(i = 0; i < SzX; i++) /* assumes SzX = SzY */
361  for(x = i; x < SzX-i; x++)
362  for(y = i; y < SzY-i; y++)
363  if(grid[x][y] != 999)
364  grid[x][y] = score1(x, y);
365 }
366 
367 void
368 nextglenda(void)
369 {
370  int min =1000, next, dir, nextdir = 0, count = 0;
371  Point p = findglenda();
372 
373  calc();
374  calc();
375  calc();
376 
377  grid[p.x][p.y] = 1000;
378 
379  for(dir = NE; dir <= NW; dir++) {
380  next = checknext(dir, p.x, p.y);
381  if(next < min) {
382  min = next;
383  nextdir = dir;
384  ++count;
385  } else if(next == min) {
386  nextdir = (nrand(++count) == 0)?dir:nextdir;
387  }
388  }
389  if(min < 100)
390  domove(nextdir, p.x, p.y);
391  else
392  finished = Won;
393 
394  if(eqpt(findglenda(), Pt(-1, -1)))
395  finished = Lost;
396 }
397 
398 int
399 checkfinished(void)
400 {
401  int i, j;
402  for(i = 0; i < SzX; i++)
403  for(j = 0; j < SzY; j++)
404  if(grid[i][j] == 'E')
405  return 0;
406  return 1;
407 }
408 
409 void
410 move(Point m)
411 {
412  Point p, nm;
413  int x, y;
414 
415  nm = subpt(m, screen->r.min);
416 
417  /* figure out where the click falls */
418  p = pix2board(nm.x, nm.y);
419 
420  if(grid[p.x][p.y] >= 999)
421  return;
422 
423  /* reset the board scores */
424  grid[p.x][p.y] = 999;
425  for(x = 0; x < SzX; x++)
426  for(y = 0; y < SzY; y++)
427  if(grid[x][y] != 999 && grid[x][y] != 1000)
428  grid[x][y] = 100;
429 
430  nextglenda();
431 }
432 
433 void
434 resize(void)
435 {
436  int fd, size = (Dx(screen->r) > Dy(screen->r)) ? Dy(screen->r) + 20 : Dx(screen->r)+20;
437 
438  fd = open("/dev/wctl", OWRITE);
439  if(fd >= 0){
440  fprint(fd, "resize -dx %d -dy %d", size, size);
441  close(fd);
442  }
443 
444 }
445 
446 
447 void
448 eresized(int new)
449 {
450  if(new && getwindow(display, Refnone) < 0)
451  sysfatal("can't reattach to window");
452 
453  drawlevel();
454 }
455 
456 void
457 main(int argc, char **argv)
458 {
459  Mouse m;
460  Event ev;
461  int e, mousedown=0;
462  char *fontname;
463 
464  USED(argv, argc);
465 
466  if(initdraw(nil, nil, "glendy") < 0)
467  sysfatal("initdraw failed: %r");
468  einit(Emouse);
469 
470  resize();
471 
472  srand(time(0));
473 
474  allocimages();
475  initlevel(); /* must happen before "eresized" */
476  eresized(0);
477 
478  fontname = "/lib/font/bit/lucidasans/unicode.8.font";
479  if((font = openfont(display, fontname)) == nil)
480  sysfatal("font '%s' not found", fontname);
481 
482  for(;;) {
483  e = event(&ev);
484  switch(e) {
485  case Emouse:
486  m = ev.mouse;
487  if(m.buttons == 0) {
488  if(mousedown && !finished) {
489  mousedown = 0;
490  move(m.xy);
491  drawlevel();
492  }
493  }
494  if(m.buttons&1) {
495  mousedown = 1;
496  }
497  if(m.buttons&2) {
498  switch(emenuhit(2, &m, &mmenu)) {
499  case 0:
500  difficulty = DEasy;
501  initlevel();
502  break;
503  case 1:
504  difficulty = DMed;
505  initlevel();
506  break;
507  case 2:
508  difficulty = DHard;
509  initlevel();
510  break;
511  }
512  drawlevel();
513  }
514  if(m.buttons&4) {
515  switch(emenuhit(3, &m, &rmenu)) {
516  case 0:
517  initlevel();
518  break;
519  case 1:
520  memcpy(grid, ogrid, sizeof grid);
521  finished = 0;
522  break;
523  case 2:
524  exits(nil);
525  }
526  drawlevel();
527  }
528  break;
529  }
530  }
531 }