/*
 * @(#)BarrelS.c
 *
 * Taken from James G. Nourse's The Simple Solutions to Cubic Puzzles.
 * Break ability taken from the X puzzle by Don Bennett, HP Labs
 *
 * Copyright 2003 - 2009  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 Barrel */

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

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

#ifdef DEBUG
void printPuzzle(BarrelWidget w);

static char * colorName(int color)
{
	switch (color) {
	case 0:
		return "Green";
	case 1:
		return "Red";
	case 2:
		return "Yellow";
	case 3:
		return "Orange";
	case 4:
		return "Blue";
	case 5:
		return "Black";
	default:
		return "None";
	}
}

#define NRANDOM(n) 1
#else
#define NRANDOM(n) NRAND(n)
#endif

static Boolean
checkLastColorMatch(int colors[], int last)
{
	int i;

	for (i = 0; i < last; i++)
		if (colors[last] == colors[i])
			return True;
	return False;
}

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

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

static void
moveTilePiece(BarrelWidget w,
	const int direction, const int tile,
	const Boolean all)
{
#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, direction, tile, all);
}

#define ORIENTTILE(x,y) (w->barrel.tileOfPosition[y*w->barrel.tiles+x])
#define COLORTILE(x,y) ((ORIENTTILE(x,y)-1)/(w->barrel.tiles-2))
#define LEVELTILE(x,y) ((ORIENTTILE(x,y)-1)%(w->barrel.tiles-2))
#define CENTER() COLORTILE(3,2)

#define GETSOLVEDTILE(x,y) ((w->barrel.orient)?ORIENTTILE(x-1,y)+1:COLORTILE(x-1,y));
#define SOLVEDTILE(x,y) ((w->barrel.orient)?ORIENTTILE(x,y):COLORTILE(x,y))

static int
checkLevelSolved(const BarrelWidget w, int i)
{
	int color, j, inc;

	if (w->barrel.orient) {
		for (j = 0; j < w->barrel.faces; j++) {
			color = COLORTILE(1, j);
			inc = LEVELTILE(1, j);
			if (i >= 2 && i <= w->barrel.tiles - 2) {
				if (color != COLORTILE(i, j)) {
					return j;
				}
				if (inc + i != LEVELTILE(i, j)) {
					return j;
				}
			} else if (i == 1) {
				if (color == w->barrel.faces)
					return j;
				if (inc != 0)
					return j;
				if (j != 0 && color == COLORTILE(i, j))
					return j;
			} else if (i == w->barrel.faces &&
					(j & 1) == 1 &&
					color != w->barrel.faces &&
					LEVELTILE(w->barrel.tiles - 1, j) <
					w->barrel.faces) {
				return j;
			}
		}
	} else {
		for (j = 0; j < w->barrel.faces; j++) {
			color = COLORTILE(1, j);
			if (i >= 2 && i < w->barrel.faces) {
				if (color != COLORTILE(i, j)) {
					return j;
				}
			} else if (i == 1) {
				int k;

				if (color == w->barrel.faces)
					return j;
				for (k = 0; k < j; k++)
					if (color == COLORTILE(i, k))
						return j;
			} else if (i == w->barrel.faces &&
					(j & 1) == 1 &&
					color != w->barrel.faces) {
				return j;
			}
		}
	}
	return w->barrel.faces;
}

static int
findOtherColor(BarrelWidget w, int level, int colors[])
{
	int i, j, color;
	int nrand = NRANDOM(2);

	for (i = 0; i < w->barrel.faces; i++) {
		if (i == 0)
			j = (w->barrel.faces - 1) / 2;
		else if (nrand == 0) {
			if (i % 2 == 0) {
				j = (w->barrel.faces - 1) / 2 + (i + 1) / 2;
			} else {
				j = (w->barrel.faces - 1) / 2 - (i + 1) / 2;
			}
		} else {
			if (i % 2 == 0) {
				j = (w->barrel.faces - 1) / 2 - (i + 1) / 2;
			} else {
				j = (w->barrel.faces - 1) / 2 + (i + 1) / 2;
			}
		}
		if ((j & 1) == 1 && (level == 2 || level == 5))
			continue;
		for (color = 0; color < w->barrel.faces; color++) {
			if (COLORTILE(level, j) == colors[color]) {
				break;
			}
			if (colors[color] == -1 ||
					color == w->barrel.faces - 1) {
				return j;
			}
		}
	}
	return w->barrel.faces;
}

static int
findMatch(BarrelWidget w, int level, int match)
{
	int face;

	for (face = 0; face < w->barrel.faces; face++) {
		if (SOLVEDTILE(level, face) == match) {
			return face;
		}
	}
	return w->barrel.faces;
}

static int
findLevelOrient(BarrelWidget w, int match)
{
	int face, level;

	for (level = 1; level < w->barrel.tiles; level++) {
		for (face = 0; face < w->barrel.faces; face++) {
			if (ORIENTTILE(level, face) == match) {
				return level;
			}
		}
	}
	return w->barrel.tiles;
}

static int
findFaceOrient(BarrelWidget w, int level, int match)
{
	int face;

	for (face = 0; face < w->barrel.faces; face++) {
		if (ORIENTTILE(level, face) == match) {
			return face;
		}
	}
	return w->barrel.faces;
}

#define LeftAway(w) if (!w->barrel.pairs){\
  moveTilePiece(w,TOP,1,False);moveTilePiece(w,TOP,2,False);}else\
  moveTilePiece(w,TOP,1,False)
#define LeftAway2(w) LeftAway(w);LeftAway(w)
#define LeftTowards(w) if (!w->barrel.pairs){\
  moveTilePiece(w,BOTTOM,1,False);moveTilePiece(w,BOTTOM,2,False);}else\
  moveTilePiece(w,BOTTOM,1,False)
#define LeftTowards2(w) LeftTowards(w);LeftTowards(w)
#define RightAway(w) if (!w->barrel.pairs){\
  moveTilePiece(w,TOP,w->barrel.tiles-2,False);\
  moveTilePiece(w,TOP,w->barrel.tiles-3,False);}else\
  moveTilePiece(w,TOP,w->barrel.tiles-2,False)
#define RightAway2(w) RightAway(w);RightAway(w)
#define RightTowards(w) if (!w->barrel.pairs){\
  moveTilePiece(w,BOTTOM,w->barrel.tiles-2,False);\
  moveTilePiece(w,BOTTOM,w->barrel.tiles-3,False);}else\
  moveTilePiece(w,BOTTOM,w->barrel.tiles-2,False)
#define RightTowards2(w) RightTowards(w);RightTowards(w)

#define LeftSlide(w) moveTilePiece(w,LEFT,-1,False)
#define RightSlide(w) moveTilePiece(w,RIGHT,1,False)

/*
John Ewing & Czes Kosniowski, Puzzle it Out: "
Cubes Groups and Puzzles, Cambridge University Press,
New York, 1982,  "Cylinder Puzzle", I only have pages 50-53
*/

