/*
 * @(#)HexagonS.c
 *
 * Taken from the X puzzle by Don Bennett, HP Labs
 *
 * Copyright 2021 David A. Bagley, bagleyd AT verizon.net
 *
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the author not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * This program is distributed in the hope that it will be "useful",
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * $XConsortium: puzzle.c,v 1.14 94/03/28 18:34:10 gildea Exp $
 */

/*
 * Puzzle - (C) Copyright 1987, 1988 Don Bennett.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 */

/*
 *  Puzzle
 *
 * Don Bennett, HP Labs
 *
 * this is the code that does the real work to solve the
 * puzzle.  (Commonly seen as a 4x4 grid of sliding pieces
 * numbered 1-15 with one empty space.)
 *
 * The idea for the solution algorithm - solving the puzzle
 * in layers working from the outside in - comes to me
 * indirectly from John Nagle.
 */

#define JMP
#ifdef JMP
#include <setjmp.h> /* longjmp ... interrupt */
#endif
#include "HexagonsP.h"
#define MAX_PLAN	1000
#define QUEUE_SIZE	1000
#define SOLVE_COORD	6

#define PUZZLE_SIZE MIN(w->hexagons.sizeX, w->hexagons.sizeY)

#if 0
static int DIST(HexagonsWidget w, int loc1, int row1, int loc2, int row2)
{
	int trbl1, tlbr1;
	int trbl2, tlbr2;
	int row, trbl, tlbr;

	trbl1 = toTrBl(w, loc1, row1);
	tlbr1 = toTlBr(w, loc1, row1);
	trbl2 = toTrBl(w, loc2, row2);
	tlbr2 = toTlBr(w, loc2, row2);
	row = ABS(row2 - row1);
	trbl = ABS(trbl2 - trbl1);
	tlbr = ABS(tlbr2 - tlbr1);
	return MIN(MIN((row + trbl), (row + tlbr)), (trbl + tlbr));
}

static int otherDir[SOLVE_COORD] = { BL, LEFT, TL, TR, RIGHT, BR };
#endif

/* layer info macros -> (innermost 7 tiles are layer zero,
 *			ordinal goes up as you move out)
 * layerHeight		- returns number of (rows down),
 *			(columns across) the layer starts;
 * layerWidth		- number of blocks wide the layer is;
 */

#define layerHeight(l)	(layers-1-(l))
#define layerWidth(l)	(PUZZLE_SIZE-layerHeight(l))

/* macros for finding the corners of each layer */

#define UL(l) (layerHeight(l)*(PUZZLE_SIZE+1))
#define UR(l) (layerHeight(l)*(PUZZLE_SIZE+1)+layerWidth(l)-1)
#define L(l) (layerHeight(l)*(PUZZLE_SIZE+1))
#define R(l) (layerHeight(l)*(PUZZLE_SIZE+1)+layerWidth(l)-1)
#define LL(l) ((layerHeight(l)+layerWidth(l)-1)*PUZZLE_SIZE+layerHeight(l))
#define LR(l) ((layerHeight(l)+layerWidth(l)-1)*(PUZZLE_SIZE+1))

/* get the x and y coordinates of a location in the matrix */

/*#define toTLBR(loc, locRow)	(toTlBr(w, loc, locRow))
#define toRow(loc)	(toRow(w, loc))
#define toTRBL(loc, locRow)	(toTrBl(w, loc, locRow))
#define toPosition(row,trbl)	(toPosition(w, row, trbl)*/
#define spaceTLBR(locRow)	toTlBr(w, w->hexagons.spacePosition[0], locRow)
#define spaceTRBL(locRow)	toTrBl(w, w->hexagons.spacePosition[0], locRow)
#define spaceRow	toRow(w, w->hexagons.spacePosition[0])

/* space perspective
#define nextLeft(loc)	(tileNFrom(w, loc, 1, ROW, LOW))
#define nextRight(loc)	(tileNFrom(w, loc, 1, ROW, HIGH))
#define nextLeftUp(loc)	(tileNFrom(w, loc, 1, TLBR, LOW))
#define nextLeftDown(loc)	(tileNFrom(w, loc, 1, TRBL, HIGH))
#define nextRightUp(loc)	(tileNFrom(w, loc, 1, TRBL, LOW))
#define nextRightDown(loc)	(tileNFrom(w, loc, 1, TLBR, HIGH))*/

