ref: 8348e316b6d659c2632c6bcbbcc2c0a2bf5f5da8
parent: 6c7e3210c963313a6cbc34725d631fcbeef62bdb
author: jgstratton <jgstratton@cyber.lan>
date: Sat Sep 25 13:07:29 EDT 2021
Initial add
--- 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;
+}