/*
 * @(#)SkewbS.c
 *
 * Taken from the Mickey's Challenge by Christoph Bandelow
 * Break ability taken from the X puzzle by Don Bennett, HP Labs
 *
 * Copyright 2009 - 2010  David A. Bagley, bagleyd@tux.org
 *
 * 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 Skewb */

#include "rngs.h"
#define JMP
#ifdef JMP
#include <setjmp.h> /* longjmp ... interrupt */
#endif
#include "SkewbP.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(SkewbWidget 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(SkewbWidget w)
{
	XEvent event;

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

static void
movePuzzlePiece(SkewbWidget 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);
}

static int
findSquare(SkewbWidget w, int color)
{
	int i;

	for (i = 0; i < MAX_FACES; i++) {
		if (w->skewb.cubeLoc[i][MAX_ORIENT].face == color)
			return i;
	}
	return MAX_FACES;
}

static Boolean fixedCorner(int corner)
{
	return ((((corner & 4) / 4) + ((corner & 2) / 2) +
		(corner & 1)) % 2 == 0);
}

#define MAX_CORNERS 8
static int skewbCorner[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 skewbCornerOrient[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}
};

/* Corner layout, bits correspond to position
   2 6
 2 3 7 6
 0 1 5 4
   0 4
   2 6
Bandelow uses a different notation, advantage with his notation is that
odd and even corners do not exchange.  With my notation, 2 bits and only
2 bits are different to exchange.
 */

static int cornerColor(SkewbWidget w, int corner, int n)
{
	return w->skewb.cubeLoc[skewbCorner[corner][n]][skewbCornerOrient[corner][n]].face;
}

static int
findCorner(SkewbWidget w, int corner)
{
	/* only need to check 4 corners */
	/* -0-, _3_, 5, 6 or 1, 2, -4-, _7_ */
	int i, j, t, count;
	int c[3];

	c[0] = skewbCorner[corner][0];
	c[1] = skewbCorner[corner][1];
	c[2] = skewbCorner[corner][2];
	for (i = 0; i < MAX_CORNERS; i++) {
		/* fixed and free corners can not interchange */
		if ((fixedCorner(corner) && (fixedCorner(i))) ||
				(!fixedCorner(corner) && (!fixedCorner(i)))) {
			count = 0;
			for (j = 0; j < 3; j++) {
				t = cornerColor(w, i, j);
				if (c[0] == t || c[1] == t || c[2] == t)
					count++;
			}
			if (count == 3) /* Got all 3 */
				return i;
		}	
	}
	return MAX_CORNERS;
}

