Logo Search packages:      
Sourcecode: vgacardgames version File versions  Download package

klondike.c

/*
 * Klondike
 *
 * Copyright (C) Evan Harris, 1991, 1994
 *
 * Permission is granted to freely redistribute and modify this code,
 * providing the author(s) get credit for having written it.
 */

#include <stdio.h>
#include <getopt.h>

#include "klondike.h"

unsigned char     column[COLUMNS];        /* First card of column */
unsigned char     stock, pile;                  /* First card of stock, pile */
short       cards[NUMCARDS];        /* Positions of cards */
unsigned char     next[NUMCARDS];               /* Card underneath */
unsigned char     hidden[NUMCARDS];       /* Cards which are face down */
unsigned char     foundation[NUMSUITS];

int stockcycled;        /* The number of times stock has been cycled */


void main(int argc, char **argv)
{
    short cmd, dest;
    int cycle = 0, stockmove = 1;
    int c, err = 0;

    while ((c = getopt(argc, argv, "cm:")) != -1) {
      switch (c) {
        case 'c':
          cycle = 1;
          break;
        case 'm':
          stockmove = atoi(optarg);
          if (stockmove == 0) {
            err++;
          }
          break;
        case '?':
          err++;
          break;
      }
    }
    if (err) {
      fprintf(stderr, "Usage: %s [-c] [-m N]", argv[0]);
      fprintf(stderr, "\t-c    cycle through stock forever\n");
      fprintf(stderr, "\t-m N  move through stock N cards at a time\n");
      exit(1);
    }


    
    InitDisplay(argc, argv);

    InitRandom(NEW);
    Deal();

    for (;;) {
      cmd = GetCmd();
      if (cmd == QUIT) {
          EndDisplay();
          exit(0);
      }
      else if (cmd == NEWGAME) {
          InitRandom(NEW);
          Deal();
      }
      else if (cmd == RESTART) {
          InitRandom(LAST);
          Deal();
      }
      else if (cmd == FROMSTOCK) {
          FromStock(cycle, stockmove);
      }
      else if (ISCARD(NOHINT(cmd))) {
          dest = FindDest(cmd);
          if (dest != NOPOSN)
            MakeMove((unsigned char)NOHINT(cmd), dest);
      }
    }

    /* Never reached */
}


void Deal()
{
    unsigned char i, j;
    unsigned char row, col;
    short r;

    /* Initialise the deck */
    for (i = 0; i < NUMCARDS; i++) {
      cards[i] = NOPOSN;
      next[i] = NOCARD;
    }
    for (i = 0; i < NUMSUITS; i++)
      foundation[i] = ACE;
    pile = NOCARD;
            
    /* Deal the deck */
    row = 0;
    col = 0;
    for (i = 0; i < NUMCARDS; i++) {
      r = Random(NUMCARDS - i);
      for (j = 0; j < NUMCARDS && r >= 0; j++) {
          if (cards[j] == NOPOSN)
            r--;
      }
      r = j - 1;

      cards[r] = POSN(col, row);
      if (col != STOCK) {
          if (row == 0)
            column[col] = r;
          else {
            for (j = 0; cards[j] != POSN(col, row - 1); j++)
                ;
            next[j] = r;
          }
          if (col == row) {
            hidden[r] = 0;
            col++; 
            row = 0;
          }
          else {
            hidden[r] = 1;
            row++;
          }
      }
      else {
          if (row == 0)
            stock = r;
          else {
            for (j = 0; cards[j] != POSN(col, row - 1); j++)
                ;
            next[j] = r;
          }
          hidden[r] = 0;
          row++;
      }
    }

    stockcycled = 0;

    for (i = 0; i < COLUMNS; i++)
      DisplayColumn((short)i);
    DisplayFoundations();
    DisplayStockPile();

    return;
}


short FindDest(short card)
{
    unsigned char i, c;
    short move;

    if (HASHINT(card))
      return FindHintedDest((short)NOHINT(card), (short)HINT(card));

    move = CanMoveOff((unsigned char)card);
    if (move == DESIRABLE)
      return MOVEOFF;

    if (TYPE(card) == KING) {
      if (ROW(cards[card]) == 0 && COL(cards[card]) != PILE) {
          if (move == POSSIBLE)
            return MOVEOFF;
          else
            return NOPOSN;
      }
      for (i = 0; i < COLUMNS; i++)
          if (column[i] == NOCARD)
            return (short)POSN(i, 0);
    }
    else {
      for (i = 0; i < COLUMNS; i++)
          if (i != COL(cards[card]) && column[i] != NOCARD) {
            c = column[i];
            while (next[c] != NOCARD)
                c = next[c];
            if ((TYPE(c) == TYPE(card) + 1) &&
                ((ISBLACK(c) && ISRED(card)) || 
                 (ISRED(c) && ISBLACK(card)))) {
                return (short)POSN(COL(cards[c]), ROW(cards[c]) + 1);
            }
          }
    }

    if (move == POSSIBLE)
      return MOVEOFF;
    else
      return NOPOSN;
}


