#ident "$Id: hanoi.c,v 1.5 2006/05/30 21:12:33 pwh Rel $"

/*
 * Tower of Hanoi Puzzle.
 */

#include        <stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<errno.h>

#include	"hanoi.h"

#define		DEFAULT_HEIGHT	6
#define		SOLVED		"Solved!"
#define		HELP_SCREEN	1
#define		INSTRUCTIONS	2


static void printVersion ( void )

{
   fprintf ( stdout, "%s\nRelease:  %s\nDate:  %s\n", PUZZLE_TITLE, RELSTRING,
								RELDATE );
}


static void printHelp ( const char *progname )

{
   fprintf ( stdout, "\n\tUse:\n\t----\n\
\t%s [-s|-] [-S|N|F|X|W] [tower_height ...]\n\t%s -h|i\n\n\
\tOptions:\n\t--------\n\
\t-s  Display the solution.\n\
\t-   Display the solution to the screen as narrative.\n\
\t-S|N|F|X|W  Animation speed (Slow/Normal/Fast/eXtreme/Warp).\n\
\ttower_height specifies the number of disks in the tower.  Specifying\n\
\t    multiple tower heights on the command line presents the puzzle\n\
\t    once for each height specified.  If no tower height is specified\n\
\t    then a %d disk tower is used.\n\
\t-h  Display help screen (this screen).\n\
\t-i  Display instructions.\n",
	progname, progname, DEFAULT_HEIGHT );
}


static void printInstructions ( void )

{
   fprintf ( stdout, "\n\tObject:\n\t-------\n\
\tMoving disks one at a time, move the tower from the left peg to the\n\
\tright peg.  Use the arrow keys (on a keypad to the right of the main\n\
\tkeyboard or turn off Num Lock and use the number keypad) to control\n\
\tdisk movement.\n\n\
\tRules:\n\t------\n\
\tThe only restriction on moves is that you may never put a larger disk\n\
\ton top of a smaller disk.\n" );
}


static const char *basename ( const char *path )

{
   int	start = strlen ( path );

   while ( start > 0 &&  path [start - 1] != '/' ) --start;

   return ( path + start );
}


main ( int argc, char **argv )

{
   int		status = 0;
   int		height = DEFAULT_HEIGHT;
   int		showSolution = 0;
   int		animated = 1;
   int		speed = 0;
   const char	*progName = basename ( *argv );

   if ( argc > 1 ) {

	int	help = 0;

	++argv;

	while ( *argv && **argv == '-' ) {

		int	opt_ptr = 1;
		int	opt_ch;

		while ( opt_ch = argv [0] [opt_ptr] ) {

			switch ( opt_ch ) {

			   case 'h':
			   case 'H':

				help |= HELP_SCREEN;
				break;

			   case 'i':
			   case 'I':

				help |= INSTRUCTIONS;
				break;

			   case 'S':

				speed = SLOW_SPEED;
				break;

			   case 'N':

				speed = NORMAL_SPEED;
				break;


			   case 'F':

				speed = HIGH_SPEED;
				break;

			   case 'X':

				speed = XTREME_SPEED;
				break;

			   case 'W':

				speed = WARP_SPEED;
				break;

			   case 's':

				showSolution = 1;
				break;

			   case '-':

				animated = 0;
				break;

			   default:

				fprintf ( stderr,
				"Invalid command line option (%c) ignored\n",
								opt_ch );
				break;
			}

			++opt_ptr;
		}

		if ( opt_ptr == 1 ) animated = 0;

		++argv;
		--argc;
	}

	if ( help ) {

		printVersion ();

		if ( help & HELP_SCREEN ) printHelp ( progName );

		if ( help & INSTRUCTIONS ) printInstructions ();

		fputc ( '\n', stdout );

		while ( *argv ) ++argv;

	} else if ( ! *argv ) --argv;
   }

   while ( ! status && *argv ) {

	PUZZLE	*puzzle;

	if ( argc > 1 ) {

		if ( ( height = strtol ( *argv, ( char ** ) NULL, 10 ) ) < 1 )
			fprintf ( stderr,
				"Invalid tower height (%s) on command line.\n",
									*argv );
	}

	++argv;

	if ( height > 0
		&& ( puzzle = openPuzzle ( height, animated, speed ) ) ) {

		animated = isAnimated ( puzzle );

		if ( showSolution || ! animated ) {

			if ( ! solvePuzzle ( puzzle, speed )
						|| ! isSolved ( puzzle ) ) {

				if ( ! errno ) status = 1;

				if ( ! animated ) {

					fprintf ( stdout,
						"ERROR - not a solution!\n" );
				}

			} else if ( animated ) {

				char	*p = SOLVED;

				move ( puzzle->y0 + 2, puzzle->xc
						- ( sizeof ( SOLVED ) >> 1 ) );
				while ( *p ) addch ( *p++ );
				move ( 0, 0 );
			}

		} else {

			if ( ! speed ) setSpeed ( puzzle, WARP_SPEED );
			if ( ! playGame ( puzzle ) ) status = 1;
		}

		closePuzzle ( puzzle );

	} else status = 1;
   }

   return ( status );
}


Last updated: Friday, June 12, 2015 08:21:43 AM