Charles.Forsyth20060303a828770d19 years agoHistory
917 lines · 21.3 KB · Brainfuck
RawDownload
implement Cardlib;include "sys.m";	sys: Sys;include "draw.m";include "sets.m";	sets: Sets;	Set, set, A, B, All, None: import sets;include "../spree.m";	spree: Spree;	Attributes, Range, Object, Clique, Member, rand: import spree;include "objstore.m";	objstore: Objstore;include "cardlib.m"; MAXPLAYERS: con 4; Layobject: adt {	lay:		ref Object;	name:	string;	packopts:		int;	pick {	Obj =>		obj:		ref Object;		# nil if it's a frame	Frame =>		facing:	int;				# only valid if for frames	}}; clique:	ref Clique;cmembers: array of ref Cmember;cpids := array[8] of list of ref Cmember; # XXX first string is unnecessary as it's held in the Layobject anyway?layouts := array[17] of list of (string, ref Layout, ref Layobject);maxlayid := 1;cmemberid := 1; archiveobjs: array of list of (string, ref Object); defaultrank := array[13] of {12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};defaultsuitrank := array[] of {CLUBS => 0, DIAMONDS => 1, HEARTS => 2, SPADES => 3}; table := array[] of {	0 =>	array[] of {		(-1, dTOP|EXPAND, dBOTTOM, dTOP),	},	1 => array [] of {		(0, dBOTTOM|FILLX, dBOTTOM, dTOP),		(-1, dTOP|EXPAND, dBOTTOM, dTOP),	},	2 => array[] of {		(0, dBOTTOM|FILLX, dBOTTOM, dTOP),		(1, dTOP|FILLX, dTOP, dBOTTOM),		(-1, dTOP|EXPAND, dBOTTOM, dTOP)	},	3 => array[] of {		(2, dRIGHT|FILLY, dRIGHT, dLEFT),		(0, dBOTTOM|FILLX, dBOTTOM, dTOP),		(1, dTOP|FILLX, dTOP, dBOTTOM),		(-1, dRIGHT|EXPAND, dBOTTOM, dTOP)	},	4 => array[] of {		(1, dLEFT|FILLY, dLEFT, dRIGHT),		(3, dRIGHT|FILLY, dRIGHT, dLEFT),		(0, dBOTTOM|FILLX, dBOTTOM, dTOP),		(2, dTOP|FILLX, dTOP, dBOTTOM),		(-1, dRIGHT|EXPAND, dBOTTOM, dTOP)	},};  init(mod: Spree, g: ref Clique){	sys = load Sys Sys->PATH;	sets = load Sets Sets->PATH;	if (sets == nil)		panic(sys->sprint("cannot load %s: %r", Sets->PATH));	objstore = load Objstore Objstore->PATH;	if (objstore == nil)		panic(sys->sprint("cannot load %s: %r", Objstore->PATH));	objstore->init(mod, g);	clique = g;	spree = mod;} archive(): ref Object{	for (i := 0; i < len cmembers; i++) {		cp := cmembers[i];		setarchivename(cp.obj, "member" + string i);		setarchivename(cp.layout.lay, "layout" + string i);		sel := cp.sel;		if (sel.stack != nil)			setarchivename(sel.stack, "sel" + string i);	}	for (i = 0; i < len layouts; i++) {		for (ll := layouts[i]; ll != nil; ll = tl ll) {			(name, lay, layobj) := hd ll;			if (name != nil)				layobj.lay.setattr("layname", name, None);			pick l := layobj {			Frame =>				l.lay.setattr("facing", sides[l.facing], None);			Obj =>				setarchivename(l.obj, "layid" + l.obj.getattr("layid"));			}		}	}	# XXX should archive layouts that aren't particular to a member.	archiveobj := clique.newobject(nil, None, "archive");	setarchivename(archiveobj, "archive");	archiveobj.setattr("maxlayid", string maxlayid, None);	archiveobj.setattr("cmemberid", string cmemberid, None);	return archiveobj;} setarchivename(o: ref Object, name: string){	objstore->setname(o, name);} getarchiveobj(name: string): ref Object{	return objstore->get(name);} archivearray(a: array of ref Object, name: string){	for (i := 0; i < len a; i++)		objstore->setname(a[i], name + string i);} getarchivearray(name: string): array of ref Object{	l: list of ref Object;	for (i := 0; ; i++) {		o := objstore->get(name + string i);		if (o == nil)			break;		l = o :: l;	}	a := array[i] of ref Object;	for (; l != nil; l = tl l)		a[--i] = hd l;	return a;} unarchive(): ref Object{	objstore->unarchive();	archiveobj := getarchiveobj("archive");	cpl: list of ref Cmember;	for (i := 0; (o := getarchiveobj("member" + string i)) != nil; i++) {		cp := ref Cmember(			i,			int o.getattr("id"),			clique.membernamed(o.getattr("name")),			o,			ref Layout(getarchiveobj("layout" + string i)),			ref Selection(getarchiveobj("sel" + string i), -1, 1, (0, 0), nil)		);		cp.sel.ownerid = cp.id;		sel := cp.sel;		if (sel.stack != nil && (selstr := sel.stack.getattr("sel")) != nil) {			(n, val) := sys->tokenize(selstr, " ");			if (tl val != nil && hd tl val == "-")				(sel.r.start, sel.r.end) = (int hd val, int hd tl tl val);			else {				idxl: list of int;				sel.isrange = 0;				for (; val != nil; val = tl val)					idxl = int hd val :: idxl;				sel.idxl = idxl;			}		}		lay := cp.layout.lay;		# there should be exactly one child, of type "layframe"		if (len lay.children != 1 || lay.children[0].objtype != "layframe")			panic("invalid layout");		x := strhash(nil, len layouts);		layouts[x] = (nil, cp.layout, obj2layobj(lay.children[0])) :: layouts[x];		unarchivelayoutobj(cp.layout, lay.children[0]);		cpl = cp :: cpl;	}	cmembers = array[len cpl] of ref Cmember;	for (; cpl != nil; cpl = tl cpl) {		cp := hd cpl;		cmembers[cp.ord] = cp;		idx := cp.id % len cpids;		cpids[idx] = cp :: cpids[idx];	}			maxlayid = int archiveobj.getattr("maxlayid");	cmemberid = int archiveobj.getattr("cmemberid");	return archiveobj;} unarchivelayoutobj(layout: ref Layout, o: ref Object){	for (i := 0; i < len o.children; i++) {		child := o.children[i];		layobj := obj2layobj(child);		if (layobj.name != nil) {			x := strhash(layobj.name, len layouts);			layouts[x] = (layobj.name, layout, layobj) :: layouts[x];		}		if (tagof(layobj) == tagof(Layobject.Frame))			unarchivelayoutobj(layout, child);	}} obj2layobj(o: ref Object): ref Layobject{	case o.objtype {	"layframe" =>		return ref Layobject.Frame(			o,			o.getattr("layname"),			s2packopts(o.getattr("opts")),			searchopt(sides, o.getattr("facing"))		);	"layobj" =>		return ref Layobject.Obj(			o,			o.getattr("layname"),			s2packopts(o.getattr("opts")),			getarchiveobj("layid" + o.getattr("layid"))		);	* =>		panic("invalid layobject found, of type '" + o.objtype + "'");		return nil;	}} Cmember.join(member: ref Member, ord: int): ref Cmember{	cmembers = (array[len cmembers + 1] of ref Cmember)[0:] = cmembers;	if (ord == -1)		ord = len cmembers - 1;	else {		cmembers[ord + 1:] = cmembers[ord:len cmembers - 1];		for (i := ord + 1; i < len cmembers; i++)			cmembers[i].ord = i;	}	cp := cmembers[ord] = ref Cmember(ord, cmemberid++, member, nil, nil, nil);	cp.obj = clique.newobject(nil, All, "member");	cp.obj.setattr("id", string cp.id, All);	cp.obj.setattr("name", member.name, All);	cp.obj.setattr("you", string cp.id, None.add(member.id));	cp.obj.setattr("cliquetitle", clique.fname, All);	cp.layout = newlayout(cp.obj, None.add(member.id));	cp.sel = ref Selection(nil, cp.id, 1, (0, 0), nil); 	idx := cp.id % len cpids;	cpids[idx] = cp :: cpids[idx];	return cp;} Cmember.find(p: ref Member): ref Cmember{	id := p.id;	for (i := 0; i < len cmembers; i++)		if (cmembers[i].p.id == id)			return cmembers[i];	return nil;} Cmember.index(ord: int): ref Cmember{	if (ord < 0 || ord >= len cmembers)		return nil;	return cmembers[ord];} Cmember.next(cp: self ref Cmember, fwd: int): ref Cmember{	if (!fwd)		return cp.prev(1);	x := cp.ord + 1;	if (x >= len cmembers)		x = 0;	return cmembers[x];} Cmember.prev(cp: self ref Cmember, fwd: int): ref Cmember{	if (!fwd)		return cp.next(1);	x := cp.ord - 1;	if (x < 0)		x = len cmembers - 1;	return cmembers[x];}	Cmember.leave(cp: self ref Cmember){	ord := cp.ord;	cmembers[ord] = nil;	cmembers[ord:] = cmembers[ord + 1:];	cmembers[len cmembers - 1] = nil;	cmembers = cmembers[0:len cmembers - 1];	for (i := ord; i < len cmembers; i++)		cmembers[i].ord = i;	cp.obj.delete();	dellayout(cp.layout);	cp.layout = nil;	idx := cp.id % len cpids;	l: list of ref Cmember;	ll := cpids[idx];	for (; ll != nil; ll = tl ll)		if (hd ll != cp)			l = hd ll :: l;	cpids[idx] = l;	cp.ord = -1;} Cmember.findid(id: int): ref Cmember{	for (l := cpids[id % len cpids]; l != nil; l = tl l)		if ((hd l).id == id)			return hd l;	return nil;} newstack(parent: ref Object, owner: ref Member, spec: Stackspec): ref Object{	vis := All;	if (spec.conceal) {		vis = None;		if (owner != nil)			vis = vis.add(owner.id);	}	o := clique.newobject(parent, vis, "stack");	o.setattr("maxcards", string spec.maxcards, All);	o.setattr("style", spec.style, All); 	# XXX provide some means for this to contain the member's name?	o.setattr("title", spec.title, All);	return o;} makecard(deck: ref Object, c: Card, rear: string): ref Object{	card := clique.newobject(deck, None, "card");	card.setattr("face", string c.face, All);	vis := None;	if(c.face)		vis = All;	card.setattr("number", string (c.number * 4 + c.suit), vis);	if (rear != nil)		card.setattr("rear", rear, All);	return card;} makecards(deck: ref Object, r: Range, rear: string){	for (i := r.start; i < r.end; i++)		for(suit := 0; suit < 4; suit++)			makecard(deck, (suit, i, 0), rear);} # deal n cards to each member, if possible.# deal in chunks for efficiency.# if accuracy is required (e.g. dealing from an unshuffled# deck containing known cards) then this'll have to change.deal(deck: ref Object, n: int, stacks: array of ref Object, first: int){	ncards := len deck.children;	ord := 0;	permember := n;	leftover := 0;	if (n * len stacks > ncards) {		# if trying to deal more cards than we've got,		# deal all that we've got, distributing the remainder fairly.		permember = ncards / len stacks;		leftover = ncards % len stacks;	}	for (i := 0; i < len stacks; i++) {		n = permember;		if (leftover > 0) {			n++;			leftover--;		}		priv := stacks[(first + i) % len stacks];		deck.transfer((ncards - n, ncards), priv, len priv.children);		priv.setattr("n", string (int priv.getattr("n") + n), All);		# make cards visible to member		for (j := len priv.children - n; j < len priv.children; j++)			setface(priv.children[j], 1); 		ncards -= n;	}} setface(card: ref Object, face: int){	# XXX check parent stack style and if it's a pile,	# only expose a face up card at the top. 	card.setattr("face", string face, All);	if (face)		card.setattrvisibility("number", All);	else		card.setattrvisibility("number", None);} nmembers(): int{	return len cmembers;} getcard(card: ref Object): Card{	n := int card.getattr("number");	(suit, num) := (n % 4, n / 4);	return Card(suit, num, int card.getattr("face"));} getcards(stack: ref Object): array of Card{	a := array[len stack.children] of Card;	for (i := 0; i < len a; i++)		a[i] = getcard(stack.children[i]);	return a;} discard(stk, pile: ref Object, facedown: int){	n := len stk.children;	if (facedown)		for (i := 0; i < n; i++)			setface(stk.children[i], 0);	stk.transfer((0, n), pile, len pile.children);} # shuffle children into a random order.  first we make all the children# invisible (which will cause them to be deleted in the clients) then# shuffle to our heart's content, and make visible again...shuffle(o: ref Object){	ovis := o.visibility;	o.setvisibility(None);	a := o.children;	n := len a;	for (i := 0; i < n; i++) {		j := i + rand(n - i);		(a[i], a[j]) = (a[j], a[i]);	}	o.setvisibility(ovis);} sort(o: ref Object, rank, suitrank: array of int){	if (rank == nil)		rank = defaultrank;	if (suitrank == nil)		suitrank = defaultsuitrank;	ovis := o.visibility;	o.setvisibility(None);	cardmergesort(o.children, array[len o.children] of ref Object, rank, suitrank);	o.setvisibility(ovis);} cardcmp(a, b: ref Object, rank, suitrank: array of int): int{	c1 := getcard(a);	c2 := getcard(b);	if (suitrank[c1.suit] != suitrank[c2.suit])		return suitrank[c1.suit] - suitrank[c2.suit];	return rank[c1.number] - rank[c2.number];} cardmergesort(a, b: array of ref Object, rank, suitrank: array of int){	r := len a;	if (r > 1) {		m := (r-1)/2 + 1;		cardmergesort(a[0:m], b[0:m], rank, suitrank);		cardmergesort(a[m:], b[m:], rank, suitrank);		b[0:] = a;		for ((i, j, k) := (0, m, 0); i < m && j < r; k++) {			if (cardcmp(b[i], b[j], rank, suitrank) > 0)				a[k] = b[j++];			else				a[k] = b[i++];		}		if (i < m)			a[k:] = b[i:m];		else if (j < r)			a[k:] = b[j:r];	}} # reverse and flip all cards in stack.flip(stack: ref Object){	ovis := stack.visibility;	stack.setvisibility(None);	a := stack.children;	(n, m) := (len a, len a / 2);

Lines 1–500 of 917.