/*
 * @(#)BevelS.c
 *
 * Copyright 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 Bevel */

#include "rngs.h"
#define JMP
#ifdef JMP
#include <setjmp.h> /* longjmp ... interrupt */
#endif
#include "BevelP.h"

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

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

static void
movePuzzlePiece(BevelWidget w, int face, int position,
	int direction, 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, control);
}

#define MAX_CORNERS 8
static int bevelCorner[MAX_CORNERS][3] =
{
	{1, 4, 5},
	{1, 2, 4},
	{0, 1, 5},
	{0, 2, 1},
	{3, 5, 4},
	{2, 3, 4},
	{0, 5, 3},
	{0, 3, 2}
};

static int bevelCornerOrient[MAX_CORNERS][3] =
{
	{2, 2, 3},
	{1, 2, 3},
	{3, 3, 2},
	{2, 3, 0},
	{1, 0, 1},
	{1, 2, 0},
	{0, 1, 0},
	{1, 3, 0}
};

/* Corners layout, bits correspond to position
   2 6
 2 3 7 6
 0 1 5 4
   0 4
   2 6
*/

static int cornerColor(BevelWidget w, int corner, int n)
{
	return w->bevel.cubeLoc[bevelCorner[corner][n]][bevelCornerOrient[corner][n]].face;
}

static int
findOtherCorner(BevelWidget w, int corner, int color0, int color1)
{
	int i, j, color, count;

	for (i = 0; i < MAX_CORNERS; i++) {
		if (i == corner)
			continue;
		count = 0;
		for (j = 0; j < 3; j++) {
			color = cornerColor(w, i, j);
			if (color == color0 || color == color1)
				count++;
			if (count == 2)
				return i;
		}
	}
	return MAX_CORNERS;
}

static int
findCorner(BevelWidget w, int color0, int color1, int color2)
{
	int i, j, color, count;

	for (i = 0; i < MAX_CORNERS; i++) {
		count = 0;
		for (j = 0; j < 3; j++) {
			color = cornerColor(w, i, j);
			if (color == color0 || color == color1 || color == color2)
				count++;
			if (count == 3)
				return i;
		}
	}
	return MAX_CORNERS;
}

static void
setSecondCorner(BevelWidget w)
{
	int fixedCorner = 3;
	int color0 = cornerColor(w, fixedCorner, 0);
	int color1 = cornerColor(w, fixedCorner, 1);
	int foundCorner = findOtherCorner(w, fixedCorner, color0, color1);
#ifdef DEBUG
	int targetCorner = 7;
	(void) printf("secondCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif
	switch (foundCorner) {
	case 0:	
		movePuzzlePiece(w, 4, 1, LEFT, FALSE);
		movePuzzlePiece(w, 4, 1, TOP, FALSE);
		movePuzzlePiece(w, 2, 1, TOP, FALSE);
		break;
	case 1:	
		movePuzzlePiece(w, 2, 1, LEFT, FALSE);
		movePuzzlePiece(w, 2, 1, TOP, FALSE);
		break;
	case 2:	
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		movePuzzlePiece(w, 0, 1, BOTTOM, FALSE);
		break;
	case 4:	
		movePuzzlePiece(w, 4, 1, TOP, FALSE);
		movePuzzlePiece(w, 2, 1, TOP, FALSE);
		break;
	case 5:	
		movePuzzlePiece(w, 2, 1, TOP, FALSE);
		break;
	case 6:	
		movePuzzlePiece(w, 0, 1, BOTTOM, FALSE);
		break;
	}
	/* rotate "turnstile" if needed */
	if (color0 != w->bevel.cubeLoc[0][1].face) {
		if (color0 == w->bevel.cubeLoc[2][0].face) {
			movePuzzlePiece(w, 3, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 3, 1, LEFT, FALSE);
			movePuzzlePiece(w, 3, 2, TOP, FALSE);
		} else {
			movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 3, 1, TOP, FALSE);
			movePuzzlePiece(w, 3, 0, LEFT, FALSE);
		}
	}
}