/* Page 51 - 53 */
#define L(w) LeftTowards(w);LeftSlide(w);LeftAway(w);RightSlide(w)
#define R(w) RightTowards(w);LeftSlide(w);RightAway(w);RightSlide(w)
#define L_1(w) LeftSlide(w);LeftTowards(w);RightSlide(w);LeftAway(w)
#define R_1(w) LeftSlide(w);RightTowards(w);RightSlide(w);RightAway(w)
/* Swaps 5 beads on rows 3 and 4 */
#define Lx7(w) L(w);L(w);L(w);L(w);L(w);L(w);L(w)
#define Rx7(w) R(w);R(w);R(w);R(w);R(w);R(w);R(w)
#define L_1x7(w) L_1(w);L_1(w);L_1(w);L_1(w);L_1(w);L_1(w);L_1(w)
#define R_1x7(w) R_1(w);R_1(w);R_1(w);R_1(w);R_1(w);R_1(w);R_1(w)
/* commutatorx2 swap (9, 10, 11) the center beads */
#define commutator(w) L(w);R_1(w);L_1(w);R(w)
#define commutator_1(w) R_1(w);L(w);R(w);L_1(w)
#define commutatorx2(w) commutator(w);commutator(w) /* moves left */
#define commutator_1x2(w) commutator_1(w);commutator_1(w) /* moves right */

#define Lb(w) LeftAway(w);LeftSlide(w);LeftTowards(w);RightSlide(w)
#define Rb(w) RightAway(w);LeftSlide(w);RightTowards(w);RightSlide(w)
#define Lb_1(w) LeftSlide(w);LeftAway(w);RightSlide(w);LeftTowards(w)
#define Rb_1(w) LeftSlide(w);RightAway(w);RightSlide(w);RightTowards(w)
/* Swaps 5 beads on rows 2 and 3 */
#define Lbx7(w) Lb(w);Lb(w);Lb(w);Lb(w);Lb(w);Lb(w);Lb(w)
#define Rbx7(w) Rb(w);Rb(w);Rb(w);Rb(w);Rb(w);Rb(w);Rb(w)
#define Lb_1x7(w) Lb_1(w);Lb_1(w);Lb_1(w);Lb_1(w);Lb_1(w);Lb_1(w);Lb_1(w)
#define Rb_1x7(w) Rb_1(w);Rb_1(w);Rb_1(w);Rb_1(w);Rb_1(w);Rb_1(w);Rb_1(w)
#define commutatorb(w) Lb(w);Rb_1(w);Lb_1(w);Rb(w)
#define commutatorb_1(w) Rb_1(w);Lb(w);Rb(w);Lb_1(w)
/* commutatorx2 =~ commutatorbx2 */
#define commutatorbx2(w) commutatorb(w);commutatorb(w) /* moves left */
#define commutator_1bx2(w) commutatorb_1(w);commutatorb_1(w) /* moves right */
/* There is at least one more page but do not have copy. */

/*
James G Nourse, The Simple Solutions to Cubic, Puzzles,
Bantam Books, New York, November 1981, "The Barrel", pp 24-42.
*/

#if 0
/* Page 27 */
/* Near Swap 3rd column beads in 1 and 3 rows,
   not for oriented T3230NS */
#define L2_11_3NS(w) \
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightTowards2(w)
/* Near Swap 3rd column beads in 3 and 5 rows,
   not for oriented T3234NS */
#define L2_11_19NS(w) \
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w)
/* HS1 == R3230 */
#endif

/* H2 Page 28 22->12 12->11, 5242 = 4232 */
#define L2_4232(w) if (NRANDOM(2)==1)\
  {LeftSlide(w);RightAway(w);RightSlide(w);RightTowards(w);} else\
  {LeftSlide(w);RightTowards(w);RightSlide(w);RightAway(w);}
#define L2_5242(w) L2_4232(w)

/* HS3 == HS2,HS2 T5232 */
#define L2_5232(w) L2_5242(w)L2_4232(w)

/* HS4 21->11 */
#define L2_5032(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w)
/* HS5 23->11 */
#define L2_5432(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w)

/* First level is actually tricky,
   short steps to line up for full insertion */
/* Page 29 1B */
#define L1_B(w) LeftAway(w);RightAway(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w)
/* Page 30 1C */
#define L1_E(w) RightAway(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w)
#define L1_C(w) LeftTowards2(w);L1_E(w)
/* Page 30 1D */
#define L1_D(w) LeftTowards(w);\
  LeftSlide(w);LeftAway(w);RightSlide(w)
#define L1_F(w) RightTowards(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w)
#define L1_G(w) LeftTowards(w);\
  LeftSlide(w);LeftAway(w);RightSlide(w)

#if 0
/* Page 33 R2B */
/* HS1 Page 29 Add RightTowards2 cleaner */
#define L2_7_6(w) \
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w)
/* Add RightAway2 cleaner */
#define L2_15_14(w) \
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w)

/* Page 30 R1C */
#define R19_6(w) RightTowards2(w);R7_6(w)
#define R7_14(w) RightAway2(w);R15_14(w)
/* Page 31 R1F */
#define R7_18(w) LeftAway2(w);R7_6(w);LeftTowards2(w);RightTowards2(w)
#define R15_2(w) LeftTowards2(w);R15_14(w);LeftAway2(w);RightAway2(w)
#endif

/* Page 31 */
/* 7->6 */
#define L2_3121(w) \
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w)
/* 6->19 */
#define L2_2134(w) L2_3121(w)
/* 15->14 */
#define L2_3323(w) \
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w)
/* 14->3 */
#define L2_2330(w) L2_3323(w)
/* 11->10 */
#define L2_3222(w) if (NRANDOM(2)==1)\
  {LeftTowards(w);RightTowards(w);L2_3323(w);LeftAway(w);}else\
  {LeftAway(w);RightAway(w);L2_3121(w);LeftTowards(w);}
/* 6->7 */
#define L2_2131(w) \
  LeftSlide(w);LeftAway2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);LeftTowards2(w);RightSlide(w)
/* 14->15 */
#define L2_2333(w) \
  LeftSlide(w);LeftTowards2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);LeftAway2(w);RightSlide(w)
/* 10->11 */
#define L2_2232(w) if (NRANDOM(2)==1)\
  {LeftTowards(w);L2_2333(w);RightAway(w);LeftAway(w);}else\
  {LeftAway(w);L2_2131(w);RightTowards(w);LeftTowards(w);}

/* L2_11_6 == R1E */
#if 0
/* Cleaner but probably unnecessary, 4 changed, upside-down L */
#define L2_11_6C(w) R11_6(w);RightAway2(w)
#define L2_11_14C(w) R11_14(w);RightTowards2(w)
#endif


/* Page 34, solve level 3, where 4 and 5 scratch area */
/* 7->15 15->17 */
#define L3_3133(w) if (NRANDOM(2)==1)\
  {LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards2(w);}else\
  {LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway2(w);}
#define L3_3331(w) L3_3133(w)

