/*
 * @(#)PyraminxS.c
 *
 * Taken from the algorithm in The Simple Solutions to Cubic Puzzles
 * by James G. Nourse (also looked at Puzzle It Out: Cubes, Groups
 * and Puzzles by John Ewing & Czes Kosniowski)
 * Break ability taken from the X puzzle by Don Bennett, HP Labs
 *
 * Copyright 1999 - 2023  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.
 */

/* Solver file for Pyraminx */
#include "rngs.h"
#define JMP
#ifdef JMP
#include <setjmp.h> /* longjmp ... interrupt */
#endif
#include "PyraminxP.h"

/* Moving Nourse's large corners translates as:
 * move the whole puzzle
 * undo the face move */
#define rotateTrivialCornerCW(w,f) movePuzzlePiece(w,f,0,(f%2)?TR:BL,PERIOD3,FALSE)
#define rotateTrivialCornerCCW(w,f) movePuzzlePiece(w,f,0,(f%2)?BL:TR,PERIOD3,FALSE)
#define rotateCornerCW(w,f) movePuzzlePiece(w,f,1,(f%2)?TR:BL,PERIOD3,TRUE); \
	movePuzzlePiece(w,f,indexToEdge(w, 2),(f%2)?BL:TR,PERIOD3,FALSE)
#define rotateCornerCCW(w,f) movePuzzlePiece(w,f,1,(f%2)?BL:TR,PERIOD3,TRUE); \
	movePuzzlePiece(w,f,indexToEdge(w, 2),(f%2)?TR:BL,PERIOD3,FALSE)

#define topFaceTrans(tf,f) ((tf==0)?f:((tf==1)?MAX_FACES-1-(f+MAX_FACES/2)%MAX_FACES:((tf==2)?(f+MAX_FACES/2)%MAX_FACES:MAX_FACES-1-f)))

#define P_PLUS rotateCornerCW(w,topFaceTrans(topFace,0)) /* Posterior Corner CW */
#define B_PLUS rotateCornerCW(w,topFaceTrans(topFace,1)) /* Bottom Corner CW */
#define L_PLUS rotateCornerCW(w,topFaceTrans(topFace,2)) /* Left Corner CW */
#define R_PLUS rotateCornerCW(w,topFaceTrans(topFace,3)) /* Right Corner CW */
#define P_MINUS rotateCornerCCW(w,topFaceTrans(topFace,0)) /* Posterior Corner CCW */
#define B_MINUS rotateCornerCCW(w,topFaceTrans(topFace,1)) /* Bottom Corner CCW */
#define L_MINUS rotateCornerCCW(w,topFaceTrans(topFace,2)) /* Left Corner CCW */
#define R_MINUS rotateCornerCCW(w,topFaceTrans(topFace,3)) /* Right Corner CCW */

#define rotateWholeCW(w,f) movePuzzlePiece(w,f,1,(f%2)?TR:BL,PERIOD3,TRUE)
#define rotateWholeCCW(w,f) movePuzzlePiece(w,f,1,(f%2)?BL:TR,PERIOD3,TRUE)
#define B_PLUS_WHOLE rotateWholeCW(w,topFaceTrans(topFace,1)) /* Bottom Corner CW */
#define B_MINUS_WHOLE rotateWholeCCW(w,topFaceTrans(topFace,1)) /* Bottom Corner CCW */

#define rotateEdgeRightPos(w,f,p) movePuzzlePiece(w,f,p,RIGHT,PERIOD2,FALSE)
#define rotateEdgeTopPos(w,f,p) movePuzzlePiece(w,f,p,TOP,PERIOD2,FALSE)
#define rotateEdgeTRPos(w,f,p) movePuzzlePiece(w,f,p,TR,PERIOD2,FALSE)
#define rotateEdgeRight(w,f) rotateEdgeRightPos(w,f,indexToCenter(w,0))
#define rotateEdgeTop(w,f) rotateEdgeTopPos(w,f,indexToCenter(w,0))
#define rotateEdgeTR(w,f) rotateEdgeTRPos(w,f,indexToCenter(w,2))


