DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T p

⟦ad79e2cef⟧ TextFile

    Length: 23213 (0x5aad)
    Types: TextFile
    Names: »puzzle15.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Puzzle15/puzzle15.c« 

TextFile

/*
 * This program simulates a simple toy with many many variations.
 *
 * Compile with -DARROWKEYS if your curses library understands about
 * arrow keys (and your keyboards have them).
 * Compile with -DNOSIGNAL if your machine does not support the signal
 * function to catch ctrl-C.
 * Compile with "-DDIECHAR='<somechar>'" if you would like the program
 * to exit gracefully when <somechar> is typed. All the quotes in and
 * around this argument are necessary. The double quotes prevent the
 * shell from stripping the single quotes. Instead of '<somechar' you
 * can also type the ascii value of the key. If you do so, the double
 * quotes are not needed.
 *
 * The copyright message is there to prevent uncontrolled spreading of
 * a zillion different versions.
 *
 * You can mail your improvements and suggestions to me. I may include
 * them in a future version of the program.
 *
 * I do not guarantee the fitness of this program for any purpose.
 * USE IT AT YOUR OWN RISK.
 *
 * Peter Knoppers - knop@duteca.UUCP
 * Bilderdijkhof 59
 * 2624 ZG  Delft
 * The Netherlands
 *
 *
 * The following lines are put in the compiled program by the C compiler
 * where they can be found by programs such as (Bsd) strings.
 */
char   *this_is = "puzzle15 V2.0 Feb 24 1989";
char   *author0 = "(C) Copyright 1985, 1988, 1989 Peter Knoppers";
char   *author1 = "Arrow keys added by Paul Lew 1988";
char   *author2 = "Clock added by Bo Kullmar 1988";
char   *author3 = "Select-tile method suggested by Larry Hastings 1988";
char   *authorx = "Additions merged by Peter Knoppers";
char   *release1 = "Permission to use and redistribute unmodified ";
char   *release2 = "copies with source is granted to everyone";
char   *release3 = "Distribution of modified copies is NOT allowed";

#include <curses.h>
#ifndef NOSIGNAL
#include <signal.h>
#endif
#include <ctype.h>

#ifndef DIECHAR
#define DIECHAR 999		/* any non-ASCII value will do */
#endif
#define DEFSIZE		  4	/* default size of board */
#define BLANK		  0
#define UNSPECIFIED	  (-1)
/* classification of arguments */
#define MOVEMETHOD	  1
#define CURSORMETHOD	  2
#define FACEMETHOD	  3
/* magic values are required to be different, no other restrictions apply */
/* magic values for Movemethods */
#define MOVEBLANK	  4
#define MOVETILE	  5
#define SELECTTILE	  6
/* magic values for Cursormethods */
#define VIKEYS		  7
#ifdef ARROWKEYS
#define ARROWK		  8
#endif
#define NUMBERKEYS	  9
#define FACEKEYS	 10
#define KEYS		 11
/* magic values for Facemethods */
#define NUMBERFACES	 12
#define ALPHAFACES	 13
#define NUMBERALPHAFACES 14
#define ALPHANUMBERFACES 15
#define FACES		 16

unsigned long   Time_start;
int     Movecnt = 0;

char   *malloc ();		/* to satisfy lint */
long    time ();

int     Sizex = UNSPECIFIED;	/* x-size of the board */
int     Sizey = UNSPECIFIED;	/* y-size of the board */
int     Size2;			/* total surface of the board */
int     Movemethod = UNSPECIFIED;
int     Cursormethod = UNSPECIFIED;
int     Facemethod = UNSPECIFIED;
char   *Movename;		/* name of the selected Movemethod */
char   *Cursorname;		/* name of the selected Cursormethod */
char   *Cursorkeys;		/* the user-defined Cursorkeys */
char   *Facename;		/* name of the selected Facemethod */
char   *Facechars;		/* the user-defined tile-faces */
int     Up;			/* key-codes for cursor movements */
int     Down;
int     Left;
int     Right;
int     Newpos;			/* new position for empty field */
char   *Myname;			/* name used to invoke this program */
/*
 * All possible keyword arguments are listed in the Argopts table.
 * This is done in order to
 * - ensure that every keyword appears at only one place in the program
 *   (this makes the program easier to modify/maintain)
 * - put most of the knowledge about incompatible arguments in one place
 *   instead of scattering it all over the program.
 * - simplify the argument parser
 *   (I haven't been completely succesfull in this respect...)
 */
