#ident "$Id: game.c,v 1.3 2004/11/17 17:25:56 pwh Rel $"

/*
 * Interactive Panex puzzle logic.
 */

#include        <stdio.h>
#include	<curses.h>

#include	"panex.h"

#define		CONGRATULATIONS	"CONGRATULATIONS!!!"
#define		TAUNT		"See, wasn't that easy?"

/* Move stack. */
#define	STACK_SIZE	100000

typedef struct {

	int	src;
	int	dest;

} MOVE;

typedef struct {

	int	top;
	int	contents;
	MOVE	moves [STACK_SIZE];

} MOVE_STACK;


static void resetMoveStack ( MOVE_STACK *stack )

{
   stack->top = stack->contents = 0;
}


static void pushMove ( MOVE_STACK *stack, int src, int dest )

{
   stack->moves [stack->top].src = src;
   stack->moves [stack->top].dest = dest;
   if ( ++stack->top == STACK_SIZE ) stack->top = 0;

   if ( stack->contents < STACK_SIZE ) ++stack->contents;
}


static const MOVE *popMove ( MOVE_STACK *stack )

{
   const MOVE	*move = NULL;

   if ( stack->contents ) {

	--stack->contents;

	if ( --stack->top < 0 ) stack->top += STACK_SIZE;

	move = stack->moves + stack->top;
   }

   return ( move );
}


int playGame ( PUZZLE *puzzle )

{
   int	status = 1;
   int	yt;
   int	xp [3];
   int	c = 'r';

   yt = puzzle->y0 + 2;
   xp [0] = puzzle->x0 + puzzle->height + 1;
   xp [1] = xp [0] + ( ( puzzle->height + 1 ) << 1 );
   xp [2] = xp [1] + ( ( puzzle->height + 1 ) << 1 );

   while ( c == 'r' ) {

	int		peg = LEFT_PEG;
	int		src = -1;
	int		cur_ch = ACS_DIAMOND;
	int		done = 0;
	MOVE_STACK	moveHistory;
	const MOVE	*lastMove;

	resetMoveStack ( &moveHistory );

	move ( yt, xp [0] );
	addch ( cur_ch );
	move ( 0, 0 );
	refresh ();

	while ( ! done ) {

		switch ( c = getch () ) {

		   char	*p;

		   case 'v':
		   case 'j':
		   case KEY_DOWN:

			if ( src != -1 ) {

				move ( yt, xp [peg] );
				addch ( ' ' );

				if ( src != peg ) pushMove ( &moveHistory, src,
									peg );
				if ( src == peg
					|| moveDisk ( puzzle, src, peg ) ) {

					if ( isSolved ( puzzle ) ) {

						p = CONGRATULATIONS;

						move ( yt, puzzle->xc
						- ( sizeof ( CONGRATULATIONS )
								>> 1 ) );
						
						while ( *p ) addch ( *p++ );
						done = 1;
					}

					cur_ch ^= A_REVERSE;
					src = -1;

				} else beep ();

			} else beep ();

			break;

		   case '^':
		   case 'k':
		   case KEY_UP:

			if ( src == -1 && puzzle->peg_tops [peg] > 0 ) {

				src = peg;
				cur_ch ^= A_REVERSE;
				
			} else beep ();

			break;

		   case '<':
		   case 'h':
		   case KEY_LEFT:

			if ( peg > LEFT_PEG && ( src == -1
						|| src == ( peg - 1 )
						|| puzzle->peg_tops [peg - 1]
							<= puzzle->height ) ) {

				move ( yt, xp [peg--] );
				addch ( ' ' );

			} else beep ();

			break;

		   case '>':
		   case 'l':
		   case KEY_RIGHT:

			if ( peg < RIGHT_PEG && ( src == -1
						|| src == ( peg + 1 )
						|| puzzle->peg_tops [peg + 1]
							<= puzzle->height ) ) {

				move ( yt, xp [peg++] );
				addch ( ' ' );

			} else beep ();

			break;

		   case 's':

			move ( yt, xp [peg] );
			addch ( ' ' );

			puzzle->speed = XTREME_SPEED;
			puzzle->warpFactor = 2;

			if ( ( status = generalSolution ( puzzle,
							puzzle->height ) )
						&& isSolved ( puzzle ) ) {
				p = TAUNT;
				move ( yt, puzzle->xc
						- ( sizeof ( TAUNT ) >> 1 ) );
				while ( *p ) addch ( *p++ );
			}

			done = 1;
			break;

		   case ESC:

			if ( src != -1 ) {

				cur_ch ^= A_REVERSE;
				src = -1;
				break;
			}

		   case 'q':

			puzzle->moves = 0;
			status = 0;

		   case 'r':

			done = 1;
			break;

		   case 'u':

			if ( lastMove = popMove ( &moveHistory ) ) {

				if ( src != -1 ) {

					src = -1;
					cur_ch ^= A_REVERSE;
				}

				move ( yt, xp [peg] );
				addch ( ' ' );
				puzzle->moves -= 2;
				peg = lastMove->src;
				moveDisk ( puzzle, lastMove->dest, peg );

			} else beep();

			break;

		   case 'S':

			puzzle->speed = SLOW_SPEED;
			puzzle->warpFactor = 1;
			break;

		   case 'N':

			puzzle->speed = NORMAL_SPEED;
			puzzle->warpFactor = 1;
			break;

		   case 'F':

			puzzle->speed = HIGH_SPEED;
			puzzle->warpFactor = 1;
			break;

		   case 'X':

			puzzle->speed = XTREME_SPEED;
			puzzle->warpFactor = 1;
			break;

		   case 'W':

			puzzle->speed = XTREME_SPEED;
			puzzle->warpFactor = 2;
			break;

		   case ERR:

			break;

		   default:

			beep ();
			break;
		}

		if ( ! done ) {

			move ( yt, xp [peg] );
			addch ( cur_ch );
		}

		move ( 0, 0 );
		refresh ();
	}

	if ( c != 'q' && c != 'r' && c != ESC )
		while ( ( c = getch() ) == ERR );

	if ( c == 'r' ) {

		resetPuzzle ( puzzle );
		displayPuzzle ( puzzle );

	} else ungetch ( c );
   }

   return ( status );
}


Last updated: Saturday, August 01, 2009 10:49:29 PM