static int edgeMateFace[MAX_FACES][3] =
{
	{2, 3, 1},
	{3, 2, 0},
	{0, 1, 3},
	{1, 0, 2}
};

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(PyraminxWidget 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(PyraminxWidget w)
{
	XEvent event;

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

static void
movePuzzlePiece(PyraminxWidget w, int face, int position,
	int direction, int style, int control)
{
#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
	movePuzzleDelay(w, face, position, direction, style, control);
}

static int
indexToCorner(PyraminxWidget w, int cornerIndex) {
	switch (cornerIndex) { /* Pyraminx -> 0, 4, 8 */
	case 0:
		return 0;
	case 1:
		return (w->pyraminx.size - 1) * (w->pyraminx.size - 1);
	case 2:
		return w->pyraminx.size * w->pyraminx.size - 1;
	default:
		(void) printf("corner unknown %d\n", cornerIndex);
	}
	return -1;
}

static int
cornerToIndex(PyraminxWidget w, int corner) {
	int temp; /* Pyraminx -> {0, -1, -1, -1, 1, -1, -1, -1, 2} */

	if (corner == 0)
		return 0;
	temp = (w->pyraminx.size - 1) * (w->pyraminx.size - 1) - corner;
	if (temp == 0)
		return 1;
	else if (temp < 0) {
		temp = w->pyraminx.size * w->pyraminx.size - 1 - corner;
		if (temp == 0)
			return 2;
	}
	return -1;
}

static int
indexToEdge(PyraminxWidget w, int edgeIndex) {
	switch (edgeIndex) { /* Pyraminx -> 1, 3, 6 */
	case 0:
		return (w->pyraminx.size >> 1) * (w->pyraminx.size >> 1)
			+ (((w->pyraminx.size & 1) == 0) ? 1 : 0);
	case 1:
		return (w->pyraminx.size >> 1) * (w->pyraminx.size >> 1)
			+ 2 * (w->pyraminx.size >> 1)
			- (((w->pyraminx.size & 1) == 0) ? 1 : 0);
	case 2:
		return w->pyraminx.size * w->pyraminx.size - w->pyraminx.size;
	default:
		(void) printf("edge unknown %d\n", edgeIndex);
	}
	return -1;
}

static int
edgeToIndex(PyraminxWidget w, int edge) {
	int temp; /* Pyraminx -> {-1, 0, -1, 1, -1, -1, 2, -1, -1} */

	temp = (w->pyraminx.size >> 1) * (w->pyraminx.size >> 1)
			+ 2 * (w->pyraminx.size >> 1)
			- (((w->pyraminx.size & 1) == 0) ? 1 : 0)
			- edge;
	if (temp == 0)
		return 1;
	else if (temp > 0) {
		temp = (w->pyraminx.size >> 1) * (w->pyraminx.size >> 1)
			+ (((w->pyraminx.size & 1) == 0) ? 1 : 0)
			- edge;
		if (temp == 0)
			return 0;
	} else if (temp < 0) {
		temp = w->pyraminx.size * w->pyraminx.size - w->pyraminx.size
			- edge;
		if (temp == 0)
			return 2;
	}
	return -1;
}

static int
indexToCenter(PyraminxWidget w, int centerIndex) {
	switch (centerIndex) { /* Pyraminx -> 2, 5, 7 */
	case 0:
		return 2;
	case 1:
		return (w->pyraminx.size - 1) * (w->pyraminx.size - 1) + 1;
	case 2:
		return w->pyraminx.size * w->pyraminx.size - 2;
	default:
		(void) printf("center unknown %d\n", centerIndex);
	}
	return -1;
}

static int
centerToIndex(PyraminxWidget w, int center) {
	int temp; /* Pyraminx -> {-1, -1, 0, -1, -1, 1, -1, 2, -1} */

	if (center == 2)
		return 0;
	temp = (w->pyraminx.size - 1) * (w->pyraminx.size - 1) + 1 - center;
	if (temp == 0)
		return 1;
	else if (temp < 0) {
		temp = w->pyraminx.size * w->pyraminx.size - 2 - center;
		if (temp == 0)
			return 2;
	}
	return -1;
}

/* This is impossible to do with Drag and Drop as implemented.
 * Use the keypad.  Turn the trivial corners so that the
 * colors match the adjacent pieces all around. */
static void
orientTrivialCorners(PyraminxWidget w)
{
	int face, currentColor;

	for (face = 0; face < MAX_FACES; face++) {
		currentColor = w->pyraminx.facetLoc[face][indexToCorner(w, 0)].face;
		if (currentColor != w->pyraminx.facetLoc[face][indexToCenter(w, 0)].face) {
			if (currentColor == w->pyraminx.facetLoc[MAX_FACES - face - 1][indexToCenter(w, 2)].face) {
				rotateTrivialCornerCCW(w,face);
			} else {
				rotateTrivialCornerCW(w,face);
			}
		}
	}
}

static int
findFaceColor(PyraminxWidget w, int face)
{
	int colors[3], color, cornerFace;

	switch (face) {
	case 0:
		colors[0] = w->pyraminx.facetLoc[1][indexToCenter(w, 0)].face;
		colors[1] = w->pyraminx.facetLoc[3][indexToCenter(w, 1)].face;
		colors[2] = w->pyraminx.facetLoc[2][indexToCenter(w, 2)].face;
		break;
	case 1:
		colors[0] = w->pyraminx.facetLoc[0][indexToCenter(w, 0)].face;
		colors[1] = w->pyraminx.facetLoc[2][indexToCenter(w, 1)].face;
		colors[2] = w->pyraminx.facetLoc[3][indexToCenter(w, 2)].face;
		break;
	case 2:
		colors[0] = w->pyraminx.facetLoc[3][indexToCenter(w, 0)].face;
		colors[1] = w->pyraminx.facetLoc[1][indexToCenter(w, 1)].face;
		colors[2] = w->pyraminx.facetLoc[0][indexToCenter(w, 2)].face;
		break;
	case 3:
		colors[0] = w->pyraminx.facetLoc[2][indexToCenter(w, 0)].face;
		colors[1] = w->pyraminx.facetLoc[0][indexToCenter(w, 1)].face;
		colors[2] = w->pyraminx.facetLoc[1][indexToCenter(w, 2)].face;
		break;
	default:
		colors[0] = colors[1] = colors[2] = 0;
		(void) printf("Wrong face %d.\n", face);
	}
	for (color = 0; color < MAX_FACES; color++) {
		for (cornerFace = 0; cornerFace < 3; cornerFace++) {
			if (color == colors[cornerFace])
				break;
		}
		if (cornerFace == 3)
			return color;
	}
	(void) printf("No opposite color found!\n");
	return 0;
}

static Boolean
checkPiece(PyraminxWidget w, int color, int face, int position)
{
	int newFace, newPosition, positionIndex;

	positionIndex = edgeToIndex(w, position);
	if (positionIndex == -1) {
		positionIndex = 0;
		(void) printf("position %d incorrect\n", position);
	}
	newFace = edgeMateFace[face][positionIndex];
	newPosition = indexToEdge(w, positionIndex);
	return (w->pyraminx.facetLoc[newFace][newPosition].face == color);
}

static void
findPiece(PyraminxWidget w, int color0, int color1, int *face, int *position)
{
	int faceSkip, positionIndex;

	/* Check starting face first */
	for (positionIndex = 0; positionIndex < 3; positionIndex++) {
		*position = indexToEdge(w, positionIndex);
		if (w->pyraminx.facetLoc[*face][*position].face == color0 &&
				checkPiece(w, color1, *face, *position)) {
			return;
		}
		if (w->pyraminx.facetLoc[*face][*position].face == color1 &&
				checkPiece(w, color0, *face, *position)) {
			return;
		}
	}
	faceSkip = *face;
	for (*face = 0; *face < MAX_FACES; (*face)++) {
		if (*face == faceSkip)
			continue;
		for (positionIndex = 0; positionIndex < 3; positionIndex++) {
			*position = indexToEdge(w, positionIndex);
			if (w->pyraminx.facetLoc[*face][*position].face == color0 &&
					checkPiece(w, color1, *face, *position)) {
				return;
			}
			if (w->pyraminx.facetLoc[*face][*position].face == color1 &&
					checkPiece(w, color0, *face, *position)) {
				return;
			}
		}
	}
	(void) printf("Piece %d %d not found!\n", color0, color1);
}

static void
faceCorners(PyraminxWidget w, int face, int faceColor)
{
	int otherFace;

	if (faceColor != w->pyraminx.facetLoc[face][indexToCenter(w, 0)].face) {
		if (faceColor == w->pyraminx.facetLoc[MAX_FACES - 1 - face][indexToCenter(w, 2)].face) {
			rotateCornerCW(w, face);
		} else {
			rotateCornerCCW(w, face);
		}
	}
	otherFace = (face + 2) % 4;
	if (faceColor != w->pyraminx.facetLoc[face][indexToCenter(w, 1)].face) {
		if (faceColor == w->pyraminx.facetLoc[otherFace][indexToCenter(w, 0)].face) {
			rotateCornerCW(w, otherFace);
		} else {
			rotateCornerCCW(w, otherFace);
		}
	}
	otherFace = MAX_FACES - 1 - face;
	if (faceColor != w->pyraminx.facetLoc[face][indexToCenter(w, 2)].face) {
		if (faceColor == w->pyraminx.facetLoc[otherFace][indexToCenter(w, 0)].face) {
			rotateCornerCCW(w, otherFace);
		} else {
			rotateCornerCW(w, otherFace);
		}
	}
}

#if 0
/* This is a general approach that seems unwieldy right now. */
static void
faceEdge(PyraminxWidget w, int topFace, int position, int faceColor)
{
	int otherColor, newFace, newPosition;

	switch (edgeToIndex(w, position)) {
		case 0:
			newFace = (topFace + 2) % 4;
			newPosition = position + 1;
			break;
		case 1:
			newFace = MAX_FACES - 1 - topFace;
			newPosition = position - 1;
			break;
		case 2:
			newFace = MAX_FACES - 1 - ((topFace + 2) % 4);
			newPosition = position - 1;
			break;
		default:
			(void) printf("Wrong position %d.\n", position);
	}
	otherColor = w->pyraminx.facetLoc[newFace][newPosition].face;
	/* newFace and newPosition variables are reused here */
	newFace = topFace; /* This narrows down the cases */
	findPiece(w, faceColor, otherColor, &newFace, &newPosition);
	(void) printf("topFace %d, position %d, newFace %d, newPosition %d, faceColor %d, otherColor %d\n", topFace, position, newFace, newPosition, faceColor, otherColor);
}
#else
/* Move to position 6 and then into correct position. */
static void
faceEdge6(PyraminxWidget w, int topFace, int faceColor)
{
	int otherColor, newFace, newPosition, position;

	position = indexToEdge(w, 2);
	newFace = MAX_FACES - 1 - ((topFace + 2) % 4);
	newPosition = indexToCenter(w, 1);
	otherColor = w->pyraminx.facetLoc[newFace][newPosition].face;
	/* newFace and newPosition variables are reused here */
	newFace = topFace; /* This narrows down the cases below */
	findPiece(w, faceColor, otherColor, &newFace, &newPosition);
	if (newFace == topFace) {
		switch (edgeToIndex(w, newPosition)) {
			case 0: /* Move LT to FT */
				L_MINUS;
				B_PLUS;
				L_MINUS;
				B_MINUS;
				L_MINUS;
				break;
			case 1: /* Move FR to FT */
				R_PLUS;
				B_MINUS;
				R_PLUS;
				B_PLUS;
				R_PLUS;
				break;
			case 2:
				/* Move FT to FT */
				/* No move :) */
				break;
			default:
				(void) printf("Wrong new position %d.\n", newPosition);
		}
	} else { /* Trivial more figuring... */
		int newIndex = edgeToIndex(w, newPosition);
		if ((newFace == topFaceTrans(topFace, 1) || newFace == topFaceTrans(topFace, 2))
				&& newIndex == 1) { /* Move FL to FT */
			R_MINUS;
			B_PLUS;
			R_PLUS;
		} else if ((newFace == topFaceTrans(topFace, 1) || newFace == topFaceTrans(topFace, 3))
				&& newIndex == 0) { /* Move FR to FT */
			L_PLUS;
			B_MINUS;
			L_MINUS;
		} else if ((newFace == topFaceTrans(topFace, 2) || newFace == topFaceTrans(topFace, 3))
				&& newIndex == 2) { /* Move LR to FT */
			R_MINUS;
			B_MINUS;
			R_PLUS;
		} else
			(void) printf("Wrong new face %d or new position %d.\n", newFace, newPosition);
	}
		/* Not correctly positioned... need to flip it */
	if (faceColor != w->pyraminx.facetLoc[topFace][position].face) {
		R_MINUS;
		B_PLUS;
		R_PLUS;
		L_PLUS;
		B_PLUS;
		L_MINUS;
	}
}
#endif

static int
pickTopFace(PyraminxWidget w)
{
	/* Pick a face (0) and determine which color it is by looking at its
	 * opposite corner.  Whatever color is not there is what this
	 * face should be.  Turn whole corners to match */
	int topFace, faceColor, aBottomFace;

	/* Could have hard coded at 0 but this way is more challenging */
	topFace = NRAND(4);
	faceColor = findFaceColor(w, topFace);
	faceCorners(w, topFace, faceColor);
#if 0
	faceEdge(w, topFace, indexToEdge(w, 0), faceColor);
	faceEdge(w, topFace, indexToEdge(w, 1), faceColor);
	faceEdge(w, topFace, indexToEdge(w, 2), faceColor);
#else
	faceEdge6(w, topFace, faceColor);
	aBottomFace = MAX_FACES - 1 - ((topFace + 2) % 4);
	movePuzzlePiece(w, aBottomFace, indexToEdge(w, 2),
		((topFace & 1) == 1) ? TR : BL, PERIOD3, TRUE);
	faceEdge6(w, topFace, faceColor);
	movePuzzlePiece(w, aBottomFace, indexToEdge(w, 2),
		((topFace & 1) == 1) ? TR : BL, PERIOD3, TRUE);
	faceEdge6(w, topFace, faceColor);
#endif
	return topFace;
}

static void
alignWholeCorner(PyraminxWidget w, int topFace)
{
	int frontColor, leftColor, rightColor;

	frontColor = w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToCenter(w, 2)].face;
	leftColor = w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToCenter(w, 1)].face;
	rightColor = w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToCenter(w, 0)].face;

	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 1)].face == frontColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 1)].face == leftColor) {
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 2)].face == leftColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 2)].face == rightColor) {
		B_PLUS_WHOLE;
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 0)].face == rightColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 0)].face == frontColor) {
		B_MINUS_WHOLE;
		return;
	}

	/* CW */
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 1)].face == rightColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 1)].face == frontColor) {
		B_PLUS;
		B_MINUS_WHOLE;
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 2)].face == frontColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 2)].face == leftColor) {
		B_PLUS;
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 0)].face == leftColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 0)].face == rightColor) {
		B_PLUS;
		B_PLUS_WHOLE;
		return;
	}

	/* CCW */
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 1)].face == leftColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 1)].face == rightColor) {
		B_MINUS;
		B_PLUS_WHOLE;
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 2)].face == rightColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 2)].face == frontColor) {
		B_MINUS;
		B_MINUS_WHOLE;
		return;
	}
	if (w->pyraminx.facetLoc[topFaceTrans(topFace, 3)][indexToEdge(w, 0)].face == frontColor &&
			w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 0)].face == leftColor) {
		B_MINUS;
		return;
	}
	(void) printf("Could not align whole corner!\n");
}