static void
setThirdCorner(BevelWidget w)
{
	int fixedCorner = 3;
	int color0 = cornerColor(w, fixedCorner, 1);
	int color1 = cornerColor(w, fixedCorner, 2);
	int foundCorner = findOtherCorner(w, fixedCorner, color0, color1);
#ifdef DEBUG
	int targetCorner = 1;
	(void) printf("thirdCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif
	switch (foundCorner) {
	case 0:	
		movePuzzlePiece(w, 4, 2, TOP, FALSE);
		break;
	case 2:	
		movePuzzlePiece(w, 5, 2, TOP, FALSE);
		movePuzzlePiece(w, 4, 2, TOP, FALSE);
		break;
	case 4:	
		movePuzzlePiece(w, 4, 1, TOP, FALSE);
		movePuzzlePiece(w, 2, 1, LEFT, FALSE);
		break;
	case 5:	
		movePuzzlePiece(w, 2, 1, LEFT, FALSE);
		break;
	case 6:	
		movePuzzlePiece(w, 5, 1, TOP, FALSE);
		movePuzzlePiece(w, 4, 1, TOP, FALSE);
		movePuzzlePiece(w, 2, 1, LEFT, FALSE);
		break;
	}
	/* rotate "turnstile" if needed */
	if (color0 != w->bevel.cubeLoc[2][2].face) {
		if (color0 == w->bevel.cubeLoc[1][1].face) {
			movePuzzlePiece(w, 4, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 4, 1, LEFT, FALSE);
			movePuzzlePiece(w, 4, 2, TOP, FALSE);
		} else {
			movePuzzlePiece(w, 4, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 4, 1, TOP, FALSE);
			movePuzzlePiece(w, 4, 0, LEFT, FALSE);
		}
	}
}

static void
setFourthCorner(BevelWidget w)
{
	int fixedCorner = 3;
	int color0 = cornerColor(w, fixedCorner, 0);
	int color1 = cornerColor(w, fixedCorner, 2);
	int foundCorner = findOtherCorner(w, fixedCorner, color0, color1);
#ifdef DEBUG
	int targetCorner = 2;
	(void) printf("forthCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif
	switch (foundCorner) {
	case 0:	
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		break;
	case 4:	
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		break;
	case 5:
		movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		break;
	case 6:	
		movePuzzlePiece(w, 5, 1, TOP, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		break;
	}
	/* rotate "turnstile" if needed */
	if (color0 != w->bevel.cubeLoc[0][3].face) {
		if (color0 == w->bevel.cubeLoc[1][3].face) {
			movePuzzlePiece(w, 5, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 5, 1, TOP, FALSE);
			movePuzzlePiece(w, 5, 0, LEFT, FALSE);
			movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		} else {
			movePuzzlePiece(w, 5, 2, TOP, FALSE);
			movePuzzlePiece(w, 5, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 5, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 5, 1, LEFT, FALSE);
		}
	}
}

static void
turnOver(BevelWidget w)
{
	movePuzzlePiece(w, 0, 0, BOTTOM, TRUE);
	movePuzzlePiece(w, 0, 0, BOTTOM, TRUE);
	movePuzzlePiece(w, 0, 0, LEFT, TRUE);
}

static void
setFifthCorner(BevelWidget w)
{
	int color0 = w->bevel.cubeLoc[0][0].face;
	int color1 = w->bevel.cubeLoc[3][0].face;
	int color2 = w->bevel.cubeLoc[2][1].face;
	int foundCorner = findCorner(w, color0, color1, color2);
#ifdef DEBUG
	int targetCorner = 7;
	(void) printf("fifthCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif

	switch (foundCorner) {
	case 1:
		if (w->bevel.cubeLoc[1][1].face == color0) {
			movePuzzlePiece(w, 2, 2, TOP, FALSE);
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
		} else if (w->bevel.cubeLoc[1][1].face == color1) {
			movePuzzlePiece(w, 2, 2, TOP, FALSE);
			movePuzzlePiece(w, 0, 2, TOP, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
		} else /* if (w->bevel.cubeLoc[1][1].face == color2) */ {
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		}
		break;
	case 2:
		if (w->bevel.cubeLoc[5][2].face == color0) {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
		} else if (w->bevel.cubeLoc[5][2].face == color2) {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		} else /* if (w->bevel.cubeLoc[5][2].face == color1) */ {
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
		}
		break;
	case 3:	
		if (w->bevel.cubeLoc[2][3].face == color0) {
			movePuzzlePiece(w, 0, 2, LEFT, FALSE);
		} else if (w->bevel.cubeLoc[2][3].face == color1) {
			movePuzzlePiece(w, 0, 2, TOP, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
		} else /* if (w->bevel.cubeLoc[2][3].face == color2) */ {
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 2, LEFT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 2, LEFT, FALSE);
		}
		break;
	case 7:	
		if (w->bevel.cubeLoc[2][0].face == color0) {
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 1, LEFT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 2, TOP, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
		} else if (w->bevel.cubeLoc[2][0].face == color1) {
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
		}
		break;
	}
}

static void
setSixthCorner(BevelWidget w)
{
	int color0 = w->bevel.cubeLoc[2][1].face;
	int color1 = w->bevel.cubeLoc[4][0].face;
	int color2 = w->bevel.cubeLoc[1][2].face;
	int foundCorner = findCorner(w, color0, color1, color2);
#ifdef DEBUG
	int targetCorner = 1;
	(void) printf("sixthCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif

	switch (foundCorner) {
	case 1:
		if (w->bevel.cubeLoc[1][1].face == color0) {
			movePuzzlePiece(w, 2, 2, TOP, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 1, LEFT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
		} else if (w->bevel.cubeLoc[1][1].face == color1) {
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 0, LEFT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		}
		break;
	case 2:
		if (w->bevel.cubeLoc[0][3].face == color0) {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		} else if (w->bevel.cubeLoc[0][3].face == color1) {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 1, LEFT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
		} else /* if (w->bevel.cubeLoc[0][3].face == color2) */ {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 0, LEFT, FALSE);
			movePuzzlePiece(w, 2, 1, TOP, FALSE);
			movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		}
		break;
	case 3:
		if (w->bevel.cubeLoc[1][0].face == color0) {
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		} else if (w->bevel.cubeLoc[1][0].face == color1) {
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 1, LEFT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
		} else /* if (w->bevel.cubeLoc[1][0].face == color2) */ {
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		}
		break;
	}
}

static void
setLastCorners(BevelWidget w)
{
	int color0 = w->bevel.cubeLoc[0][0].face;
	int color1 = w->bevel.cubeLoc[1][2].face;
	int color2 = w->bevel.cubeLoc[5][1].face;
	int foundCorner = findCorner(w, color0, color1, color2);
#ifdef DEBUG
	int targetCorner = 2;
	(void) printf("seventhCorner %d\n", targetCorner);
	(void) printf("foundCorner %d\n", foundCorner);
#endif

	switch (foundCorner) {
	case 2:
		if (w->bevel.cubeLoc[1][3].face == color0) {
			movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 1, 1, LEFT, FALSE);
			movePuzzlePiece(w, 1, 2, TOP, FALSE);
			movePuzzlePiece(w, 1, 1, TOP, FALSE);
			movePuzzlePiece(w, 1, 0, LEFT, FALSE);
		} else if (w->bevel.cubeLoc[1][3].face == color2) {
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 1, LEFT, FALSE);
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
		}
		break;
	case 3:
		if (w->bevel.cubeLoc[1][0].face == color0) {
			movePuzzlePiece(w, 0, 2, TOP, FALSE);
		} else if (w->bevel.cubeLoc[1][0].face == color1) {
			movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 1, 1, LEFT, FALSE);
			movePuzzlePiece(w, 1, 2, TOP, FALSE);
			movePuzzlePiece(w, 1, 1, TOP, FALSE);
		} else /* if (w->bevel.cubeLoc[1][0].face == color2) */ {
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 1, LEFT, FALSE);
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		}
		break;
	}
}


/* 6 moves */
static void
swap4(BevelWidget w, int corner, int face)
{
	int i;
	Boolean which = NRAND(2);

	switch (corner) {
	case 0:
		switch (face) {
		case 1:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 1, 1, LEFT, FALSE);
				else
					movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
			}
			break;
		case 4:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 4, 1, LEFT, FALSE);
				else
					movePuzzlePiece(w, 4, 3, BOTTOM, FALSE);
			}
			break;
		case 5:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 5, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 5, 2, TOP, FALSE);
			}
			break;
		}
		break;
	case 1:
		switch (face) {
		case 1:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 1, 2, LEFT, FALSE);
			}
			break;
		case 2:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 2, 1, LEFT, FALSE);
				else
					movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			}
			break;
		case 4:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 4, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 4, 2, TOP, FALSE);
			}
			break;
		}
		break;
	case 2:
		switch (face) {
		case 0:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 0, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 0, 2, TOP, FALSE);
			}
			break;
		case 1:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 1, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 1, 2, TOP, FALSE);
			}
			break;
		case 5:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 5, 1, LEFT, FALSE);
				else
					movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
			}
			break;
		}
		break;
	case 3:
		switch (face) {
		case 0:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 0, 1, LEFT, FALSE);
				else
					movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			}
			break;
		case 1:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 1, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
			}
			break;
		case 2:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 2, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 2, 2, TOP, FALSE);
			}
			break;
		}
		break;
	case 4:
		switch (face) {
		case 3:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
			}
			break;
		case 4:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
			}
			break;
		case 5:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 5, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 5, 3, RIGHT, FALSE);
			}
			break;
		}
		break;
	case 5:
		switch (face) {
		case 2:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
			}
			break;
		case 3:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 3, 0, RIGHT, FALSE);
				else
					movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
			}
			break;
		case 4:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 4, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 4, 3, RIGHT, FALSE);
			}
			break;
		}
		break;
	case 6:
		switch (face) {
		case 0:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 0, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			}
			break;
		case 3:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 3, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 3, 3, RIGHT, FALSE);
			}
			break;
		case 5:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 5, 0, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 5, 2, RIGHT, FALSE);
			}
			break;
		}
		break;
	case 7:
		switch (face) {
		case 0:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 0, 1, BOTTOM, FALSE);
				else
					movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			}
			break;
		case 2:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 2, 1, TOP, FALSE);
				else
					movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
			}
			break;
		case 3:
			for (i = 0; i < 6; i++) {
				if ((i + which) % 2 == 0)
					movePuzzlePiece(w, 3, 0, LEFT, FALSE);
				else
					movePuzzlePiece(w, 3, 2, TOP, FALSE);
			}
			break;
		}
		break;
	}
}