short FindHintedDest(short card, short hint)
{
    unsigned char c;
    short move;

    if (hint == FOUNDATION) {
      move = CanMoveOff((unsigned char)card);
      if (move != IMPOSSIBLE)
          return MOVEOFF;
      else
          return NOPOSN;
    }

    if (TYPE(card) == KING) {
      if (ROW(cards[card]) == 0 && COL(cards[card]) != PILE)
          return NOPOSN;
      if (column[hint] == NOCARD)
          return (short)POSN(hint, 0);
    }
    else {
      if (hint != COL(cards[card])) {
          c = column[hint];
          while (next[c] != NOCARD)
            c = next[c];
          if ((TYPE(c) == TYPE(card) + 1) &&
            ((ISBLACK(c) && ISRED(card)) || 
             (ISRED(c) && ISBLACK(card))))
            return (short)POSN(COL(cards[c]), ROW(cards[c]) + 1);
      }
    }

    return NOPOSN;
}


void MakeMove(unsigned char card, short dest)
{
    short col, row, oldcol;
    unsigned char c, i;

    if (dest == MOVEOFF) {
      MoveOff(card);
      return;
    }

    col = COL(dest);
    row = ROW(dest);
    oldcol = -1;

    if (pile == card) {
      pile = next[card];
      next[card] = NOCARD;
      oldcol = PILE;
    }
    for (i = 0; oldcol == -1 && i < COLUMNS; i++) {
      if (column[i] == card) {
          column[i] = NOCARD;
          oldcol = i;
      }
    }
    for (i = 0; oldcol == -1 && i < NUMCARDS; i++) {
      if (next[i] == card) {
          if (hidden[i])
            hidden[i] = 0;
          next[i] = NOCARD;
          oldcol = COL(cards[i]);
      }
    }

    if (row > 0) {
      c = column[col];
      while (next[c] != NOCARD)
          c = next[c];
      next[c] = card;
    }
    else
      column[col] = card;
    while (card != NOCARD) {
      cards[card] = POSN(col, row++);
      card = next[card];
    }

    DisplayColumn(oldcol);
    DisplayColumn(col);

    return;
}


void FromStock(int cycle, int stockmove)
{
    unsigned char oldpile, oldstock;
    int i;

    if (stock != NOCARD) {
      for (i = 0; i < stockmove && stock != NOCARD; i++) {
          oldpile = pile;
          pile = stock;
          stock = next[stock];
          next[pile] = oldpile;
          cards[pile] = POSN(PILE, 0);
      }

      DisplayStockPile();

    } else if ((++stockcycled) / stockmove == 0 || cycle) {
      while (pile != NOCARD) {
          oldstock = stock;
          stock = pile;
          pile = next[pile];
          next[stock] = oldstock;
          cards[stock] = POSN(STOCK, 0);
          hidden[stock] = 0;
      }

      DisplayStockPile();

    }

    return;
}


void MoveOff(unsigned char card)
{
    unsigned char i;
    short oldcol;

    if (card == pile && TYPE(card) == foundation[SUIT(card)]) {
      pile = next[card];
      next[card] = NOCARD;
      cards[card] = POSN(FOUNDATION, 0);
      foundation[SUIT(card)]++;

      DisplayFoundations();
      DisplayStockPile();
    }
    else if (next[card] == NOCARD && TYPE(card) == foundation[SUIT(card)]) {
      oldcol = -1;
      for (i = 0; oldcol == -1 && i < COLUMNS; i++) {
          if (column[i] == card) {
            column[i] = NOCARD;
            oldcol = i;
          }
      }
      for (i = 0; oldcol == -1 && i < NUMCARDS; i++) {
          if (next[i] == card) {
            if (hidden[i])
                hidden[i] = 0;
            next[i] = NOCARD;
            oldcol = COL(cards[i]);
          }
      }

      cards[card] = POSN(FOUNDATION, 0);
      foundation[SUIT(card)]++;

      DisplayFoundations();
      DisplayColumn((short)oldcol);
    }

    return;
}


short CanMoveOff(unsigned char card)
{
    if (foundation[SUIT(card)] != TYPE(card) || 
      (COL(cards[card]) != PILE && next[card] != NOCARD))
      return IMPOSSIBLE;

    if (LowestFoundation((unsigned char)SUIT(card)))
      return DESIRABLE;

    return POSSIBLE;
}


unsigned char LowestFoundation(unsigned char suit)
{
    unsigned char i;

    for (i = 0; i < NUMSUITS; i++)
      if (foundation[i] < foundation[suit])
          return FALSE;
    return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index