static void
setFirstSquare(SkewbWidget w)
{
	int i = findSquare(w, 0); /* Red */

#ifdef DEBUG
	(void) printf("firstSquare %d\n", i);
#endif
	switch (i) {
	case 0:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[0][MAX_ORIENT].rotation == 2) {
			if (NRAND(2) == 0) {
				movePuzzlePiece(w, 0, 3, BL, TRUE);
				movePuzzlePiece(w, 0, 0, TL, TRUE);
			} else {
				movePuzzlePiece(w, 0, 0, BR, TRUE);
				movePuzzlePiece(w, 0, 3, TR, TRUE);
			}	
		}	
		break;
	case 1:
		if (w->skewb.cubeLoc[1][MAX_ORIENT].rotation == 0) {
			movePuzzlePiece(w, 0, 1, TR, TRUE);
		} else {
			movePuzzlePiece(w, 0, 0, BR, TRUE);
		}
		break;
	case 2:
		if (w->skewb.cubeLoc[2][MAX_ORIENT].rotation == 1) {
			movePuzzlePiece(w, 0, 0, TL, TRUE);
		} else {
			movePuzzlePiece(w, 0, 3, TR, TRUE);
		}
		break;
	case 3:
		if (w->skewb.cubeLoc[3][MAX_ORIENT].rotation == 0) {
			movePuzzlePiece(w, 0, 2, TL, TRUE);
		} else {
			movePuzzlePiece(w, 0, 3, BL, TRUE);
		}
		break;
	case 4:
		if (w->skewb.cubeLoc[4][MAX_ORIENT].rotation == 0) {
			if (NRAND(2) == 0) {
				movePuzzlePiece(w, 2, 3, BL, TRUE);
				movePuzzlePiece(w, 0, 3, BL, TRUE);
			} else {
				movePuzzlePiece(w, 2, 0, BR, TRUE);
				movePuzzlePiece(w, 0, 0, BR, TRUE);
			}
		} else {
			if (NRAND(2) == 0) {
				movePuzzlePiece(w, 2, 3, TR, TRUE);
				movePuzzlePiece(w, 0, 3, TR, TRUE);
			} else {
				movePuzzlePiece(w, 2, 0, TL, TRUE);
				movePuzzlePiece(w, 0, 0, TL, TRUE);
			}
		}
		break;
	case 5:
		if ( w->skewb.cubeLoc[5][MAX_ORIENT].rotation == 1) {
			movePuzzlePiece(w, 0, 2, BR, TRUE);
		} else {
			movePuzzlePiece(w, 0, 1, BL, TRUE);
		}
		break;
	}
	if (w->skewb.cubeLoc[0][MAX_ORIENT].rotation == 3) {
		movePuzzlePiece(w, 2, 3, LEFT, 2);
	} else if (w->skewb.cubeLoc[0][MAX_ORIENT].rotation == 1) {
		movePuzzlePiece(w, 2, 3, RIGHT, 2);
	}
}

static void
setSecondSquare(SkewbWidget w)
{
	int i = findSquare(w, 2); /* White */

#ifdef DEBUG
	(void) printf("secondSquare %d\n", i);
#endif
	switch (i) {
	case 1:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[1][MAX_ORIENT].rotation == 1) {
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
		} else {
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		}
		return;
	case 2:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[2][MAX_ORIENT].rotation != 0) {
			if (NRAND(2) == 0) {
				movePuzzlePiece(w, 0, 2, BR, FALSE);
				movePuzzlePiece(w, 0, 1, TR, FALSE);
			} else {
				movePuzzlePiece(w, 0, 1, BL, FALSE);
				movePuzzlePiece(w, 0, 2, TL, FALSE);
			}
		}
		return;
	case 3:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[3][MAX_ORIENT].rotation != 1) {
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		} else {
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		}
		return;
	case 4:
		if (w->skewb.cubeLoc[4][MAX_ORIENT].rotation == 1)
			movePuzzlePiece(w, 0, 2, TL, FALSE);
		else
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		return;
	case 5:
		if (NRAND(2) == 0)
			movePuzzlePiece(w, 0, 0, TL, FALSE);
		else
			movePuzzlePiece(w, 0, 3, TR, FALSE);
		if (w->skewb.cubeLoc[4][MAX_ORIENT].rotation == 1)
			movePuzzlePiece(w, 0, 2, TL, FALSE);
		else
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		return;
	case 0:
		(void) printf("Wrong face %d\n", i);
		return;
	}
}

static void
setFirstCorner(SkewbWidget w)
{
	/* 0, 3, 5, 6 */
	int i = findCorner(w, 3); /* Red, White, Blue */

#ifdef DEBUG
	(void) printf("firstCorner %d\n", i);
#endif
	/* check if correctly placed already */
	if (i == 3) {
		if (w->skewb.cubeLoc[1][0].face == 0) {
			/* Diagram 4, turns 3 CW */
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		} else if (w->skewb.cubeLoc[2][3].face == 0) {
			/* Reverse Diagram 4, turns 3 CCW */
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		/* } else if (w->skewb.cubeLoc[0][2].face == 0) { */
		}
		return;
	}
	if (i != 0) {
		/* move to 0 if not already */
		/*if (i == 3) {
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		} else*/ if (i == 5) {
			movePuzzlePiece(w, 0, 0, BR, FALSE);
		} else if (i == 6) {
			movePuzzlePiece(w, 0, 0, TL, FALSE);
		}
	}
	/* rotate "turnstile" if needed */
	if (w->skewb.cubeLoc[1][2].face == 1) {
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 0, 3, BL, FALSE);
		} else {
			movePuzzlePiece(w, 0, 3, TR, FALSE);
		}
	}
	if (w->skewb.cubeLoc[1][2].face == 0) {
		/* Diagram 3b */
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		return;
	} else {
		/* Diagram 3a */
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
	}
}