#define nextRight(loc)	(tileNFrom(w, loc, 1, ROW, LOW))
#define nextLeft(loc)	(tileNFrom(w, loc, 1, ROW, HIGH))
#define nextRightDown(loc)	(tileNFrom(w, loc, 1, TLBR, LOW))
#define nextRightUp(loc)	(tileNFrom(w, loc, 1, TRBL, HIGH))
#define nextLeftDown(loc)	(tileNFrom(w, loc, 1, TRBL, LOW))
#define nextLeftUp(loc)	(tileNFrom(w, loc, 1, TLBR, HIGH))

#if 0
static int sizeX = 0, sizeY = 0;
static int layers;
static int *tmpMatrix;
static int *targetM;
static Boolean *locked;
static int *locList;

static Boolean solvingFlag = False;
#ifdef JMP
static Boolean abortSolvingFlag = False;
static jmp_buf solve_env;

static void
abortSolving(void)
{
	if (solvingFlag)
		abortSolvingFlag = True;
}

#ifdef WINVER
static Boolean
processMessage(UINT msg)
{
	switch (msg) {
	case WM_KEYDOWN:
	case WM_CLOSE:
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
		abortSolving();
		return True;
	default:
		return False;
	}
}
#else
static void
processButton(void /*XButtonEvent *event*/)
{
	abortSolving();
}

static void
processVisibility(XVisibilityEvent *event)
{
	if (event->state != VisibilityUnobscured)
		abortSolving();
}

static void
getNextEvent(HexagonsWidget w, XEvent *event)
{
	if (!XCheckMaskEvent(XtDisplay(w), VisibilityChangeMask, event))
		(void) XNextEvent(XtDisplay(w), event);
}

static void
processEvent(XEvent *event)
{
	switch(event->type) {
	case KeyPress:
	case ButtonPress:
		processButton(/*&event->xbutton*/);
		break;
	case VisibilityNotify:
		processVisibility(&event->xvisibility);
		break;
	default:
		break;
	}
}

static void
processEvents(HexagonsWidget w)
{
	XEvent event;

	while (XPending(XtDisplay(w))) {
		getNextEvent(w, &event);
		processEvent(&event);
	}
}
#endif
#endif

static int
findPiece(HexagonsWidget w, int piece)
{
	int i;
	char *buf1 = NULL, *buf2 = NULL;

	for (i = 0; i < w->hexagons.sizeSize; i++)
		if (w->hexagons.tileOfPosition[i] == piece) {
			/*(void) printf("position=%d, piece=%d at %d\n",
				i, piece, w->hexagons.tileOfPosition[i]);*/
			return i;
		}

	intCat(&buf1, "Piece ", piece);
	stringCat(&buf2, buf1, "not found, exiting.");
	free(buf1);
	DISPLAY_ERROR(buf2);
	free(buf2);
	return -1;
}

static void
logMoveSpace(HexagonsWidget w, int firstX, int firstY,
		int lastX, int lastY, int dir)
{
	int count = ABS(firstX - lastX) + ABS(firstY - lastY) + 1;
	int i;

	for (i = 0; i < count; i++)
		movePuzzleDir(w, dir, DOUBLE);
}

