/*****************************************************************************/
/*									     */
/*									     */
/*	X patience - r_Spider.c						     */
/*									     */
/*	written by Heiko Eissfeldt and Michael Bischoff			     */
/*									     */
/*	24-Feb-1993: First release (0.1)				     */
/*	26-Nov-1993: release (0.8)					     */
/*									     */
/*									     */
/*****************************************************************************/
#include "xpat.h"

/************************************************************************/
/*									*/
/*	Spider routines:						*/
/*									*/
/************************************************************************/

/* check, if new cards may be dealt */
static int Spider_new_cards(void)
{   Pileindex i;

    if (!CARDS_ON_PILE(IDECK))
	return 0;	/* no more cards */

#ifdef SPIDER_COMPATIBLE
    /* may not have a single free slot */
    for (i = FIRST_SLOT; i <= LAST_SLOT; ++i)
	if (EMPTY(i))
	    return 0;
    return 1;
#else
    {
    int ideal_columns = 0;
    int have_no_empty = 1;
    /* check if there are empty slots and not continuous slots */
    for (i = FIRST_SLOT; i <= LAST_SLOT; ++i) {
	if (EMPTY(i)) have_no_empty = 0;
	if (EMPTY(i) || select_max(i, 0) == INDEX_OF_FIRST_CARD(i))
	    ideal_columns++;
    }
    return have_no_empty || (ideal_columns == rules.numslots);
    }
#endif
}

/* check, if sequence from 'startindex' to 'endindex' forms a complete suit */
static int Spider_is_complete( Cardindex startindex, Cardindex endindex )
{
    if (startindex + rules.cards_per_color - 1 == endindex) {
	int i;			/* must check, if jokers inside */
	for (i = endindex; i >= startindex; --i)
	    if (IS_JOKER(game.cards[i]))
		return -1;
	return startindex;	/* only full stack movable */
    }
    return -1;
}

/* check, if this slots contains a complete sequence
 * which could be put on stack. */
static int Spider_stackable(Pileindex src)	/* src is index of a slot */
{
    if (EMPTY(src))
	return -1;
    return Spider_is_complete(select_max(src, 0), INDEX_OF_LAST_CARD(src));
}

static int Spider_good_hint(int srcindex, int dstpile)
{
   if (IS_STACK(dstpile))   /* strongly encourage dropping the whole suit */
       return 10000;
   if (SUIT(game.cards[srcindex]) == SUIT(game.cards[INDEX_OF_LAST_CARD(dstpile)]))
       return 30;
   if (game.ind[getpile(srcindex)] != srcindex && 
       game.visible[srcindex-1] &&
       RANK(game.cards[srcindex]) == RANK(game.cards[srcindex-1]) - 1)
       return 1; /* hint doesn't make anything better */
   else
       return 15 + RANK(game.cards[srcindex]);	/* upper ones first */
}

/* calculate score according to Spider documentation */
static int Spider_score(void)
{   Pileindex i;
    Cardindex j;
    int score;
    int total_visible;
    int resolved_suits_in_slots=0;
    int resolved_suits_in_stacks=0;

    /* set score to the maximum of facedown cards turned */
    score = ((rules.numcards % rules.numslots) + 
	      rules.numslots * rules.facedown) * 10;

    for (i = FIRST_SLOT; i <= LAST_SLOT; i++) {
	total_visible = 1;
	for (j = game.ind[i]; j < INDEX_OF_LAST_CARD(i); j++) {
	    if (game.visible[j] && 
	      Spider_alternate(game.cards[j], game.cards[j+1])) {
		/* visible combined cards give 2 Points */
		score += 2;
	    }
	    if (!game.visible[j]) {
		/* each of the unvisible cards at start got 10 Points at first.
		   Now clear the points for each yet invisible card. */
		score -= 10;
		total_visible = 0;     /* something is hidden in this slot */
	    }
	}
	/* 15 points for each fully visible slot */
	score += total_visible * 15;

	/* check for completed suits (even if stacked on each other) */
	if (!EMPTY(i)) {
	    /* each full sequence gets 50 points total 
	       (12 * 2 points are already there) so add 26 points. */
	    Cardindex running_index = INDEX_OF_LAST_CARD(i);
	    Cardindex block_index;

	    while ((block_index=
		Spider_is_complete(
		    getblock(
			running_index,-graphic.pile[i].y),running_index)
		   ) != -1) {
		running_index = 
		    block_index == game.ind[i] ? block_index 
		                                     : block_index - 1;
		score += 50 - 2 * (rules.cards_per_color - 1);
		resolved_suits_in_slots++;
	    }
	}
    }
    /* check the stacks for complete sequences */
    for (i = 0; i < rules.numstacks; ++i)
	if (!EMPTY(STACK(i))) {
	    score += 50;	/* each completed sequence got 50 points */
	    resolved_suits_in_stacks ++;
	}

    if ((resolved_suits_in_slots + resolved_suits_in_stacks) / 4 /*suits*/ == 
	rules.numdecks) {
	resolved_suits_in_slots -= 3;
	if (resolved_suits_in_slots > 0) 
	    score += resolved_suits_in_slots * 2;
    }
    return score;
}

struct rules Spider_rules = {
    "Spider", "Spider",
    NULL,       /* description of this game variant */
    0, /* (EXACT_MATCH << MOVE_SHIFT) | (ALL_VALID << PLACE_SHIFT), */
    104,	/* two full decks of 52 cards */
    8,		/* eight stacks */
    10,		/* eight slots */
    0,		/* no Tmps */
    2,		/* two decks */
    13,		/* thirteen ranks, no jokers */
    0,		/* jokers */
    0, 0,	/* no flips, no turns */
    NULL,
    Spider_relaxed_alternate,
    Spider_alternate,
    Spider_new_cards,
    Spider_stackable,
    Spider_good_hint,
    4, 1,
    Spider_score, 1000,	/* score */
    generic_automove,
    NULL,
    generic_minwindow
};