static void
setSecondCorner(SkewbWidget w)
{
	/* 1, 2, 4, 7 */
	int i = findCorner(w, 7); /* Red, Green, White */

#ifdef DEBUG
	(void) printf("secondCorner %d\n", i);
#endif
	/* check if correctly placed already */
	if (i == 7) {
		if (w->skewb.cubeLoc[3][3].face == 0) {
			/* Mirror Diagram 4, turns 3 CCW */
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		} else if (w->skewb.cubeLoc[2][0].face == 0) {
			/* Mirror Reverse Diagram 4, turns 3 CW */
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		/* } else if (w->skewb.cubeLoc[0][1].face == 0) { */
		}
		return;
	}
	if (i != 4) {
		/* move to 4 if not already */
		/*if (i == 7) {
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		} else*/ if (i == 1) {
			movePuzzlePiece(w, 0, 3, BL, FALSE);
		} else if (i == 2) {
			movePuzzlePiece(w, 0, 3, TR, FALSE);
		}
	}
	/* rotate "turnstile" if needed */
	if (w->skewb.cubeLoc[3][1].face == 3) {
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 0, 0, BR, FALSE);
		} else {
			movePuzzlePiece(w, 0, 0, TL, FALSE);
		}
	}
	if (w->skewb.cubeLoc[3][1].face == 0) {
		/* Mirror Diagram 3b */
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 3, BL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
	} else { /* Mirror Diagram 3a */
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
	}
}

static void
otherSide(SkewbWidget w)
{
	if (NRAND(2) == 0) {
		movePuzzlePiece(w, 0, 2, BR, TRUE);
		movePuzzlePiece(w, 0, 0, BR, TRUE);
	} else {
		movePuzzlePiece(w, 0, 1, BL, TRUE);
		movePuzzlePiece(w, 0, 3, BL, TRUE);
	}
}

static void
setThirdSquare(SkewbWidget w)
{
	int i = findSquare(w, 4); /* Pink */

#ifdef DEBUG
	(void) printf("thirdSquare %d, ", i);
	if (i == MAX_FACES)
		(void) printf("i == MAX_FACES\n");
	else
		(void) printf("%d %d\n",
			w->skewb.cubeLoc[i][MAX_ORIENT].face,
			w->skewb.cubeLoc[i][MAX_ORIENT].rotation);
#endif
	switch (i) {
	case 0:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[0][MAX_ORIENT].rotation != 0) {
			if (NRAND(2) == 0) {
				movePuzzlePiece(w, 3, 3, BL, FALSE);
				movePuzzlePiece(w, 1, 0, TL, FALSE);
			} else {
				movePuzzlePiece(w, 1, 0, BR, FALSE);
				movePuzzlePiece(w, 3, 3, TR, FALSE);
			}
		}
		return;
	case 1:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[1][MAX_ORIENT].rotation == 0) {
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
		} else {
			movePuzzlePiece(w, 3, 3, BL, FALSE);
		}
		return;
	case 2:
		if (w->skewb.cubeLoc[2][MAX_ORIENT].rotation == 1) {
			movePuzzlePiece(w, 3, 3, TR, FALSE);
		} else {
			movePuzzlePiece(w, 1, 0, TL, FALSE);
		}
		return;
	case 3:
		if (w->skewb.orient &&
				w->skewb.cubeLoc[3][MAX_ORIENT].rotation == 0) {
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
		} else {
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		}
		return;
	case 4:
	case 5:
		(void) printf("Wrong face %d\n", i);
		return;
	}
}