/* 22 moves */
static void
swap3AroundCorner(BevelWidget w, int corner, int side, Boolean cw)
{
	int i;

	switch (corner) {
	case 0:
		switch (side) {
		case 1:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 0, LEFT, FALSE);
					movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 1, LEFT, FALSE);
					movePuzzlePiece(w, 1, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 2, TOP, FALSE);
				}	
			}
			break;
		case 4:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 2, TOP, FALSE);
					movePuzzlePiece(w, 4, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 1, LEFT, FALSE);
				}	
			}
			break;
		case 5:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 5, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 1, LEFT, FALSE);
					movePuzzlePiece(w, 5, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 1, LEFT, FALSE);
				}	
			}
			break;
		}
		break;
	case 1:
		switch (side) {
		case 1:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 0, LEFT, FALSE);
					movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 1, LEFT, FALSE);
					movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 2, TOP, FALSE);
				}	
			}
			break;
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 2, TOP, FALSE);
					movePuzzlePiece(w, 2, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
				}	
			}
			break;
		case 4:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 1, LEFT, FALSE);
				}	
			}
			break;
		}
		break;
	case 2:
		switch (side) {
		case 0:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 0, LEFT, FALSE);
					movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 2, TOP, FALSE);
					movePuzzlePiece(w, 5, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 2, TOP, FALSE);
				}	
			}
			break;
		case 1:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 0, LEFT, FALSE);
					movePuzzlePiece(w, 1, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 1, LEFT, FALSE);
					movePuzzlePiece(w, 1, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 2, TOP, FALSE);
				}	
			}
			break;
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 0, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 2, TOP, FALSE);
					movePuzzlePiece(w, 0, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 1, LEFT, FALSE);
				}	
			}
			break;
		}
		break;
	case 3:
		switch (side) {
		case 0:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 1, TOP, FALSE);
					movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 2, TOP, FALSE);
					movePuzzlePiece(w, 0, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 1:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 0, LEFT, FALSE);
					movePuzzlePiece(w, 1, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 1, LEFT, FALSE);
					movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 2, TOP, FALSE);
				}	
			}
			break;
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 2, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 1, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 2, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 1, LEFT, FALSE);
				}	
			}
			break;
		}
		break;
	case 4:
		switch (side) {
		case 3:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
				}	
			}
			break;
		case 4:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 1, TOP, FALSE);
					movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 5:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 5, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 5, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
				}	
			}
			break;
		}
		break;
	case 5:
		switch (side) {
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 1, TOP, FALSE);
					movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 1, LEFT, FALSE);
					movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 3:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 4, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 4, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 1, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
				}	
			}
			break;
		case 4:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 4, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 1, LEFT, FALSE);
				}	
			}
			break;
		}
		break;
	case 6:
		switch (side) {
		case 0:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 1, TOP, FALSE);
					movePuzzlePiece(w, 5, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 5, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 1, TOP, FALSE);
					movePuzzlePiece(w, 0, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 3:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 5, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 5, 0, BOTTOM, FALSE);
				}	
			}
			break;
		}
		break;
	case 7:
		switch (side) {
		case 0:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 1, TOP, FALSE);
					movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 0, LEFT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 2, TOP, FALSE);
					movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
				}	
			}
			break;
		case 2:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 3, 0, LEFT, FALSE);
					movePuzzlePiece(w, 2, 1, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
					movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 3, 2, TOP, FALSE);
				}	
			}
			break;
		case 3:
			if (cw) {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 0, LEFT, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 2, 1, TOP, FALSE);
				}	
			} else {
				for (i = 0; i < 8; i++) {
					movePuzzlePiece(w, 2, 3, RIGHT, FALSE);
					movePuzzlePiece(w, 3, 2, TOP, FALSE);
					if (i % 4 != 3)
						movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
				}	
			}
			break;
		}
		break;
	}
}

