shithub: klondike

Download patch

ref: 8348e316b6d659c2632c6bcbbcc2c0a2bf5f5da8
parent: 6c7e3210c963313a6cbc34725d631fcbeef62bdb
author: jgstratton <jgstratton@cyber.lan>
date: Sat Sep 25 13:07:29 EDT 2021

Initial add

diff: cannot open b/cards//null: file does not exist: 'b/cards//null'
--- a/README.md
+++ b/README.md
@@ -1,1 +1,7 @@
-# plan9-klondike
\ No newline at end of file
+# plan9-klondike
+This code is originally by Felipe Bichued, and is Public Domain. You can find it listed on https://9p.io/wiki/plan9/Contrib_index/index.html, or, if you are using 9front, under:
+	9fs sources
+	cd /n/sources/contrib/bichued/root/sys/src/games/klondike/
+
+## Changes made to the original version
+1. New mkfile that installs the card images. Card locations added at build time.
--- /dev/null
+++ b/card.c
@@ -1,0 +1,168 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "klondike.h"
+
+char *suitpathfmt[] = {
+	"%s/c%d.bit",
+	"%s/d%d.bit",
+	"%s/s%d.bit",
+	"%s/h%d.bit"
+};
+
+Image*
+opencard(int suit, int rank)
+{
+	char *s;
+	Image *img;
+
+	s = smprint(suitpathfmt[suit], CARDPATH, rank);
+	if(s == nil)
+		sysfatal("smprint: %r");
+	img = openimage(s);
+	free(s);
+	return img;
+}
+
+Card*
+cardinit(int suit, int rank, int up)
+{
+	Card *c;
+
+	c = malloc(sizeof(Card));
+	c->suit = suit;
+	c->rank = rank;
+	c->up = up;
+	c->img[0] = cardback;
+	c->img[1] = opencard(suit, rank+1);
+	c->p = ZP;
+	return c;
+}
+
+int
+turncard(Point xy)
+{
+	Card *c;
+	Cardstack *src, *dst;
+	
+	src = chosenstack(xy);
+	if(src == nil)
+		return 0;
+	if(!canturn(src))
+		return 0;
+	if(src == stock && src->n == 0){
+		while((c = pop(waste)) != nil){
+			c->up = 0;
+			push(stock, c);
+		}
+	}
+	else{
+		c = pop(src);
+		if(!c->up)
+			c->up++;
+		dst = src == stock ? waste : src;
+		push(dst, c);
+	}
+	drawtable(screen);
+	return 1;
+}
+
+void
+putinfoundation(Point xy)
+{
+	int i;
+	Card *c;
+	Cardstack *src, *dst;
+
+	src = chosenstack(xy);
+	if(src == nil || src == stock
+	|| stackinarray(src, foundation, nelem(foundation))
+	|| movpilesize(xy, src) == 0
+	|| !top(src)->up)
+		return;
+	c = pop(src);
+	dst = src;
+	for(i = 0; i < nelem(foundation); i++){
+		dst = foundation[i];
+		if(validmove(c, dst))
+			break;
+		dst = src;
+	}
+	push(dst, c);
+	drawtable(screen);
+}
+
+int
+canturn(Cardstack *cs)
+{
+	Card *c;
+
+	if(cs == stock)
+		return 1;
+	if(stackinarray(cs, tableau, nelem(tableau))){
+		if(cs->n == 0)
+			return 0;
+		c = top(cs);
+		if(!c->up)
+			return 1;
+	}
+	return 0;
+}
+
+int
+candrop(Card *c, Cardstack *cs)
+{
+	int a1, a2;
+	Rectangle cr, sr;
+
+	cr = cardrect(c);
+	sr = stackrect(cs);
+	if(rectclip(&sr, cr)){
+		a1 = Dx(cr) * Dy(cr);
+		a2 = Dx(sr) * Dy(sr);
+		if((double) a2/a1 > 0.25) /*arbitrary*/
+			return 1;
+	}
+	return 0;
+}
+
+int
+samesuit(Card *c1, Card *c2)
+{
+	return c1->suit == c2->suit;
+}
+
+int
+samecolor(Card *c1, Card *c2)
+{
+	return c1->suit%2 == c2->suit%2;
+}
+
+int
+insequence(Card *c1, Card *c2, int b)
+{
+	return c1->rank == c2->rank+b;
+}
+
+int
+validmove(Card *c, Cardstack *dst)
+{
+	Card *t;
+
+	t = top(dst);
+	if(stackinarray(dst, foundation, nelem(foundation))){
+		if(dst->n == 0)
+			return c->rank == Ace;
+		return samesuit(c, t)
+		&& insequence(c, t, Bup)  
+		&& t->up;
+	}
+	if(stackinarray(dst, tableau, nelem(tableau))){
+		if(dst->n == 0)
+			return c->rank == King;
+		return !samecolor(c, t) 
+		&& insequence(c, t, Tdn) 
+		&& t->up;
+	}
+	return 0;
+}
--- /dev/null
+++ b/cards/COPYRIGHT
@@ -1,0 +1,12 @@
+/*****************************************************************************\
+ *  Card Bitmaps copyright (c) Joseph L. Traub 1992                          *
+ *                                                                           *
+ *  These cards are provided free of charge to any and all who wish to use   *
+ *  in any of their works.  They can be freely copied and redistributed in   *
+ *  any piece of software, either commercial or public, however the cards    *
+ *  themselves MUST remain in the public domain and this notice must         *
+ *  accompany these bitmaps.  If you make any changes to the bitmaps please  *
+ *  let me know so that there might remain a very good set of public domain  *
+ *  bitmaps for a deck of cards.  Enjoy.                                     *
+ *                    Joseph L. Traub (jtraub@zso.dec.com)                   *
+\*****************************************************************************/
binary files /dev/null b/cards/back.bit differ
binary files /dev/null b/cards/c1.bit differ
binary files /dev/null b/cards/c10.bit differ
binary files /dev/null b/cards/c11.bit differ
binary files /dev/null b/cards/c12.bit differ
binary files /dev/null b/cards/c13.bit differ
binary files /dev/null b/cards/c2.bit differ
binary files /dev/null b/cards/c3.bit differ
binary files /dev/null b/cards/c4.bit differ
binary files /dev/null b/cards/c5.bit differ
binary files /dev/null b/cards/c6.bit differ
binary files /dev/null b/cards/c7.bit differ
binary files /dev/null b/cards/c8.bit differ
binary files /dev/null b/cards/c9.bit differ
binary files /dev/null b/cards/d1.bit differ
binary files /dev/null b/cards/d10.bit differ
binary files /dev/null b/cards/d11.bit differ
binary files /dev/null b/cards/d12.bit differ
binary files /dev/null b/cards/d13.bit differ
binary files /dev/null b/cards/d2.bit differ
binary files /dev/null b/cards/d3.bit differ
binary files /dev/null b/cards/d4.bit differ
binary files /dev/null b/cards/d5.bit differ
binary files /dev/null b/cards/d6.bit differ
binary files /dev/null b/cards/d7.bit differ
binary files /dev/null b/cards/d8.bit differ
binary files /dev/null b/cards/d9.bit differ
binary files /dev/null b/cards/h1.bit differ
binary files /dev/null b/cards/h10.bit differ
binary files /dev/null b/cards/h11.bit differ
binary files /dev/null b/cards/h12.bit differ
binary files /dev/null b/cards/h13.bit differ
binary files /dev/null b/cards/h2.bit differ
binary files /dev/null b/cards/h3.bit differ
binary files /dev/null b/cards/h4.bit differ
binary files /dev/null b/cards/h5.bit differ
binary files /dev/null b/cards/h6.bit differ
binary files /dev/null b/cards/h7.bit differ
binary files /dev/null b/cards/h8.bit differ
binary files /dev/null b/cards/h9.bit differ
binary files /dev/null b/cards/s1.bit differ
binary files /dev/null b/cards/s10.bit differ
binary files /dev/null b/cards/s11.bit differ
binary files /dev/null b/cards/s12.bit differ
binary files /dev/null b/cards/s13.bit differ
binary files /dev/null b/cards/s2.bit differ
binary files /dev/null b/cards/s3.bit differ
binary files /dev/null b/cards/s4.bit differ
binary files /dev/null b/cards/s5.bit differ
binary files /dev/null b/cards/s6.bit differ
binary files /dev/null b/cards/s7.bit differ
binary files /dev/null b/cards/s8.bit differ
binary files /dev/null b/cards/s9.bit differ
--- /dev/null
+++ b/draw.c
@@ -1,0 +1,78 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "klondike.h"
+
+void
+drawcard(Card *c)
+{
+	draw(bb,  cardrect(c), c->img[c->up], nil,  ZP);
+}
+
+void
+drawstack(Cardstack *cs)
+{
+	int i;
+	Rectangle cr;
+	
+	if(cs->n == 0){
+		cr = Rect(0, 0, Cwid, Cht);
+		border(bb, rectaddpt(cr, cs->p), 1, display->black, ZP);
+	}
+	else{
+		if(cs->dpad != 0 && cs->upad != 0)
+			for(i = 0; i < cs->n; i++)
+				drawcard(cs->c[i]);
+		else
+			drawcard(top(cs));
+	}
+}
+
+void
+drawtable(Image *img)
+{
+	int i;
+	
+	tablemath();
+	draw(bb, bb->r, display->white, nil, ZP);
+	drawstack(stock);
+	drawstack(waste);
+	for(i = 0; i < nelem(foundation); i++)
+		drawstack(foundation[i]);
+	for(i = 0; i < nelem(tableau); i++)
+		drawstack(tableau[i]);
+	draw(img, bb->r, bb, nil, bb->r.min);
+}
+
+void
+translate(Card *ca[], Point dt)
+{
+	Rectangle cr;
+	Card *c, **cp;
+
+	cr = cardrect(ca[0]);
+	for(cp = ca; *cp != nil; cp++)
+		combinerect(&cr, cardrect(*cp));
+	draw(bb, cr, bb2, nil, cr.min);
+	for(cp = ca; (c = *cp); cp++) {
+		c->p = addpt(c->p, dt);
+		drawcard(c);
+		combinerect(&cr, cardrect(c));
+	}
+	draw(screen, cr, bb, nil, cr.min);
+}
+
+Image*
+openimage(char *path)
+{
+	int fd;
+	Image *img;
+
+	if((fd = open(path, OREAD)) < 0)
+		sysfatal("open %s: %r", path);
+	img = readimage(display, fd, 0);
+	if(img == nil)
+		sysfatal("readimage %s: %r", path);
+	close(fd);
+	return img;
+}
--- /dev/null
+++ b/jons_notes.txt
@@ -1,0 +1,9 @@
+Original:
+	https://9p.io/wiki/plan9/contrib_index_test/index.html
+
+	9fs sources
+	/n/sources/contrib/bichued/root/sys/src/games/klondike/
+
+Changes:
+	New Make file that copies card dir.
+	Code takes card path as a #define
--- /dev/null
+++ b/klondike.c
@@ -1,0 +1,219 @@
+/*Felipe Bichued <bichued(at)gmail(dot)com>*/
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include <cursor.h>
+#include "klondike.h"
+
+char *buttons[] =
+{
+	"New",
+	"Quit",
+	0
+};
+
+Menu menu = 
+{
+	buttons
+};
+
+Cardstack *stock;
+Cardstack *waste;
+Cardstack *foundation[4];
+Cardstack *tableau[7];
+Card *movpile[14];/*13 cards + 1 nil*/
+Card *allcards[52];
+
+int dealtflag;
+Image *bb, *bb2;
+Image *cardback;
+Mouse mouse;
+
+void
+resize(void)
+{
+	int fd;
+
+	fd = open("/dev/wctl", OWRITE);
+	if(fd > 0){
+		fprint(fd, "resize -dx %d -dy %d", Swid, Sht);
+		close(fd);
+	}
+}
+
+void
+eresized(int n)
+{
+	if(n && getwindow(display, Refnone) < 0)
+		exits("eresized");
+	freeimage(bb);
+	bb = allocimage(display, screen->r, screen->chan, 0, 0);
+	freeimage(bb2);
+	bb2 = allocimage(display, screen->r, screen->chan, 0, 0);
+	resize();
+	drawtable(screen);
+}
+
+void
+gameinit(void)
+{
+	int i;
+	cardback = openimage(smprint("%s/back.bit", CARDPATH));
+	stock = stackinit(0, 0, 0, 52);
+	waste = stackinit(0, 0, 0, 52);
+	for(i = 0; i < nelem(foundation); i++)
+		foundation[i] = stackinit(0, 0, 0, 13);
+	for(i = 0; i < nelem(tableau); i++)
+		tableau[i] = stackinit(0, Upad, Dpad, i+13);
+	for(i = 0; i < 52; i++)
+		allcards[i] = cardinit(i%nelem(foundation), i%13, 0);
+	for(i = 0; i < nelem(movpile); i++)
+		movpile[i] = nil;
+	bb = allocimage(display, screen->r, screen->chan, 0, 0);
+	bb2 = allocimage(display, screen->r, screen->chan, 0, 0);
+	resize();
+}
+
+void
+shuffle(void)
+{
+	int i, r;
+	Card *c;
+
+	srand(time(0));
+	for(i = 52; i > 0; i--){
+		r = nrand(i);
+		c = allcards[i-1];
+		allcards[i-1] = allcards[r];
+		allcards[r] = c;
+	}
+}
+
+void
+deal(void)
+{
+	int i, j;
+	Card *c;
+	
+	shuffle();
+	for(i = 0; i < 52; i++)
+		push(stock, allcards[i]);
+	for(i = 0; i < nelem(tableau); i++)
+		for(j = 0; j <= i; j++){
+			c = pop(stock);
+			if(i == j)
+				c->up++;
+			push(tableau[i], c);
+		}
+	dealtflag = 1;
+}
+
+void 
+cleangame(void){
+	int i;
+
+	if(!dealtflag)
+		return;
+	while(pop(stock) != nil);
+	while(pop(waste) != nil);
+	for(i = 0; i < nelem(foundation); i++)
+		while(pop(foundation[i]) != nil);
+	for(i = 0; i < nelem(tableau); i++)
+		while(pop(tableau[i]) != nil);
+	for(i = 0; i < 52; i++)
+		allcards[i]->up = 0;
+	for(i = 0; i < nelem(movpile); i++)
+		movpile[i] = nil;
+	dealtflag = 0;
+}
+
+void
+waitbutrelease(int but)
+{
+	do mouse = emouse();
+	while(mouse.buttons == but);
+}
+
+void
+drag(void)
+{
+	int i, n;
+	Point oxy, dxy;
+	Cardstack *src, *dst;
+
+	oxy = mouse.xy;
+	src = chosenstack(oxy);
+	if(src == nil)
+		return;
+	n = movpilesize(oxy, src);
+	if(n == 0)
+		return;
+	while(n--)
+		movpile[n] = pop(src);
+	drawtable(bb2);
+	//translate(movpile, ZP);
+	do{
+		dxy = subpt(mouse.xy, oxy);
+		oxy = mouse.xy;
+		if(dxy.x != 0 || dxy.y != 0)
+			translate(movpile, dxy);
+		mouse = emouse();
+	}while(mouse.buttons == 1);
+	dst = droptarget(movpile[0]);
+	if(dst == nil || !validmove(movpile[0], dst))
+		dst = src;
+	for(i = 0; movpile[i] != nil; i++)
+		push(dst, movpile[i]);
+	drawtable(screen);
+	for(i = 0; movpile[i] != nil; i++)
+		movpile[i] = nil;
+}
+
+int
+finished(void)
+{
+	int i;
+
+	for(i = 0; i < nelem(foundation); i++)
+		if(foundation[i]->n != 13)
+			return 0;
+	return 1;
+}
+
+void
+main(void)
+{
+	if(initdraw(nil, nil, "klondike") < 0)
+		sysfatal("initdraw: %r");
+	einit(Emouse);
+	gameinit();
+Start:
+	cleangame();
+	deal();
+	drawtable(screen);
+	for(;;){			
+		mouse = emouse();
+		switch(mouse.buttons){
+		case 1:
+			if(turncard(mouse.xy))
+				waitbutrelease(1);
+			else
+				drag();
+			break;
+		case 2:
+			putinfoundation(mouse.xy);
+			waitbutrelease(2);
+			break;
+		case 4:
+			switch(emenuhit(3, &mouse, &menu)){
+			case 0:
+				goto Start;
+			case 1:
+				exits(0);
+			}
+		}
+		if(finished())
+			goto Start;
+	}
+}
--- /dev/null
+++ b/klondike.h
@@ -1,0 +1,81 @@
+enum{
+	Xpad = 10,
+	Ypad = 20,
+	Sht = 508,
+	Swid = 594
+};
+
+enum{
+	Dpad = 6,
+	Upad = 18,
+	Cwid = 72,
+	Cht = 99
+};
+
+enum{
+	Tdn = -1, 
+	Bup = 1
+};
+
+enum{
+	Ace = 0,
+	King = 12
+};
+
+typedef struct Card Card;
+struct Card{
+	int suit;
+	int rank;
+	int up;
+	Point p;
+	Image *img[2];
+};
+
+typedef struct Cardstack Cardstack;
+struct Cardstack
+{
+	int sz;
+	int n;
+	int upad;
+	int dpad;
+	Point p;
+	Card **c;
+};
+
+extern Cardstack *stock;
+extern Cardstack *waste;
+extern Cardstack *foundation[4];
+extern Cardstack *tableau[7];
+extern Image *bb, *bb2;
+extern Image *cardback;
+extern Mouse mouse;
+/* extern char *cardpath = "./cards"; */
+extern char cardpath[];
+
+/*card.c*/
+Card* cardinit(int, int, int);
+int turncard(Point);
+int canturn(Cardstack*);
+int candrop(Card*, Cardstack*);
+int validmove(Card*, Cardstack*);
+void putinfoundation(Point);
+
+/*draw.c*/
+void drawtable(Image*);
+void translate(Card*[], Point);
+Image* openimage(char*);
+
+/*stack.c*/
+Cardstack* stackinit(int, int, int, int);
+void push(Cardstack*, Card*);
+Card* pop(Cardstack*);
+Card* top(Cardstack*);
+
+/*math.c*/
+void tablemath(void);
+int stackinarray(Cardstack*, Cardstack*[], int);
+Rectangle cardrect(Card*);
+Rectangle stackrect(Cardstack*);
+Cardstack* chosenstack(Point);
+Cardstack* droptarget(Card*);
+int movpilesize(Point, Cardstack*);
--- /dev/null
+++ b/math.c
@@ -1,0 +1,150 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "klondike.h"
+
+void
+stackmath(Cardstack *cs)
+{
+	int i, y;
+	Card *c;
+
+	y = cs->p.y;
+	for(i = 0; i < cs->n; i++){
+		c = cs->c[i];
+		c->p = Pt(cs->p.x, y);
+		if(c->up)
+			y += cs->upad;
+		else
+			y += cs->dpad;
+	}
+}
+
+void
+tablemath()
+{
+	int i, x, y;
+
+	stock->p.x = Xpad;
+	stock->p.y = Ypad;
+	stock->p = addpt(screen->r.min, stock->p);
+	stackmath(stock);
+	waste->p.x = Cwid+Xpad*2;
+	waste->p.y = Ypad;
+	waste->p = addpt(screen->r.min, waste->p);
+	stackmath(waste);
+	x = Xpad;
+	y = Cht+Ypad*2;
+	for(i = 0; i < nelem(tableau); i++){
+		tableau[i]->p.x = x;
+		tableau[i]->p.y = y;
+		tableau[i]->p = addpt(screen->r.min, tableau[i]->p);
+		stackmath(tableau[i]);
+		x += Cwid+Xpad;
+	}
+	x = tableau[3]->p.x - screen->r.min.x;
+	y = Ypad;
+	for(i = 0; i < nelem(foundation); i++){
+		foundation[i]->p.x = x;
+		foundation[i]->p.y = y;
+		foundation[i]->p = addpt(screen->r.min, foundation[i]->p);
+		stackmath(foundation[i]);
+		x += Cwid+Xpad;
+	}
+}
+
+int
+stackinarray(Cardstack *cs, Cardstack *csa[], int n)
+{
+	int i;
+
+	for(i = 0; i < n; i++)
+		if(cs == csa[i])
+			return 1;
+	return 0;
+}
+
+int
+ptinstack(Point xy, Cardstack *cs)
+{
+	return ptinrect(xy, stackrect(cs));
+}
+
+Rectangle
+cardrect(Card *c)
+{
+	return rectaddpt(Rect(0, 0, Cwid, Cht), c->p);
+}
+
+Rectangle
+stackrect(Cardstack *cs)
+{
+	int i;
+	Card *c;
+	Rectangle sr;
+
+	sr = Rpt(ZP, ZP);
+	for(i = 0; i < cs->n-1; i++){
+		c = cs->c[i];
+		if(c->up)
+			sr.max.y += cs->upad;
+		else
+			sr.max.y += cs->dpad;
+	}
+	sr.max.x += Cwid;
+	sr.max.y += Cht;
+	return rectaddpt(sr, cs->p);
+}
+
+Cardstack*
+chosenstack(Point xy)
+{
+	int i;
+
+	if(ptinstack(xy, stock))
+		return stock;
+	if(ptinstack(xy, waste))
+		return waste;
+	for(i = 0; i < nelem(foundation); i++)
+		if(ptinstack(xy, foundation[i]))
+			return foundation[i];
+	for(i = 0; i < nelem(tableau); i++)
+		if(ptinstack(xy, tableau[i]))
+			return tableau[i];
+	return nil;
+}
+
+Cardstack*
+droptarget(Card *c)
+{
+	int i;
+
+	for(i = 0; i < nelem(foundation); i++)
+		if(candrop(c, foundation[i]))
+			return foundation[i];
+	for(i = 0; i < nelem(tableau); i++)
+		if(candrop(c, tableau[i]))
+			return tableau[i];
+	return nil;
+}
+
+int
+movpilesize(Point xy, Cardstack *cs)
+{
+	Card *c;
+	Rectangle cr;
+	int i;
+	
+	if(cs->n == 0)
+		return 0;
+	cr = cardrect(top(cs));
+	i = cs->n - 1;
+	while(!ptinrect(xy, cr)){
+		c = cs->c[--i];
+		if(c->up)
+			cr.min.y -= cs->upad;
+		else
+			return 0;
+	}
+	return cs->n - i;
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,32 @@
+
+</$objtype/mkfile
+
+#BIN=/$objtype/bin/games
+#CARDPATH=/sys/lib/klondike/cards
+BIN=/usr/sdf/bin
+CARDPATH=/usr/sdf/lib/klondike/cards
+#BIN=./
+#CARDPATH=cards
+
+CFLAGS= -DCARDPATH="$CARDPATH"
+TARG=klondike
+OFILES=\
+	card.$O\
+	draw.$O\
+	klondike.$O\
+	math.$O\
+	stack.$O\
+
+UPDATE=\
+	mkfile\
+	${OFILES:%.$O=%.c}\
+
+build: $O.out
+	echo build
+
+install:
+	mkdir -p $CARDPATH
+	cp cards/* $CARDPATH
+	cp $O.out $BIN/$TARG
+
+</sys/src/cmd/mkone
\ No newline at end of file
--- /dev/null
+++ b/proto
@@ -1,0 +1,13 @@
+386	- sys sys
+	bin	- sys sys
+		games	- sys sys
+			klondike	- sys sys
+sys	- sys sys
+	games	- sys sys
+		lib	- sys sys
+			klondike	- sys sys
+				+	- sys sys
+	src	- sys sys
+		games	- sys sys
+			klondike	- sys sys
+				+	- sys sys
--- /dev/null
+++ b/stack.c
@@ -1,0 +1,42 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "klondike.h"
+
+Cardstack*
+stackinit(int n, int upad, int dpad, int sz)
+{
+	Cardstack *cs;
+
+	cs = malloc(sizeof(Cardstack));
+	cs->sz = sz;
+	cs->n = n;
+	cs->upad = upad;
+	cs->dpad = dpad;
+	cs->p = ZP;
+	cs->c = malloc(sz*sizeof(Card*));
+	return cs;
+}
+
+Card*
+pop(Cardstack *cs)
+{
+	if(cs->n == 0)
+		return nil;
+	return cs->c[--cs->n];
+}
+
+Card*
+top(Cardstack *cs)
+{
+	if(cs->n == 0)
+		return nil;
+	return cs->c[cs->n-1];
+}
+
+void
+push(Cardstack *cs, Card *c)
+{
+	if(cs->n < cs->sz)
+		cs->c[cs->n++] = c;
+}