/* Page 35 */
/* 3->7 7->3 */
#define L3_3031(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w)
#define L3_3130(w) L3_3031(w)
/* 15->19 19->15 */
#define L3_3334(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w)
#define L3_3433(w) L3_3334(w)

/* 16->15 */
#define L3_4333(w) \
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w)
/* 8->7 */
#define L3_4131(w) \
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w)

/* Page 35 */
/* 12->15 */
#define L3_4233(w) \
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w)
/* 12->7 */
#define L3_4231(w) \
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w)

/* 8->15 */
#define L3_4133(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w)
/* 16->7 */
#define L3_4331(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w)

/* 22->7 */
#define L3_5231(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w)
/* 22->15 */
#define L3_5233(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w)

/* 21->19 */
#define L3_5034(w) \
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w)
/* 23->3 */
#define L3_5430(w) \
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w)

/* Page 38, skip to solve the 3 plungers now, level 4 scratch area */
/* 16->22 */
#define L5_4352(w) \
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards2(w)
/* 8->22 */
#define L5_4152(w) \
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway2(w)

/* 20->21 */
#define L5_4450(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w)
/* 4->23 */
#define L5_4054(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w)

/* Page 40, just complete Level 4, All are swaps from this point */
/* 12->8, 8->12 */
#define L4_4241(w) \
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w)

/* 12->16, 16->12 */
#define L4_4243(w) \
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w)

/* 8->20, 20->8 */
#define L4_4144(w) \
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightTowards2(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w)