static void
moveSpace(HexagonsWidget w, int direction, int distance)
{
	int i, step, count;
	int firstX, firstY, lastX, lastY, shiftDir;
	int tempSpaceRow = spaceRow;
	int tempSpaceTrBl = spaceTRBL(tempSpaceRow);
	int tempSpaceTlBr = spaceTLBR(tempSpaceRow);
	int dir = direction, dist = distance;

#ifdef JMP
#ifdef WINVER
	MSG msg;

	if (PeekMessage(&msg, NULL, 0, 0, 0)) {
		if (!processMessage(msg.message)) {
			if (GetMessage(&msg, NULL, 0, 0))
				DispatchMessage(&msg);
		}
	}
#else
	processEvents(w);
#endif
	if (solvingFlag && abortSolvingFlag)
		longjmp(solve_env, 1);
#endif
	if (dist == 0)
		return;

	if (dir == LEFT) {
		dir = RIGHT;
		dist = -dist;
	} else if (dir == TL) {
		dir = BR;
		dist = -dist;
	} else if (dir == TR) {
		dir = BL;
		dist = -dist;
	}
	firstX = spaceX;
	firstY = spaceRow;
	step = 1;
	count = dist;
	if (dist < 0) {
		step = -1;
		count = -count;
	}

	/* firstX,Y are the location of the first piece to be shifted */
	if (dir == RIGHT)
		firstX += step;
	else if (dir == BR)
		firstY += step;
	else if (dir == BL)
		firstY += step;

	/* shiftDir is the direction the pieces need to be shifted */
	if (dist < 0) {
		shiftDir = dir;
	} else {
		shiftDir = otherDir[dir];
	}
	for (i = 0; i < count; i++) {
		if (dir == RIGHT) {
			tempSpaceX += step;
		} else if (dir == BR) {
			tempSpaceRow += step;
		} else if (dir == BL) { /* forced */
			tempSpaceRow += step;
		}
	}
	lastX = tempSpaceX;
	lastY = tempSpaceRow;

	/* the blocks firstX,Y through lastX,Y need to be shifted
	 * one block in the shiftDir direction;
	 */

	logMoveSpace(w, firstX, firstY, lastX, lastY, shiftDir);
}

#ifdef DEBUG
static void
printMatrix(HexagonsWidget w, int **mat)
{
	int i, j;

	for (j = 0; j < w->hexagons.sizeY; j++) {
		for (i = 0; i < w->hexagons.sizeX; i++)
			(void) printf(" %2d ",(*mat)[toPosition(w, i, j)]);
		(void) printf("\n");
	}
	(void) printf("\n");
}
#endif