static void
setFace0Pos4(BevelWidget w, int color)
{
	int face = 0;
	int pos = 4;
	Boolean which = NRAND(2);

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[3][7].face == color) {
		swap4(w, 6, 3);
	} else if (w->bevel.cubeLoc[5][6].face == color) {
		swap4(w, 6, 5);
	} else if (w->bevel.cubeLoc[1][6].face == color) {
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		swap4(w, 2, 1);
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
	} else if (w->bevel.cubeLoc[2][5].face == color) {
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
		swap4(w, 7, 2);
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[4][7].face == color) {
		if (which) {
			movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
			swap4(w, 5, 4);
			movePuzzlePiece(w, 3, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
		} else {
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
			movePuzzlePiece(w, 5, 2, TOP, FALSE);
			swap4(w, 0, 4);
			movePuzzlePiece(w, 5, 2, TOP, FALSE);
			movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		}
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}

#if 0
static void
setFace0Pos5(BevelWidget w, int color)
{
	int face = 0;
	int pos = 5;
	Boolean which = NRAND(2);

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[2][7].face == color) {
		swap4(w, 7, 2);
	} else if (w->bevel.cubeLoc[3][4].face == color) {
		swap4(w, 7, 3);
	} else if (w->bevel.cubeLoc[1][5].face == color) {
		movePuzzlePiece(w, 0, 1, LEFT, FALSE);
		swap4(w, 3, 1);
		movePuzzlePiece(w, 0, 1, LEFT, FALSE);
	} else if (w->bevel.cubeLoc[5][4].face == color) {
		movePuzzlePiece(w, 0, 1, TOP, FALSE);
		swap4(w, 6, 5);
		movePuzzlePiece(w, 0, 1, TOP, FALSE);
	} else if (w->bevel.cubeLoc[4][6].face == color) {
		if (which) {
			movePuzzlePiece(w, 0, 1, LEFT, FALSE);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			swap4(w, 1, 4);
			movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 1, LEFT, FALSE);
		} else {
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
			movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
			swap4(w, 4, 4);
			movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 1, TOP, FALSE);
		}
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}