static void
placeThirdCorner(SkewbWidget w)
{
	/* 0, 3, 5, 6 */
	int i = findCorner(w, 0); /* Pink, Yellow, Blue */

#ifdef DEBUG
	(void) printf("thirdCorner %d\n", i);
#endif
	/* check if correctly placed already */
	if (i == 3) {
		return;
	}
	/* move to 3 if not already */
	if (i == 5) { /* Diagram 6b, 7b */
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
		} else {
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
		}
	} else if (i == 6) { /* Diagram 6a, 7a */
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
		} else {
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
		}
	} else {
		(void) printf("Wrong corner %d\n", i);
		return;
	}
}

static void
placeFourthCorner(SkewbWidget w)
{
	/* 1, 2, 4, 7 */
	int i = findCorner(w, 1); /* Pink, Green, Yellow */

#ifdef DEBUG
	(void) printf("forthCorner %d\n", i);
#endif
	/* check if correctly placed already */
	if (i == 2) {
		return;
	}
	if (i == 1) { /* Diagram 6c, 7c */
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		} else {
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
		}
	} else if (i == 7) { /* Diagram 6d, 7d */
		if (NRAND(2) == 0) {
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		} else {
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
		}
	} else {
		(void) printf("Wrong corner %d\n", i);
		return;
	}
}

/* This does not have to be solved for Mickey's challenge,
   but needed on the skewb. */
/* Its more efficient to check more things and use all the moves
   available from "Mickey's Challenge" book, but going to cut down
   for now. */
static void
setFifthSixthCorner(SkewbWidget w)
{
	/* 3, 7 */
	int i = w->skewb.cubeLoc[0][3].face;
	int j = w->skewb.cubeLoc[0][0].face;
	int ri, rj;

	if (i == 4)
		ri = 0;
	else if (i == 2)
		ri = -1;
	else if (i == 1)
		ri = 1;
	else {
		(void) printf("Wrong corner 3\n");
		return;
	}
	if (j == 4)
		rj = 0;
	else if (j == 2)
		rj = 1;
	else if (j == 3)
		rj = -1;
	else {
		(void) printf("Wrong corner 7\n");
		return;
	}
#ifdef DEBUG
	(void) printf("fifthSixthCorner face 4");
	(void) printf(": 3 %d", i);
	(void) printf(", 7 %d", j);
	(void) printf(",  %d %d\n", ri, rj);
#endif
	if (ri == 0 && rj == 0)
		return;
	if (ri == 1 && rj == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister upsidedown, TT2 */
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		} else {
			/* Diagram 11, Triangle twister upsidedown, TT2 */
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
		}
	} else if (ri == -1 && rj == -1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Reverse Triangle twister upsidedown, TT2 */
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
		} else {
			/* Diagram 11, Reverse Mirror Triangle twister, TT2 */
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
		}
	} else if (ri == -1 && rj == 0) {
		if (NRAND(2) == 0) {
			/* Diagram 8, Reverse Mirror Triangle twister, TT */
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
		} else {
			/* Diagram 10, Reverse Mirror Triangle twister, TT */
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		}
	} else if (rj == -1 && ri == 0) {
		if (NRAND(2) == 0) {
			/* Diagram 8, Triangle twister, TT */
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
		} else {
			/* Diagram 10, Triangle twister, TT */
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
		}
	} else if (ri == 1 && rj == 0) {
		if (NRAND(2) == 0) {
			/* Diagram 8, Mirror Triangle twister, TT */
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
		} else {
			/* Diagram 10, Mirror Triangle twister, TT */
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
		}
	} else if (rj == 1 && ri == 0) {
		if (NRAND(2) == 0) {
			/* Diagram 8, Reverse Triangle twister, TT */
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		} else {
			/* Diagram 10, Reverse Triangle twister, TT */
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		}
	} else if (rj == -1 && ri == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister 90 degrees, TT2 */
			movePuzzlePiece(w, 5, 2, BR, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 5, 2, BR, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 5, 2, TL, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 5, 2, TL, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
		} else {
			/* Diagram 11, Triangle twister 90 degrees, TT2 */
			movePuzzlePiece(w, 5, 1, BL, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 5, 1, BL, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 5, 1, TR, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 5, 1, TR, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
		}
	} else if (rj == 1 && ri == -1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister 270 degrees, TT2 */
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 5, 2, BR, FALSE);
			movePuzzlePiece(w, 2, 3, TR, FALSE);
			movePuzzlePiece(w, 5, 2, BR, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 5, 2, TL, FALSE);
			movePuzzlePiece(w, 2, 3, BL, FALSE);
			movePuzzlePiece(w, 5, 2, TL, FALSE);
		} else {
			/* Diagram 11, Triangle twister 270 degrees, TT2 */
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 5, 1, BL, FALSE);
			movePuzzlePiece(w, 2, 0, TL, FALSE);
			movePuzzlePiece(w, 5, 1, BL, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 5, 1, TR, FALSE);
			movePuzzlePiece(w, 2, 0, BR, FALSE);
			movePuzzlePiece(w, 5, 1, TR, FALSE);
		}
	}	
}