static void
planMove(HexagonsWidget w, int startLoc, int endLoc, int **path)
{
	int i, nextLoc = 0, nextDist, chosen, moveNum;
	Boolean foundPath = False;
	int locX, locY;
	int locQueue[QUEUE_SIZE];
	int locDist[QUEUE_SIZE];
	Boolean locQueueUsed[QUEUE_SIZE];
	int queueHead = 0, queueTail = 0;
	int candidate[SOLVE_COORD];
	int endRow = toRow(w, endLoc), startRow = toRow(w, startLoc);

	for (i = 0; i < w->hexagons.sizeSize; i++) {
		tmpMatrix[i] = (locked[i]) ? -1 : 0;
		locList[i] = -1;
	}

	for (i = 0; i < QUEUE_SIZE; i++)
		locQueueUsed[i] = False;

	locQueue[0] = startLoc;
	locDist[0] = DIST(endLoc, endRow, startLoc, startRow);
	tmpMatrix[startLoc] = 1;
	queueTail++;

	/* if the selected element has a distance of zero,
	 * we have found it; (This really is not a queue,
	 * but rather a range of elements to be searched
	 * for an element of the desired properties;
	 */

	/* as we search for a path,
	 * LINK array is used to indicate the direction from which
	 * we moved into a location;
	 * TMP_MATRIX array is used to keep track of the move number;
	 */

	while (queueHead < queueTail && !foundPath) {
		/* find the entry that
		 * (1) has the smallest distance and
		 * (2) has the smallest move number;
		 */

		nextLoc = locQueue[queueHead];
		nextDist = locDist[queueHead];
		chosen = queueHead;

		for (i = queueHead + 1; i < queueTail; i++)
			if (!locQueueUsed[i] &&
					((locDist[i] < nextDist) ||
					((locDist[i] == nextDist) &&
					(tmpMatrix[locQueue[i]] <
					tmpMatrix[nextLoc])))) {
				nextLoc = locQueue[i];
				nextDist = locDist[i];
				chosen = i;
			}
		if (nextDist == 0) {
			foundPath = True;
			break;
		}
		locQueueUsed[chosen] = True;

		/* permute the chosen element */
		candidate[TL] = nextLeftUp(nextLoc);
		candidate[LEFT] = nextLeft(nextLoc);
		candidate[BL] = nextLeftDown(nextLoc);
		candidate[BR] = nextRightDown(nextLoc);
		candidate[RIGHT] = nextRight(nextLoc);
		candidate[TR] = nextRightUp(nextLoc);
		locX = toColumn(w, nextLoc);
		locY = toRow(w, nextLoc);
		/* Fix for edges */
		if (locX == 0)
			candidate[LEFT] = -1;
		if (locX == w->hexagons.sizeX - 1)
			candidate[RIGHT] = -1;
		if (locY == 0)
			candidate[TOP] = -1;
		if (locY == w->hexagons.sizeY - 1)
			candidate[BOTTOM] = -1;
		moveNum = tmpMatrix[nextLoc] + 1;
		for (i = 0; i < SOLVE_COORD; i++)
			if (candidate[i] != -1 &&
					tmpMatrix[candidate[i]] == 0) {
				tmpMatrix[candidate[i]] = moveNum;
				/*
				 * the next line works because the
				 * candidate index is same as the
				 * direction moved to reach the
				 * candidate;
				 */
				locList[candidate[i]] = i;
				locQueue[queueTail] = candidate[i];
				int candRow = toRow(w, candidate[i]);
				locDist[queueTail] =
					DIST(endLoc, endRow, candidate[i], candRow);
				queueTail++;
				if (queueTail == QUEUE_SIZE) {
					DISPLAY_ERROR(
					"Queue size is exceeded, exiting.");
						return;
				}
			}

		/* delete used items from the front of the queue */
		while (locQueueUsed[queueHead] && queueHead < queueTail)
			queueHead++;
	}

#ifdef DEBUG
	print_matrix(w, &(w->hexagons.tileOfPosition));
	print_matrix(w, &locked);
#endif /* DEBUG */
	if (!foundPath) {
		char *buf1 = NULL, *buf2 = NULL;

		intCat(&buf1, "Could not find a way to move ", startLoc);
		stringCat(&buf2, buf1, " (");
		free(buf1);
		intCat(&buf1, buf2, toColumn(w, startLoc));
		free(buf2);
		stringCat(&buf2, buf1, ",");
		free(buf1);
		intCat(&buf1, buf2, toRow(w, startLoc));
		free(buf2);
		stringCat(&buf2, buf1, ") to ");
		free(buf1);
		intCat(&buf1, buf2, endLoc);
		free(buf2);
		stringCat(&buf2, buf1, " (");
		free(buf1);
		intCat(&buf1, buf2, toColumn(w, endLoc));
		free(buf2);
		stringCat(&buf2, buf1, ",");
		free(buf1);
		intCat(&buf1, buf2, toRow(w, endLoc));
		free(buf2);
		stringCat(&buf2, buf1, "), exiting.");
		free(buf1);
		DISPLAY_ERROR(buf2);
		free(buf2);
		return;
	}

	/*
	 * copy the path we found into the path array;
	 * element 0 will contain the number of moves in the path;
	 * by the time we get there, nextLoc is in the final location
	 */

	(*path)[0] = tmpMatrix[nextLoc] - 1;
	for (i = (*path)[0]; i > 0; i--) {
		(*path)[i] = locList[nextLoc];
		switch(locList[nextLoc]) {
		case LEFT:
			nextLoc = nextRight(nextLoc);
			break;
		case RIGHT:
			nextLoc = nextLeft(nextLoc);
			break;
		case TR:
			nextLoc = nextLeftDown(nextLoc);
			break;
		case TL:
			nextLoc = nextRightDown(nextLoc);
			break;
		case BL:
			nextLoc = nextRightUp(nextLoc);
			break;
		case BR:
			nextLoc = nextLeftUp(nextLoc);
			break;
		}
	}
}