static void
setFace0Pos6(BevelWidget w, int color)
{
	int face = 0;
	int pos = 6;
	Boolean which = NRAND(2);

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[1][7].face == color) {
		swap4(w, 3, 1);
	} else if (w->bevel.cubeLoc[2][4].face == color) {
		swap4(w, 3, 2);
	} else if (w->bevel.cubeLoc[3][6].face == color) {
		movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
		swap4(w, 7, 3);
		movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
	} else if (w->bevel.cubeLoc[5][7].face == color) {
		movePuzzlePiece(w, 0, 2, TOP, FALSE);
		swap4(w, 2, 5);
		movePuzzlePiece(w, 0, 2, TOP, FALSE);
	} else if (w->bevel.cubeLoc[4][5].face == color) {
		if (which) {
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			swap4(w, 5, 4);
			movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 2, RIGHT, FALSE);
		} else {
			movePuzzlePiece(w, 0, 2, TOP, FALSE);
			movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
			swap4(w, 0, 4);
			movePuzzlePiece(w, 1, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 2, TOP, FALSE);
		}
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}

static void
setFace0Pos7(BevelWidget w, int color)
{
	int face = 0;
	int pos = 7;
	Boolean which = NRAND(2);

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[1][4].face == color) {
		swap4(w, 2, 1);
	} else if (w->bevel.cubeLoc[5][5].face == color) {
		swap4(w, 2, 5);
	} else if (w->bevel.cubeLoc[2][6].face == color) {
		movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
		swap4(w, 3, 2);
		movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[3][5].face == color) {
		movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
		swap4(w, 6, 3);
		movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
	} else if (w->bevel.cubeLoc[4][4].face == color) {
		if (which) {
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
			movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
			swap4(w, 1, 4);
			movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
			movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
		} else {
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
			movePuzzlePiece(w, 5, 1, TOP, FALSE);
			swap4(w, 4, 4);
			movePuzzlePiece(w, 5, 1, TOP, FALSE);
			movePuzzlePiece(w, 0, 3, RIGHT, FALSE);
		}
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}

