💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › games › spider.c captured on 2021-12-17 at 13:26:06.

View Raw

More Information

-=-=-=-=-=-=-

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
enum{GAP = 12};
typedef struct Card Card;
struct Card{int v; Card *next;} deck[104], *found[8], *tab[10], **fromtab, *from, *c;
void
threadmain(int, char**){
	Keyboardctl *kbd;
	Mousectl *m;
	Image *bg, *fg, *tmp, *back, *cards;
	Rune k;
	Rectangle r;
	int w, h, i, j, b, stock = 5;
	enum{REDRAW, MOUSE, KEYBOARD};
	Alt a[] = {
		[REDRAW]{nil, nil, CHANRCV},
		[MOUSE]{nil, nil, CHANRCV},
		[KEYBOARD]{nil, &k, CHANRCV},
		{nil, nil, CHANEND}
	};
	if(initdraw(nil, nil, "spider") < 0)
		sysfatal("initdraw: %r");
	if((i = open("/sys/games/lib/cards/default.bit", OREAD)) < 0)
		sysfatal("couldn't find cards: %r");
	if((cards = readimage(display, i, 0)) == nil)
		sysfatal("readimage: /sys/games/lib/cards/default.bit bad format");
	close(i);
	w = Dx(cards->r) / 13;
	h = Dy(cards->r) / 4;
	bg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, DDarkgreen);
	fg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, DPaleyellow);
	tmp = allocimage(display, Rect(0, 0, 4, 4), RGBA32, 1, DBlue);
	back = allocimage(display, Rect(0, 0, w, h), RGBA32, 0, DNofill);
	if(bg == nil || fg == nil || tmp == nil || back == nil)
		sysfatal("allocimage: %r");
	draw(tmp, Rect(2, 2, 3, 3), fg, nil, ZP);
	draw(back, back->r, tmp, nil, ZP);
	freeimage(tmp);
	border(back, back->r, 1, fg, ZP);
	if((m = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	a[REDRAW].c = m->resizec;
	a[MOUSE].c = m->c;
	a[MOUSE].v = &m->Mouse;
	if((kbd = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard: %r");
	a[KEYBOARD].c = kbd->c;
	srand(truerand());
	for(j = 0; j < 104; j++)
		deck[j].v = j % 52;
	while(j > 1){
		i = nrand(j--);
		k = deck[i].v;
		deck[i].v = deck[j].v;
		deck[j].v = k;
	}
	for(i = 0; i < 10; i++)
		tab[i] = deck + i;
	for(i = 0; i < 44; i++){
		deck[i].next = deck + i + 10;
		deck[i].v -= 52;
	}
	sendul(m->resizec, 1);
	for(;;)
		switch(alt(a)){
		case MOUSE:
			if(!m->buttons)
				break;
			b = m->buttons;
			do readmouse(m); while(m->buttons);
			i = m->xy.x - (screen->r.min.x + screen->r.max.x - 10 * w - 9 * GAP >> 1);
			j = m->xy.y - screen->r.min.y - GAP;
			if(i < 0 || j < 0)
				fromtab = nil;
			else if(stock && j < h && i < (stock + 3) * w / 4){
	deal:
				for(i = 0; i < 10 && tab[i] != nil; i++)
					;
				if(i == 10){
					from = nil;
					j = 54 + --stock * 10;
					r.min.x = screen->r.min.x + screen->r.max.x - 10 * w - 9 * GAP >> 1;
					for(i = 0; 1; i++){
						r.max.x = r.min.x + w;
						r.min.y = screen->r.min.y + GAP + h + GAP + h / 4;
						for(c = tab[i]; c->next != nil && c->v < 0; c = c->next)
							r.min.y += h / 8;
						for(; c->next != nil; c = c->next)
							r.min.y += h / 4;
						c->next = deck + j++;
						if(i == 9)
							break;
						r.max.y = r.min.y + h;
						draw(screen, r, cards, nil, Pt(c->next->v % 13 * w, c->next->v / 13 * h));
						flushimage(display, 1);
						sleep(200);
						r.min.x = r.max.x + GAP;
					}
				}
			}
			else if(i % (w + GAP) >= w || (i /= (w + GAP)) >= 10)
				fromtab = nil;
			else if(tab[i] == nil){
				if(fromtab != nil && j >= h + GAP && j < h + h + GAP){
	empty:
					tab[i] = from;
					if(*fromtab == from)
						*fromtab = nil;
					else{
						while((*fromtab)->next != from)
							fromtab = &(*fromtab)->next;
						(*fromtab)->next = nil;
						if((*fromtab)->v < 0)
							(*fromtab)->v += 52;
					}
				}
				fromtab = nil;
			}
			else{
				j -= h + GAP;
				for(c = tab[i]; c->next != nil && c->v < 0; c = c->next)
					j -= h / 8;
				if(j < 0)
					fromtab = nil;
				else{
					for(; c->next != nil && j >= h / 4; c = c->next)
						j -= h / 4;
					if(j >= h)
						fromtab = nil;
					else if(fromtab != nil && fromtab != tab + i
					&& c->next == nil && c->v % 13 == from->v % 13 + 1){
	move:
						c->next = from;
						if(*fromtab == from)
							*fromtab = nil;
						else{
							while((*fromtab)->next != from)
								fromtab = &(*fromtab)->next;
							(*fromtab)->next = nil;
							if((*fromtab)->v < 0)
								(*fromtab)->v += 52;
						}
						while(from->next != nil)
							from = from->next;
						if(from->v % 13 == 0){
							from = nil;
							j = 0;
							for(c = tab[i]; c->next != nil; c = c->next){
								if(c->v % 13 && c->v == c->next->v + 1)
									j++;
								else{
									from = c;
									j = 0;
								}
							}
							if(j == 12){
								for(j = 0; found[j] != nil; j++)
									;
								found[j] = c;
								if(from == nil)
									tab[i] = nil;
								else{
									from->next = nil;
									if(from->v < 0)
										from->v += 52;
								}
							}
						}
						fromtab = nil;
					}
					else{
						if(fromtab == tab + i)
							b = 6;
						from = c;
						fromtab = nil;
						while(c->next != nil && c->v == c->next->v + 1)
							c = c->next;
						if(c->next == nil){
							for(j = 0; j < 10; j++){
								if(j == i || tab[j] == nil)
									continue;
								for(c = tab[j]; c->next != nil; c = c->next)
									;
								if(c->v == from->v + 1 && c->v % 13)
									break;
							}
							if(j == 10)
								for(j = 0; j < 10; j++){
									if(j == i || tab[j] == nil)
										continue;
									for(c = tab[j]; c->next != nil; c = c->next)
										;
									if(c->v % 13 == from->v % 13 + 1)
										break;
								}
							if(j == 10)
								for(j = 0; j < 10; j++){
									if(j == i)
										continue;
									if(tab[j] == nil){
										c = nil;
										break;
									}
								}
							if(j < 10){
								fromtab = tab + i;
								if(b & 6){
									i = j;
									if(c == nil)
										goto empty;
									else
										goto move;
								}
							}
						}
					}
				}
			}
			if(0)
		case REDRAW:
			if(getwindow(display, Refnone) < 0)
				sysfatal("getwindow: %r");
			draw(screen, screen->r, bg, nil, ZP);
			r.min.y = screen->r.min.y + GAP;
			r.max.y = r.min.y + h;
			if(stock){
				r.min.x = screen->r.min.x + screen->r.max.x - 10 * w - 9 * GAP >> 1;
				for(i = 1; i < stock; i++){
					r.max.x = r.min.x + w / 4;
					draw(screen, r, back, nil, ZP);
					r.min.x = r.max.x;
				}
				r.max.x = r.min.x + w;
				draw(screen, r, back, nil, ZP);
			}
			r.max.x = screen->r.min.x + screen->r.max.x - 6 * w - 7 * GAP >> 1;
			for(i = 0; i < 8; i++){
				r.min.x = r.max.x + GAP;
				r.max.x = r.min.x + w;
				if(found[i] == nil)
					border(screen, r, 1, fg, ZP);
				else
					draw(screen, r, cards, nil, Pt(found[i]->v % 13 * w, found[i]->v / 13 * h));
			}
			r.min.x = screen->r.min.x + screen->r.max.x - 10 * w - 9 * GAP >> 1;
			for(i = 0; i < 10; i++, r.min.x += GAP + w){
				r.max.x = r.min.x + w;
				r.min.y = screen->r.min.y + GAP + h + GAP;
				if(tab[i] == nil){
					r.max.y = r.min.y + h;
					border(screen, r, 1, fg, ZP);
					continue;
				}
				for(c = tab[i]; c->next != nil && c->v < 0; c = c->next){
					r.max.y = r.min.y + h / 8;
					draw(screen, r, back, nil, ZP);
					r.min.y = r.max.y;
				}
				while(c->next != nil){
					r.max.y = r.min.y + h / 4;
					draw(screen, r, cards, nil, Pt(c->v % 13 * w, c->v / 13 * h));
					r.min.y = r.max.y;
					c = c->next;
				}
				r.max.y = r.min.y + h;
				draw(screen, r, cards, nil, Pt(c->v % 13 * w, c->v / 13 * h));
				if(fromtab == tab + i){
					for(c = from->next; c != nil; c = c->next)
						r.min.y -= h / 4;
					border(screen, r, -GAP >> 1, fg, ZP);
				}
			}
			flushimage(display, 1);
			break;
		case KEYBOARD:
			switch(k){
			case Kdel: case 'q':
				threadexitsall(nil);
			case Kesc:
				if((i = open("/dev/wctl", OWRITE)) >= 0){
					write(i, "hide", 4);
					close(i);
				}
				break;
			default:
				if(stock)
					goto deal;
			}
			break;
		default:
			sysfatal("evpla laxa landicosa");
		}
}