static void
myMoveSpaceTo(HexagonsWidget w, int loc) {
	int i, currentDir, dist = 0;
	int plan[MAX_PLAN];
	int *planPtr = &(plan[0]);

	planMove(w, toPosition(w, spaceX, spaceRow), loc, &planPtr);
	currentDir = plan[1];
	for (i = 1; i <= plan[0]; i++) {
		if (plan[i] == currentDir) {
			dist++;
		} else if (plan[i] == otherDir[currentDir]) {
			dist--;
		} else {
			moveSpace(w, currentDir, dist);
			currentDir = plan[i];
			dist = 1;
		}
	}
	moveSpace(w, currentDir, dist);
}

static void
movePiece(HexagonsWidget w, int location, int targetLoc) {
	int i;
	int plan[MAX_PLAN];
	int *planPtr = &(plan[0]);
	int loc = location;

	planMove(w, loc, targetLoc, &planPtr);
	for (i = 1; i <= plan[0]; i++)
		switch(plan[i]) {
		case LEFT:
			locked[loc] = True;
			myMoveSpaceTo(w, nextLeft(loc));
			locked[loc] = False;
			myMoveSpaceTo(w, loc);
			loc = nextLeft(loc);
			break;
		case RIGHT:
			locked[loc] = True;
			myMoveSpaceTo(w, nextRight(loc));
			locked[loc] = False;
			myMoveSpaceTo(w, loc);
			loc = nextRight(loc);
			break;
		case TOP:
			locked[loc] = True;
			myMoveSpaceTo(w, nextUp(loc));
			locked[loc] = False;
			myMoveSpaceTo(w, loc);
			loc = nextUp(loc);
			break;
		case BOTTOM:
			locked[loc] = True;
			myMoveSpaceTo(w, nextDown(loc));
			locked[loc] = False;
			myMoveSpaceTo(w, loc);
			loc = nextDown(loc);
			break;
		}
}

/* SYSV386 gets this from libBerk.a */
#if defined(USG) && !defined(CRAY) && !defined(SYSV386)
int gettimeofday (tvp, tzp)
    struct timeval *tvp;
    struct timezone *tzp;
{
    time (&tvp->tv_sec);
    tvp->tv_usec = 0L;

    /* ignore tzp for now since this file doesn't use it */
}
#endif

static void
myFree(void)
{
	if (tmpMatrix)
		free(tmpMatrix);
	if (targetM)
		free(targetM);
	if (locked)
		free(locked);
	if (locList)
		free(locList);
}

static void
myInitialize(HexagonsWidget w)
{
	/* Initialize the position and
	 * the targetM matrices;
	 */
	int i;
	int spX, spY;

	sizeX = w->hexagons.sizeX;
	sizeY = w->hexagons.sizeY;

	layers = PUZZLE_SIZE >> 1;

	tmpMatrix = (int *) malloc(sizeof (int) * (size_t) w->hexagons.sizeSize);
	targetM = (int *) malloc(sizeof (int) * (size_t) w->hexagons.sizeSize);
	locked = (Boolean *) malloc(sizeof (int) * (size_t) w->hexagons.sizeSize);
	locList = (int *) malloc(sizeof (int) * (size_t) w->hexagons.sizeSize);

	for (i = 0; i < w->hexagons.sizeSize; i++)
		locked[i] = False;

	if (!tmpMatrix || !targetM || !locked || !locList ||
			!w->hexagons.tileOfPosition) {
		DISPLAY_ERROR("Not enough memory, exiting.");
	}

	for (i = 0; i < w->hexagons.sizeSize - 1; i++) {
		targetM[i] = i + 1;
	}
	targetM[w->hexagons.sizeSize - 1] = 0;

	/*
	 * Move the space into the LR corner of the
	 * innermost layer;
	 * For each of the outer layers, move the space
	 * left one and up one;
	 */

	spX = w->hexagons.sizeX - 1;
	spY = w->hexagons.sizeY - 1;

	/* Make solution with space at center bottom right */
	for (i = 0; i < layers - 1; i++) {
		/* move the space left one; */
		targetM[toPosition(w, spX, spY)] =
			targetM[toPosition(w, (spX - 1), spY)];
		targetM[toPosition(w, (spX - 1), spY)] = 0;
		spX -= 1;

		/* move the space up one; */
		targetM[toPosition(w, spX, spY)] =
			targetM[toPosition(w, spX, (spY - 1))];
		targetM[toPosition(w, spX, (spY - 1))] = 0;
		spY -= 1;
	}
}