static void
setFace2Pos4(BevelWidget w, int color)
{
	int face = 2;
	int pos = 4;

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[3][6].face == color) {
		swap4(w, 5, 2);
	} else if (w->bevel.cubeLoc[4][5].face == color) {
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
		swap4(w, 5, 4);
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[5][7].face == color) {
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
		swap4(w, 4, 5);
		movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[1][7].face == color) {
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 4, 1, LEFT, FALSE);
		swap4(w, 0, 1);
		movePuzzlePiece(w, 4, 1, LEFT, FALSE);
		movePuzzlePiece(w, 3, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}
#endif

static void
setFace2Pos7(BevelWidget w, int color)
{
	int face = 2;
	int pos = 7;

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[1][5].face == color) {
		swap4(w, 1, 2);
	} else if (w->bevel.cubeLoc[4][6].face == color) {
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		swap4(w, 1, 4);
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[5][4].face == color) {
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		movePuzzlePiece(w, 1, 1, LEFT, FALSE);
		swap4(w, 4, 4);
		movePuzzlePiece(w, 1, 1, LEFT, FALSE);
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[3][4].face == color) {
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
		movePuzzlePiece(w, 1, 1, LEFT, FALSE);
		movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
		swap4(w, 4, 3);
		movePuzzlePiece(w, 4, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 1, 1, LEFT, FALSE);
		movePuzzlePiece(w, 2, 3, BOTTOM, FALSE);
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}

static void
setFace1Pos4(BevelWidget w, int color)
{
	int face = 1;
	int pos = 4;

	if (w->bevel.cubeLoc[face][pos].face == color) {
		return;
	} else if (w->bevel.cubeLoc[2][6].face == color) {
		swap4(w, 1, 1);
	} else if (w->bevel.cubeLoc[4][4].face == color) {
		/* collides with its opposite */
		/*movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
		swap4(w, 1, 4);
		movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);*/
		swap3AroundCorner(w, 1, 4, TRUE);
	} else if (w->bevel.cubeLoc[3][5].face == color) {
		movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		swap4(w, 4, 4);
		movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
	} else if (w->bevel.cubeLoc[5][5].face == color) {
		movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
		swap4(w, 4, 5);
		movePuzzlePiece(w, 4, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 2, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 1, 0, BOTTOM, FALSE);
	} else {
		(void) printf("Fix face %d pos %d\n", face, pos);
	}
}

static void
setFace0(BevelWidget w)
{
	int face = 0;
	int pos = 0;
	Boolean which = NRAND(2);
	int i;
	int color = w->bevel.cubeLoc[face][pos].face;

#ifdef DEBUG
	(void) printf("face %d: zeroethEdge %d\n", face, color);
#endif
	setFace0Pos4(w, color);
	for (i = 0; i < MAX_ORIENT - 1; i++) {
		movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
		color = w->bevel.cubeLoc[face][pos].face;
		setFace0Pos4(w, color);
	}
}

static void
setFaceTop(BevelWidget w)
{
	int face = 2;
	int pos = 0;
	Boolean which = NRAND(2);
	int i;
	int color = w->bevel.cubeLoc[face][pos].face;

#ifdef DEBUG
	(void) printf("face %d: zeroethEdge %d\n", face, color);
#endif
	setFace2Pos7(w, color);
	for (i = 0; i < MAX_ORIENT - 1; i++) {
		movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
		color = w->bevel.cubeLoc[face][pos].face;
		setFace2Pos7(w, color);
	}
	face = 1;
	which = NRAND(2);
	color = w->bevel.cubeLoc[face][pos].face;
	setFace1Pos4(w, color);
	for (i = 0; i < MAX_ORIENT - 1; i++) {
		movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
		color = w->bevel.cubeLoc[face][pos].face;
		setFace1Pos4(w, color);
	}
	movePuzzlePiece(w, 0, 0, BOTTOM, TRUE);
	movePuzzlePiece(w, 0, 0, BOTTOM, TRUE);
}