static Boolean
checkX3Solved(PyraminxWidget w) {
	int face, position;
	PyraminxLoc test = {0, 0};

	for (face = 0; face < MAX_FACES; face++)
		for (position = 0; position < w->pyraminx.sizeSize; position++) {
			if (cornerToIndex(w, position) == -1 &&
					centerToIndex(w, position) == -1 &&
					edgeToIndex(w, position) == -1)
				continue;
			if (position == 0) {
				test.face = w->pyraminx.facetLoc[face][position].face;
				test.rotation = w->pyraminx.facetLoc[face][position].rotation;
			} else if (test.face != /* MAX_SIDES * view + face */
					w->pyraminx.facetLoc[face][position].face ||
					(w->pyraminx.orient && test.rotation !=
					w->pyraminx.facetLoc[face][position].rotation))
				return False;
		}
	return True;
}

static int
exactCenter(PyraminxWidget w)
{
	int size = w->pyraminx.size;
	int i;

	if (size % 3 == 0)
		size--; /* no exact center here */
	if ((size + 2) % 3 == 0) {
		i = ((size - 1) / 3) * 2;
		return i * i + i;
	} else /*if ((size + 1) % 3 == 0)*/ {
		i = ((size - 2) / 3) * 2 + 1;
		return i * i + i;
	}
}

/* I could not find a reasonable solution with 1
   and only 1 center on its proper color, so avoiding */
static Boolean
checkMiddleSolvable(PyraminxWidget w) {
	int face, position, count = 0;
	PyraminxLoc test = {0, 0};

	for (face = 0; face < MAX_FACES; face++) {
		position = 0;
		test.face = w->pyraminx.facetLoc[face][position].face;
		position = exactCenter(w);
		count += ((test.face == w->pyraminx.facetLoc[face][position].face) ? 1 : 0);
	}
#ifdef DEBUG
	(void) printf("count %d\n", count);
#endif
	return ((count & 1) == 0);
}

static void
bottomWholeCorner(PyraminxWidget w, int topFace)
{
	int j = 0;

	do {
		int i = 0;

		if (j > 0) {
#ifdef DEBUG
			(void) printf("try again\n");
#endif
			movePuzzlePiece(w,
				((topFace >> 1) << 1) + (((topFace & 1) == 1) ? 0 : 1), exactCenter(w),
				TR, PERIOD3, FALSE);
		}
		alignWholeCorner(w, topFace);
		while (!checkX3Solved(w)) {
			if (i++ > 2 || j > 2) {
				(void) printf("Infinite Loop detected %d %d!\n", i, j);
				return;
			}
			if (w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToCenter(w, 2)].face ==
					w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToEdge(w, 0)].face) {
				if (w->pyraminx.facetLoc[topFaceTrans(topFace, 1)][indexToCenter(w, 0)].face ==
						w->pyraminx.facetLoc[topFaceTrans(topFace, 2)][indexToEdge(w, 1)].face) {
					R_MINUS;
					B_MINUS;
					R_PLUS;
					B_MINUS;
					R_MINUS;
					B_MINUS;
					R_PLUS;
				} else {
				/* Short cut: Alternate sequence */
				/* Could be solved by using above sequence but adds extra loops. */
					R_MINUS;
					B_PLUS;
					R_PLUS;
					B_PLUS;
					R_MINUS;
					B_PLUS;
					R_PLUS;
				}
			} else {
				L_PLUS;
				B_MINUS;
				L_MINUS;
				R_MINUS;
				B_MINUS;
				R_PLUS;

				L_PLUS;
				B_MINUS;
				L_MINUS;
				R_MINUS;
				B_MINUS;
				R_PLUS;
			}
			alignWholeCorner(w, topFace);
		}
#ifdef DEBUG
		(void) printf("loops %d\n", i);
#endif
		j++;
	} while (((w->pyraminx.size & 1) == 0) && !checkMiddleSolvable(w));
}

