#!/bin/sh echo 'Start of solitare, part 01 of 01:' echo 'x - Makefile' sed 's/^X//' > Makefile << '/' X####################################################################### X# This Makefile understandsd g++ and interviews X# ####################################################################### XCC = gcc XGXX = g++ XGFLAGS= -g XLIBS = -lInterViewsX11 -lg++ -lX11 -lm X# The following two rules add automaticity to c++ suffixes X.SUFFIXES: .cc .C X.cc.o: X $(GXX) $(GFLAGS) -c $< X.C.o: X $(GXX) $(GFLAGS) -c $< X####################################################################### Xsolitare: solitare.o card.o pile.o X $(GXX) $(GFLAGS) -o solitare solitare.o card.o pile.o $(LIBS) / echo 'x - card.h' sed 's/^X//' > card.h << '/' X// X// card.h - definition for card behavior X// cards have a suit, a rank, and know how to draw themselves X// X// written by tim budd, oregon state university, 1990 X// X X# ifndef Cardh X# define Cardh X X# define CardWidth 68 X# define CardHeight 75 X X// X// ---------------------------- class Link X// Xclass Link { Xprotected: X Link *link; X X Link * next (); X void setLink (Link *ele); X}; X Xinline void Link::setLink(Link *ele) { link = ele; } X Xinline Link * Link::next() { return link; } X X// X// ---------------------------- class Card X// Xclass Card : public Link X{ X public: X // constructor X Card(int s, int c); X X int color (); X void draw (); X void erase (); X int faceUp (); X void flip (); X int includes (int, int); X int locx (); X int locy (); X void moveTo (int, int); X Card * next (); X int rankCount (); X void setLink (Card * aCard); X int suitValue (); X X private: X int suit; // suit value X int rank; // rank value X int up; // true if face up X int x; // x location of card X int y; // y location of card X}; X Xinline int Card::color() { return suit % 2; } X Xinline int Card::faceUp() { return up; } X Xinline void Card::flip() { up = ! up; } X Xinline int Card::locx() { return x; } X Xinline int Card::locy() { return y; } X Xinline void Card::moveTo(int sx, int sy) { x = sx; y = sy; } X Xinline Card * Card::next() { return (Card *) Link::next(); } X Xinline int Card::rankCount() { return rank; } X Xinline void Card::setLink (Card * aCard) { Link::setLink(aCard); } X Xinline int Card::suitValue() { return suit; } X X/* define an empty card pointer */ X# define nilcard (Card *) 0 X X# endif / echo 'x - game.h' sed 's/^X//' > game.h << '/' X// interface description of game window for X// solitaire game X// X// written by tim budd, oregon state university, 1990 X// X X# ifndef SeenGameh X# define SeenGameh X X# include X# include X X# include "pile.h" X Xclass GameWindow : public MonoScene X{ Xpublic: X Pile *discard; // the discard pile X Pile *deck; // the umplayed card deck X X GameWindow(); X X void newGame(); // start a new game X void clearArea (int, int, int, int); X int suitCanAdd(Card*); X Pile * suitAddPile(Card*); X int tableCanAdd(Card*); X Pile * tableAddPile(Card*); X Xprotected: X Pile * allPiles[13]; // all piles X Pile * suitPiles[4]; // the pile of suits X Pile * table[7]; // the playing table X X void virtual Handle (Event&); X void virtual Redraw(Coord,Coord,Coord,Coord); X}; X# endif / echo 'x - pile.h' sed 's/^X//' > pile.h << '/' X// X// pile.h - interface for class Pile, representing a pile of cards X// uses instances of class Card X// X// written by tim budd, oregon state university, 1990 X// X X# ifndef SeenPileh X# define SeenPileh X X# include "card.h" X X// X// ---------------------------- class Pile X// Xclass Pile X{ Xpublic: X Pile(); X Pile(int, int); X X void virtual addCard (Card *); X int virtual canTake(Card *); X int contains (int, int); X void virtual display(); X void virtual initialize(); X Card * removeCard (); X void virtual select(int, int); X void shuffleTo (Pile *); X Xprivate: X int x; // x location of pile X int y; // y location of pile X Xprotected: X Card *top; // first card in pile X}; X Xinline Pile::Pile() { top = nilcard; } X Xinline Pile::Pile(int a, int b) { x = a; y = b; top = nilcard; } X X// X// ---------------------------- class SuitPile X// X// X// SuitPile - the pile of suit cards X// at the top of the board X Xclass SuitPile : public Pile X{ Xpublic: X int virtual canTake (Card *); X}; X X// X// ---------------------------- class TablePile X// X// Xclass TablePile : public Pile X{ X public: X TablePile(int c, int x, int y) : Pile(x, y) { column = c; } X X void virtual addCard (Card *); X int virtual canTake (Card *); X void copyBuild (Card *, Pile *); X void virtual display (); X void virtual select (int, int); X void virtual initialize (); X Xprivate: X int column; // our column number X}; X X X// X// ---------------------------- class DeckPile X// X// X Xclass DeckPile : public Pile X{ Xpublic: X void virtual addCard (Card *); X void virtual initialize (); X void virtual select (int, int); X}; X X// X// ---------------------------- class DiscardPile X// X// X Xclass DiscardPile : public Pile X{ Xpublic: X void virtual addCard (Card *); X void virtual select (int, int); X}; X X# endif / echo 'x - card.cc' sed 's/^X//' > card.cc << '/' X// X// card.c - implementation of card behavior X// X// written by tim budd, oregon state university, 1990 X// X X# include "card.h" X# include X# include X X// the actual drawing is done using interview tools: Xextern Canvas * drawField; Xextern Painter * painter; X X// X// ---------------------------- class Card X// X Xstatic char *suits[ ] = {"Heart", "Club", "Diamond", "Spade" }; X Xstatic char *ranks[ ] = {"blank", "Ace", "2", "3", "4", "5", "6", X "7", "8", "9", "10", "Jack", "Queen", "King" }; X X X// constructor XCard::Card(int s, int c) X{ X suit = s; X rank = c; X up = 0; X x = y = 0; X} X X// draw Xvoid Card::draw() X{ X // erase the card and redraw it X erase(); X painter->Rect(drawField, x, y, x+CardWidth, y+CardHeight); X if (up) { // draw the card face up X painter->MoveTo(x+12, y+round(CardHeight*0.80)); X painter->Text(drawField, suits[suit]); X painter->MoveTo(x+15, y+round(CardHeight*0.60)); X painter->Text(drawField, ranks[rank]); X } X else { int n; // draw the card face down X n = x+round(CardWidth*0.3); X painter->Line(drawField, n, y+5, n, y+CardHeight-10); X n = x+round(CardWidth*0.7); X painter->Line(drawField, n, y+5, n, y+CardHeight-10); X n = y+round(CardHeight*0.3); X painter->Line(drawField, x+5, n, x+CardWidth-10, n); X n = y+round(CardHeight*0.7); X painter->Line(drawField, x+5, n, x+CardWidth-10, n); X } X} X X// erase Xvoid Card::erase() X{ Color *fg, *bg; X X // first get the foreground and background colors X fg = painter->GetFgColor(); X bg = painter->GetBgColor(); X // then reverse them X painter->SetColors(bg, fg); X // then draw a filled rectangle X painter->FillRect(drawField, x, y, x+CardWidth, y+CardHeight); X // then restore the colors X painter->SetColors(fg, bg); X} X X// includes Xint Card::includes(int a, int b) X{ X return (a >= x) && (a <= x + CardHeight) && (b >= y) && X (b <= y + CardWidth); X} / echo 'x - pile.cc' sed 's/^X//' > pile.cc << '/' X// X// pile.c -- implementation for class Pile X// X// X// written by tim budd, oregon state university, 1990 X// X X# include "game.h" X Xextern GameWindow * game; Xextern Pile * newDeck; X X// X// ---------------------------- class Pile X// X Xvoid Pile::addCard(Card *aCard) X{ X if (aCard != nilcard) { X aCard->setLink(top); X top = aCard; X top->moveTo(x, y); X } X} X Xint Pile::canTake(Card *aCard) X{ X return 0; X} X Xint Pile::contains(int a, int b) X{ X for (Card *p = top; p != nilcard; p = p->next()) X if (p->includes(a, b)) X return 1; X return 0; X} X Xvoid Pile::display() X{ X if (top == nilcard) X game->clearArea(x, y, x+CardWidth, y+CardHeight); X else X top->draw(); X} X Xvoid Pile::initialize() X{ X top = nilcard; X} X XCard *Pile::removeCard() X{ Card *p; X X if (top == nilcard) X return nilcard; X p = top; X top = top->next(); X return p; X} X Xvoid Pile::select(int x, int y) X{ /* do nothing */ ; } X Xextern "C" { int rand(); } X Xvoid Pile::shuffleTo(Pile *aPile) X{ Card *p, *q; X int max, limit, i; X X // first see how many cards we have X for (max = 0, p = top; p != nilcard; p = p->next()) { X max++; X if (p->faceUp()) p->flip(); X } X X // then pull them out, randomly, one at a time X for (; max > 0; max--) { X limit = ((rand() >> 3) % max) + 1; X for (i = 1, p = top; i <= limit; ) { X while (p->faceUp()) p = p->next(); X i += 1; X if (i <= limit) p = p->next(); X } X q = new Card(p->suitValue(), p->rankCount()); X aPile->addCard(q); X p->flip(); X } X} X X// X// ---------------------------- class DeckPile X// X Xvoid DeckPile::initialize() X{ X Pile::initialize(); X newDeck->shuffleTo(this); X} X Xvoid DeckPile::addCard(Card *c) X{ X if (c->faceUp()) X c->flip(); X Pile::addCard(c); X} X Xvoid DeckPile::select(int x, int y) // turn over a new card X{ Card *c; X X if (top == nilcard) X ; X else { X c = removeCard(); X if (c != nilcard) X (game->discard)->addCard(c); X } X display(); X (game->discard)->display(); X} X X// X// ---------------------------- class DiscardPile X// X Xvoid DiscardPile::addCard(Card *c) X{ X if (!(c->faceUp())) X c->flip(); X Pile::addCard(c); X} X Xvoid DiscardPile::select(int x, int y) // play the current face card X{ Card *c; X int i; X Pile *aPile; X X if (top == nilcard) return; X // see if we can move it to a suit pile X if (game->suitCanAdd(top)) { X aPile = game->suitAddPile(top); X aPile->addCard(removeCard()); X display(); X aPile->display(); X return; X } X // else see if we can move to a table pile X if (game->tableCanAdd(top)) { X aPile = game->tableAddPile(top); X aPile->addCard(removeCard()); X display(); X aPile->display(); X return; X } X // else do nothing X} X X// X// ---------------------------- class SuitPile X// X Xint SuitPile::canTake(Card *aCard) X{ X if (top == nilcard) { // we're empty, can take an ace X if (aCard->rankCount() == 1) return 1; X return 0; X } X if (top->suitValue() != aCard->suitValue()) return 0; X if ((top->rankCount() + 1) == aCard->rankCount()) X return 1; X return 0; X} X X// X// ---------------------------- class TablePile X// X Xvoid TablePile::initialize() X{ int i; X X // put the right number of cards on the table X Pile::initialize(); X for (i = 0; i <= column; i++) X addCard((game->deck)->removeCard()); X // flip the last one X if (top != nilcard) { X top->flip(); X } X} X Xvoid TablePile::addCard(Card *aCard) X{ int tx, ty; X X if (top == nilcard) X Pile::addCard(aCard); X else { X tx = top->locx(); X ty = top->locy(); X // figure out where to place the card X if (top->faceUp() && top->next() != nilcard && X (top->next())->faceUp()) X ; // do nothing, place on top of top card X else X // else move it down a bit X ty -= round(CardHeight * 0.5); X Pile::addCard(aCard); X top->moveTo(tx, ty); X } X} X Xint TablePile::canTake(Card *aCard) X{ X if (top == nilcard) { // can take kings on an empty pile X if (aCard->rankCount() == 13) return 1; X return 0; X } X // see if colors are different X if (top->color() == aCard->color()) return 0; X // see if numbers are legal X if ((top->rankCount() - 1) == aCard->rankCount()) X return 1; X return 0; X} X Xvoid TablePile::copyBuild(Card *c, Pile *aPile) X{ Card *d; X X top->erase(); X d = removeCard(); X display(); X if (c != d) copyBuild(c, aPile); X aPile->addCard(d); X aPile->display(); X} X Xstatic void stackDisplay(Card *p) X{ X if (p->next()) X stackDisplay(p->next()); X p->erase(); X p->draw(); X} X Xvoid TablePile::display() X{ Card *p; X X // zero or one cards, can't do any better X if (top == nilcard) X Pile::display(); X // otherwise half display all the covered cards X else { X /*for (p = top->next(); p != nilcard; p = p->next()) X p->halfDraw(); X top->draw(); */ X stackDisplay(top); X } X} X Xvoid TablePile::select(int x, int y) X{ Card *c; X int i; X X // no cards, do nothing X if (top == nilcard) return; X X // if top card is not flipped, flip it now X if (! top->faceUp()) { X top->erase(); X top->flip(); X top->draw(); X return; X } X X // if it was to top card, see if we can move it X if (top->includes(x, y)) { X // see if we can move it to a suit pile X if (game->suitCanAdd(top)) { X copyBuild(top, game->suitAddPile(top)); X return; X } X // else see if we can move to a table pile X // but only if it is not part of pile X if ((top->next() == nilcard) || ! (((top->next())->faceUp()))) X if (game->tableCanAdd(top)) { X copyBuild(top, game->tableAddPile(top)); X return; X } X } X // else see if we can move a pile X for (c = top->next(); c != nilcard; c = c->next()) X if (c->faceUp() && c->includes(x, y)) { X if (game->tableCanAdd(c)) { X copyBuild(c, game->tableAddPile(c)); X } X return; X } X // else do nothing X} / echo 'x - solitare.cc' sed 's/^X//' > solitare.cc << '/' X// X// solitaire game using Interviews interface X// X// written by tim budd, oregon state university, 1990 X// X X# include X# include X# include X# include X# include X# include X# include X X# include "game.h" X X# define BoardWidth 600 X# define BoardHeight 450 X XGameWindow *game; X Xextern "C" { Xvoid exit(); X} X X// The Quit button at the bottom of the screen halts game Xclass QuitButton : public PushButton X{ Xpublic: X QuitButton() : PushButton("quit", new ButtonState(false), true) {;} X void virtual Press() { exit(0); } X}; X X// The Start button at the bottom of the screen starts game Xclass StartButton : public PushButton X{ Xpublic: X StartButton() : PushButton("start", new ButtonState(false), true) {;} X void virtual Press() { game->newGame(); } X}; X XCanvas * drawField; // the drawing area for game XPainter * painter; // the object used to draw the cards XPile * newDeck; // the original unshuffled deck X X// X// the main program X// create a new game window X// map it onto the screen with two buttons at bottom X// start it up X// X Xint main (int argc, char ** argv) { X X World *world = new World("solitaire", argc, argv); X X game = new GameWindow; X X world->InsertApplication( new VBox(game, X new HBox(new QuitButton, new StartButton))); X X drawField = game->GetCanvas(); X X world->Run(); X} X X// X// initialize the game window X// XGameWindow::GameWindow(){ X int i, j, hight; X X // create a new shape for our drawing area X shape = new Shape; X shape->Rect(BoardWidth, BoardHeight); X shape->Rigid(hfil, hfil, vfil, vfil); X X // create a new sensor so that we can catch mouse down events X input = new Sensor; X input->Catch(DownEvent); X X // create a new painter for drawing X painter = new Painter; X X // now some game specific initialization X // create the original (unshuffled) deck X newDeck = new Pile(-100, -100); X for (i = 0; i < 4; i++) X for (j = 1; j <= 13; j++) X newDeck->addCard(new Card(i, j)); X X // create suit piles X hight = BoardHeight - round(1.5*CardHeight); X // create the deck and discard piles X allPiles[0] = deck = new DeckPile(500, hight); X allPiles[1] = discard = new DiscardPile(400, hight); X // create suit piles X for (i = 0; i < 4; i++) X allPiles[i+2] = suitPiles[i] = X new SuitPile(30 + (round(1.4*CardWidth) * i), hight); X X X // create tableau X hight = BoardHeight - round(2.7*CardHeight); X for (i = 0; i < 7; i++) X allPiles[i+6] = table[i] = X new TablePile(i, 10 + (round(1.2*CardWidth) * i), X hight); X X} X X// X// start up a new game X// Xvoid GameWindow::newGame() X{ int i; X X // initialize all the piles X for (i = 0; i < 13; i++) X allPiles[i]->initialize(); X X // then redraw the game window X Draw(); X} X X// X// redraw the window X// Xvoid GameWindow::Redraw(Coord a, Coord b, Coord c, Coord d) X{ int i; X X // first clear the entire playing area X clearArea(0,0, BoardWidth, BoardHeight); X X // then display the piles X for (i = 0; i < 13; i++) X allPiles[i]->display(); X} X X// X// handle a mouse down event in the game window X// Xvoid GameWindow::Handle (Event& e) X{ int i; X X // we are only interested in mouse down events X if (e.eventType != DownEvent) return; X X for (i = 0; i < 13; i++) X if (allPiles[i]->contains(e.x, e.y)) { X allPiles[i]->select(e.x, e.y); X return; X } X return; X} X X// X// see if any of the suit piles can add a specific card X// Xint GameWindow::suitCanAdd(Card *aCard) X{ int i; X X for (i = 0; i < 4; i++) X if (suitPiles[i]->canTake(aCard)) return 1; X return 0; X} X X// X// see if any of the table piles can add a specific card X// Xint GameWindow::tableCanAdd(Card *aCard) X{ int i; X X for (i = 0; i < 7; i++) X if (table[i]->canTake(aCard)) return 1; X return 0; X} X X// X// return which of the suit piles can add a card X// XPile *GameWindow::suitAddPile(Card *aCard) X{ int i; X X for (i = 0; i < 4; i++) X if (suitPiles[i]->canTake(aCard)) X return suitPiles[i]; X // hopefully this won't happen X return newDeck; X} X X// X// return which of the table piles can add a card X// XPile *GameWindow::tableAddPile(Card *aCard) X{ int i; X X for (i = 0; i < 7; i++) X if (table[i]->canTake(aCard)) X return table[i]; X // hopefully this won't happen X return newDeck; X} X X// X// clear out a given area in the game window X// Xvoid GameWindow::clearArea(int a, int b, int c, int d) X{ Color *fg, *bg; X X // first get the foreground and background colors X fg = painter->GetFgColor(); X bg = painter->GetBgColor(); X // then reverse them X painter->SetColors(bg, fg); X // then draw a filled rectangle X painter->FillRect(drawField, a, b, c, d); X // then restore the colors X painter->SetColors(fg, bg); X} / echo 'Part 01 of solitare complete.' exit