summaryrefslogtreecommitdiff
path: root/appl/spree/lib/tricks.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/spree/lib/tricks.b')
-rw-r--r--appl/spree/lib/tricks.b140
1 files changed, 140 insertions, 0 deletions
diff --git a/appl/spree/lib/tricks.b b/appl/spree/lib/tricks.b
new file mode 100644
index 00000000..3763bac5
--- /dev/null
+++ b/appl/spree/lib/tricks.b
@@ -0,0 +1,140 @@
+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";
+}