/* Size 4 pyraminx */
/* switch 2 and 3 so can have odd and even have a parity meaning for edgesLR */
static void
printFacets(PyraminxWidget w)
{
	int face, position, square;

	for (face = 0; face < MAX_FACES; face++) {
		square = 1;
		for (position = 0; position < w->pyraminx.sizeSize; position++) {
			(void) printf("%d %d  ",
				w->pyraminx.facetLoc[face][position].face,
				w->pyraminx.facetLoc[face][position].rotation);
			if (position == square * square - 1) {
				(void) printf("\n");
				++square;
			}
		}
		(void) printf("\n");
	}
	(void) printf("\n");
}

static int edgeLRMateFace[MAX_FACES][6] =
{
	{2, 3, 3, 2, 1, 1},
	{3, 2, 2, 3, 0, 0},
	{0, 1, 1, 0, 3, 3},
	{1, 0, 0, 1, 2, 2}
};

static int edgeLRMatePositionIndex[6] =
{3, 2, 1, 0, 5, 4};

static int
indexToEdgeLR(PyraminxWidget w, int edgeIndex)
{
	switch (edgeIndex) { /* Size 4 Pyraminx -> 1, 3, 4, 8, 11, 13 */
	case 0:
		return 1;
	case 1:
		return 3;
	case 3:
		return (w->pyraminx.size - 2) * (w->pyraminx.size - 2);
	case 2:
		return (w->pyraminx.size - 1) * (w->pyraminx.size - 1) - 1;
	case 4:
		return (w->pyraminx.size - 1) * (w->pyraminx.size - 1) + 2;
	case 5:
		return w->pyraminx.size * w->pyraminx.size - 3;
	default:
		(void) printf("edge unknown %d\n", edgeIndex);
	}
	return -1;
}

static int
edgeLRToIndex(PyraminxWidget w, int edge)
{
	int temp; /* Size 4 Pyraminx -> {-1, 0, -1, 1, 3, -1, -1, -1, 2, -1, -1, 4, -1, 5, -1, -1} */

	if (edge == 1)
		return 0;
	else if (edge == 3)
		return 1;
	temp = (w->pyraminx.size - 1) * (w->pyraminx.size - 1) - 1 - edge;
	if (temp == 0)
		return 2;
	else if (temp > 0) {
		temp = (w->pyraminx.size - 2) * (w->pyraminx.size - 2) - edge;
		if (temp == 0)
			return 3;
	} else if (temp < 0) {
		if (temp == -3)
			return 4;
		temp = w->pyraminx.size * w->pyraminx.size - 3 - edge;
		if (temp == 0)
			return 5;
	}
	return -1;
}

static Boolean
checkPieceLR(PyraminxWidget w, int color, int face, int position)
{
	int newFace, newPosition, positionIndex, newPositionIndex;

	positionIndex = edgeLRToIndex(w, position);
	if (positionIndex == -1) {
		positionIndex = 0;
		(void) printf("position %d incorrect\n", position);
	}
	newFace = edgeLRMateFace[face][positionIndex];
	newPositionIndex = edgeLRMatePositionIndex[positionIndex];
	newPosition = indexToEdgeLR(w, newPositionIndex);
	return (w->pyraminx.facetLoc[newFace][newPosition].face == color);
}

/* color0 is even position */
static void
findPieceLR(PyraminxWidget w, int color0, int color1, int *face, int *position)
{
	int faceSkip, positionIndex, startPositionIndex;

	startPositionIndex = edgeLRToIndex(w, *position);
	/* Check starting face first */
	for (positionIndex = 0; positionIndex < 6; positionIndex++) {
		*position = indexToEdgeLR(w, positionIndex);
		if (((startPositionIndex + positionIndex) % 2) == 0) {
			if (w->pyraminx.facetLoc[*face][*position].face == color0 &&
					checkPieceLR(w, color1, *face, *position)) {
#ifdef DEBUG
				(void) printf("LRe %d %d\n", *face, *position);
#endif
				return;
			}
		} else {
			if (w->pyraminx.facetLoc[*face][*position].face == color1 &&
					checkPieceLR(w, color0, *face, *position)) {
#ifdef DEBUG
				(void) printf("LRo %d %d\n", *face, *position);
#endif
				return;
			}
		}
	}
	faceSkip = *face;
	for (*face = 0; *face < MAX_FACES; (*face)++) {
		if (*face == faceSkip)
			continue;
		for (positionIndex = 0; positionIndex < 6; positionIndex++) {
			*position = indexToEdgeLR(w, positionIndex);
			if (((startPositionIndex + positionIndex) % 2) == 0) {
				if (w->pyraminx.facetLoc[*face][*position].face == color0 &&
						checkPieceLR(w, color1, *face, *position)) {
#ifdef DEBUG
					(void) printf("LR e %d %d\n", *face, *position);
#endif
					return;
				}
			} else {
				if (w->pyraminx.facetLoc[*face][*position].face == color1 &&
						checkPieceLR(w, color0, *face, *position)) {
#ifdef DEBUG
					(void) printf("LR o %d %d\n", *face, *position);
#endif
					return;
				}
			}
		}
	}
	(void) printf("PieceLR %d %d not found!\n", color0, color1);
	printFacets(w);
}

static void
solve0LR0(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][0].face;
	int color1 = w->pyraminx.facetLoc[2][0].face;
	int startFace = 0, startPositionIndex = 0;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
			break;
		case 1:
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TOP, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, startFace, position,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				LEFT, PERIOD3, FALSE);
			break;
		case 4:
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				BOTTOM, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, face, position,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				RIGHT, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), position,
				TR, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				RIGHT, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 4:
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve0LR1(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][0].face;
	int color1 = w->pyraminx.facetLoc[3][0].face;
	int startFace = 0, startPositionIndex = 1;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
			(void) printf("impossible\n");
			break;
		case 1:
			break;
		case 2:
			movePuzzlePiece(w, startFace, position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TR, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				LEFT, PERIOD3, FALSE);
			break;
		case 4:
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, face, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, face, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TR, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				BL, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				BOTTOM, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, face, position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, face, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, face, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 4:
			movePuzzlePiece(w, face, position,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, face, position,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve0LR2(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[2][indexToCorner(w, 1)].face;
	int color1 = w->pyraminx.facetLoc[3][indexToCorner(w, 2)].face;
	int startFace = 2, startPositionIndex = 4;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
			(void) printf("impossible\n");
			break;
		case 2:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			break;
		case 4:
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 4),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 4),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				BL, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 4),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 4),
				BOTTOM, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			break;
		case 4:
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve1LR0(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][0].face;
	int color1 = w->pyraminx.facetLoc[2][0].face;
	int startFace = 0, startPositionIndex = 3;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
			(void) printf("impossible\n");
			break;
		case 2:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			break;
		case 3:
			break;
		case 4:
			movePuzzlePiece(w, startFace, position,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, position,
				LEFT, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), position,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), position,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 4:
			(void) printf("impossible\n");
			break;
		case 5:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve1LR1(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][0].face;
	int color1 = w->pyraminx.facetLoc[3][0].face;
	int startFace = 0, startPositionIndex = 2;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
		case 3:
			(void) printf("impossible\n");
			break;
		case 2:
			break;
		case 4:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 4:
			(void) printf("impossible\n");
			break;
		case 5:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve1LR2(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[2][indexToCorner(w, 1)].face;
	int color1 = w->pyraminx.facetLoc[3][indexToCorner(w, 2)].face;
	int startFace = 2, startPositionIndex = 5;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
		case 2:
		case 3:
			(void) printf("impossible\n");
			break;
		case 4:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BL, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 0:
			(void) printf("impossible\n");
			break;
		case 1:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			break;
		case 2:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			break;
		case 4:
			(void) printf("impossible\n");
			break;
		case 5:
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve2LR1(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[2][0].face;
	int color1 = w->pyraminx.facetLoc[1][0].face;
	int startFace = 2, startPositionIndex = 1;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
		case 2:
		case 3:
			(void) printf("impossible\n");
			break;
		case 4:
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			break;
		case 1:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		switch (positionIndex) {
		case 1:
			break;
		case 2:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			break;
		case 4:
			break;
		}
		break;
	case 3:
		break;
	}
}