struct argtablemember
{
    char   *a_name;		/* what the user types */
    int     a_type;		/* what kind of spec. it is */
    int     a_magic;		/* magic value */
} Argopts[] =
{
    {
        "moveblank", MOVEMETHOD, MOVEBLANK
    },
    {
	"movetile", MOVEMETHOD, MOVETILE
    },
    {				/* SELECTTILE must be before FACEKEYS */
	"selecttile", MOVEMETHOD, SELECTTILE
    },
    {
	"vikeys", CURSORMETHOD, VIKEYS
    },
#ifdef ARROWKEYS
    {
	"arrowkeys", CURSORMETHOD, ARROWK
    },
#endif
    {
	"numberkeys", CURSORMETHOD, NUMBERKEYS
    },
    {
	"facekeys", CURSORMETHOD, FACEKEYS
    },
    {
	"keys", CURSORMETHOD, KEYS
    },
    {
	"numberfaces", FACEMETHOD, NUMBERFACES
    },
    {
	"alphafaces", FACEMETHOD, ALPHAFACES
    },
    {
	"numberalphafaces", FACEMETHOD, NUMBERALPHAFACES
    },
    {
	"alphanumberfaces", FACEMETHOD, ALPHANUMBERFACES
    },
    {
	"faces", FACEMETHOD, FACES
    },
    {
	(char *) 0, 0, 0
    }
};

die ()				/* nice exit on ctrl-C */
{
#ifndef NOSIGNAL
    signal (SIGINT, SIG_IGN);	/* ignore ctrl-C */
#endif
    mvprintw (LINES - 1, 0, "Goodbye. ");
    clrtoeol ();
    refresh ();
    endwin ();			/* shutdown curses, restore ttymode */
    exit (0);
}

