12 static Cursor bunny = {
13 .set = {0x0,0x32,0x60,0x76,0x40,0x6e,0x3,0xec,0xf,0xfc,0x1f,0xf8,0x27,0x9c,0x3,0xc,0x33,0xcc,0x73,0xce,0x67,0x9e,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe,0x6e,0x76},
14 .clr = {0xf8,0xcd,0x90,0x89,0xa3,0x91,0xcc,0x12,0x90,0x2,0x20,0x6,0x58,0x62,0x7c,0xf2,0x4c,0x33,0x8c,0x31,0x98,0x61,0x80,0x1,0x80,0x1,0x80,0x1,0x91,0x89}
24 typedef struct Ghost Ghost;
25 typedef struct CList CList;
26 typedef struct CGroup CGroup;
34 enum { NOTARG, LTARG, RTARG } targettype;
71 n = calloc(sizeof(void*), ghost.w);
72 for(x = 0; x < ghost.w; x++){
73 n[x] = calloc(sizeof(void*), ghost.h);
74 for(y = 0; y < ghost.h; y++)
75 n[x][y] = calloc(sizeof(uchar), NState);
78 for(y = 0; y < ghost.h; y++)
79 for(x = 0; x < ghost.w; x++){
80 p = ghost.f[x + y * ghost.w];
81 if(x > 0 && y > 0) n[x-1][y-1][p]++;
82 if(y > 0) n[x][y-1][p]++;
83 if(x < ghost.w-1 && y > 0) n[x+1][y-1][p]++;
84 if(x > 0) n[x-1][y][p]++;
85 if(x < ghost.w-1) n[x+1][y][p]++;
86 if(x > 0 && y < ghost.h-1) n[x-1][y+1][p]++;
87 if(y < ghost.h-1) n[x][y+1][p]++;
88 if(x < ghost.w-1 && y < ghost.h-1) n[x+1][y+1][p]++;
94 freeneighbours(uchar ***n)
98 for(x = 0; x < ghost.w; x++){
99 for(y = 0; y < ghost.h; y++)
107 printcl(CList *cl, int ncl)
111 for(i = 0; i < ncl; i++){
112 print("%d: ", cl[i].mines);
113 for(j = 0; j < cl[i].pts; j++)
114 print("%d ", cl[i].pt[j]);
121 mklists(CList **clp, int *nclp)
130 for(y = 0; y < ghost.h; y++)
131 for(x = 0; x < ghost.w; x++)
132 if(MineField[x][y].Picture <= Empty8 && nei[x][y][MUnknown] > 0){
133 cl = realloc(cl, (ncl + 1) * sizeof(CList));
135 memset(c, 0, sizeof(CList));
136 c->mines = MineField[x][y].Picture - nei[x][y][MMine];
137 if(x > 0 && y > 0 && ghost.f[(x-1)+(y-1)*ghost.w] == MUnknown)
138 c->pt[c->pts++] = (x-1)+(y-1)*ghost.w;
139 if(y > 0 && ghost.f[(x)+(y-1)*ghost.w] == MUnknown)
140 c->pt[c->pts++] = (x)+(y-1)*ghost.w;
141 if(x < ghost.w-1 && y > 0 && ghost.f[(x+1)+(y-1)*ghost.w] == MUnknown)
142 c->pt[c->pts++] = (x+1)+(y-1)*ghost.w;
143 if(x > 0 && ghost.f[(x-1)+(y)*ghost.w] == MUnknown)
144 c->pt[c->pts++] = (x-1)+(y)*ghost.w;
145 if(x < ghost.w-1 && ghost.f[(x+1)+(y)*ghost.w] == MUnknown)
146 c->pt[c->pts++] = (x+1)+(y)*ghost.w;
147 if(x > 0 && y < ghost.h-1 && ghost.f[(x-1)+(y+1)*ghost.w] == MUnknown)
148 c->pt[c->pts++] = (x-1)+(y+1)*ghost.w;
149 if(y < ghost.h-1 && ghost.f[(x)+(y+1)*ghost.w] == MUnknown)
150 c->pt[c->pts++] = (x)+(y+1)*ghost.w;
151 if(x < ghost.w-1 && y < ghost.h-1 && ghost.f[(x+1)+(y+1)*ghost.w] == MUnknown)
152 c->pt[c->pts++] = (x+1)+(y+1)*ghost.w;
160 ismember(CList *c, int p)
164 for(i = 0; i < c->pts; i++)
171 splitknown(CList **clp, int *nclp, int i, int *lastq)
179 cl = realloc(cl, sizeof(CList) * (ncl + cl[i].pts - 1));
180 memset(cl + ncl, 0, sizeof(CList) * (cl[i].pts - 1));
181 for(j = 1; j < cl[i].pts; j++){
182 cl[ncl - 1 + j].mines = cl[i].pts == cl[i].mines;
183 cl[ncl - 1 + j].pts = 1;
184 cl[ncl - 1 + j].pt[0] = cl[i].pt[j];
185 cl[*lastq].next = ncl - 1 + j;
186 *lastq = ncl - 1 + j;
188 cl[i].mines = cl[i].pts == cl[i].mines;
189 *nclp += cl[i].pts - 1;
195 merge(CList **clp, int *nclp, int start, int split)
206 for(i = 0; i < *nclp; i++)
207 if(cl[i].pts == 0 || start >= 0 && start != i)
219 for(i = 0; i < *nclp; i++){
221 if(r == q || r->pts < q->pts) continue;
222 for(j = k = 0; j < q->pts; j++, k++){
224 if(r->pt[r->pts - 1] < p)
231 for(j = k = l = 0; j < q->pts; j++, k++){
234 r->pt[l++] = r->pt[k++];
237 r->pt[l++] = r->pt[k++];
239 r->mines -= q->mines;
240 if(r->mines < 0 || r->mines > r->pts){
244 if(r->pts == 0 && r->mines == 0)
246 if(r->next == -2 && r->pts > 0){
251 if(split && r->pts > 1 && (r->pts == r->mines || r->mines == 0)){
252 splitknown(&cl, nclp, i, &lastq);
261 for(i = 0, j = 0; i < *nclp; i++)
262 if(cl[i].mines != 0 || cl[i].pts != 0)
271 countref(CList *cl, int ncl, uchar *ref)
275 memset(ref, 0, ghost.w * ghost.h);
276 for(i = 0; i < ncl; i++)
277 for(j = 0; j < cl[i].pts; j++)
282 clgroup(CList *cl, int ncl, uchar *ref)
287 g = calloc(ncl, sizeof(int));
288 for(i = 0; i < ncl; i++)
291 for(i = 0; i < ncl; i++)
292 for(j = 0; j < cl[i].pts; j++){
293 if(ref[cl[i].pt[j]] == 1) continue;
294 for(k = 0; k < ncl; k++)
295 if(g[i] != g[k] && ismember(&cl[k], cl[i].pt[j]))
297 if(k == ncl) continue;
305 for(k = 0; k < ncl; k++)
314 groupmin(int *g, int ncl)
319 bs = calloc(sizeof(u32int), ncl + 31 >> 5);
320 for(i = 0; i < ncl; i++)
321 bs[g[i]>>5] |= 1<<(g[i] & 31);
322 for(i = 0; i < ncl; i++){
323 for(j = 0; j < g[i]; j++)
324 if((bs[j>>5] & 1<<(j & 31)) == 0)
326 if(j == g[i]) continue;
329 for(j = 0; j < ncl; j++)
332 bs[og>>5] &= ~(1<<(og & 31));
333 bs[ng>>5] |= 1<<(ng & 31);
336 for(i = 0; i < ncl; i++)
344 mkgroups(CList *cl, int ncl, uchar *ref, CGroup **gp)
350 gr = clgroup(cl, ncl, ref);
351 ng = groupmin(gr, ncl);
352 g = calloc(sizeof(CGroup), ng);
353 for(i = 0; i < ng; i++){
355 for(j = 0; j < ncl; j++)
358 p->cl = calloc(sizeof(CList), p->ncl);
359 for(j = 0, k = 0; j < ncl; j++)
369 freegroups(CGroup *g, int ng)
373 for(i = 0; i < ng; i++){
374 for(j = 0; j <= g[i].max; j++)
383 binom(mpint *acc, mpint *temp, int n, int k)
387 for(i = 0; i < k; i++){
389 mpmul(acc, temp, acc);
391 for(i = 2; i <= k; i++){
393 mpdiv(acc, temp, acc, nil);
397 static void countcomb(CList *cl, int ncl, mpint **);
400 cltry(CList *cl, int ncl, int p, int v, mpint **cnt)
405 cm = calloc(ncl + 1, sizeof(CList));
406 memcpy(cm, cl, ncl * sizeof(CList));
407 memset(&cm[ncl], 0, sizeof(CList));
412 if(merge(&cm, &ncm, ncl, 1) < 0){
416 countcomb(cm, ncm, cnt);
421 countcomb(CList *cl, int ncl, mpint **cnt)
427 ref = calloc(ghost.w, ghost.h);
428 countref(cl, ncl, ref);
429 for(i = 0; i < ncl; i++)
430 for(j = 0; j < cl[i].pts; j++){
433 cltry(cl, ncl, p, 0, cnt);
434 cltry(cl, ncl, p, 1, cnt);
442 for(i = 0; i < ncl; i++){
444 binom(rc, c0, cl[i].pts, cl[i].mines);
446 if(mpcmp(rc, mpzero) != 0)
450 mpadd(cnt[nm], rc, cnt[nm]);
460 totcomb(int tot, int nf, CGroup *g, int ng)
463 mpint *r, *v, *t, *m;
466 for(i = 0; i < ng; i++){
467 for(j = 0; j <= g[i].max; j++)
468 if(g[i].cnt[j] != nil)
483 for(i = 0; i < ng; i++){
484 m = g[i].cnt[g[i].cur];
489 binom(v, t, nf, tot - s);
492 for(i = 0; i < ng; i++){
495 if(++g[i].cur > g[i].max){
499 while(g[i].cnt[g[i].cur] == nil);
509 freefields(uchar *ref)
514 for(p = 0; p < ghost.w * ghost.h; p++)
515 if(ref[p] == 0 && ghost.f[p] == MUnknown)
521 basecounts(CGroup *g, int ng)
528 for(i = 0; i < ng; i++){
531 for(j = 0; j < p->ncl; j++)
532 p->max += p->cl[j].mines;
533 p->cnt = calloc(p->max + 1, sizeof(mpint *));
534 countcomb(p->cl, p->ncl, p->cnt);
535 if(p->max > allmax) allmax = p->max;
541 fieldcombs(CList *cl, int ncl, int *xp, int *yp)
548 mpint *min, *v, **alt, **backup;
552 ref = calloc(ghost.w, ghost.h);
553 countref(cl, ncl, ref);
554 nf = freefields(ref);
555 ng = mkgroups(cl, ncl, ref, &g);
556 allmax = basecounts(g, ng);
557 alt = calloc(allmax + 1, sizeof(mpint *));
563 for(gp = g; gp < g + ng; gp++)
564 for(l = gp->cl; l < gp->cl + gp->ncl; l++){
566 for(i = 0; i < l->pts; i++){
570 if(ref[p] == 1 && ref1++ != 0)
574 cltry(gp->cl, gp->ncl, p, 1, alt);
577 v = totcomb(ghost.nmines, nf, g, ng);
578 if(*xp < 0 || mpcmp(v, min) < 0){
585 for(k = 0; k <= gp->max; k++)
587 memset(alt, 0, (gp->max + 1) * sizeof(mpint *));
592 v = totcomb(ghost.nmines - 1, nf - 1, g, ng);
593 if(*xp < 0 || mpcmp(v, min) < 0){
595 for(p = 0; p < ghost.w * ghost.h; p++)
596 if(ref[p] == 0 && ghost.f[p] == MUnknown && i-- == 0)
611 ghostprep(CList **clp, int *nclp)
617 ghost.nmines = MinesRemain;
618 ghost.f = calloc(ghost.w, ghost.h);
619 for(x = 0; x < ghost.w; x++){
620 for(y = 0; y < ghost.h; y++)
621 switch(MineField[x][y].Picture){
631 ghost.f[x + y * ghost.w] = MEmpty;
634 ghost.f[x + y * ghost.w] = MMine;
637 ghost.f[x + y * ghost.w] = MUnknown;
644 ghostfind(CList *cl, int ncl, Point *targp)
652 merge(&cl, &ncl, -1, 0);
656 for(i = 0; i < ncl; i++)
657 if(cl[i].mines == 0 || cl[i].mines == cl[i].pts)
658 for(j = 0; j < cl[i].pts; j++){
659 p = Pt(cl[i].pt[j]%ghost.w, cl[i].pt[j]/ghost.w);
660 pd = subpt(addpt(addpt(mulpt(p, 16), Pt(12+8, 57+8)), Origin), targ);
661 d = pd.x * pd.x + pd.y * pd.y;
662 if(rt == NOTARG || d < min){
663 rt = cl[i].mines == cl[i].pts ? RTARG : LTARG;
667 ghost.f[cl[i].pt[j]] = cl[i].mines == cl[i].pts ? MMine : MEmpty;
670 fieldcombs(cl, ncl, &x, &y);
684 postnote(PNPROC, ghost.pid, "kill");
697 ghost.Rendez.l = &ghost;
698 if(rc = rfork(RFPROC|RFMEM), rc == 0){
701 while(!ghost.active || ghost.targettype != NOTARG)
703 g = ghost.generation;
704 ghostprep(&cl, &ncl);
706 rt = ghostfind(cl, ncl, &p);
708 if(ghost.generation == g){
709 ghost.targettype = rt;
724 for(i = 0; i < ghost.nmoves; i++)
725 if(eqpt(ghost.moves[i], p))
733 if(ghost.nmoves == nelem(ghost.moves))
734 memmove(ghost.moves + 1, ghost.moves, sizeof(ghost.moves) - sizeof(Point));
736 memmove(ghost.moves + 1, ghost.moves, ghost.nmoves++ * sizeof(Point));
748 q = subpt(p, ghost.cpos);
752 d = 2 / d * 2 * (1 + d / (400 + d));
753 move(addpt(ghost.cpos, Pt(ceil(q.x * d), ceil(q.y * d))));
767 move(addpt(ghost.cpos, Pt(nrand(20) - 10, nrand(20) - 10)));
773 p = Pt(Origin.x + MaxX * 8 + 12, Origin.y + 28);
774 if(TURBO || ptinrect(ghost.cpos, insetrect(Rpt(p, p), -4))){
778 ghost.targettype = NOTARG;
791 if(ghost.targettype != NOTARG){
792 p = addpt(addpt(mulpt(ghost.target, 16), Pt(12+8, 57+8)), Origin);
793 if(TURBO || ptinrect(ghost.cpos, insetrect(Rpt(p, p), -4))){
794 switch(ghost.targettype){
795 case LTARG: LeftClick(ghost.target); break;
796 case RTARG: RightClick(ghost.target); break;
798 ghost.targettype = NOTARG;
801 if(Status != Game && !TURBO) ghost.wait = 100;
803 flushimage(display, 1);
814 GhostReset(int deltarg)
820 ghost.cpos = LastMouse.xy;
824 ghost.targettype = NOTARG;