/* 16->4, 4->16 */
#define L4_4340(w) \
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w);\
  LeftSlide(w);RightAway(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightTowards2(w);RightSlide(w);RightAway(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightAway2(w);\
  LeftSlide(w);RightAway2(w);RightSlide(w);RightTowards(w)

static int
findL1Color(BarrelWidget w, int colors[])
{
	int searchLevel = 3;
	int piece = findOtherColor(w, searchLevel, colors);

#ifdef DEBUG
	(void) printf("1: search level %d, piece %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		RightTowards2(w);
		return CENTER();
	case 1:
		RightTowards(w);
		return CENTER();
	case 2:
		return CENTER();
	case 3:
		RightAway(w);
		return CENTER();
	case 4:
		RightAway2(w);
		return CENTER();
	}
	searchLevel = 4;
	piece = findOtherColor(w, searchLevel, colors);
#ifdef DEBUG
	(void) printf("1: search level %d, piece %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		RightTowards2(w);
		L2_4232(w);
		return CENTER();
	case 1:
		RightTowards(w);
		L2_4232(w);
		return CENTER();
	case 2:
		L2_4232(w);
		return CENTER();
	case 3:
		RightAway(w);
		L2_4232(w);
		return CENTER();
	case 4:
		RightAway2(w);
		L2_4232(w);
		return CENTER();
	}
	searchLevel = 5;
	piece = findOtherColor(w, searchLevel, colors);
#ifdef DEBUG
	(void) printf("1: search level %d, piece %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		L2_5032(w);
		return CENTER();
	case 2:
		L2_5232(w);
		return CENTER();
	case 4:
		L2_5432(w);
		return CENTER();
	}
	searchLevel = 2;
	piece = findOtherColor(w, searchLevel, colors);
#ifdef DEBUG
	(void) printf("1: search level %d, piece %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		LeftTowards(w);
		L2_2131(w);
		LeftAway(w);
		RightTowards(w);
		return CENTER();
	case 2:
		L2_2232(w);
		return CENTER();
	case 4:
		LeftAway(w);
		L2_2333(w);
		LeftTowards(w);
		RightAway(w);
		return CENTER();
	}
	(void) printf("findL1Color: Could not find!\n");
	return 5;
}

static int
findL2(BarrelWidget w, int color)
{
	int searchLevel = 3;
	int piece = findMatch(w, searchLevel, color);

#ifdef DEBUG
	(void) printf("2: search level %d, %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		RightTowards2(w);
		return CENTER();
	case 1:
		RightTowards(w);
		return CENTER();
	case 2:
		return CENTER();
	case 3:
		RightAway(w);
		return CENTER();
	case 4:
		RightAway2(w);
		return CENTER();
	}
	searchLevel = 4;
	piece = findMatch(w, searchLevel, color);
#ifdef DEBUG
	(void) printf("2: search level %d, %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		RightTowards2(w);
		L2_4232(w);
		return CENTER();
	case 1:
		RightTowards(w);
		L2_4232(w);
		return CENTER();
	case 2:
		L2_4232(w);
		return CENTER();
	case 3:
		RightAway(w);
		L2_4232(w);
		return CENTER();
	case 4:
		RightAway2(w);
		L2_4232(w);
		return CENTER();
	}
	searchLevel = 5;
	piece = findMatch(w, searchLevel, color);
#ifdef DEBUG
	(void) printf("2: search level %d, %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		L2_5032(w);
		return CENTER();
	case 2:
		L2_5232(w);
		return CENTER();
	case 4:
		L2_5432(w);
		return CENTER();
	}
	searchLevel = 2;
	piece = findMatch(w, searchLevel, color);
#ifdef DEBUG
	(void) printf("2: search level %d, %d\n", searchLevel, piece);
#endif
	switch (piece) {
	case 0:
		LeftTowards(w);
		L2_2131(w);
		LeftAway(w);
		RightTowards(w);
		return CENTER();
	case 2:
		L2_2232(w);
		return CENTER();
	case 4:
		LeftAway(w);
		L2_2333(w);
		LeftTowards(w);
		RightAway(w);
		return CENTER();
	}
	(void) printf("findL2: Could not find!\n");
	return 5;
}

static int
findL3Color(BarrelWidget w, int face, int color)
{
	int searchLevel = 3;
	int piece = findMatch(w, searchLevel, color);

#ifdef DEBUG
	(void) printf("3: search level %d, face %d, piece %d\n",
		searchLevel, face, piece);
#endif
	if (face == 2) {
		switch (piece) {
		case 0:
			RightTowards2(w);
			return searchLevel;
		case 1:
			RightTowards(w);
			return searchLevel;
		case 2:
			return searchLevel;
		case 3:
			RightAway(w);
			return searchLevel;
		case 4:
			RightAway2(w);
			return searchLevel;
		}
	} else {
		switch (piece) {
		case 0:
			switch (face) {
			case 1: /* 3->7 */
				L3_3031(w);
				return searchLevel;
			case 3: /* 3->15 */
				RightAway2(w);
				L3_3133(w);
				RightTowards2(w);
				return searchLevel;
			case 4: /* 3->19 */
				RightAway(w);
				L3_3334(w);
				RightTowards(w);
				return searchLevel;
			default:
				(void) printf("Should not get here\n");
			}
			return searchLevel;
		case 1:
			switch (face) {
			case 0: /* 7->3 */
				L3_3130(w);
				return searchLevel;
			case 3: /* 7->15 */
				L3_3133(w);
				return searchLevel;
			case 4: /* 7->19 */
				RightTowards2(w);
				L3_3133(w);
				RightAway2(w);
				return searchLevel;
			default:
				(void) printf("Should not get here\n");
			}
			return searchLevel;
		case 2:
			(void) printf("Should have been set first\n");
			return searchLevel;
/* 7->15 15->17  L3_3133(w) move 2 */
/* 3->7 7->3     L3_3031(w) move 1 */
/* 15->19 19->15 L3_3334(w) move 1 */
		case 3:
			switch (face) {
			case 0: /* 15->3 */
				RightAway2(w);
				L3_3133(w);
				RightTowards2(w);
				return searchLevel;
			case 1: /* 15->7 */
				L3_3331(w);
				return searchLevel;
			case 4: /* 15->19 */
				L3_3334(w);
				return searchLevel;
			default:
				(void) printf("Should not get here\n");
			}
			return searchLevel;
		case 4:
			switch (face) {
			case 0: /* 19->3 */
				RightTowards(w);
				L3_3031(w);
				RightAway(w);
				return searchLevel;
			case 1: /* 19->7 */
				RightTowards2(w);
				L3_3133(w);
				RightAway2(w);
				return searchLevel;
			case 3: /* 19->15 */
				L3_3433(w);
				return searchLevel;
			default:
				(void) printf("Should not get here\n");
			}
			return searchLevel;
		}
	}
	searchLevel = 4;
	piece = findMatch(w, searchLevel, color);
#ifdef DEBUG
	(void) printf("3: search level %d, face %d, piece %d\n",
		searchLevel, face, piece);
#endif
	switch (piece) {
	case 0:
		switch (face) {
		case 0: /* 4->3 */
			RightTowards(w);
			L3_4131(w);
			RightAway(w);
			return searchLevel;
		case 1: /* 4->7 */
			RightTowards2(w);
			L3_4233(w);
			RightAway2(w);
			return searchLevel;
		case 2: /* 4->11 */
			RightTowards(w);
			L3_4133(w);
			RightAway(w);
			return searchLevel;
		case 3: /* 4->15 */
			RightAway2(w);
			L3_4331(w);
			RightTowards2(w);
			return searchLevel;
		case 4: /* 4->19 */
			RightTowards2(w);
			L3_4231(w);
			RightAway2(w);
			return searchLevel;
		}
		break;
	case 1:
		switch (face) {
		case 0: /* 8->3 */
			RightTowards(w);
			L3_4231(w);
			RightAway(w);
			return searchLevel;
		case 1: /* 8->7 */
			L3_4131(w);
			return searchLevel;
		case 2: /* 8->11 */
			RightTowards(w);
			L3_4233(w);
			RightAway(w);
			return searchLevel;
		case 3: /* 8->15 */
			L3_4133(w);
			return searchLevel;
		case 4: /* 8->19 */
			RightTowards2(w);
			L3_4331(w);
			RightAway2(w);
			return searchLevel;
		}
		break;
	case 2:
		switch (face) {
		case 0: /* 12->3 */
			RightTowards(w);
			L3_4331(w);
			RightAway(w);
			return searchLevel;
		case 1: /* 12->7 */
			L3_4231(w);
			return searchLevel;
		case 2: /* 12->11 */
			if (NRANDOM(2) == 1) {
				RightAway(w);
				L3_4131(w);
				RightTowards(w);
			} else {
				RightTowards(w);
				L3_4333(w);
				RightAway(w);
			}
			return searchLevel;
		case 3: /* 12->15 */
			L3_4233(w);
			return searchLevel;
		case 4: /* 12->19 */
			RightAway(w);
			L3_4133(w);
			RightTowards(w);
			return searchLevel;
		}
		break;
	case 3:
		switch (face) {
		case 0: /* 16->3 */
			RightAway2(w);
			L3_4133(w);
			RightTowards2(w);
			return searchLevel;
		case 1: /* 16->7 */
			L3_4331(w);
			return searchLevel;
		case 2: /* 16->11 */
			RightAway(w);
			L3_4231(w);
			RightTowards(w);
			return searchLevel;
		case 3: /* 16->15 */
			L3_4333(w);
			return searchLevel;
		case 4: /* 16->19 */
			RightAway(w);
			L3_4233(w);
			RightTowards(w);
			return searchLevel;
		}
		break;
/* 16->15 L3_4333(w) */
/* 8->7   L3_4131(w) */
/* 12->15 L3_4233(w) */
/* 12->7  L3_4231(w) */
/* 8->15  L3_4133(w) */
/* 16->7  L3_4331(w) */
	case 4:
		switch (face) {
		case 0: /* 20->3 */
			RightAway2(w);
			L3_4233(w);
			RightTowards2(w);
			return searchLevel;
		case 1: /* 20->7 */
			RightTowards2(w);
			L3_4133(w);
			RightAway2(w);
			return searchLevel;
		case 2: /* 20->11 */
			RightAway(w);
			L3_4331(w);
			RightTowards(w);
			return searchLevel;
		case 3: /* 20->15 */
			RightAway2(w);
			L3_4231(w);
			RightTowards2(w);
			return searchLevel;
		case 4: /* 20->19 */
			RightAway(w);
			L3_4333(w);
			RightTowards(w);
			return searchLevel;
		}
		break;
	}
	searchLevel = 5;
#ifdef DEBUG
	(void) printf("3: search level %d, face %d, piece %d\n",
		searchLevel, face, piece);
#endif
	piece = findMatch(w, searchLevel, color);
	switch (piece) {
	case 0:
		switch (face) {
		case 0: /* 21->3 */
			RightAway(w);
			L3_5034(w);
			RightTowards(w);
			return searchLevel;
		case 1: /* 21->7 */
			RightAway2(w);
			L3_5034(w);
			RightTowards2(w);
			return searchLevel;
		case 2: /* 21->11 */
			RightTowards2(w);
			L3_5034(w);
			RightAway2(w);
			return searchLevel;
		case 3: /* 21->15 */
			RightTowards(w);
			L3_5034(w);
			RightAway(w);
			return searchLevel;
		case 4: /* 21->19 */
			L3_5034(w);
			return searchLevel;
		}
		break;
	case 2:
		switch (face) {
		case 0: /* 22->3 */
			RightTowards(w);
			L3_5231(w);
			RightAway(w);
			return searchLevel;
		case 1: /* 22->7 */
			L3_5231(w);
			return searchLevel;
		case 2: /* 22->11 */
			if (NRANDOM(2) == 1) {
				RightAway(w);
				L3_5231(w);
				RightTowards(w);
			} else {
				RightTowards(w);
				L3_5233(w);
				RightAway(w);
			}
			return searchLevel;
		case 3: /* 22->15 */
			L3_5233(w);
			return searchLevel;
		case 4: /* 22->19 */
			RightAway(w);
			L3_5233(w);
			RightTowards(w);
			return searchLevel;
		}
		break;
/* 22->7  L3_5231(w) */
/* 22->15 L3_5233(w) */
/* 21->19 L3_5034(w) */
/* 23->3  L3_5430(w) */
	case 4:
		switch (face) {
		case 0: /* 23->3 */
			L3_5430(w);
			return searchLevel;
		case 1: /* 23->7 */
			RightAway(w);
			L3_5430(w);
			RightTowards(w);
			return searchLevel;
		case 2: /* 23->11 */
			RightAway2(w);
			L3_5430(w);
			RightTowards2(w);
			return searchLevel;
		case 3: /* 23->15 */
			RightTowards2(w);
			L3_5430(w);
			RightAway2(w);
			return searchLevel;
		case 4: /* 23->19 */
			RightTowards(w);
			L3_5430(w);
			RightAway(w);
			return searchLevel;
		}
		break;
	}
	(void) printf("findL3Color: Could not find!\n");
	return 0;
}

static Boolean
findL5Color(BarrelWidget w, int face, int color)
{
	int searchLevel = 4;
	int piece = findMatch(w, searchLevel, color);

#ifdef DEBUG
	(void) printf("5: search level %d, face %d, piece %d\n",
		searchLevel, face, piece);
#endif
	switch (piece) {
	case 0:
		switch (face) {
		case 0: /* 4->21 */
			RightAway(w);
			L5_4450(w);
			RightTowards(w);
			return True;
		case 2: /* 4->22 */
			RightTowards(w);
			L5_4152(w);
			RightAway(w);
			return True;
		case 4: /* 4->23 */
			L5_4054(w);
			return True;
		}
		break;
	case 1:
		switch (face) {
		case 0: /* 8->21 */
			RightAway2(w);
			L5_4450(w);
			RightTowards2(w);
			return True;
		case 2: /* 8->22 */
			L5_4152(w);
			return True;
		case 4: /* 8->23 */
			RightAway(w);
			L5_4054(w);
			RightTowards(w);
			return True;
		}
		break;
	case 2:
		switch (face) {
		case 0: /* 12->21 */
			RightTowards2(w);
			L5_4450(w);
			RightAway2(w);
			return True;
		case 2: /* 12->22 */
			if (NRANDOM(2) == 1) {
				RightAway(w);
				L5_4152(w);
				RightTowards(w);
			} else {
				RightTowards(w);
				L5_4352(w);
				RightAway(w);
			}
			return True;
		case 4: /* 12->23 */
			RightAway2(w);
			L5_4054(w);
			RightTowards2(w);
			return True;
		}
		break;
/* 16->22  L5_4352(w) */
/* 8->22   L5_4152(w) */
/* 20->21   L5_4450(w)*/
/* 4->23   L5_4054(w) */
	case 3:
		switch (face) {
		case 0: /* 16->21 */
			RightTowards(w);
			L5_4450(w);
			RightAway(w);
			return True;
		case 2: /* 16->22 */
			L5_4352(w);
			return True;
		case 4: /* 16->23 */
			RightTowards2(w);
			L5_4054(w);
			RightAway2(w);
			return True;
		}
		break;
	case 4:
		switch (face) {
		case 0: /* 20->21 */
			L5_4450(w);
			return True;
		case 2: /* 20->22 */
			RightAway(w);
			L5_4352(w);
			RightTowards(w);
			return True;
		case 4: /* 20->23 */
			RightTowards(w);
			L5_4054(w);
			RightAway(w);
			return True;
		}
		break;
	}
	(void) printf("findL5Color: Could not find!\n");
	return False;
}

static Boolean
findL4Color(BarrelWidget w, int face, int color)
{
	int searchLevel = 4;
	int piece = findMatch(w, searchLevel, color);

#ifdef DEBUG
	(void) printf("4: search level %d, face %d, piece %d\n",
		searchLevel, face, piece);
#endif
	switch (piece) {
	case 0:
		switch (face) {
		case 1: /* 4->8 */
			RightTowards(w);
			L4_4241(w);
			RightAway(w);
			return True;
		case 2: /* 4->12 */
			RightAway2(w);
			L4_4340(w);
			RightTowards2(w);
			return True;
		case 3: /* 4->16 */
			L4_4340(w);
			return True;
		case 4: /* 4->20 */
			RightTowards2(w);
			L4_4241(w);
			RightAway2(w);
			return True;
		}
		break;
	case 1:
		switch (face) {
		case 0: /* 8->4 */
			RightTowards(w);
			L4_4241(w);
			RightAway(w);
			return True;
		case 2: /* 8->12 */
			L4_4241(w);
			return True;
		case 3: /* 8->16 */
			RightAway2(w);
			L4_4144(w);
			RightTowards2(w);
			return True;
		case 4: /* 8->20 */
			L4_4144(w);
			return True;
		}
		break;
	case 2:
		switch (face) {
		case 0: /* 12->4 */
			RightAway2(w);
			L4_4340(w);
			RightTowards2(w);
			return True;
		case 1: /* 12->8 */
			L4_4241(w);
			return True;
		case 3: /* 12->16 */
			L4_4243(w);
			return True;
		case 4: /* 12->20 */
			RightTowards2(w);
			L4_4144(w);
			RightAway2(w);
			return True;
		}
		break;
/* 12->8   L4_4241(w) */
/* 12->16  L4_4243(w) */
/* 8->20   L4_4144(w) */
/* 16->4   L4_4340(w) */
	case 3:
		switch (face) {
		case 0: /* 16->4 */
			L4_4340(w);
			return True;
		case 1: /* 16->8 */
			RightTowards2(w);
			L4_4340(w);
			RightAway2(w);
			return True;
		case 2: /* 16->12 */
			L4_4243(w);
			return True;
		case 4: /* 16->20 */
			RightAway(w);
			L4_4243(w);
			RightTowards(w);
			return True;
		}
		break;
	case 4:
		switch (face) {
		case 0: /* 20->4 */
			RightAway2(w);
			L4_4243(w);
			RightTowards2(w);
			return True;
		case 1: /* 20->8 */
			L4_4144(w);
			return True;
		case 2: /* 20->12 */
			RightTowards2(w);
			L4_4144(w);
			RightAway2(w);
			return True;
		case 3: /* 20->16 */
			RightAway(w);
			L4_4243(w);
			RightTowards(w);
			return True;
		}
		break;
	}
	(void) printf("findL4Color: Could not find!\n");
	return False;
}

static Boolean
solveRightColor(BarrelWidget w, int level, int face)
{
	int piece, check, searchLevel = 4;

	piece = COLORTILE(1, face);
	if (level == 5)
		piece = w->barrel.faces;
	else
		piece = COLORTILE(1, face);
	check = COLORTILE(level, face);
	if (piece == check)
		return True;
	if (level == 3) {
		searchLevel = findL3Color(w, face, piece);
	} else if (level == 4) {
		(void) findL4Color(w, face, piece);
	} else {
		(void) findL5Color(w, face, piece);
	}
	check = COLORTILE(level, face);
	if (piece != check) {
		(void) printf("error level %d, searchLevel %d, face %d, piece %d, check %d\n",
			level, searchLevel, face, piece, check);
		return False;
	}
	return True;
}

static void
solveL0(BarrelWidget w)
{
		if (w->barrel.tileOfPosition[0] > 0)
			RightSlide(w);
		if (w->barrel.spacePosition[2] == 0) {
			moveTilePiece(w, TOP, 0, True);
		} else if (w->barrel.spacePosition[2] == 6) {
			moveTilePiece(w, TOP, 0, True);
			moveTilePiece(w, TOP, 0, True);
		} else if (w->barrel.spacePosition[1] == w->barrel.tiles) {
			moveTilePiece(w, BOTTOM, 0, True);
		} else if (w->barrel.spacePosition[1] == 0) {
			moveTilePiece(w, BOTTOM, 0, True);
			moveTilePiece(w, BOTTOM, 0, True);
		}
}

static int
moveToCenter(BarrelWidget w, int level, int face)
{
#if DEBUG
	printf("moveToCenter level %d, face %d\n", level, face);
#endif
	/* move to 11 */
	if (level == 1) {
		switch (face) {
		case 0:
			LeftTowards2(w);
			Lbx7(w);
			LeftAway2(w);
			return CENTER();
		case 1:
			LeftTowards(w);
			L_1x7(w);
			LeftAway(w);
			return moveToCenter(w, 2, 0);
		case 3:
			LeftAway(w);
			Lb_1x7(w);
			LeftTowards(w);
			return moveToCenter(w, 2, 4);
		case 4:
			LeftAway2(w);
			Lx7(w);
			LeftTowards2(w);
			return CENTER();
		}
	} else if (level == 2) {
		switch (face) {
		case 0:
			LeftTowards(w);
			RightAway(w);
			L2_2131(w);
			RightTowards(w);
			LeftAway(w);
			return CENTER();
		case 1:
			RightAway(w);
			L2_2131(w);
			RightTowards(w);
			return CENTER();
		case 2:
			L2_2232(w);
			return CENTER();
		case 3:
			RightTowards(w);
			L2_2333(w);
			RightAway(w);
			return CENTER();
		case 4:
			LeftAway(w);
			RightTowards(w);
			L2_2333(w);
			RightAway(w);
			LeftTowards(w);
			return CENTER();
		}
	} else if (level == 3) {
		switch (face) {
		case 0:
			RightTowards2(w);
			return CENTER();
		case 1:
			RightTowards(w);
			return CENTER();
		case 2:
			return CENTER();
		case 3:
			RightAway(w);
			return CENTER();
		case 4:
			RightAway2(w);
			return CENTER();
		}
	} else if (level == 4) {
		switch (face) {
		case 0: /* 4->11 */
			RightTowards(w);
			L3_4133(w);
			RightAway(w);
			return CENTER();
		case 1: /* 8->11 */
			RightTowards(w);
			L3_4233(w);
			RightAway(w);
			return CENTER();
		case 2: /* 12->11 */
			if (NRANDOM(2) == 1) {
				RightAway(w);
				L3_4131(w);
				RightTowards(w);
			} else {
				RightTowards(w);
				L3_4333(w);
				RightAway(w);
			}
			return CENTER();
		case 3: /* 16->11 */
			RightAway(w);
			L3_4231(w);
			RightTowards(w);
			return CENTER();
		case 4: /* 20->11 */
			RightAway(w);
			L3_4331(w);
			RightTowards(w);
			return CENTER();
		}
	} else if (level == 5) {
		switch (face) {
		case 0: /* 21->11 */
			RightTowards2(w);
			L3_5034(w);
			RightAway2(w);
			return CENTER();
		case 2: /* 22->11 */
			if (NRANDOM(2) == 1) {
				RightAway(w);
				L3_5231(w);
				RightTowards(w);
			} else {
				RightTowards(w);
				L3_5233(w);
				RightAway(w);
			}
			return CENTER();
		case 4: /* 23->11 */
			RightAway2(w);
			L3_5430(w);
			RightTowards2(w);
			return CENTER();
		}
	}
	return -1;
}

static Boolean
solveL1Orient(BarrelWidget w)
{
	int orient[MAX_FACES] = {-1, -1, -1, -1, -1};
	int piece = checkLevelSolved(w, 1);
	int currentLevel, currentFace;
#ifdef DEBUG
	int ok = -2;
#endif

	if (piece == w->barrel.faces) {
		return True;
	}
	piece = 1;
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	/* G1 B17 Y9 R5 O13 */
	if (ORIENTTILE(1, 2) != piece) {
		currentLevel = findLevelOrient(w, piece);
		currentFace = findFaceOrient(w, currentLevel, piece);
		if (currentLevel == 1) {
			switch (currentFace) {
			case 0:
				LeftTowards2(w);
				break;
			case 1:
				LeftTowards(w);
				break;
			case 3:
				LeftAway(w);
				break;
			case 4:
				LeftAway2(w);
				break;
			}
		} else {
			if (currentLevel == 2) {
				switch (currentFace) {
				case 0:
					LeftTowards2(w);
					break;
				case 1:
					LeftTowards(w);
					break;
				case 3:
					LeftAway(w);
					break;
				case 4:
					LeftAway2(w);
					break;
				}
				LeftSlide(w);
				if (NRANDOM(2) == 1) {
					LeftAway(w);
					RightSlide(w);
					LeftTowards(w);
				} else {
					LeftTowards(w);
					RightSlide(w);
					LeftAway(w);
				}
			} else {
				(void) moveToCenter(w, currentLevel,
					currentFace);
				LeftSlide(w);
				if (NRANDOM(2) == 1) {
					LeftAway(w);
					RightSlide(w);
					LeftTowards(w);
				} else {
					LeftTowards(w);
					RightSlide(w);
					LeftAway(w);
				}
				LeftSlide(w);
				if (NRANDOM(2) == 1) {
					LeftAway(w);
					RightSlide(w);
					LeftTowards(w);
				} else {
					LeftTowards(w);
					RightSlide(w);
					LeftAway(w);
				}
			}
		}
	}
	piece = 17;
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	if (ORIENTTILE(2, 2) != piece) {
		currentLevel = findLevelOrient(w, piece);
		currentFace = findFaceOrient(w, currentLevel, piece);
#ifdef DEBUG
		ok =
#else
		(void)
#endif
		moveToCenter(w, currentLevel, currentFace);
		L2_3222(w);
#ifdef DEBUG
		(void) printf("solving level 1, %d %d %d\n",
			currentLevel, currentFace, ok);
#endif
	}
	orient[0] = ORIENTTILE(1, 2);
	orient[1] = ORIENTTILE(2, 2);
#ifdef DEBUG
	(void) printf("1A: 1,2: %d, 2,2: %d\n",
		orient[0], orient[1]);
#endif
	piece = 9;
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	if (ORIENTTILE(3, 2) != piece) {
		currentLevel = findLevelOrient(w, piece);
		currentFace = findFaceOrient(w, currentLevel, piece);
#ifdef DEBUG
		ok =
#else
		(void)
#endif
		moveToCenter(w, currentLevel, currentFace);
#ifdef DEBUG
		(void) printf("solving level 1, %d %d %d\n",
			currentLevel, currentFace, ok);
#endif
	}
	orient[0] = ORIENTTILE(1, 2);
	orient[1] = ORIENTTILE(2, 2);
	orient[2] = ORIENTTILE(3, 2);
#ifdef DEBUG
	(void) printf("1B: 1,2: %d, 2,2: %d, 3,2: %d\n",
		orient[0], orient[1], orient[2]);
#endif
	RightTowards2(w);LeftAway(w);LeftSlide(w);
	LeftTowards2(w);RightSlide(w);
	orient[0] = ORIENTTILE(1, 3);
	orient[1] = ORIENTTILE(2, 3);
	orient[2] = ORIENTTILE(2, 1);
#ifdef DEBUG
	(void) printf("1C: 1,3: %d, 2,3: %d, 2,1: %d\n",
		orient[0], orient[1], orient[2]);
#endif
	L1_D(w);
	orient[0] = ORIENTTILE(1, 4);
	orient[1] = ORIENTTILE(1, 3);
	orient[2] = ORIENTTILE(1, 1);
	orient[3] = ORIENTTILE(2, 1); /* see if already in place */
#ifdef DEBUG
	(void) printf("1E: 1,4: %d, 1,3: %d, 1,1: %d, 2,1: %d\n",
		orient[0], orient[1], orient[2], orient[3]);
#endif
	piece = 5;
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	if (ORIENTTILE(2, 1) != piece) {
		currentLevel = findLevelOrient(w, piece);
		currentFace = findFaceOrient(w, currentLevel, piece);
#ifdef DEBUG
		ok =
#else
		(void)
#endif
		moveToCenter(w, currentLevel, currentFace);
#ifdef DEBUG
		(void) printf("solving level 1, %d %d %d\n",
			currentLevel, currentFace, ok);
#endif
		L1_E(w);
	}
	orient[0] = ORIENTTILE(1, 4);
	orient[1] = ORIENTTILE(1, 3);
	orient[2] = ORIENTTILE(1, 1);
	orient[3] = ORIENTTILE(2, 1);
	orient[4] = ORIENTTILE(2, 3); /* see if already in place */
#ifdef DEBUG
	(void) printf("1F: 1,4: %d, 1,3: %d, 1,1: %d, 2,1: %d, 2,3: %d\n",
		orient[0], orient[1], orient[2], orient[3], orient[4]);
#endif
	piece = 13;
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	if (ORIENTTILE(2, 3) != piece) {
		currentLevel = findLevelOrient(w, piece);
		currentFace = findFaceOrient(w, currentLevel, piece);
#ifdef DEBUG
		ok =
#else
		(void)
#endif
		moveToCenter(w, currentLevel, currentFace);
#ifdef DEBUG
		(void) printf("solving level 1, %d %d\n",
			currentLevel, currentFace);
#endif
		L1_F(w);
	}
	orient[0] = ORIENTTILE(1, 4);
	orient[1] = ORIENTTILE(1, 3);
	orient[2] = ORIENTTILE(1, 1);
	orient[3] = ORIENTTILE(2, 1);
	orient[4] = ORIENTTILE(2, 3); /* see if already in place */
#ifdef DEBUG
	(void) printf("1G: 1,4: %d, 1,3: %d, 1,1: %d, 2,1: %d, 2,3: %d\n",
		orient[0], orient[1], orient[2], orient[3], orient[4]);
#endif
	L1_G(w);
	orient[0] = ORIENTTILE(1, 0);
	orient[1] = ORIENTTILE(1, 4);
	orient[2] = ORIENTTILE(1, 2);
	orient[3] = ORIENTTILE(1, 1);
	orient[4] = ORIENTTILE(1, 3); /* see if already in place */
#ifdef DEBUG
	(void) printf("1H: 1,0: %d, 1,4: %d, 1,2: %d, 1,1: %d, 1,3: %d\n",
		orient[0], orient[1], orient[2], orient[3], orient[4]);
#endif
	return True;
}

static Boolean
solveL1Color(BarrelWidget w)
{
	int colors[MAX_FACES+1] = {-1, -1, -1, -1, -1, -1};
	int piece = checkLevelSolved(w, 1);

	if (piece == w->barrel.faces) {
		return True;
	}
#ifdef DEBUG
	(void) printf("solving level 1, piece %d\n", piece);
#endif
	/* rotate first column to non black, put in 9 */
	if (COLORTILE(1, 2) == w->barrel.faces) {
		if (NRANDOM(2) == 1) {
			if (COLORTILE(1, 1) != w->barrel.faces) {
				LeftTowards(w);
			} else if (COLORTILE(1, 3) == w->barrel.faces) {
				LeftTowards2(w);
			} else {
				LeftAway(w);
			}
		} else {
			if (COLORTILE(1, 3) != w->barrel.faces) {
				LeftAway(w);
			} else if (COLORTILE(1, 1) == w->barrel.faces) {
				LeftAway2(w);
			} else {
				LeftTowards(w);
			}
		}
	}
	colors[0] = w->barrel.faces;
	colors[1] = COLORTILE(1, 2);
	colors[2] = COLORTILE(2, 2);
#ifdef DEBUG
	(void) printf("1A: 1,2: %s, 2,2: %s\n",
		colorName(colors[1]),
		colorName(colors[2]));
#endif
		if (checkLastColorMatch(colors, 2)) {
			colors[2] = -1;
			/* rotate 3rd column to non black and non matching */
			colors[2] = findL1Color(w, colors);
			L1_B(w);
		} else {
			LeftAway(w);
		}
		colors[3] = COLORTILE(2, 4); /* see if already in place */
#ifdef DEBUG
		(void) printf("1B: 1,1: %s, 2,1: %s, 2,4: %s\n",
			colorName(colors[1]),
			colorName(colors[2]),
			colorName(colors[3]));
#endif
		LeftTowards2(w);
		if (checkLastColorMatch(colors, 3)) {
			colors[3] = -1;
			/* rotate 3rd column to non black and non matching */
			colors[3] = findL1Color(w, colors);
			L1_E(w);
		}
#ifdef DEBUG
		(void) printf("1C: 1,3: %s, 2,3: %s, 2,1: %s\n",
			colorName(colors[1]),
			colorName(colors[2]),
			colorName(colors[3]));
#endif
		L1_D(w);
		colors[4] = COLORTILE(2, 1); /* see if already in place */
#ifdef DEBUG
		(void) printf("1E: 1,4: %s, 1,3: %s, 1,1: %s, 2,1: %s\n",
			colorName(colors[1]),
			colorName(colors[2]),
			colorName(colors[3]),
			colorName(colors[4]));
#endif
#if 1
		if (checkLastColorMatch(colors, 4)) {
			colors[4] = -1;
			/* rotate 3rd column to non black and non matching */
			colors[4] = findL1Color(w, colors);
			L1_E(w);
		}
		colors[5] = COLORTILE(2, 3); /* see if already in place */
#ifdef DEBUG
		(void) printf("1F: 1,4: %s, 1,3: %s, 1,1: %s, 2,1: %s, 2,3: %s\n",
			colorName(colors[1]),
			colorName(colors[2]),
			colorName(colors[3]),
			colorName(colors[4]),
			colorName(colors[5]));
#endif
		if (checkLastColorMatch(colors, 5)) {
			colors[5] = -1;
			/* rotate 3rd column to non black and non matching */
			colors[5] = findL1Color(w, colors);
			L1_F(w);
		}
#ifdef DEBUG
		(void) printf("1G: 1,4: %s, 1,3: %s, 1,1: %s, 2,1: %s, 2,3: %s\n",
			colorName(colors[1]),
			colorName(colors[2]),
			colorName(colors[3]),
			colorName(colors[4]),
			colorName(colors[5]));
#endif
		L1_G(w);
	piece = checkLevelSolved(w, 1);
	if (piece != w->barrel.faces) {
		(void) printf("Error in level 1, aborting, %d\n", piece);
		return False;
	}
#endif
	return True;
}

static Boolean
solveL2(BarrelWidget w)
{
	/*int faces[MAX_FACES] = {1, 3, 2, 0, 5};*/
	int piece = checkLevelSolved(w, 2);

	if (piece == w->barrel.faces) {
		return True;
	}
#ifdef DEBUG
	(void) printf("solving level 2, piece %d\n", piece);
#endif
	{
		piece = GETSOLVEDTILE(2, 1);
		if (piece != SOLVEDTILE(2, 1)) {
			/* rotate 3rd column to non black and non matching */
			piece = findL2(w, piece);
			if (piece == w->barrel.faces) {
				(void) printf("error in level 2");
				return False;
			}
			LeftTowards(w);
			L2_3222(w)
			LeftAway(w);
		}
		piece = GETSOLVEDTILE(2, 3);
		if (piece != SOLVEDTILE(2, 3)) {
			/* rotate 3rd column to non black and non matching */
			piece = findL2(w, piece);
			if (piece == w->barrel.faces) {
				(void) printf("error in level 2");
				return False;
			}
			LeftAway(w);
			L2_3222(w)
			LeftTowards(w);
		}
		piece = GETSOLVEDTILE(2, 2);
		if (piece != SOLVEDTILE(2, 2)) {
			/* rotate 3rd column to non black and non matching */
			piece = findL2(w, piece);
			if (piece == w->barrel.faces) {
				(void) printf("error in level 2");
				return False;
			}
			L2_3222(w)
		}
		piece = GETSOLVEDTILE(2, 0);
		if (piece != SOLVEDTILE(2, 0)) {
			/* rotate 3rd column to non black and non matching */
			piece = findL2(w, piece);
			if (piece == w->barrel.faces) {
				(void) printf("error in level 2");
				return False;
			}
			LeftTowards2(w);
			L2_3222(w)
			LeftAway2(w);
		}
		piece = GETSOLVEDTILE(2, 4);
		if (piece != SOLVEDTILE(2, 4)) {
			/* rotate 3rd column to non black and non matching */
			piece = findL2(w, piece);
			if (piece == w->barrel.faces) {
				(void) printf("error in level 2");
				return False;
			}
			LeftAway2(w);
			L2_3222(w)
			LeftTowards2(w);
		}
	}
	return True;
}

static Boolean
solveL3Color(BarrelWidget w)
{
	int piece = checkLevelSolved(w, 3);

	if (piece == w->barrel.faces) {
		return True;
	}
#ifdef DEBUG
	(void) printf("solving level 3, piece %d\n", piece);
#endif
	if (!solveRightColor(w, 3, 2))
		return False;
	if (NRANDOM(2) == 1) {
		if (!solveRightColor(w, 3, 1))
			return False;
		if (!solveRightColor(w, 3, 3))
			return False;
	} else {
		if (!solveRightColor(w, 3, 3))
			return False;
		if (!solveRightColor(w, 3, 1))
			return False;
	}
	if (NRANDOM(2) == 1) {
		if (!solveRightColor(w, 3, 0))
			return False;
		if (!solveRightColor(w, 3, 4))
			return False;
	} else {
		if (!solveRightColor(w, 3, 4))
			return False;
		if (!solveRightColor(w, 3, 0))
			return False;
	}
	return True;
}

static Boolean
solveL5Color(BarrelWidget w)
{
	int piece = checkLevelSolved(w, 5);

	if (piece == w->barrel.faces) {
		return True;
	}
#ifdef DEBUG
	(void) printf("solving level 5, piece %d\n", piece);
#endif
	if (!solveRightColor(w, 5, 2))
		return False;
	if (NRANDOM(2) == 1) {
		if (!solveRightColor(w, 5, 0))
			return False;
		if (!solveRightColor(w, 5, 4))
			return False;
	} else {
		if (!solveRightColor(w, 5, 4))
			return False;
		if (!solveRightColor(w, 5, 0))
			return False;
	}
	return True;
}

static Boolean
solveL4Color(BarrelWidget w)
{
	int piece = checkLevelSolved(w, 4);

	if (piece == w->barrel.faces) {
		return True;
	}
#ifdef DEBUG
	(void) printf("solving level 4, piece %d\n", piece);
#endif
	if (!solveRightColor(w, 4, 2))
		return False;
	if (NRANDOM(2) == 1) {
		if (!solveRightColor(w, 4, 1))
			return False;
		if (!solveRightColor(w, 4, 3))
			return False;
	} else {
		if (!solveRightColor(w, 4, 3))
			return False;
		if (!solveRightColor(w, 4, 1))
			return False;
	}
	if (NRANDOM(2) == 1) {
		if (!solveRightColor(w, 4, 0))
			return False;
		if (!solveRightColor(w, 4, 4))
			return False;
	} else {
		if (!solveRightColor(w, 4, 4))
			return False;
		if (!solveRightColor(w, 4, 0))
			return False;
	}
	return True;
}

/* This procedure coordinates the solution process. */
void
solveSomeTiles(BarrelWidget w)
{
	setPuzzle(w, ACTION_RESET);
#ifdef JMP
	if (!setjmp(solve_env))
#endif
	{
		solvingFlag = True;
		if (!checkSolved(w)) {
			solveL0(w);
			if (w->barrel.orient) {
				/* work in progress */
				if (!solveL1Orient(w))
					return;
				if (!solveL2(w))
					return;
#if 0
				if (!solveL3Orient(w))
					return;
				if (!solveL5Orient(w))
					return;
				if (!solveL4Orient(w))
					return;
#endif
			} else {
				if (!solveL1Color(w))
					return;
				if (!solveL2(w))
					return;
#if 1
				if (!solveL3Color(w))
					return;
				if (!solveL5Color(w))
					return;
				if (!solveL4Color(w))
					return;
#endif
			}
		}
	}
#ifdef JMP
	else {
		drawAllTiles(w);
	}
	abortSolvingFlag = False;
#endif
	solvingFlag = False;
	w->barrel.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_COMPUTED);
}