main (argc, argv)		/* scan the arguments, call game() */
char  **argv;
{
    struct argtablemember  *atmp;/* to walk Argopts table */
    int     swap;		/* to revers directions */

    Myname = *argv;		/* save this for usage () */
 /* 
  * scan the arguments
  */
    while (*++argv != ((char *) 0))
    {				/* walk argument list */
	for (atmp = Argopts; atmp -> a_name != (char *) 0; atmp++)
	{			/* scan the keyword list */
	    if (strcmp (*argv, atmp -> a_name) == 0)
	    {			/* found keyword */
		switch (atmp -> a_type)
		{
		    case MOVEMETHOD: 
			if (Movemethod != UNSPECIFIED)
			    conflict (Movename, atmp -> a_name);
			Movename = atmp -> a_name;
			Movemethod = atmp -> a_magic;
			break;
		    case CURSORMETHOD: 
			if (Cursormethod != UNSPECIFIED)
			    conflict (Cursorname, atmp -> a_name);
			Cursorname = atmp -> a_name;
			Cursormethod = atmp -> a_magic;
			if (atmp -> a_magic == KEYS)
			{
			    if ((Cursorkeys = *++argv) == (char *) 0)
				novalue (*--argv);/* never returns */
			    if (strlen (Cursorkeys) != 4)
			    {
				printf ("%s need 4 cursorkeys\n",
					Cursorname);
				usage ();
			    }
			}
			break;
		    case FACEMETHOD: 
			if (Facemethod != UNSPECIFIED)
			    conflict (Facename, atmp -> a_name);
			Facename = atmp -> a_name;
			Facemethod = atmp -> a_magic;
			if (atmp -> a_magic == FACES)
			    if ((Facechars = *++argv) == (char *) 0)
				novalue (*--argv);
			break;
		    default: 
			printf ("aargh: bad switch (atmp -> a_type = %d)\n",
				atmp -> a_type);
			exit (1);
		}
		break;
	    }
	}
	if (atmp -> a_name == (char *) 0)/* not a keyword */
	    if (isdigit (**argv) && (Sizex == UNSPECIFIED))
	    {			/* it's a boardsize specification */
		if (sscanf (*argv, "%dx%d", &Sizex, &Sizey) != 2)
		    if (sscanf (*argv, "%d", &Sizex) == 1)
			Sizey = Sizex;
		    else
		    {
			printf ("bad argument %s\n", *argv);
			usage ();
		    }
	    }
	    else		/* it's garbage */
	    {
		printf ("bad argument %s\n", *argv);
		usage ();
	    }
    }

 /* 
  * insert default values
  */
    if (Sizex == UNSPECIFIED)
	Sizex = Sizey = DEFSIZE;

    if (Cursormethod == UNSPECIFIED)
    {				/* find first CURSORMETHOD in Argopts */
	for (atmp = Argopts; atmp -> a_name != (char *) 0; atmp++)
	    if (atmp -> a_type == CURSORMETHOD)
		break;
	if (atmp -> a_name == (char *) 0)
	{
	    printf ("aargh: can't find default Cursormethod\n");
	    exit (1);
	}
	Cursormethod = atmp -> a_magic;
	Cursorname = atmp -> a_name;
    }

    if (Facemethod == UNSPECIFIED)
    {				/* find first FACEMETHOD in Argopts */
	for (atmp = Argopts; atmp -> a_name != (char *) 0; atmp++)
	    if (atmp -> a_type == FACEMETHOD)
		break;
	if (atmp -> a_name == (char *) 0)
	{
	    printf ("aargh: can't find default Facemethod\n");
	    exit (1);
	}
	Facemethod = atmp -> a_magic;
	Facename = atmp -> a_name;
    }

    if (Movemethod == UNSPECIFIED)
	if (Cursormethod == FACEKEYS)
	    Movemethod = SELECTTILE;/* by implication */
	else
	{			/* find first MOVEMETHOD in Argopts */
	    for (atmp = Argopts; atmp -> a_name != (char *) 0; atmp++)
		if (atmp -> a_type == MOVEMETHOD)
		    break;
	    if (atmp -> a_name == (char *) 0)
	    {
		printf ("aargh: can't find default Movemethod\n");
		exit (1);
	    }
	    Movemethod = atmp -> a_magic;
	    Movename = atmp -> a_name;
	}

    if ((Cursormethod == FACEKEYS) && (Movemethod != SELECTTILE))
	conflict (Cursorname, Movename);/* does not return */
    switch (Cursormethod)
    {
	case VIKEYS: 
	    Up = 'k';
	    Down = 'j';
	    Left = 'h';
	    Right = 'l';
	    break;
#ifdef ARROWKEYS
	case ARROWK: 
	    Up = KEY_UP;
	    Down = KEY_DOWN;
	    Left = KEY_LEFT;
	    Right = KEY_RIGHT;
	    break;
#endif
	case NUMBERKEYS: 
	    Up = '8';
	    Down = '2';
	    Left = '4';
	    Right = '6';
	    break;
	case FACEKEYS: 
	    Up = 1000;		/* values must not correspond to any ASCII */
	    Down = 1001;	/*   value, otherwise no restrictions */
	    Left = 1002;
	    Right = 1003;
	    break;
	case KEYS: 
	    Up = Cursorkeys[0];
	    Down = Cursorkeys[1];
	    Left = Cursorkeys[2];
	    Right = Cursorkeys[3];
	    break;
	default: 
	    printf ("aargh: bad switch (Cursormethod = %d)\n",
		    Cursormethod);
	    exit (1);
    }

    if (Movemethod == MOVETILE)
    {				/* revers cursor directions */
	swap = Up;
	Up = Down;
	Down = swap;
	swap = Left;
	Left = Right;
	Right = swap;
    }

    Size2 = Sizex * Sizey;	/* surface area of the board */

    switch (Facemethod)
    {
	case NUMBERFACES: 
	    if (Size2 <= 10)	/* tiles can be labeled with 1 char */
	    {
		Facechars = "123456789";
		Facemethod = NUMBERALPHAFACES;
	    }
	    break;
	case ALPHAFACES: 
	    Facechars = "abcdefghijklmnopqrstuvwxyz";
	    break;
	case NUMBERALPHAFACES: 
	    Facechars = "0123456789abcdefghijklmnopqrstuvwxyz";
	    break;
	case ALPHANUMBERFACES: 
	    Facechars = "abcdefghijklmnopqrstuvwxyz0123456789";
	    break;
    }

    if ((Size2 - 1) > ((Facemethod == NUMBERFACES) ? 99 :
		strlen (Facechars)))
    {
	printf ("sorry, too many tiles - not enough labels\n");
	exit (0);
    }
    if ((Sizex < 2) || (Sizey < 2))
    {
	printf ("sorry, board is too small for a non-trivial game\n");
	exit (0);
    }

 /* 
  * Initialize the curses screen handling functions
  */
#ifndef NOSIGNAL
    signal (SIGINT, SIG_IGN);	/* protect this critical section */
#endif
    initscr ();
    crmode ();
    noecho ();
#ifdef ARROWKEYS
    keypad (stdscr, TRUE);
#endif
#ifndef NOSIGNAL
    signal (SIGINT, die);	/* die() knows how to restore ttymode */
#endif
 /* 
  * From now on use die() to exit the program, otherwise the
  * ttymode will not be restored.
  *
  * Now that curses has been initialized we can check whether the board
  * fits on the screen.
  */
    if (Sizex > (COLS - 1) / 5)	/* COLS works only after initscr() */
    {
	mvprintw (LINES - 2, 0,
		"sorry, your screen is not wide enough\n");
	die ();
    }
    if (Sizey > (LINES - 4) / 2)
    {
	mvprintw (LINES - 2, 0,
		"sorry, your screen is not tall enough\n");
	die ();
    }

    game ();			/* play the game */

    mvprintw (LINES - 2, 0,
	    "You've reached the solution in %d moves.\n", Movecnt);
    die ();			/* restore ttymode and exit */
}

