implement Tricks; include "sys.m"; sys: Sys; include "draw.m"; include "sets.m"; sets: Sets; Set, All, None: import sets; include "../spree.m"; spree: Spree; Attributes, Range, Object, Clique, Member: import spree; include "cardlib.m"; cardlib: Cardlib; Card, getcard: import cardlib; include "tricks.m"; clique: ref Clique; init(mod: Spree, g: ref Clique, cardlibmod: Cardlib) { sys = load Sys Sys->PATH; sets = load Sets Sets->PATH; if (sets == nil) panic(sys->sprint("cannot load %s: %r", Sets->PATH)); clique = g; spree = mod; cardlib = cardlibmod; } defaultrank := array[13] of {12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; # XXX should take a "rank" array so that we can cope with custom # card ranking Trick.new(pile: ref Object, trumps: int, hands: array of ref Object, rank: array of int): ref Trick { t := ref Trick; t.highcard = t.startcard = Card(-1, -1, -1); t.winner = -1; t.trumps = trumps; t.pile = pile; t.hands = hands; if (rank == nil) rank = defaultrank; t.rank = rank; return t; } Trick.archive(t: self ref Trick, archiveobj: ref Object, name: string) { a := clique.newobject(archiveobj, None, "trick"); cardlib->setarchivename(a, name); a.setattr("trumps", string t.trumps, None); a.setattr("winner", string t.winner, None); a.setattr("startcard.n", string t.startcard.number, None); a.setattr("startcard.suit", string t.startcard.suit, None); a.setattr("highcard.n", string t.highcard.number, None); a.setattr("highcard.suit", string t.highcard.suit, None); cardlib->setarchivename(t.pile, name + ".pile"); cardlib->archivearray(t.hands, name); for (i := 0; i < len t.rank; i++) if (t.rank[i] != defaultrank[i]) break; if (i < len t.rank) { r := ""; for (i = 0; i < len t.rank; i++) r += " " + string t.rank[i]; a.setattr("rank", r, None); } } Trick.unarchive(nil: ref Object, name: string): ref Trick { t := ref Trick; a := cardlib->getarchiveobj(name); t.trumps = int a.getattr("trumps"); t.winner = int a.getattr("winner"); t.startcard.number = int a.getattr("startcard.n"); t.startcard.suit = int a.getattr("startcard.suit"); t.highcard.number = int a.getattr("highcard.n"); t.highcard.suit = int a.getattr("highcard.suit"); t.pile = cardlib->getarchiveobj(name + ".pile"); t.hands = cardlib->getarchivearray(name); r := a.getattr("rank"); if (r != nil) { (nil, toks) := sys->tokenize(r, " "); t.rank = array[len toks] of int; i := 0; for (; toks != nil; toks = tl toks) t.rank[i++] = int hd toks; } else t.rank = defaultrank; return t; } Trick.play(t: self ref Trick, ord, idx: int): string { stack := t.hands[ord]; if (idx < 0 || idx >= len stack.children) return "invalid card to play"; c := getcard(stack.children[idx]); c.number = t.rank[c.number]; if (len t.pile.children == 0) { t.winner = ord; t.startcard = t.highcard = c; } else { if (c.suit != t.startcard.suit) { if (containssuit(stack, t.startcard.suit)) return "you must play the suit that was led"; if (c.suit == t.trumps && (t.highcard.suit != t.trumps || c.number > t.highcard.number)) { t.highcard = c; t.winner = ord; } } else if (c.suit == t.highcard.suit && c.number > t.highcard.number) { t.highcard = c; t.winner = ord; } } stack.transfer((idx, idx + 1), t.pile, len t.pile.children); stack.setattr("n", string (int stack.getattr("n") - 1), All); return nil; } containssuit(stack: ref Object, suit: int): int { ch := stack.children; n := len ch; for (i := 0; i < n; i++) if (getcard(ch[i]).suit == suit) return 1; return 0; } panic(e: string) { sys->fprint(sys->fildes(2), "tricks panic: %s\n", e); raise "panic"; }