static void
fixATriple(BevelWidget w)
{
	int corner = 3;
	int i, count = 0, pos = 0;
	int faceColor[3];
	int facetColor[3];

	for (i = 0; i < 3; i++) {
		switch (i) {
		case 0:
			pos = 6;
			break;
		case 1:
			pos = 4;
			break;
		case 2:
			pos = 7;
			break;
		}
		facetColor[i] = w->bevel.cubeLoc[bevelCorner[corner][i]][pos].face;
		faceColor[i] = w->bevel.cubeLoc[bevelCorner[corner][i]][0].face;
		if (facetColor[i] != faceColor[i])
			count++;
	}
	if (count == 3) {
		if (facetColor[2] == faceColor[1]) {
			swap3AroundCorner(w, 3, 1, False);
		} else /* if (facetColor[1] == faceColor[2]) */ {
			swap3AroundCorner(w, 3, 2, True);
		}
	}
}

static void
fixTriples(BevelWidget w)
{
	int i;
	Boolean which = NRAND(2);

	fixATriple(w);
	for (i = 0; i < MAX_ORIENT - 1; i++) {
		movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
		fixATriple(w);
	}
}

static Boolean
checkOddSplitDouble(BevelWidget w)
{
	int count = 0;

	if (w->bevel.cubeLoc[0][5].face != w->bevel.cubeLoc[0][0].face)
		count++;
	if (w->bevel.cubeLoc[0][7].face != w->bevel.cubeLoc[0][0].face)
		count++;
	if (w->bevel.cubeLoc[1][4].face != w->bevel.cubeLoc[1][0].face)
		count++;
	if (w->bevel.cubeLoc[2][7].face != w->bevel.cubeLoc[2][0].face)
		count++;
	if (w->bevel.cubeLoc[3][4].face != w->bevel.cubeLoc[3][0].face)
		count++;
	if (w->bevel.cubeLoc[5][5].face != w->bevel.cubeLoc[5][0].face)
		count++;
	if (count == 4)
		return True;
	return False;
}

static Boolean
checkEvenSplitDouble(BevelWidget w)
{
	int count = 0;

	if (w->bevel.cubeLoc[0][4].face != w->bevel.cubeLoc[0][0].face)
		count++;
	if (w->bevel.cubeLoc[0][6].face != w->bevel.cubeLoc[0][0].face)
		count++;
	if (w->bevel.cubeLoc[1][7].face != w->bevel.cubeLoc[1][0].face)
		count++;
	if (w->bevel.cubeLoc[2][4].face != w->bevel.cubeLoc[2][0].face)
		count++;
	if (w->bevel.cubeLoc[3][7].face != w->bevel.cubeLoc[3][0].face)
		count++;
	if (w->bevel.cubeLoc[5][6].face != w->bevel.cubeLoc[5][0].face)
		count++;
	if (count == 4)
		return True;
	return False;
}

static Boolean
checkConnectedDouble(BevelWidget w)
{
	int i, count;
	Boolean which = NRAND(2);

	for (i = 0; i < MAX_ORIENT; i++) {
		count = 0;
		if (w->bevel.cubeLoc[0][5].face != w->bevel.cubeLoc[0][0].face)
			count++;
		if (w->bevel.cubeLoc[0][6].face != w->bevel.cubeLoc[0][0].face)
			count++;
		if (w->bevel.cubeLoc[1][7].face != w->bevel.cubeLoc[1][0].face)
			count++;
		if (w->bevel.cubeLoc[2][4].face != w->bevel.cubeLoc[2][0].face)
			count++;
		if (w->bevel.cubeLoc[2][7].face != w->bevel.cubeLoc[2][0].face)
			count++;
		if (w->bevel.cubeLoc[3][4].face != w->bevel.cubeLoc[3][0].face)
			count++;
		if (count == 4)
			return True; /* can only be one left */
		movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
	}
	return False;
}