usage ()
{
    int     curtype = UNSPECIFIED;
    int     prevtype = UNSPECIFIED;
    char   *selecttilename = (char *) 0;
    struct argtablemember  *atmp;/* to walk Argopts table */

    printf ("usage: %s [<width[x<height>]] %s",
	    Myname, "[movemethod] [cursormethod] [facemethod]\n");
    for (atmp = Argopts; atmp -> a_name != (char *) 0; atmp++)
    {
	if (atmp -> a_magic == SELECTTILE)
	    selecttilename = atmp -> a_name;
	if (atmp -> a_type != curtype)
	{
	    curtype = atmp -> a_type;
	    if (curtype == MOVEMETHOD)
		printf ("possible movemethods:\n");
	    if (curtype == CURSORMETHOD)
		printf ("possible cursormethods:\n");
	    if (curtype == FACEMETHOD)
		printf ("possible facemethods:\n");
	}
	switch (atmp -> a_magic)
	{
	    case KEYS: 
		printf ("\t\t%s <up><down><left><right>", atmp -> a_name);
		break;
	    case FACES: 
		printf ("\t\t%s <facecharacters>", atmp -> a_name);
		break;
	    case FACEKEYS: 
		if (selecttilename == (char *) 0)
		{
		    printf ("aargh: can't find string for SELECTTILE\n");
		    exit (1);
		}
		printf ("\t\t%-20.20s (implies movemethod %s)",
			atmp -> a_name, selecttilename);
		break;
	    default: 
		printf ("\t\t%-20.20s", atmp -> a_name);
		break;
	}
	if (curtype != prevtype)
	    printf (" (this is default)\n");
	else
	    printf ("\n");
	prevtype = curtype;
    }
    exit (0);
}

conflict (word1, word2)
char   *word1;
char   *word2;
{
    printf ("You may not specify both %s and %s\n", word1, word2);
    usage ();
}

novalue (word)
char   *word;
{
    printf ("%s requires an argument\n", word);
    usage ();
}