static void
placeRemainingSquares(SkewbWidget w)
{
	int i = findSquare(w, 5); /* 1, 2, 3 */
	int j;

#ifdef DEBUG
	(void) printf("remainingSquares %d, ", i);
	if (i == MAX_FACES)
		(void) printf("i == MAX_FACES\n");
	else
		(void) printf("%d %d\n",
			w->skewb.cubeLoc[i][MAX_ORIENT].face,
			w->skewb.cubeLoc[i][MAX_ORIENT].rotation);
#endif
	switch (i) {
	case 1:
		/* Diagram 12, Square Switcher, SS */
		for (j = 0; j < 2; j++) {
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
		}
		return;
	case 2:
		return;
	case 3:
		/* Diagram 12, Reverse Square Switcher, SS */
		for (j = 0; j < 2; j++) {
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		}
		return;
	case 0:
	case 4:
	case 5:
		(void) printf("Wrong face %d\n", i);
		return;
	}
}

static void
setRemainingCorners(SkewbWidget w)
{
	/* 1, 5, 0, 4 */
	int f[4], r[4];

	f[0] = w->skewb.cubeLoc[2][0].face;
	f[1] = w->skewb.cubeLoc[2][1].face;
	f[2] = w->skewb.cubeLoc[2][2].face;
	f[3] = w->skewb.cubeLoc[2][3].face;
#ifdef DEBUG
	(void) printf("remainingCorners face 5");
	printf(": 5 %d", f[0]);
	printf(", 4 %d", f[1]);
	printf(", 0 %d", f[2]);
	printf(", 1 %d\n", f[3]);
#endif
	if (f[0] == 5)
		r[0] = 0;
	else if (f[0] == 4)
		r[0] = 1;
	else if (f[0] == 3)
		r[0] = -1;
	else {
		(void) printf("Wrong corner 5\n");
		return;
	}
	if (f[1] == 5)
		r[1] = 0;
	else if (f[1] == 0)
		r[1] = -1;
	else if (f[1] == 3)
		r[1] = 1;
	else {
		(void) printf("Wrong corner 4\n");
		return;
	}
	if (f[2] == 5)
		r[2] = 0;
	else if (f[2] == 0)
		r[2] = 1;
	else if (f[2] == 1)
		r[2] = -1;
	else {
		(void) printf("Wrong corner 0\n");
		return;
	}
	if (f[3] == 5)
		r[3] = 0;
	else if (f[3] == 4)
		r[3] = -1;
	else if (f[3] == 1)
		r[3] = 1;
	else {
		(void) printf("Wrong corner 1\n");
		return;
	}
#ifdef DEBUG
	(void) printf("remainingCorners %d %d %d %d  %d %d %d %d\n",
		f[0], f[1], f[2], f[3], r[0], r[1], r[2], r[3]);
#endif
	if (r[0] == 0 && r[1] == 0 && r[2] == 0)
		return;
	if (r[0] == 0 && r[2] == 0) {
		if (r[1] == 1) {
			/* Diagram 13, 90 degrees, mirror */
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
		} else {
			/* Diagram 13, 90 degrees, mirror upsidedown */
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		}
		return;
	}
	if (r[1] == 0 && r[3] == 0) {
		if (r[0] == 1) {
			/* Diagram 13, 90 degrees */
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		} else {
			/* Diagram 13, 90 degrees, upsidedown */
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
		}
		return;
	}
	if (r[0] == 1 && r[1] == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister TT2 90 degrees */
			movePuzzlePiece(w, 4, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 4, 0, TL, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 4, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 4, 0, BR, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
		} else {
			/* Diagram 11, Triangle twister TT2 90 degrees */
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 3, 2, BR, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 3, 2, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 3, 2, TL, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 3, 2, TL, FALSE);
		}
		return;
	}
	if (r[1] == 1 && r[2] == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister TT2, 180 degrees */
			movePuzzlePiece(w, 1, 1, TR, FALSE);
			movePuzzlePiece(w, 3, 2, TL, FALSE);
			movePuzzlePiece(w, 1, 1, TR, FALSE);
			movePuzzlePiece(w, 3, 2, TL, FALSE);
			movePuzzlePiece(w, 1, 1, BL, FALSE);
			movePuzzlePiece(w, 3, 2, BR, FALSE);
			movePuzzlePiece(w, 1, 1, BL, FALSE);
			movePuzzlePiece(w, 3, 2, BR, FALSE);
		} else {
			/* Diagram 11, Triangle twister TT2 180 degrees */
			movePuzzlePiece(w, 4, 0, BR, FALSE);
			movePuzzlePiece(w, 4, 3, BL, FALSE);
			movePuzzlePiece(w, 4, 0, BR, FALSE);
			movePuzzlePiece(w, 4, 3, BL, FALSE);
			movePuzzlePiece(w, 4, 0, TL, FALSE);
			movePuzzlePiece(w, 4, 3, TR, FALSE);
			movePuzzlePiece(w, 4, 0, TL, FALSE);
			movePuzzlePiece(w, 4, 3, TR, FALSE);
		}
		return;
	}
	if (r[2] == 1 && r[3] == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister TT2, 270 degrees */
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 4, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 4, 3, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 4, 3, BL, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 4, 3, BL, FALSE);
		} else {
			/* Diagram 11, Triangle twister TT2 270 degrees */
			movePuzzlePiece(w, 1, 1, BL, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 1, 1, BL, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 1, 1, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 1, 1, TR, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
		}
		return;
	}
	if (r[3] == 1 && r[0] == 1) {
		if (NRAND(2) == 0) {
			/* Diagram 9, Triangle twister TT2 */
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, BL, FALSE);
			movePuzzlePiece(w, 1, 0, BR, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
			movePuzzlePiece(w, 3, 3, TR, FALSE);
			movePuzzlePiece(w, 1, 0, TL, FALSE);
		} else {
			/* Diagram 11, Triangle twister TT2 */
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 2, TL, FALSE);
			movePuzzlePiece(w, 0, 1, TR, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
			movePuzzlePiece(w, 0, 2, BR, FALSE);
			movePuzzlePiece(w, 0, 1, BL, FALSE);
		}
		return;
	}
	(void) printf("Wrong corners\n");
}