static void
solve2LR2(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[2][0].face;
	int color1 = w->pyraminx.facetLoc[1][0].face;
	int startFace = 2, startPositionIndex = 2;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
		case 2:
		case 3:
			(void) printf("impossible\n");
			break;
		case 4:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			break;
		case 1:
			break;
		case 3:
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BL, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		break;
	case 3:
		break;
	}
}

static void
solve0LR4(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][indexToCorner(w, 1)].face;
	int color1 = w->pyraminx.facetLoc[1][indexToCorner(w, 2)].face;
	int startFace = 0, startPositionIndex = 4;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
			(void) printf("impossible\n");
			break;
		case 2:
			break;
		case 4:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TR, PERIOD3, FALSE);
			break;
		case 5:
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				TR, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 3,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 2),
				TR, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 3),
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 3,
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), indexToEdgeLR(w, 3),
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		break;
	case 3:
		break;
	}
}

static void
solve0LR5(PyraminxWidget w)
{
	int face, position, positionIndex;
	int color0 = w->pyraminx.facetLoc[0][indexToCorner(w, 1)].face;
	int color1 = w->pyraminx.facetLoc[1][indexToCorner(w, 2)].face;
	int startFace = 0, startPositionIndex = 5;

	face = startFace;
	position = indexToEdgeLR(w, startPositionIndex);
	findPieceLR(w, color0, color1, &face, &position);
	positionIndex = edgeLRToIndex(w, position);
#ifdef DEBUG
	(void) printf("findPieceLR color0=%d color1=%d : face=%d positionIndex=%d\n",
		color0, color1, face, positionIndex);
#endif
	switch (face) {
	case 0:
		switch (positionIndex) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
			(void) printf("impossible\n");
			break;
		case 5:
			break;
		}
		break;
	case 1:
		switch (positionIndex) {
		case 0:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			break;
		case 3:
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				BL, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				TOP, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				LEFT, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, indexToEdgeLR(w, 2),
				BOTTOM, PERIOD3, FALSE);
			movePuzzlePiece(w, startFace, 1,
				RIGHT, PERIOD3, FALSE);
			movePuzzlePiece(w, ((startFace >> 1) << 1) + (((startFace & 1) == 1) ? 0 : 1), 1,
				TR, PERIOD3, FALSE);
			break;
		}
		break;
	case 2:
		break;
	case 3:
		break;
	}
}

static void
solveTopLevel(PyraminxWidget w)
{
	solve0LR0(w);
	solve0LR1(w);
	solve0LR2(w);
}

static void
solveMiddleLevel(PyraminxWidget w)
{
	solve1LR0(w);
	solve1LR1(w);
	solve1LR2(w);
}

static void
solveBottomLevel(PyraminxWidget w)
{
	solve2LR1(w);
	solve2LR2(w);
	solve0LR4(w);
	solve0LR5(w);
}

static int
findPieceCenter(PyraminxWidget w, int color0, int startFace)
{
	int face;
	int position = exactCenter(w);

	/* Check starting face first */
	if (w->pyraminx.facetLoc[startFace][position].face == color0) {
#ifdef DEBUG
		(void) printf("Center %d %d\n", startFace, position);
#endif
		return startFace;
	}
	for (face = 0; face < MAX_FACES; face++) {
		if (face == startFace)
			continue;
		if (w->pyraminx.facetLoc[face][position].face == color0) {
#ifdef DEBUG
			(void) printf("Center fs %d %d\n", face, position);
#endif
			return face;
		}
	}
	(void) printf("Piece %d not found!\n", color0);
	return -1;
}

#if 0
static void
solveCenter0(PyraminxWidget w)
{
	int face;
	int color0 = w->pyraminx.facetLoc[0][0].face;
	int startFace = 0;
	int position = exactCenter(w);

	face = findPieceCenter(w, color0, startFace);
	(void) printf("got it %d %d\n", face, color0);
	switch (face) {
	case 0:
		return;
	case 1:
		movePuzzlePiece(w, startFace, position,
			TOP, PERIOD3, FALSE);
		return;
	case 2:
		movePuzzlePiece(w, startFace, position,
			TR, PERIOD3, FALSE);
		return;
	case 3:
		movePuzzlePiece(w, startFace, position,
			BL, PERIOD3, FALSE);
		return;
	}
}

static void
solveCenter1(PyraminxWidget w)
{
	int face;
	int color0 = w->pyraminx.facetLoc[1][0].face;
	int startFace = 1;
	int position = exactCenter(w);

	face = findPieceCenter(w, color0, startFace);
#if DEBUG
	(void) printf("solveCenter1 %d %d\n", face, color0);
#endif
	switch (face) {
	case 0:
		(void) printf("solveCenter1 impossible\n");
		return;
	case 1:
		return;
	case 2:
		movePuzzlePiece(w, startFace, position,
			TR, PERIOD3, FALSE);
		return;
	case 3:
		movePuzzlePiece(w, startFace, position,
			BL, PERIOD3, FALSE);
		return;
	}
}
#endif