game ()				/* initialize board, execute moves */
{
    register int    i, j;	/* generally used indices and counters */
    int    *board;		/* pointer to malloc-ed board */
    int     empty;		/* position of empty field */
    int     swap;		/* used to swap two tiles */
    int     nswap = 0;		/* to determine reachability */
    int     steps;		/* number of tiles that move */
    int     unchanged = 0;	/* used to indicate that board has changed */
    int     cursorx;		/* to save cursorposition while */
    int     cursory;		/*   printing error messages */
    int     m;			/* move, first character / direction */
    int     m2;			/* second character of move */
 /* 
  * Set up the board and shuffle the tiles
  */
    board = (int *) malloc ((unsigned) Size2 * sizeof (int));
    if (board == NULL)
    {
	printf ("aargh: malloc failed\n");
	die ();
    }
    srand ((int) time ((long) 0));/* initialize random number generator */
    for (i = 1; i < Size2; i++)	/* put tiles on the board in their */
	board[i - 1] = i;	/*   final positions */
    for (i = Size2 - 2; i > 0; i--)/* permutate tiles */
    {
	j = rand () % i;
	swap = board[i];
	board[i] = board[j];
	board[j] = swap;
    }
 /* 
  * Check that final position can be reached from current permutation
  */
    for (i = 0; i < Size2 - 1; i++)
	for (j = 0; j < i; j++)
	    if (board[j] > board[i])
		nswap++;
    if ((nswap % 2) != 0)	/* this position is unreachable */
    {				/*   swap two adjacent tiles */
	swap = board[1];
	board[1] = board[0];
	board[0] = swap;
    }
    empty = Size2 - 1;		/* empty field starts in lower right */
    board[empty] = BLANK;	/*   corner */
    Newpos = empty;
    Time_start = time ((long *) 0);/* start the clock */

    while (1)			/* until final position is reached */
    {
	if (unchanged == 0)	/* the board must be (re-)printed */
	{
	    printboard (board);	/* also puts cursor at Newpos */
	    unchanged++;	/* the board on the screen is up to date */
	/* 
	 * Check if final position is reached
	 */
	    for (i = 0; i < Size2 - 1; i++)
		if (board[i] != i + 1)
		    break;	/* final position is not yet reached */
	    if (i == Size2 - 1)	/* all tiles are in final positions */
		return;		/* game ends */
	}
    /* 
     * Let the user make a move
     */
	m = getch ();
	if (m == DIECHAR)
	    die ();
	if (Movemethod == SELECTTILE)
	{
	    if (Cursormethod == FACEKEYS)
	    {
		if (Facemethod == NUMBERFACES)
		{
		    if (!isdigit (m))
		    {
			getyx (stdscr, cursory, cursorx);
			mvprintw (LINES - 1, 0,
				"use one of the keys");
			for (i = 0; (i <= Size2) && (i < 10); i++)
			    printw (" %d", i);
			clrtoeol ();
			move (cursory, cursorx);
			refresh ();
			continue;
		    }
		    if ((m - '0') > (Size2 / 10))
			m -= '0';
		    else	/* we need a second digit */
		    {
			m = (m - '0') * 10;
			m2 = getch ();
			if (m == DIECHAR)
			    die ();
			if ((!isdigit (m2)) || (m + m2 - '0' >= Size2))
			{
			    getyx (stdscr, cursory, cursorx);
			    mvprintw (LINES - 1, 0,
				    "use one of the keys");
			    for (i = 0; (i < Size2 % 10) && (i + m < Size2);
				    i++)
				printw (" %d", i);
			    clrtoeol ();
			    move (cursory, cursorx);
			    refresh ();
			    continue;
			}
			m += m2 - '0';
		    }
		/* 
		 * find out where this tile is on the board
		 */
		    for (Newpos = 0; Newpos < Size2; Newpos++)
			if (board[Newpos] == m)
			    break;/* found tile */
		    if (Newpos == Size2)/* no tile with face m */
		    {
			mvprintw (LINES - 2, 0,
				"aargh: can't find tile %d on board\n", m);
			die ();
		    }
		}
		else
		{
		/* 
		 * Facemethod != NUMBERFACES
		 * This means that a single keystroke identifies the
		 * tile that is to be moved.
		 */
		    for (Newpos = 0; Newpos < Size2; Newpos++)
			if (board[Newpos] > 0)
			    if (Facechars[board[Newpos] - 1] == m)
				break;/* found tile */
		    if (Newpos == Size2)
		    {
			getyx (stdscr, cursory, cursorx);
			mvprintw (LINES - 1, 0,
				"use one of the keys ");
			for (i = 0; (i < Size2 - 1) && (i < 30); i++)
			    printw ("%c", Facechars[i]);
			if (i < Size2 - 1)
			    printw ("...");
			clrtoeol ();
			move (cursory, cursorx);
			refresh ();
			continue;
		    }
		}
	    }
	    else		/* Cursormethod != FACEKEYS */
	    {
		if (m == Up)
		{
		    if (Newpos >= Sizex)
			Newpos -= Sizex;
		    unchanged = 0;/* board must be reprinted */
		    continue;
		}
		if (m == Down)
		{
		    if (Newpos + Sizex < Size2)
			Newpos += Sizex;
		    unchanged = 0;
		    continue;
		}
		if (m == Left)
		{
		    if ((Newpos % Sizex) != 0)
			Newpos--;
		    unchanged = 0;
		    continue;
		}
		if (m == Right)
		{
		    if (((Newpos + 1) % Sizex) != 0)
			Newpos++;
		    unchanged = 0;
		    continue;
		}
	    /* 
	     * If a key not in the set { Up, Down, Left, Right } was
	     * typed we fall through and try to move the empty field to
	     * Newpos.
	     */
	    }
	/* 
	 * The user has indicated a new location for the empty field.
	 * The new position of the empty field in the array board is in
	 * Newpos.
	 * We must now check that the new position is on the same row
	 * or the same column as the current position and we must
	 * determine how many tiles must be moved.
	 */
	    if (Newpos == empty)
		continue;	/* nothing changed */
	    steps = 0;
	    if (Newpos > empty)
	    {
		if ((empty % Sizex + Newpos - empty) < Sizex)
		{
		    m = Right;
		    steps = Newpos - empty;
		}
		else
		    if (((Newpos - empty) % Sizex) == 0)
		    {
			m = Down;
			steps = (Newpos - empty) / Sizex;
		    }
	    }
	    else
	    {
		if (empty % Sizex + Newpos - empty >= 0)
		{
		    m = Left;
		    steps = empty - Newpos;
		}
		else
		    if (((empty - Newpos) % Sizex) == 0)
		    {
			m = Up;
			steps = (empty - Newpos) / Sizex;
		    }
	    }
	    if (steps == 0)
	    {
		getyx (stdscr, cursory, cursorx);
		mvprintw (LINES - 1, 0,
			"tile must be in same row as empty field\n");
		move (cursory, cursorx);
		refresh ();

		continue;
	    }
	}
	else			/* Movemethod is MOVEBLANK or MOVETILE */
	    steps = 1;		/* one step per move */
    /* 
     * m should now be one of the four directions, but it may be an
     * illegal key. This can not happen if Movemethod == SELECTTILE.
     *
     * steps indicates how many tiles are to be moved
     */
	if ((m != Up) && (m != Down) && (m != Left) && (m != Right))
	{
	    getyx (stdscr, cursory, cursorx);
#ifdef ARROWKEYS
	    if (Cursormethod == ARROWK)
		mvprintw (LINES - 1, 0,
			"Use the arrow keys for up, down, left and  right");
	    else
#endif
		if (Movemethod == MOVETILE)
		{
		    mvprintw (LINES - 1, 0,
			    "use %c for up, %c for down, ", Down, Up);
		    printw ("%c for left and %c for right", Right, Left);
		}
		else
		{
		    mvprintw (LINES - 1, 0,
			    "use %c for up, %c for down, ", Up, Down);
		    printw ("%c for left and %c for right", Left, Right);
		}
	    clrtoeol ();
	    move (cursory, cursorx);
	    refresh ();
	    continue;
	}
    /* 
     * m contains the direction to move
     * steps contains the number of tiles to move
     * Apply the move to the board.
     */
	if (m == Up)
	    if (empty >= Sizex)
		while (steps-- > 0)
		{
		    board[empty] = board[empty - Sizex];
		    board[empty - Sizex] = BLANK;
		    empty -= Sizex;
		    Movecnt++;
		}
	if (m == Down)
	    if (empty + Sizex < Size2)
		while (steps-- > 0)
		{
		    board[empty] = board[empty + Sizex];
		    board[empty + Sizex] = BLANK;
		    empty += Sizex;
		    Movecnt++;
		}
	if (m == Left)
	    if ((empty % Sizex) != 0)
		while (steps-- > 0)
		{
		    board[empty] = board[empty - 1];
		    board[empty - 1] = BLANK;
		    empty--;
		    Movecnt++;
		}
	if (m == Right)
	    if (((empty + 1) % Sizex) != 0)
		while (steps-- > 0)
		{
		    board[empty] = board[empty + 1];
		    board[empty + 1] = BLANK;
		    empty++;
		    Movecnt++;
		}
	if (steps == 1)		/* you ran into a wall */
	{
	    getyx (stdscr, cursory, cursorx);
	    mvprintw (LINES - 1, 0,
		    "Your can't cross that wall\n");
	    clrtoeol ();
	    move (cursory, cursorx);
	    refresh ();
	    continue;
	}
	if (steps != -1)	/* something is very wrong */
	{
	    mvprintw (LINES - 2, 0,
		    "aargh: couldn't move enough tiles (steps = %d)\n",
		    steps);
	    die ();
	}
	Newpos = empty;
	unchanged = 0;		/* the board must be reprinted */
    }
}