static void
setRemainingSquares(SkewbWidget w)
{
	int r[2]; /* 1, 2, 3 */ /* third value inferred */

	r[0] = 2 - w->skewb.cubeLoc[1][MAX_ORIENT].rotation;
	r[1] = w->skewb.cubeLoc[2][MAX_ORIENT].rotation;

#ifdef DEBUG
	(void) printf("remainingSquares %d %d\n", r[0], r[1]);
#endif
	if (r[0] == 0 && r[1] == 0)
		return;
	if (r[0] == 0) {
		/* Diagram 16, Twists 2 squares */
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 0, TL, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 3, BL, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 3, BL, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
	} else if (r[1] == 0) {
		/* Diagram 17, Twists 2 opposite squares */
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 0, TL, FALSE);
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 3, BL, FALSE);
		movePuzzlePiece(w, 0, 0, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
	} else {
		/* Diagram 16, Mirror Twists 2 squares */
		movePuzzlePiece(w, 0, 0, TL, FALSE);
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 3, BL, FALSE);
		movePuzzlePiece(w, 0, 0, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, BR, FALSE);
	}
}

#if 0
static void
diagram13(SkewbWidget w)
{
	/* Twister of 2 squares and 2 corners */
	movePuzzlePiece(w, 0, 1, TR, FALSE);
	movePuzzlePiece(w, 0, 2, BR, FALSE);
	movePuzzlePiece(w, 0, 3, BL, FALSE);
	movePuzzlePiece(w, 0, 2, TL, FALSE);
	movePuzzlePiece(w, 0, 0, BR, FALSE);
	movePuzzlePiece(w, 0, 1, BL, FALSE);
	movePuzzlePiece(w, 0, 3, TR, FALSE);
	movePuzzlePiece(w, 0, 1, BL, FALSE);
	movePuzzlePiece(w, 0, 3, BL, FALSE);
	movePuzzlePiece(w, 0, 0, TL, FALSE);
}

