/*****************************************************************************/
/*									     */
/*									     */
/*	X patience version 2 -- module r_Canfield.c			     */
/*									     */
/*	Characteristics of the ``Canfield'' rules			     */
/*	written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	see COPYRIGHT.xpat2 for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "xpatgame.h"


static int baserank;

static int Canfield_valid(Cardindex srcind, Pileindex dstpile) {
    int srcpile, dstcard, srccard;

    srcpile = getpile(srcind);
    if (srcpile == dstpile)
	return 0;
    if (game.piletype[srcpile] == Stack)
	return 0;
    dstcard = EMPTY(dstpile) ? -1 : game.cards[game.ind[dstpile+1]-1];
    srccard = game.cards[srcind];
    switch (game.piletype[dstpile]) {
    case Slot:	/* moves to Slot: depends on if slot is empty */
	if (EMPTY(dstpile))
	    return srcpile == IDECK || (EMPTY(IDECK) && srcpile == VDECK);
	/* dstpile not empty: rank and alternate colour! */
	if (!in_relaxed_sequence(srccard, dstcard))
	    return 0;
	if (game.piletype[srcpile] == Slot &&
	    srcind != INDEX_OF_FIRST_CARD(srcpile))
	    return 0;
	return 1;
    case Tmp:
    case FaceupDeck:
    case FacedownDeck:
	return 0;	/* only implicit moves allowable */
    case Stack:
	if (srcind != INDEX_OF_LAST_CARD(srcpile))
	    return 0;	/* only one card at a time */
	if (SUIT(srccard) != SUIT(dstpile))
	    return 0;
	if (EMPTY(dstpile))
	    return RANK(srccard) == baserank;
	return RANK(srccard) == (1 + RANK(
		  game.cards[INDEX_OF_LAST_CARD(dstpile)])) % 13;
    }
    return 0;
}

static void Canfield_newgame(void) {
    int i;
    int firstsuit;
    /* specific part: one card on a stack, 3 on the talon (VDECK) */
    for (i = 0; i < rules.numcards; ++i)
	game.visible[i] = 1;
    firstsuit = SUIT(game.cards[0]);
    baserank = RANK(game.cards[0]);
    for (i = 0; i <= firstsuit; ++i)
	game.ind[i] = 0;
    for (; i <= rules.numstacks; ++i)
	game.ind[i] = 1;
    for (; i <= rules.numstacks + rules.numslots; ++i)
	game.ind[i] = 1 + i - rules.numstacks;
    game.ind[VDECK] = 1 + rules.numslots;
    game.ind[IDECK] = 4 + rules.numslots;	/* => 3 on the talon */
    game.ind[IDECK+1] = rules.numcards;
}

static int Canfield_score(void) {
    return -52 + 5 * (game.ind[rules.numstacks] - game.counter[1]);
}

struct rules modCanfield_rules = {
    "modCanfield",	/* shortname */
    "modified Canfield",/* longname */
    "modcan",   /* abbrev */
    0,		/* layout_hints */
    DECK_SOURCE|DECK_VISIBLE|KLONDIKE_DEAL,/* variant */
    0,		/* customizable */
    0,		/* customized */
    52,		/* numcards */
    4,		/* numstacks */
    4,		/* numslots */
    0,		/* numtmps */
    1,		/* numdecks */
    13,		/* cards_per_color */
    0,		/* numjokers */
    {0, 999, 3, 0},/* param[0], param[1], param[2], param[3] */
    0,		/* facedown */
    1,		/* faceup */
    0,		/* newgame_bits */
    Canfield_newgame,/* new_game */
    NULL,	/* game_won */
    NULL,	/* new_cards */
    ES_ALL|US_RA|MG_RA|ST_ONE|DC_ALWAYS, /* move_bits */
    NULL,	/* deal_cards */
    NULL,	/* undeal_cards */
    NULL,	/* stackable */
    Canfield_valid,	/* movevalid */
    NULL,	/* valid */
    NULL,	/* relaxed_valid */
    NULL,	/* good_hint */
    NULL,	/* automove */
    Canfield_score,/* score */
    208,	/* maxscore */
    {0, TXTI_FLIP, 0, 0}, /* paramstring blocks */
    0,		/* used */
    NULL,	/* initfunc */
    NULL,	/* local keyboard bindings */
};