printboard (board)
int    *board;
{
    register int    i, j;
    int     tilewidth;
    unsigned long   time_used;
    unsigned    minutes;
    unsigned    seconds;
    unsigned long   time_now;

    tilewidth = ((Facemethod == NUMBERFACES) && (Size2 > 10)) ? 5 : 4;
    mvprintw ((LINES - 4 - 2 * Sizey) / 2,
	    (COLS - 1 - tilewidth * Sizex) / 2,
	    "+");		/* print top edge of board */
    for (j = 0; j < Sizex; j++)
	if (tilewidth == 5)
	    printw ("----+");
	else
	    printw ("---+");
    for (i = 0; i < Sizey; i++)
    {
	mvprintw ((LINES - 4 - 2 * Sizey) / 2 + i * 2 + 1,
		(COLS - 1 - tilewidth * Sizex) / 2, "| ");
	for (j = 0; j < Sizex; j++)
	    if (tilewidth == 5)
		if (board[Sizex * i + j] != BLANK)
		    if ((Size2 > 9) && (Cursormethod == FACEKEYS) &&
			    (board[Sizex * i + j] <= Size2 / 10))
			printw ("%02d | ", board[Sizex * i + j]);
		    else
			printw ("%2d | ", board[Sizex * i + j]);
		else
		    printw ("   | ");
	    else
		if (board[Sizex * i + j] != BLANK)
		    printw ("%c | ", Facechars[board[Sizex * i + j] - 1]);
		else
		    printw ("  | ");
	mvprintw ((LINES - 4 - 2 * Sizey) / 2 + i * 2 + 2,
		(COLS - 1 - tilewidth * Sizex) / 2, "+");
	for (j = 0; j < Sizex; j++)
	    if (tilewidth == 5)
		printw ("----+");
	    else
		printw ("---+");
    }
    mvprintw (LINES - 1, 0, "\n");/* erase error messages */
 /* 
  * Update the clock
  */
    time_now = time ((long *) 0);
    time_used = time_now - Time_start;
    minutes = time_used / 60;
    seconds = time_used % 60;
    mvprintw (LINES - 3, 0, "Time used: %02d min %02d sec   Move: %d",
	    minutes, seconds, Movecnt);
 /* 
  * Put cursor on the position indicated by Newpos
  */
    move ((LINES - 4 - 2 * Sizey) / 2 + (Newpos / Sizex) * 2 + 1,
	    (COLS - 1 - tilewidth * Sizex) / 2 +
	    (Newpos % Sizex) * tilewidth + tilewidth / 2);
    refresh ();			/* put all this on the screen */
}