static void
diagram14(SkewbWidget w)
{
	/* Twists 2 squares, simple but Diagram 16 more efficient */
	int i;

	for (i = 0; i < 6; i++) {
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 1, TR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
	}
}

static void
diagram15(SkewbWidget w)
{
	/* Twister of 2 squares and 3 corners */
	movePuzzlePiece(w, 0, 0, BR, FALSE);
	movePuzzlePiece(w, 0, 2, TL, FALSE);
	movePuzzlePiece(w, 0, 1, BL, FALSE);
	movePuzzlePiece(w, 0, 0, BR, FALSE);
	movePuzzlePiece(w, 0, 1, BL, FALSE);
	movePuzzlePiece(w, 0, 2, TL, FALSE);
	movePuzzlePiece(w, 0, 1, BL, FALSE);
	movePuzzlePiece(w, 0, 0, BR, FALSE);
	movePuzzlePiece(w, 0, 2, TL, FALSE);
}

static void
diagram18(SkewbWidget w)
{
	/* Twists 6 corners clockwise */
	int i;

	for (i = 0; i < 3; i++) {
		movePuzzlePiece(w, 0, 3, TR, FALSE);
		movePuzzlePiece(w, 0, 2, TL, FALSE);
		movePuzzlePiece(w, 0, 1, BL, FALSE);
		movePuzzlePiece(w, 0, 0, BR, FALSE);
	}
}
#endif

/* This procedure coordinates the solution process. */
void
solveSomePieces(SkewbWidget w)
{
	setPuzzle(w, ACTION_RESET);
	if (solvingFlag)
		return;
#ifdef JMP
	if (!setjmp(solve_env))
#endif
	{
		solvingFlag = True;
		setFirstSquare(w);
		setSecondSquare(w);
		if (NRAND(2) == 0) {
			setFirstCorner(w);
			setSecondCorner(w);
		} else {
			setSecondCorner(w);
			setFirstCorner(w);
		}
		otherSide(w);
		setThirdSquare(w);
		if (NRAND(2) == 0) {
			placeThirdCorner(w);
			placeFourthCorner(w);
		} else {
			placeFourthCorner(w);
			placeThirdCorner(w);
		}
		setFifthSixthCorner(w);
		placeRemainingSquares(w);
		setRemainingCorners(w);
		if (w->skewb.orient)
			setRemainingSquares(w);
		otherSide(w);
	}
#ifdef JMP
	abortSolvingFlag = False;
#endif
	solvingFlag = False;
	w->skewb.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_CHEAT);
	setPuzzle(w, ACTION_COMPUTED);
}