static void
fixOddSplitDouble(BevelWidget w)
{
	Boolean doubleRight = False, right = False;
	Boolean doubleLeft = False, left = False;

	if (w->bevel.cubeLoc[2][7].face == w->bevel.cubeLoc[2][1].face) {
		movePuzzlePiece(w, 0, 1, LEFT, FALSE);
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
		doubleRight = True;
	} else if (w->bevel.cubeLoc[0][5].face == w->bevel.cubeLoc[0][1].face) {
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
		right = True;
	}
	if (w->bevel.cubeLoc[1][4].face == w->bevel.cubeLoc[1][2].face) {
		movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		doubleLeft = True;
	} else if (w->bevel.cubeLoc[0][7].face == w->bevel.cubeLoc[0][3].face) {
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		left = True;
	}
	swap4(w, 3, 0);
	if (doubleLeft) {
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
		movePuzzlePiece(w, 0, 3, BOTTOM, FALSE);
	} else if (left) {
		movePuzzlePiece(w, 0, 0, LEFT, FALSE);
	}
	if (doubleRight) {
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 0, 1, LEFT, FALSE);
	} else if (right) {
		movePuzzlePiece(w, 0, 0, BOTTOM, FALSE);
	}
}

static void
fixConnectedDouble(BevelWidget w)
{
	Boolean left = False, lowerLeft = False;
	Boolean right = False, lowerRight = False;

	if (w->bevel.cubeLoc[0][6].face == w->bevel.cubeLoc[0][3].face) {
		movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
		left = True;
	}
	if (left || w->bevel.cubeLoc[1][7].face == w->bevel.cubeLoc[1][2].face) {
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 3, 1, LEFT, FALSE);
		movePuzzlePiece(w, 4, 1, LEFT, FALSE);
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		lowerLeft = True;
	}
	if (w->bevel.cubeLoc[2][7].face == w->bevel.cubeLoc[2][2].face) {
		movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 1, 1, TOP, FALSE);
		right = True;
	}
	if (right || w->bevel.cubeLoc[3][4].face == w->bevel.cubeLoc[3][0].face) {
		movePuzzlePiece(w, 0, 1, TOP, FALSE);
		movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
		lowerRight = True;
	} else {
		movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
	}
	swap4(w, 3, 1);
	if (lowerRight) {
		movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
		movePuzzlePiece(w, 0, 1, TOP, FALSE);
		if (right) {
			movePuzzlePiece(w, 1, 1, TOP, FALSE);
			movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
			movePuzzlePiece(w, 5, 0, LEFT, FALSE);
			movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
		}
	} else {
		movePuzzlePiece(w, 1, 2, RIGHT, FALSE);
		movePuzzlePiece(w, 5, 0, LEFT, FALSE);
		movePuzzlePiece(w, 3, 0, BOTTOM, FALSE);
	}
	if (lowerLeft) {
		movePuzzlePiece(w, 5, 3, BOTTOM, FALSE);
		movePuzzlePiece(w, 4, 1, LEFT, FALSE);
		movePuzzlePiece(w, 3, 1, LEFT, FALSE);
		movePuzzlePiece(w, 2, 0, BOTTOM, FALSE);
		if (left) {
			movePuzzlePiece(w, 1, 3, RIGHT, FALSE);
		}
	}
}

/* This procedure coordinates the solution process. */
void
solveSomePieces(BevelWidget w)
{
	setPuzzle(w, ACTION_RESET);
	if (solvingFlag)
		return;
#ifdef JMP
	if (!setjmp(solve_env))
#endif
	{
		solvingFlag = True;
		setSecondCorner(w);
		setThirdCorner(w);
		setFourthCorner(w);
		turnOver(w);
		setFifthCorner(w);
		setSixthCorner(w);
		setLastCorners(w);
		setFace0(w);
		setFaceTop(w);
		fixTriples(w);
		if (checkOddSplitDouble(w)) {
			fixOddSplitDouble(w);
		}
		if (checkEvenSplitDouble(w)) {
			Boolean which = NRAND(2);
			movePuzzlePiece(w, 1, 0, ((which) ? RIGHT : LEFT), TRUE);
			fixOddSplitDouble(w);
		}
		if (checkConnectedDouble(w)) {
			fixConnectedDouble(w);
		}
	}
#ifdef JMP
	abortSolvingFlag = False;
#endif
	solvingFlag = False;
	w->bevel.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_CHEAT);
	setPuzzle(w, ACTION_COMPUTED);
}