/*
 * To solve this puzzle, work from the outside in;
 * For each successive ring working your way in,
 *
 * (1) put the corners in place;
 * (2) finish off the rest of the boundaries;
 * (3) do the next layer in;
 */

static void
solveLayer0(HexagonsWidget w)
{
	movePiece(w, findPiece(w, targetM[UL(0)]), UL(0));
	myMoveSpaceTo(w, LR(0));
}

static void
doLastTwoOnEdge(HexagonsWidget w, int ntLast, int last, int tmp, int emergency)
{
	int lastPiece, ntLastPiece;

	lastPiece = targetM[last];
	ntLastPiece = targetM[ntLast];

	movePiece(w, findPiece(w, ntLastPiece), last);
	locked[last] = True;

	/*
	 * if the last piece is stuck where the next to the last
	 * piece should go, do some magic to fix things up;
	 */
	if (findPiece(w, 0) == ntLast)
		myMoveSpaceTo(w, tmp);

	if (findPiece(w, lastPiece) == ntLast) {
		/* a rescue is necessary */
		locked[last] = False;
		movePiece(w, findPiece(w, ntLastPiece), ntLast);
		locked[ntLast] = True;
		movePiece(w, findPiece(w, lastPiece), emergency);
		locked[emergency] = True;
		locked[ntLast] = False;
		movePiece(w, findPiece(w, ntLastPiece), last);
		locked[emergency] = False;
		locked[last] = True;
	}

	movePiece(w, findPiece(w, lastPiece), tmp);
	locked[tmp] = True;
	myMoveSpaceTo(w, ntLast);
	locked[tmp] = False;
	locked[last] = False;
	myMoveSpaceTo(w, last);
	myMoveSpaceTo(w, tmp);
	locked[ntLast] = True;
	locked[last] = True;
}

static void
solveLayer(HexagonsWidget w, int layer)
{
	int i, tmp, last, ntLast, emergency;
	int ul, ur, ll, lr;

	if (layer == 0) {
		solveLayer0(w);
	} else {
		/* find and put each of the corners into place */
		ul = UL(layer);
		ur = UR(layer);
		ll = LL(layer);
		lr = LR(layer);

		movePiece(w, findPiece(w, targetM[ul]), ul);
		locked[ul] = True;
		movePiece(w, findPiece(w, targetM[ur]), ur);
		locked[ur] = True;
		movePiece(w, findPiece(w, targetM[ll]), ll);
		locked[ll] = True;
		movePiece(w, findPiece(w, targetM[lr]), lr);
		locked[lr] = True;

		/*
		 * Strategy for doing the pieces between the corners:
		 * (1) put all but the last two edge pieces in place;
		 * (2) put the next to the last piece next to the
		 *	corner;
		 * (3) put the last piece one move in from its final
		 *	position;
		 * (4) move the space to the final position of the
		 *	next to the last piece;
		 * (5) slide the next to the last piece over and the
		 *	last piece into the edge where it goes.
		 */

		/* top edge */
		for (i = ul + 1; i < ur - 2; i++) {
			movePiece(w, findPiece(w, targetM[i]), i);
			locked[i] = True;
		}

		ntLast = i;
		last = i + 1;
		tmp = UR(layer - 1);
		emergency = nextDown(tmp);
		doLastTwoOnEdge(w, ntLast, last, tmp, emergency);

		/* bottom edge */
		for (i = ll + 1; i < lr - 2; i++) {
			movePiece(w, findPiece(w, targetM[i]), i);
			locked[i] = True;
		}

		ntLast = i;
		last = i + 1;
		tmp = LR(layer - 1);
		emergency = nextUp(tmp);
		doLastTwoOnEdge(w, ntLast, last, tmp, emergency);

		/* left side */
		for (i = ul + w->hexagons.sizeX; i < ll - 2 * w->hexagons.sizeX;
				i += w->hexagons.sizeX) {
			movePiece(w, findPiece(w, targetM[i]), i);
			locked[i] = True;
		}

		ntLast = i;
		last = i + w->hexagons.sizeX;
		tmp = LL(layer - 1);
		emergency = nextRight(tmp);
		doLastTwoOnEdge(w, ntLast, last, tmp, emergency);

		/* right side */
		for (i = ur + w->hexagons.sizeX; i < lr - 2 * w->hexagons.sizeX;
				i += w->hexagons.sizeX) {
			movePiece(w, findPiece(w, targetM[i]), i);
			locked[i] = True;
		}

		ntLast = i;
		last = i + w->hexagons.sizeX;
		tmp = LR(layer - 1);
		emergency = nextLeft(tmp);
		doLastTwoOnEdge(w, ntLast, last, tmp, emergency);
	}
}

