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

spider.c

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

#include "spider.h"
#include <stdlib.h>


#define U_MOVE                1
#define U_MOVEOFF       2
#define U_MOVE_EXPOSE         3
#define U_MOVEOFF_EXPOSE      4
#define U_FROMSTOCK           5

struct undo {
    unsigned char type;
    unsigned char card;
    short from;
    struct undo   *next;
};


unsigned char     column[COLUMNS];        /* First card of column */
unsigned char     stock;
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];
struct undo *undoinfo = NULL;


void main(int argc, char **argv)
{
    short cmd, dest;

    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();
      }
      else if (cmd == UNDO) {
          Undo();
      }
      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, lastr = 0;
    struct undo *u;

    /* Initialise the deck */
    for (i = 0; i < NUMCARDS; i++) {
      cards[i] = NOPOSN;
      next[i] = NOCARD;
    }
    /* Initialise foundations */
    for (i = 0; i < NUMSUITS; i++) {
      foundation[i] = 0;
    }
            
    /* Remove undo information */
    while (undoinfo) {
      u = undoinfo->next;
      free(undoinfo);
      undoinfo = u;
    }

    /* 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
            next[lastr] = r;
          lastr = r;

          if ((col < 4 && row < 5) || (row < 4)) {
            hidden[r] = 1;
            row++;
          }
          else {
            hidden[r] = 0;
            col++; 
            row = 0;
          }
      }
      else {
          if (row == 0)
            stock = r;
          else
            next[lastr] = r;
          lastr = r;
          hidden[r] = 0;
          row++;
      }
    }
    for (i = 0; i < COLUMNS; i++)
      DisplayColumn((short)i);
    DisplayFoundations();
    DisplayStockPile();

    return;
}


short FindDest(short card)
{
    unsigned char i, c;
    short first = -1;

    c = next[NOHINT(card)];
    i = 1;
    while (c != NOCARD) {
      if (SUIT(c) != SUIT(NOHINT(card)) || TYPE(c) != TYPE(NOHINT(card)) - i) {
          return NOPOSN;
      }
      c = next[c];
      i++;
    }

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

    if (CanMoveOff((unsigned char)card))
      return MOVEOFF;

    c = column[COL(cards[card])];
    if (c != card) {
      while (next[c] != card)
          c = next[c];
      if (!hidden[c] && TYPE(c) == TYPE(card) + 1 && SUIT(c) == SUIT(card)) {
          return NOPOSN;
      }
    }

    if (TYPE(card) != KING) {
      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) {
                if (SUIT(c) == SUIT(card)) {
                  return (short)POSN(COL(cards[c]), ROW(cards[c]) + 1);
                }
                else if (first == -1)
                  first = c;
            }
          }
      }
      if (first != -1) {
          return (short)POSN(COL(cards[first]), ROW(cards[first]) + 1);
      }
    }
    if (ROW(cards[card]) == 0) {
      return NOPOSN;
    }
    for (i = 0; i < COLUMNS; i++) {
      if (column[i] == NOCARD) {
          return (short)POSN(i, 0);
      }
    }

    return NOPOSN;
}


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

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

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

    return NOPOSN;
}


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

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

    col = COL(dest);
    row = ROW(dest);
    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;
            h = 1;
          }
          next[i] = NOCARD;
          oldcol = COL(cards[i]);
      }
    }

    if (h)
      AddUndo(U_MOVE_EXPOSE, card, cards[card]);
    else
      AddUndo(U_MOVE, card, cards[card]);

    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()
{
    unsigned char c, col, row;

    if (stock != NOCARD) {
      for (col = 0; col < COLUMNS; col++) {
          if (column[col] == NOCARD) {
            return;
          }
      }
      for (col = 0; col < COLUMNS; col++) {
          c = column[col];
          row = 1;
          while (next[c] != NOCARD) {
            c = next[c];
            row++;
          }
          next[c] = stock;
          stock = next[stock];
          cards[next[c]] = POSN(col, row);
          next[next[c]] = NOCARD;

          DisplayColumn((short)col);
      }

      if (stock == NOCARD)
          DisplayStockPile();

      AddUndo(U_FROMSTOCK, 0, 0);
    }

    return;
}


void MoveOff(unsigned char card)
{
    unsigned char c, lastc;
    unsigned char h = 0;
    short oldcol;

    oldcol = COL(cards[card]);
    c = column[oldcol];
    lastc = NOCARD;
    while (hidden[c]) {
      lastc = c;
      c = next[c];
    }

    for (;;) {
      while (c != NOCARD && TYPE(c) != KING && SUIT(c) != SUIT(card)) {
          lastc = c;
          c = next[c];
      }
      if (CheckFullTerminatingSuit(c)) {
          if (lastc == NOCARD)
            column[oldcol] = NOCARD;
          else {
            next[lastc] = NOCARD;
            if (hidden[lastc]) {
                hidden[lastc] = 0;
                h = 1;
            }
          }
          if (h)
            AddUndo(U_MOVEOFF_EXPOSE, c, cards[c]);
          else
            AddUndo(U_MOVEOFF, c, cards[c]);
          while (c != NOCARD) {
            cards[c] = POSN(FOUNDATION, 0);
            c = next[c];
          }

          if (foundation[SUIT(card)])
            foundation[SUIT(card) + 4] = 1;
          else
            foundation[SUIT(card)] = 1;
          DisplayFoundations();
          DisplayColumn(oldcol);

          return;
      }
      else {
          lastc = c;
          c = next[c];
      }
    }
}


short CanMoveOff(unsigned char card)
{
    unsigned char c;

    c = column[COL(cards[card])];
    while (hidden[c])
      c = next[c];
    while (c != NOCARD) {
      while (c != NOCARD && TYPE(c) != KING && SUIT(c) != SUIT(card))
          c = next[c];
      if (CheckFullTerminatingSuit(c)) 
          return TRUE;
      else
          c = next[c];
    }
    return FALSE;
}


short CheckFullTerminatingSuit(unsigned char card)
{
    unsigned char c;
    short type;

    c = card;
    type = KING;
    while (c != NOCARD && SUIT(c) == SUIT(card) && TYPE(c) == type) {
      c = next[c];
      type--;
    }

    if (c == NOCARD && type == ACE - 1)
      return TRUE;
    else
      return FALSE;
}


void AddUndo(unsigned char type, unsigned char card, short from)
{
    struct undo *undo;

    undo = (struct undo *)malloc(sizeof(struct undo));
    undo->type = type;
    undo->card = card;
    undo->from = from;
    undo->next = undoinfo;
    undoinfo = undo;

    return;
}


void Undo()
{
    struct undo *undo = undoinfo;

    if (undo == NULL)
      return;

    switch (undo->type) {
      case U_MOVE:
      UndoMove(undo->card, (short)COL(undo->from), 0);
      break;
      case U_MOVE_EXPOSE:
      UndoMove(undo->card, (short)COL(undo->from), 1);
      break;
      case U_MOVEOFF:
      UndoMoveOff(undo->card, (short)COL(undo->from), 0);
      break;
      case U_MOVEOFF_EXPOSE:
      UndoMoveOff(undo->card, (short)COL(undo->from), 1);
      break;
      case U_FROMSTOCK:
      UndoFromStock();
      break;
    }

    undoinfo = undoinfo->next;
    free(undo);

    return;
}


void UndoMove(unsigned char card, short col, unsigned char expose)
{
    unsigned char c, row;
    short oldcol;

    oldcol = COL(cards[card]);
    c = column[oldcol];
    if (c == card) {
      column[oldcol] = NOCARD;
    } else {
      while (next[c] != card)
          c = next[c];
      next[c] = NOCARD;
    }

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

    return;
}


void UndoMoveOff(unsigned char card, short col, unsigned char expose)
{
    unsigned char c, row;

    c = column[col];
    row = 0;
    if (c == NOCARD) {
      column[col] = card;
      c = card;
      while (c != NOCARD) {
          cards[c] = POSN(col, row++);
          c = next[c];
      }
    } else {
      while (next[c] != NOCARD) {
          c = next[c];
          row++;
      }
      if (expose)
          hidden[c] = 1;
      next[c] = card;
      c = next[c];
      while (c != NOCARD) {
          cards[c] = POSN(col, row++);
          c = next[c];
      }
    }
    if (foundation[SUIT(card) + 4])
      foundation[SUIT(card) + 4] = 0;
    else
      foundation[SUIT(card)] = 0;
    DisplayColumn((short)col);
    DisplayFoundations();

    return;
}


void UndoFromStock()
{
    unsigned char oldstock = stock;
    unsigned char c;
    short col;

    for (col = COLUMNS - 1; col >= 0; col--) {
      c = column[col];
      while (next[next[c]] != NOCARD) {
          c = next[c];
      }
      next[next[c]] = stock;
      stock = next[c];
      cards[stock] = POSN(STOCK, 0);
      next[c] = NOCARD;

      DisplayColumn((short)col);
    }

    if (oldstock == NOCARD)
      DisplayStockPile();

    return;
}

Generated by  Doxygen 1.6.0   Back to index