static void
solve4CenterDown(PyraminxWidget w, int startFace)
{
	int color0 = w->pyraminx.facetLoc[startFace][0].face;
	int position = exactCenter(w);
	int index = findPieceCenter(w, color0, startFace);

	if (index == 0)
		return;
	index--;
	movePuzzlePiece(w, startFace, position,
		(BOTTOM + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(TR + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(TOP + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(LEFT + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(BOTTOM + 2 * index) % COORD, PERIOD3, FALSE);

	movePuzzlePiece(w, startFace, position,
		(RIGHT + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(BL + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(LEFT + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(TOP + 2 * index) % COORD, PERIOD3, FALSE);
	movePuzzlePiece(w, startFace, position,
		(RIGHT + 2 * index) % COORD, PERIOD3, FALSE);
}

static int middleOrient[MAX_FACES];

static void
findPieceCenterOrient(PyraminxWidget w)
{
	int rotation = w->pyraminx.facetLoc[0][0].rotation;
	int position = exactCenter(w);
	int face;
	for (face = 0; face < MAX_FACES; face++) {
		middleOrient[face] =
			(w->pyraminx.facetLoc[face][position].rotation
			- rotation + COORD) % 3;
#ifdef DEBUG
		(void) printf("rotation %d %d\n", face, middleOrient[face]);
#endif
	}
}

static void
orientShuffle(PyraminxWidget w, int face, int parity, int rotation)
{
	int position = exactCenter(w);
	int i;
	for (i = 0; i <  3; i++) {
		movePuzzlePiece(w, face, position,
			(LEFT + 3 * parity + 2 * rotation) % COORD,
			PERIOD3, FALSE);
		movePuzzlePiece(w, face, position,
			(TOP + 3 * parity + 2 * rotation) % COORD,
			PERIOD3, FALSE);
		movePuzzlePiece(w, face, position,
			(RIGHT + 3 * parity + 2 * rotation) % COORD,
			PERIOD3, FALSE);
		movePuzzlePiece(w, face, position,
			(BOTTOM + 3 * parity + 2 * rotation) % COORD,
			PERIOD3, FALSE);
	}
}

static void
orientShuffleFaces(PyraminxWidget w, int face0, int face1)
{
	int newFace0, newFace1;
#ifdef DEBUG
	(void) printf("orientShuffleFaces %d %d\n", face0, face1);
#endif
	if ((face0 == 0 && face1 == 1) || (face0 == 1 && face1 == 0)
			|| (face0 == 2 && face1 == 3)
			|| (face0 == 3 && face1 == 2)) {
		newFace1 = (face0 + 2) % MAX_FACES;
		newFace0 = (face1 + 2) % MAX_FACES;
		orientShuffle(w, newFace0, (newFace0 & 1), 0);
		orientShuffle(w, newFace1, (newFace1 & 1), 0);
	} else if ((face0 == 0 && face1 == 2) || (face0 == 2 && face1 == 0)
			|| (face0 == 1 && face1 == 3)
			|| (face0 == 3 && face1 == 1)) {
		if (face0 == 1 || face0 == 3) {
			newFace0 = (face0 + 3) % MAX_FACES;
			newFace1 = (face1 + 3) % MAX_FACES;
		} else {
			newFace1 = (face0 + 3) % MAX_FACES;
			newFace0 = (face1 + 3) % MAX_FACES;
		}
		orientShuffle(w, newFace0, (newFace0 & 1), 1);
		orientShuffle(w, newFace1, (newFace1 & 1), 1);
	} else if ((face0 == 0 && face1 == 3) || (face0 == 3 && face1 == 0)
			|| (face0 == 1 && face1 == 2)
			|| (face0 == 2 && face1 == 1)) {
		newFace0 = (face0 + 2) % MAX_FACES;
		newFace1 = (face1 + 2) % MAX_FACES;
		orientShuffle(w, newFace0, (newFace0 & 1), 2);
		orientShuffle(w, newFace1, (newFace1 & 1), 2);
	}
}

static int
findCenter(PyraminxWidget w, int start, int value)
{
	int face;
	for (face = start + 1; face < MAX_FACES; face++) {
		if (middleOrient[face] == value)
			return face;
	}
	return -1;
}

static void
decideShuffle(PyraminxWidget w)
{
	int face0 = findCenter(w, -1, 1);
	int face1 = findCenter(w, -1, 2);

	if (face0 >= 0 && face1 >= 0) {
#ifdef DEBUG
		(void) printf("decideShuffle %d %d\n", face0, face1);
#endif
		orientShuffleFaces(w, face0, face1);
		findPieceCenterOrient(w);
	}
	face0 = findCenter(w, -1, 1);
	face1 = findCenter(w, face0, 1);
	if (face0 >= 0 && face1 >= 0) {
#ifdef DEBUG
		(void) printf("decideShuffle %d %d\n", face0, face1);
#endif
		orientShuffleFaces(w, face0, face1);
		findPieceCenterOrient(w);
	}
	face0 = findCenter(w, -1, 2);
	face1 = findCenter(w, face0, 2);
	if (face0 >= 0 && face1 >= 0) {
#ifdef DEBUG
		(void) printf("decideShuffle %d %d\n", face0, face1);
#endif
		orientShuffleFaces(w, face0, face1);
		findPieceCenterOrient(w);
	}
	face0 = findCenter(w, -1, 1);
	face1 = findCenter(w, -1, 2);
	if (face0 >= 0 && face1 >= 0) {
#ifdef DEBUG
		(void) printf("decideShuffle %d %d\n", face0, face1);
#endif
		orientShuffleFaces(w, face0, face1);
	}
}

static void
solveCorners(PyraminxWidget w)
{
	orientTrivialCorners(w);
	if (w->pyraminx.size > 2) {
		bottomWholeCorner(w, pickTopFace(w));
	}
	if (w->pyraminx.size > 3) {
		solveTopLevel(w);
		solveMiddleLevel(w);
		solveBottomLevel(w);
		if (w->pyraminx.size % 3 != 0) {
			solve4CenterDown(w, 0);
			if (w->pyraminx.orient) {
				findPieceCenterOrient(w);
				decideShuffle(w);
			}
		}
	}
}

#if 0
static int
findMaxMatch(PyraminxWidget w) {
	int face, corner, corners[3];
	int matchFace, matchCorner[3];
	int finalMatchFace, finalMatchCorner[3];
	int matches, greatestMatches = 0;

	corners[0] = 0;
	corners[1] = (w->pyraminx.size - 1) * (w->pyraminx.size - 1);
	corners[2] = w->pyraminx.size * w->pyraminx.size - 1;
	for (corner = 0; corner < 3; corner++) {
		matchCorner[corners[corner]] = -1;
		finalMatchCorner[corners[corner]] = -1;
	}
	(void) printf("help = %d\n", 0);
	for (face = 0; face < MAX_FACES; face++) {
		matches = 0;
		for (corner = 0; corner < 3; corner++) {
			if (w->pyraminx.facetLoc[face][corners[corner]].face ==
					w->pyraminx.facetLoc[face][2].face) {
				matchFace = face;
				matchCorner[matches] = corner;
				matches++;
			}
		}
	(void) printf("help = %d %d %d\n", matches, matchFace, matchCorner[0]);
		if (matches > greatestMatches) {
			greatestMatches = matches;
			finalMatchFace = matchFace;
			for (corner = 0; corner < 3; corner++) {
				finalMatchCorner[corner] =
					finalMatchCorner[corner];
			}
		}
	}
	return greatestMatches;
}
#endif

typedef struct _PyraminxFC {
	int face, corner;
} PyraminxFC;

static PyraminxFC pyraminxFC[3];

/* 2e */
/* rotateEdge
2      0       6 e2
0      1       2 e0
1      2       6 e2
0      0       2
2      0       6
0      0       2
1      2       6
0      1       2
*/


static void
findCornerEdgePositions(PyraminxWidget w) {
	int reference, center, counter = 0, face, corner;

	center = w->pyraminx.size >> 1;
	center = center * center + center;
	reference = w->pyraminx.facetLoc[0][center].face;
	for (face = 0; face < MAX_FACES; face++) {
		for (corner = 0; corner < 3; corner++) {
			if (reference ==
					w->pyraminx.facetLoc[face][indexToCorner(w, corner)].face) {
				pyraminxFC[counter].face = face;
				pyraminxFC[counter].corner = corner;
				counter++;
				if (counter == 3)
					return;
			}
		}
	}
}

static void
printEdgeError(PyraminxFC pfc[]) {
	(void) printf("fix me %d %d  %d %d  %d %d\n",
		pfc[0].face, pfc[0].corner,
		pfc[1].face, pfc[1].corner,
		pfc[2].face, pfc[2].corner);
}

static void
solveCornerEdgeTurn(PyraminxWidget w) {
	findCornerEdgePositions(w);

	switch (pyraminxFC[0].face) {
	case 0:
	    switch (pyraminxFC[0].corner) {
	    case 0:
		switch (pyraminxFC[1].face) {
		case 0:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    case 1:
			switch (pyraminxFC[2].face) {
			case 0:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    case 2:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 1:
		    switch (pyraminxFC[1].corner) {
		    case 1:
			switch (pyraminxFC[2].face) {
			case 1:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    case 2:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    case 1:
		switch (pyraminxFC[1].face) {
		case 0:
		    switch (pyraminxFC[1].corner) {
		    case 2:
			switch (pyraminxFC[2].face) {
			case 1:
			    switch (pyraminxFC[2].corner) {
			    case 0:
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 1:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 2:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 0:
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 3:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    case 2:
		switch (pyraminxFC[1].face) {
		case 1:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    default:
		printEdgeError(pyraminxFC);
	    }
	    break;
	case 1:
	    switch (pyraminxFC[0].corner) {
	    case 0:
		switch (pyraminxFC[1].face) {
		case 1:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    case 1:
			switch (pyraminxFC[2].face) {
			case 1:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    case 2:
			switch (pyraminxFC[2].face) {
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    case 1:
		switch (pyraminxFC[1].face) {
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    case 2:
		switch (pyraminxFC[1].face) {
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 1:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 0:
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 3:
		    switch (pyraminxFC[1].corner) {
		    case 0:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 1:
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    default:
		printEdgeError(pyraminxFC);
	    }
	    break;
	case 2:
	    switch (pyraminxFC[0].corner) {
	    case 0:
		switch (pyraminxFC[1].face) {
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 1:
			switch (pyraminxFC[2].face) {
			case 2:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		case 3:
		    switch (pyraminxFC[1].corner) {
		    case 1:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    case 1:
		switch (pyraminxFC[1].face) {
		case 2:
		    switch (pyraminxFC[1].corner) {
		    case 2:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 0:
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeRight(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    default:
		printEdgeError(pyraminxFC);
	    }
	    break;
	case 3:
	    switch (pyraminxFC[0].corner) {
	    case 0:
		switch (pyraminxFC[1].face) {
		case 3:
		    switch (pyraminxFC[1].corner) {
		    case 1:
			switch (pyraminxFC[2].face) {
			case 3:
			    switch (pyraminxFC[2].corner) {
			    case 2:
				rotateEdgeRight(w, 0);
				rotateEdgeTR(w, 0);
				rotateEdgeTop(w, 0);
				rotateEdgeTR(w, 0);
				break;
			    default:
				printEdgeError(pyraminxFC);
			    }
			    break;
			default:
			    printEdgeError(pyraminxFC);
			}
			break;
		    default:
			printEdgeError(pyraminxFC);
		    }
		    break;
		default:
		    printEdgeError(pyraminxFC);
		}
		break;
	    default:
		printEdgeError(pyraminxFC);
	    }
	    break;
	default:
	    printEdgeError(pyraminxFC);
	}
}

static void
findPieceOrder(PyraminxWidget w, int color0, int color1, int *face, int *positionIndex)
{
	for (*face = 0; *face < MAX_FACES; (*face)++) {
		for (*positionIndex = 0; *positionIndex < 3; (*positionIndex)++) {
			int position = indexToEdge(w, *positionIndex);
			if (w->pyraminx.facetLoc[*face][position].face == color0 &&
					checkPiece(w, color1, *face, position)) {
				return;
			}
		}
	}
	(void) printf("Ordered piece %d %d not found!\n", color0, color1);
}

#if 0
static void
solveEdgeEdgeTurn2(PyraminxWidget w)
{
	int face = 0;

	rotateEdgeRightPos(w, face, 1);
	rotateEdgeTopPos(w, face, indexToCorner(w, 2));
	rotateEdgeTRPos(w, face, 0);
	rotateEdgeTopPos(w, face, 0);

	rotateEdgeRightPos(w, face, 1);
	rotateEdgeTopPos(w, face, 0);
	rotateEdgeTRPos(w, face, 0);
	rotateEdgeTopPos(w, face, indexToCorner(w, 2));
}
#endif

static void
solve0Edge(PyraminxWidget w)
{
	int face = 0, otherFace = 2;
	int newFace, faceColor, otherColor, newPositionIndex;
	faceColor =  w->pyraminx.facetLoc[face][0].face;
	otherColor = w->pyraminx.facetLoc[otherFace][0].face;
	newFace = face;
	findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
	switch (newFace) {
	case 0:
		/* done */
		break;
	case 1:
		rotateEdgeTopPos(w, newFace, indexToEdge(w, 0));
		rotateEdgeRightPos(w, newFace, indexToEdge(w, 0));
		rotateEdgeTopPos(w, newFace, indexToEdge(w, 0));
		break;
	case 2:
		rotateEdgeTopPos(w, face, indexToEdge(w, 0));
		rotateEdgeRightPos(w, face, indexToEdge(w, 0));
		rotateEdgeTopPos(w, face, indexToEdge(w, 0));
		rotateEdgeRightPos(w, face, indexToEdge(w, 0));
		break;
	case 3:
		rotateEdgeRightPos(w, face, indexToEdge(w, 0));
		break;
	}
#ifdef DEBUG
	(void) printf("solve0Edge: %d %d\n", newFace, newPositionIndex);
#endif
}

static void
solve1Edge(PyraminxWidget w)
{
	int face = 0, otherFace = 3;
	int newFace, faceColor, otherColor, newPositionIndex;
	faceColor =  w->pyraminx.facetLoc[face][0].face;
	otherColor = w->pyraminx.facetLoc[otherFace][0].face;
	newFace = face;
	findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
	switch (newFace) {
	case 0:
		/* done */
		break;
	case 1:
		rotateEdgeRightPos(w, face, indexToEdge(w, 1));
		rotateEdgeTopPos(w, face, indexToEdge(w, 1));
		rotateEdgeRightPos(w, face, indexToEdge(w, 1));
		break;
	case 2:
		rotateEdgeTopPos(w, face, indexToEdge(w, 1));
		break;
	case 3:
		rotateEdgeRightPos(w, face, indexToEdge(w, 1));
		rotateEdgeTopPos(w, face, indexToEdge(w, 1));
		rotateEdgeRightPos(w, face, indexToEdge(w, 1));
		rotateEdgeTopPos(w, face, indexToEdge(w, 1));
		break;
	}
#ifdef DEBUG
	(void) printf("solve1Edge: %d %d\n", newFace, newPositionIndex);
#endif
}

static void
solve2Edge(PyraminxWidget w)
{
	int face = 0, otherFace = 1;
	int newFace, faceColor, otherColor, newPositionIndex;
	faceColor =  w->pyraminx.facetLoc[face][0].face;
	otherColor = w->pyraminx.facetLoc[otherFace][0].face;
	newFace = face;
	findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
	if (newFace == 1) {
#ifdef DEBUG
		(void) printf("solve2Edge\n");
#endif
		face = 1;
		otherFace = 3;
		faceColor =  w->pyraminx.facetLoc[face][0].face;
		otherColor = w->pyraminx.facetLoc[otherFace][0].face;
		newFace = face;
		findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
		if (newFace == 3) {
#ifdef DEBUG
			(void) printf("solve2Edge 3\n");
#endif
			rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeRightPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTopPos(w, 0, w->pyraminx.size * w->pyraminx.size - 1);
			rotateEdgeRightPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			return;
		}
		otherFace = 2;
		otherColor = w->pyraminx.facetLoc[otherFace][0].face;
		newFace = face;
		findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
		if (newFace == 2) {
#ifdef DEBUG
			(void) printf("solve2Edge 2\n");
#endif
			rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTopPos(w, 0, w->pyraminx.size * w->pyraminx.size - 1);
			rotateEdgeRightPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTopPos(w, 0, w->pyraminx.size * w->pyraminx.size - 1);
			return;
		}
#ifdef DEBUG
		(void) printf("solve2Edge opp\n");
#endif

		rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
		rotateEdgeTopPos(w, 0, indexToEdge(w, 1));
		rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
		rotateEdgeTopPos(w, 0, indexToEdge(w, 1));
	}
}

static void
solve3Edge(PyraminxWidget w)
{
	int face = 2, otherFace = 3;
	int newFace, faceColor, otherColor, newPositionIndex;
	faceColor =  w->pyraminx.facetLoc[face][0].face;
	otherColor = w->pyraminx.facetLoc[otherFace][0].face;
	newFace = face;
	findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
	if (newFace == 3) {
#ifdef DEBUG
		(void) printf("solve3Edge\n");
#endif
		otherFace = 1;
		otherColor = w->pyraminx.facetLoc[otherFace][0].face;
		newFace = face;
		findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
		if (newFace == 1) {
#ifdef DEBUG
			(void) printf("solve3Edge 1\n");
#endif
			rotateEdgeTRPos(w, 2, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTopPos(w, 2, 0);
			rotateEdgeRightPos(w, 2, 0);
			rotateEdgeTopPos(w, 2, 0);
			return;
		}
		otherFace = 3;
		otherColor = w->pyraminx.facetLoc[otherFace][0].face;
		newFace = face;
		findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
		if (newFace == 3) {
#ifdef DEBUG
			(void) printf("solve3Edge 2\n");
#endif
			rotateEdgeTRPos(w, 2, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeRightPos(w, 2, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTopPos(w, 2, w->pyraminx.size * w->pyraminx.size - 1);
			rotateEdgeRightPos(w, 2, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			return;
		}
	}
}

static void
solve4Edge(PyraminxWidget w)
{
	int face = 1, otherFace = 2;
	int newFace, faceColor, otherColor, newPositionIndex;
	faceColor =  w->pyraminx.facetLoc[face][0].face;
	otherColor = w->pyraminx.facetLoc[otherFace][0].face;
	newFace = face;
	findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
	if (newFace == 2) {
#ifdef DEBUG
		(void) printf("solve4Edge\n");
#endif
		face = 2;
		otherFace = 3;
		faceColor =  w->pyraminx.facetLoc[face][0].face;
		otherColor = w->pyraminx.facetLoc[otherFace][0].face;
		newFace = face;
		findPieceOrder(w, faceColor, otherColor, &newFace, &newPositionIndex);
		if (newFace == 2) {
#ifdef DEBUG
			(void) printf("solve4Edge 2\n");
#endif
			rotateEdgeTopPos(w, 0, w->pyraminx.size * w->pyraminx.size - 1);
			rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeRightPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			rotateEdgeTRPos(w, 0, (w->pyraminx.size - 1) * (w->pyraminx.size - 1));
			return;
		}
	}
}

static void
solveEdgeEdgeTurn(PyraminxWidget w)
{
	solve0Edge(w);
	solve1Edge(w);
	solve2Edge(w);
	solve3Edge(w);
	solve4Edge(w);
}

static int cornerFace[4];
static int centerFace[4];

static void
solveCenterEdgeRow(PyraminxWidget w, int face, Boolean dir)
{
	int i;

	if (dir) {
		for (i = 0; i < 2; i++) {
			rotateEdgeTRPos(w, face, 0);
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
		}
	} else {
		for (i = 0; i < 2; i++) {
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTRPos(w, face, 0);
		}
	}
}

static void
solveCenterEdgeColumn(PyraminxWidget w, int face, Boolean dir)
{
	int i;

	if (dir) {
		for (i = 0; i < 2; i++) {
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeTRPos(w, face, 0);
		}
	} else {
		for (i = 0; i < 2; i++) {
			rotateEdgeTRPos(w, face, 0);
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
		}
	}
}

static void
solveCenterEdgeDiagonal(PyraminxWidget w, int face, Boolean dir)
{
	int i;

	if (dir) {
		for (i = 0; i < 2; i++) {
			rotateEdgeTRPos(w, face, indexToCorner(w, 2));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeTRPos(w, face, indexToCorner(w, 2));
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
		}
	} else {
		for (i = 0; i < 2; i++) {
			rotateEdgeRightPos(w, face, indexToCorner(w, 1));
			rotateEdgeTRPos(w, face, indexToCorner(w, 2));
			rotateEdgeTopPos(w, face, indexToCorner(w, 2));
			rotateEdgeTRPos(w, face, indexToCorner(w, 2));
		}
	}
}

static int
findCenterPositions(PyraminxWidget w, int corner, int *sameFace, Boolean *dir)
{
	int face, count = 0;

	*sameFace = MAX_FACES;
	*dir = False;
	for (face = 0; face < MAX_FACES; face++) {
		cornerFace[face] =
			w->pyraminx.facetLoc[face][indexToCorner(w, corner)].face;
		centerFace[face] =
			w->pyraminx.facetLoc[face][indexToCenter(w, corner)].face;
		if (cornerFace[face] == centerFace[face]) {
			count++;
			*sameFace = face;
		}
	}
	if (count != 1) {
		*sameFace = MAX_FACES;
	} else {
		face = 0;
		if (*sameFace == 0 || *sameFace == 1)
			face = 2;
		*dir = (centerFace[face] == cornerFace[face + 1]);
		if ((*sameFace & 1) == 1)
			*dir = !(*dir);
	}
	return count;
}

static void
solveMiddleRow(PyraminxWidget w)
{
	int count, sameFace;
	Boolean dir;

	count = findCenterPositions(w, 1, &sameFace, &dir);
	if (count == 0) {
#ifdef DEBUG
		(void) printf("all row %d\n", 4);
#endif
		solveCenterEdgeRow(w, 0, True);
		count = findCenterPositions(w, 1, &sameFace, &dir);
	}
	if (count == 1) {
#ifdef DEBUG
		(void) printf("row %d %d\n", sameFace, dir);
#endif
		solveCenterEdgeRow(w, sameFace, dir);
		return;
	}
#ifdef DEBUG
	(void) printf("row done\n"); /* count == 4 */
#endif
}

static void
solveMiddleColumn(PyraminxWidget w)
{
	int count, sameFace;
	Boolean dir;

	count = findCenterPositions(w, 2, &sameFace, &dir);
	if (count == 0) {
#ifdef DEBUG
		(void) printf("all column %d\n", 4);
#endif
		solveCenterEdgeColumn(w, 0, True);
		count = findCenterPositions(w, 2, &sameFace, &dir);
	}
	if (count == 1) {
#ifdef DEBUG
		(void) printf("column %d %d\n", sameFace, dir);
#endif
		solveCenterEdgeColumn(w, sameFace, dir);
		return;
	}
#ifdef DEBUG
	(void) printf("column done\n"); /* count == 4 */
#endif
}

static void
solveMiddleDiagonal(PyraminxWidget w)
{
	int count, sameFace;
	Boolean dir;

	count = findCenterPositions(w, 0, &sameFace, &dir);
	if (count == 0) {
#ifdef DEBUG
		(void) printf("all diagonal %d\n", 4);
#endif
		solveCenterEdgeDiagonal(w, 0, True);
		count = findCenterPositions(w, 0, &sameFace, &dir);
	}
	if (count == 1) {
#ifdef DEBUG
		(void) printf("diagonal %d %d\n", sameFace, dir);
#endif
		solveCenterEdgeDiagonal(w, sameFace, dir);
		return;
	}
#ifdef DEBUG
	(void) printf("diagonal done\n"); /* count == 4 */
#endif
}

static void
solveCenterEdgeTurn(PyraminxWidget w)
{
	solveMiddleRow(w);
	solveMiddleColumn(w);
	solveMiddleDiagonal(w);
}

static void
solveEdges(PyraminxWidget w) {
	solveCornerEdgeTurn(w);
	if (w->pyraminx.size > 2) {
		if (w->pyraminx.sticky || w->pyraminx.size % 2 != 0) {
			solveEdgeEdgeTurn(w);
		}
		solveCenterEdgeTurn(w);
	}
}

#if 0
From Puzzle It Out: Cubes, Groups and Puzzles
/* Upper(U) = Posterior (P) */
/*      P       */
/*   e3    e4   */
/* L    e1    B */
/*   e2    e5   */
/*      R       */
#define e1_e2_e3 P_MINUS; R_PLUS; P_PLUS; R_MINUS
#define e1_e3_e2 R_PLUS; P_MINUS; R_MINUS; P_PLUS
#define e1_e3_e4 L_PLUS; P_PLUS; R_PLUS; P_MINUS; R_MINUS; L_MINUS
#define e1_e4_e3 L_PLUS; R_PLUS; P_PLUS; R_MINUS; P_MINUS; L_MINUS
#define e2_e1_e4 R_PLUS; P_PLUS; R_MINUS; P_MINUS
#define e4_e1_e2 P_PLUS; R_PLUS; P_MINUS; R_MINUS
#define e5_e1_e3 R_MINUS; P_MINUS; R_PLUS; P_PLUS
#define e3_e1_e5 P_MINUS; R_MINUS; P_PLUS; R_PLUS
#define e1_e3 R_PLUS; P_MINUS; R_MINUS; P_PLUS;\
 R_MINUS; L_PLUS; R_PLUS; L_MINUS
#define e3_e5 P_MINUS; R_MINUS; P_PLUS;\
 R_MINUS; L_PLUS; R_PLUS; L_MINUS; R_PLUS
#endif

/* This procedure coordinates the solution process. */
void
solveSomePieces(PyraminxWidget w)
{
	setPuzzle(w, ACTION_RESET);
	if (solvingFlag)
		return;
#ifdef JMP
	if (!setjmp(solve_env))
#endif
	{
		solvingFlag = True;
		if (!checkSolved(w)) {
			if (w->pyraminx.mode == PERIOD2)
				solveEdges(w);
			else if (w->pyraminx.mode == PERIOD3)
				solveCorners(w);
		}
	}
#ifdef JMP
	abortSolvingFlag = False;
#endif
	solvingFlag = False;
	w->pyraminx.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_COMPUTED);
}