/* not used */
static void
solveRow(HexagonsWidget w, int row)
{
	int i, loc, last, ntLast, tmp, emergency;

	for (i = 0; i < w->hexagons.sizeX - 2; i++) {
		loc = toPosition(w, i, row);
		movePiece(w, findPiece(w, targetM[loc]), loc);
		locked[loc] = True;
	}
	ntLast = toPosition(w, w->hexagons.sizeX - 2, row);
	last = toPosition(w, w->hexagons.sizeX - 1, row);
	tmp = last + w->hexagons.sizeX;
	emergency = tmp + w->hexagons.sizeX;
	doLastTwoOnEdge(w, ntLast, last, tmp, emergency);
}

/* This procedure coordinates the solution process. */
void
solveSomeTiles(HexagonsWidget w)
{
	int i;

	if (sizeX != w->hexagons.sizeX || sizeY != w->hexagons.sizeY) {
		myFree();
		myInitialize(w);
	}
	setPuzzle(w, ACTION_RESET);
	/*
	 * determine the position we want to be in when
	 * we are done; This position will have the space in
	 * the center;  Then, we'll move the space back to
	 * the outside.
	 */
	if (solvingFlag)
		return;

#ifdef JMP
	if (!setjmp(solve_env))
#endif
	if (w->hexagons.sizeY == 1)
		moveSpace(w, RIGHT, w->hexagons.sizeX - spaceX - 1);
	else if (w->hexagons.sizeX == 1)
		moveSpace(w, BOTTOM, w->hexagons.sizeY - spaceRow - 1);
	else {
		solvingFlag = True;

		/* solve each layer */
		for (i = layers - 1; i >= 0; i--) {
			solveLayer(w, i);
		}
		/* move the space back out to the LR corner; */
		/* i is the layer the space is moving into */
		for (i = 1; i < layers; i++) {
			moveSpace(w, BOTTOM, 1);
			moveSpace(w, RIGHT, 1);
		}
	}
#ifdef JMP
	else {
		drawAllBlocks(w);
	}
	abortSolvingFlag = False;
#endif
	for (i = 0; i < w->hexagons.sizeSize; i++)
		locked[i] = False;
	solvingFlag = False;
	w->hexagons.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_COMPUTED);
}
#else
void
solveSomeTiles(HexagonsWidget w) {
	int loc1;
	/*int row1, loc2, row2;
	int min;*/
	/* add some test cases here */
	/*for (loc1 = 0; loc1 < w->hexagons.sizeSize; loc1++) {
		row1 = toRow(w, loc1);
		for (loc2 = 0; loc2 < w->hexagons.sizeSize; loc2++) {
			row2 = toRow(w, loc2);
			min = DIST(w, loc1, row1, loc2, row2);
			(void) printf("  %d, min %d\n", loc2, min);
		}
	}*/
	for (loc1 = 0; loc1 < w->hexagons.sizeSize; loc1++) {
		(void) printf("%d:  %d %d %d %d %d %d\n", loc1,
			nextRightUp(loc1),
			nextRight(loc1),
			nextRightDown(loc1),
			nextLeftDown(loc1),
			nextLeft(loc1),
			nextLeftUp(loc1));
	}
}
#endif
