/*
 * @(#)MballS.c
 *
 * Break ability taken from the X puzzle by Don Bennett, HP Labs
 *
 * Copyright 2010  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.
 */

/* Many ideas found at
  http://wsd.com/masterball now offline, but thanks to wayback machine see
  http://web.archive.org/web/20041025133454/wsd.com/masterball
  Also
  http://www.permutationpuzzles.org/rubik/mball/rainbow.html
  just make sure you subtract 1 as I start from 0.
  And
  http://www.jaapsch.net/puzzles/masterball.html
 */

/* Solver file for Mball */

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

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

/* r-> rotate */
#define rCW(w,b) movePuzzlePiece(w,0,b,CW,FALSE)
#define rCCW(w,b) movePuzzlePiece(w,0,b,CCW,FALSE)
/* f -> flip */
#define f(w,i) movePuzzlePiece(w,i,0,mapWedgeToDir[(w->mball.wedges-\
 MIN_WEDGES)/2][i],FALSE)
#define fo(w,i,o) f(w,(i+o+w->mball.wedges)%w->mball.wedges)

#define rPuzzleCW(w,b) movePuzzlePiece(w,0,b,CW,TRUE)
#define rPuzzleCCW(w,b) movePuzzlePiece(w,0,b,CCW,TRUE)
#define fPuzzle(w,i) movePuzzlePiece(w,i,0,mapWedgeToDir[(w->mball.wedges-\
 MIN_WEDGES)/2][i],TRUE)

/* i is positive, j can be negative but not less than -(# wedges) */
#define ringAdd(w,i,j) ((i+j+w->mball.wedges)%w->mball.wedges)

static void
movePuzzlePiece(MballWidget w, int wedge, int band,
	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, wedge, band, direction, control);
}

static void
rnCW(MballWidget w, int b, int n)
{
	int i;

	for (i = 0; i < n; i++) {
		rCW(w, b);
	}
}

static void
rnCCW(MballWidget w, int b, int n)
{
	int i;

	for (i = 0; i < n; i++) {
		rCCW(w, b);
	}
}

static void
rnHalf(MballWidget w, int b)
{
	int i;

	if (NRAND(2) == 0) {
		for (i = 0; i < w->mball.wedges / 2; i++) {
			rCW(w, b);
		}
	} else {
		for (i = 0; i < w->mball.wedges / 2; i++) {
			rCCW(w, b);
		}
	}
}

static void
rNHalfCW(MballWidget w)
{
	int i;

	for (i = 0; i < w->mball.bands / 2; i++) {
		rCW(w, i);
	}
}

static void
rNHalfCCW(MballWidget w)
{
	int i;

	for (i = 0; i < w->mball.bands / 2; i++) {
		rCCW(w, i);
	}
}

static void
rNHalfHalf(MballWidget w)
{
	if (NRAND(2) == 0) {
		rNHalfCW(w);
	} else {
		rNHalfCCW(w);
	}
}

static void
rSHalfCW(MballWidget w)
{
	int i;

	for (i = w->mball.bands - 1; i >= (w->mball.bands + 1) / 2; i--) {
		rCW(w, i);
	}
}

static void
rSHalfCCW(MballWidget w)
{
	int i;

	for (i = w->mball.bands - 1; i >= (w->mball.bands + 1) / 2; i--) {
		rCCW(w, i);
	}
}

static void
rSHalfHalf(MballWidget w)
{
	if (NRAND(2) == 0) {
		rSHalfCW(w);
	} else {
		rSHalfCCW(w);
	}
}

#ifdef EXTRA
static void
rNPoleCW(MballWidget w, int b)
{
	int i;

	for (i = 0; i <= b; i++) {
		rCW(w, i);
	}
}

static void
rNPoleCCW(MballWidget w, int b)
{
	int i;

	for (i = 0; i <= b; i++) {
		rCCW(w, i);
	}
}

static Boolean
allTop(MballWidget w)
{
	int tz, band;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		for (band = 0; band < w->mball.bands; band++) {
			if (w->mball.mballLoc[tz][band].direction == 1) {
				return False;
			}
		}
	}
	return True;
}
#endif

static int
wedgeFromPosition(MballWidget w, int position)
{
	return position % w->mball.wedges;
}

static int
bandFromPosition(MballWidget w, int position)
{
	return position / w->mball.wedges;
}

static int
findColor(MballWidget w, int wedgeColor, int band)
{
	int i, tz, b;

	for (i = 0; i < 2; i++) {
		/* only check the 2 bands that are possible */
		if (i == 0)
			b = band;
		else
			b = w->mball.bands - 1 - band;
		for (tz = 0; tz < w->mball.wedges; tz++) {
			if (wedgeColor == w->mball.mballLoc[tz][b].wedge) {
#ifdef DEBUG
				(void) printf("Color for wedge %d, band %d is %d\n", tz, b, wedgeColor);
#endif
				if (w->mball.orient) {
					if ((i == 0 && w->mball.mballLoc[tz][b].direction == 1) ||
							(i == 1 && w->mball.mballLoc[tz][b].direction == 0))
						continue;
				} else { /* finding solved portion */
					if (tz <= wedgeColor && b < band)
						continue;
				}
				return tz + b * w->mball.wedges;
			}
		}
	}
	(void) printf("Color not found for %d %d\n", wedgeColor, band);
	return w->mball.wedges * w->mball.bands;
}

static int
findOppSameLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges / 2; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[tz + w->mball.wedges / 2][band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findAdjOppLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + 1) % w->mball.wedges][w->mball.bands - 1 - band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findNextAdjSameLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + 2) % w->mball.wedges][band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findAdjOppOppLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + w->mball.wedges / 2 - 1) % w->mball.wedges][w->mball.bands - 1 - band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findAdjSameLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + 1) % w->mball.wedges][band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findOppOppLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + w->mball.wedges / 2) % w->mball.wedges][w->mball.bands - 1 - band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findAdjOppSameLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + w->mball.wedges / 2 - 1) % w->mball.wedges][band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static int
findNextAdjOppLat(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges; tz++) {
		if (w->mball.mballLoc[tz][band].wedge ==
				w->mball.mballLoc[(tz + 2) % w->mball.wedges][w->mball.bands - 1 - band].wedge) {
			return tz;
		}
	}
	return w->mball.wedges;
}

static Boolean
checkBandSolved(MballWidget w, int band)
{
	int tz;

	for (tz = 0; tz < w->mball.wedges - 1; tz++) {
		if (w->mball.mballLoc[tz][band].wedge !=
				w->mball.mballLoc[tz][w->mball.bands - 1 - band].wedge) {
			return FALSE;
		}
	}
	return TRUE;
}

static Boolean
checkSegmentSolved(MballWidget w, int wedge, int band, int lat)
{
	return (w->mball.mballLoc[wedge][lat].wedge ==
			w->mball.mballLoc[wedge][band].wedge);
}

#ifdef EXTRA
/* swaps 4 for 4 wedges, diagonal */
static void
swap4by4d(MballWidget w)
{
	rCCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
	rCW(w, 0);
	f(w, 3);
	rCW(w, 0);
	f(w, 3);
	rCCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
	rCW(w, 0);
	f(w, 3);
	rCW(w, 0);
	f(w, 3);
	rCCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
	rCW(w, 0);
	f(w, 3);
	rCW(w, 0);
	f(w, 3);
	rCCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
}

/* swaps 4 for 4 wedges, diag, moves 2 to bottom and 2 to top */
static void
swap4by4op(MballWidget w, int wedge, int band)
{
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
}

/* swaps 4 for 4 wedges, adj, moves 2 to bottom and 2 to top */
static void
swap4by4(MballWidget w)
{
	rCW(w, 0);
	f(w, 0);
	rnCW(w, 0, 2);
	f(w, 0);
	rnCW(w, 0, 2);
	f(w, 0);
	rCW(w, 0);
	f(w, 0);
}

/* swaps 2 for 4 wedges, swap 2&3, 30 moves */
/* Interesting thing is in a different order (say cw first then ccw) */
/* it is period 24 but here its period 60. */
static void
swap2by4(MballWidget w)
{
	int i;

	for (i = 0; i < 7; i++) {
		rCCW(w, 0);
		f(w, 2);
		rCW(w, 0);
		f(w, 3);
	}
	rCCW(w, 0);
	f(w, 2);
}

/* 1,0 -> 2,0  1,1 -> 1,0  2, 0 -> 1, 1 */
static void
flipFor4_3(MballWidget w, int wedge, int band)
{
	/* 0 1 -1  0 -1 0  0 -1 0  0 1 1  0 -1 0  0 -1 0 */
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCW(w, band);
}

/* flip bottom 0 & 1 wedge */
static void
flipFor4a(MballWidget w, int wedge, int band)
{
#ifdef DEBUG
	(void) printf("flipFor4a %d %d\n", wedge, band);
#endif
	/* 0 0 -1  0 -1 0  0 1 0  0 1 1  0 1 0  0 -1 0 */
	f(w, wedge);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCW(w, band);
}
#endif

/* flip first for 4, flip 0th top wedge and 3rd bottom (diagonal) */
static void
flipFor4d(MballWidget w, int wedge, int band)
{
	/* 0 1 0  0 1 -1  0 -1 0  0 1 -1  0 1 0  0 1 -1 */
#ifdef DEBUG
	(void) printf("flipFor4d %d %d\n", wedge, band);
#endif
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
}

/* flip 0th wedge */
static void
flipFor4w(MballWidget w, int wedge, int band)
{
	/* 0 0 -1  0 1 0  0 1 -1  0 1 0  0 1 -1  0 -1 0  0 1 0  0 0 0 */
#ifdef DEBUG
	(void) printf("flipFor4w %d %d\n", wedge, band);
#endif
	f(w, wedge);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
}

/* flip 4 0th & 5th wedges */
static void
flipFor6_4(MballWidget w, int wedge, int band)
{
	/* 0 0 -1  0 -1 1  0 1 0  0 0 0 */
#ifdef DEBUG
	(void) printf("flipFor6_4 %d %d\n", wedge, band);
#endif
	f(w, wedge);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
}

/* flip 2 3rd bottom & 5th top wedges */
static void
flipFor6_4s(MballWidget w, int wedge, int band)
{
	/* 0 1 2  0 1 0  0 -1 -2  0 1 2  0 2 0  0 -1 -2 */
#ifdef DEBUG
	(void) printf("flipFor6_4s %d %d\n", wedge, band);
#endif
	f(w, wedge);
	rCCW(w, band);
	rnCCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCCW(w, band);
	rnCCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rnCCW(w, band, 2);
	f(w, wedge);
	rCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
}

/* flip 4 1st & 5th wedges */
static void
flipFor6_4sm(MballWidget w, int wedge, int band)
{
	/* 0 0 0  0 1 0  0 -2 0  0 1 -1  0 1 1  0 -1 0 */
#ifdef DEBUG
	(void) printf("flipFor6_4sm %d %d\n", wedge, band);
#endif
	rCCW(w, band);
	f(w, wedge);
	rnCW(w, band, 2);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
}

/* flip 1st top & 1st bottom */
static void
flipFor6w(MballWidget w, int wedge, int band)
{
#ifdef DEBUG
	(void) printf("flipFor6w %d %d\n", wedge, band);
#endif
	/* 0 1 2  0 -1 -1  0 1 2  0 -1 -2  0 1 -2  0 -1 -2 */
	f(w, wedge);
	rCCW(w, band);
	rnCCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rnCCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
}

#ifdef EXTRA
/* 123 -> 231 */
static void
flipFor6_3(MballWidget w, int wedge, int band)
{
	/* 0 1 -1  0 1 0  0 -1 0  0 1 0  0 1 0  0 0 0  0 -1 1  0 -1 -1  0 -1 1  0 0 0 */
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
}

/* 123 -> 312 */
static void
flipFor6_3r(MballWidget w, int wedge, int band)
{
	f(w, wedge);
	rCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
}

/* flip 3 4th top & bottom & 5th wedge top */
static void
flipFor6_3f(MballWidget w, int wedge, int band)
{
	/* 0 0 1  0 -1 1  0 1 -1  0 -1 0  0 -1 0  0 1 0  0 1 -1  0 0 0 */
	f(w, wedge);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	f(w, wedge);
	rCCW(w, band);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
}

/* flip 0th top & 5th bottom */
static void
flipFor6d(MballWidget w, int wedge, int band)
{
#ifdef DEBUG
	(void) printf("flipFor6d %d %d\n", wedge, band);
#endif
	/* 0 0 1  0 -1 -2  0 -2 -1  0 -2 0  0 2 1  0 1 2 */
	f(w, wedge);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCW(w, band);
	rnCW(w, w->mball.bands - 1 - band, 2);
	f(w, wedge);
	rnCW(w, band, 2);
	rCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rnCW(w, band, 2);
	f(w, wedge);
	rnCCW(w, band, 2);
	rCCW(w, w->mball.bands - 1 - band);
	f(w, wedge);
	rCCW(w, band);
	rnCCW(w, w->mball.bands - 1 - band, 2);
}

/* I found this 8+4 move one... ok probably not the first.  :) */
/* it flips 3, 4 both on top and flips 7 on top with 3 on bottom */
static void
simpleSwap(MballWidget w)
{
	rnCW(w, 2, 4);
	rnCW(w, 3, 4);
	rCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
	rCCW(w, 0);
	f(w, 0);
	rCW(w, 0);
	f(w, 0);
	rnCW(w, 2, 4);
	rnCW(w, 3, 4);
}
#endif

/* post part of threeOut move I found */
static void
threeOut1(MballWidget w, int wedge, int band)
{
	int b = w->mball.bands - 1 - band;
	int tz = (wedge + 7) % w->mball.wedges;
	int lon = wedge;

/* f2 *r1*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r4*f1 *f2 */
	rCW(w, band); f(w, lon);
	rCCW(w, band); f(w, lon);
	rCCW(w, b); f(w, lon);
	rCW(w, b); f(w, lon);
	f(w, tz);
}

/* I found this 10 move for 3 out by accident.  :)
   2 moves added to make it pretty. */
/* lower band 2 -> 4, 3 -> 2, 4 -> 3; 10 moves */
static void
threeOut(MballWidget w, int wedge, int band)
{
	int tz = (wedge + 7) % w->mball.wedges;

/* f2 *r1*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r4*f1 *f2 */
	f(w, tz);
	threeOut1(w, wedge, band);
}

#ifdef EXTRA
/* Combining above threeOut and a rotation. */
/* lower band 2 -> 5, 5 -> 2; 31 moves */
static void
twoOut(MballWidget w, int wedge, int band)
{
/* f2 *r1*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r4*f1 *f2
*f7 *r1*f6 *r1^(-1)*f6 *r4^(-1)*f6 *r4*f6 *f7
*f5 *r1*f4 *r1^(-1)*f4 *r4^(-1)*f4 *r4*f4 *f5
*r4 */
	threeOut(w, wedge, band);
	threeOut(w, (wedge + 3) % w->mball.wedges, band);
	threeOut(w, (wedge + 5) % w->mball.wedges, band);
	rCW(w, w->mball.bands - 1 - band);
}
#endif

/* Small changes to help save 2 moves */
static void
twoOut1(MballWidget w, int wedge, int band)
{
/* r1*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r4*f1 *f2
*f7 *r1*f6 *r1^(-1)*f6 *r4^(-1)*f6 *r4*f6 *f7
*f5 *r1*f4 *r1^(-1)*f4 *r4^(-1)*f4 *r4*f4 *f5
*r4 */
	threeOut1(w, (wedge + 1) % w->mball.wedges, band);
	threeOut(w, (wedge + 4) % w->mball.wedges, band);
	threeOut(w, (wedge + 6) % w->mball.wedges, band);
	rCW(w, w->mball.bands - 1 - band);
}

#ifdef EXTRA
/* 37 moves to flip just one wedge band */
static void
flipWedgeSegment(MballWidget w, int wedge, int band)
{
	int tz = (wedge + 7) % w->mball.wedges;
	int lon = (wedge + 4) % w->mball.wedges;

/* r4^(-2)*f3
*f2 *r1*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r4*f1 *f2
*f7 *r1*f6 *r1^(-1)*f6 *r4^(-1)*f6 *r4*f6 *f7
*f5 *r1*f4 *r1^(-1)*f4 *r4^(-1)*f4 *r4*f4 *f5
*r4
*f3 *r4^2 */
	rnCCW(w, band, 2); f(w, tz);
	twoOut(w, lon, band);
	f(w, tz);
	rnCW(w, band, 2);
}
#endif

/* Slight improvement, 35 moves to flip just one wedge band */
static void
flipWedgeSegment1(MballWidget w, int wedge, int band)
{
	int b = w->mball.bands - 1 - band;

/* r4^(-2)
    *r1*f0 *r1^(-1)*f0 *r4^(-1)*f0 *r4*f0 *f1
*f6 *r1*f5 *r1^(-1)*f5 *r4^(-1)*f5 *r4*f5 *f6
*f4 *r1*f3 *r1^(-1)*f3 *r4^(-1)*f3 *r4*f3 *f4
*r4
*f1 *r4^2 */
	rnCCW(w, b, 2);
	twoOut1(w, wedge, band);
	f(w, wedge);
	rnCW(w, b, 2);
}

#ifdef EXTRA
/* saturn move got from www.jaapsch.net/puzzles/saturn.htm
  A/A/C/A/A A A/A/C/A/A
  Not sure if it works as described... seem to make then numbers
  counterclockwise and there is an extra twist.
*/
static void
saturnMove(MballWidget w, int wedge, int band)
{
	int tz = (wedge + w->mball.wedges / 2) % w->mball.wedges;

	rCCW(w, band); f(w, tz);
	rCCW(w, band); f(w, tz);
	rCW(w, band); f(w, tz);
	rCCW(w, band); f(w, tz);
	rnCCW(w, band, 3); f(w, tz);
	rCCW(w, band); f(w, tz);
	rCW(w, band); f(w, tz);
	rCCW(w, band); f(w, tz);
	rCCW(w, band); f(w, tz);
}

/* Described by David Joyner works similar for both 10 and 12 wedges */
/* http://www.usna.edu/Users/math/wdj/mball/puck.htm */
static void
puckMove(MballWidget w, int wedge)
{
/* (f1*f2*f3*f4*f5*f6)^2 */
	f(w, wedge);
	fo(w, wedge, 1);
	fo(w, wedge, 2);
	fo(w, wedge, 3);
	fo(w, wedge, 4);
	fo(w, wedge, 5);
	f(w, wedge);
	fo(w, wedge, 1);
	fo(w, wedge, 2);
	fo(w, wedge, 3);
	fo(w, wedge, 4);
	fo(w, wedge, 5);
}
#endif

/* these Saturn moves are my own... I removed the rotation by changing
flips and took some starting moves above but changed to make work. */

/* Also 2 pair move is sometimes needed and this is not mentioned in
above web site. */
/* Saturn move 01/34 */
static void
saturn2Pair(MballWidget w, int tz)
{
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 7);
	f(w, tz);
	fo(w, tz, 7);
	fo(w, tz, 6);
	fo(w, tz, 7);
	fo(w, tz, 5);
	f(w, tz);
	fo(w, tz, 6);
	fo(w, tz, 7);
}

/* 0 -> 2, 12 -> 01_ */
static void
saturn3Jump(MballWidget w, int tz)
{
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 7);
	fo(w, tz, 5);
	f(w, tz);
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 7);
	f(w, tz);
	fo(w, tz, 6);
	fo(w, tz, 7);
	f(w, tz);
	fo(w, tz, 7);
}

/* 2 -> 0, 10_ -> 21 */
static void
saturn3JumpBack(MballWidget w, int tz)
{
	fo(w, tz, 7);
	f(w, tz);
	fo(w, tz, 7);
	fo(w, tz, 6);
	f(w, tz);
	fo(w, tz, 7);
	fo(w, tz, 5);
	fo(w, tz, 6);
	f(w, tz);
	fo(w, tz, 5);
	fo(w, tz, 7);
	fo(w, tz, 5);
	fo(w, tz, 6);
	fo(w, tz, 5);
	fo(w, tz, 6);
}

/* This will swap 2 wedges side by side, but only if even number of bands */
static void
swapEven(MballWidget w, int tz)
{
	fo(w, tz, 5);
	rNHalfCCW(w);
	fo(w, tz, 5);
	rNHalfCW(w);
	rSHalfCCW(w);
	fo(w, tz, 5);
	rSHalfCW(w);
	fo(w, tz, 5);
}

#ifdef EXTRA
static void
longSwapAdj34(MballWidget w)
{
/* f1 *r3*r4*f2*f4 *r1*r4^(-1)*f4 *r4^4*f4
  *r4*r1^(-1)*f4 *r4^4*f2 *r3^(-1)*r4^(-1)*f1 */
	f(w, 0);
	rCW(w, 2); rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCCW(w, 3); f(w, 5);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 5);
	rCW(w, 3); rCCW(w, 0); f(w, 5);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 7);
	rCCW(w, 2); rCCW(w, 3); f(w, 0);
}

/* swap wedges 3 & 4 for both bands */
static void
swapAdj34(MballWidget w)
{
/* f1 *r1*f4 *r1^(-1)*r4*f4 *r4^(-1)*f1 */
	f(w, 0);
	rCW(w, 0); f(w, 5);
	rCCW(w, 0); rCW(w, 3); f(w, 5);
	rCCW(w, 3); f(w, 0);
}
#endif

/* swap wedges from opposite sides for 0 & 4 for both bands */
static void
swapOp04(MballWidget w, int wedge, int band)
{
/* r1*f4 *r1^(-1)*r4*f4 *r4^(-1) */
	int b = w->mball.bands - 1 - band;
	int tz = (wedge + 5) % w->mball.wedges;

	rCW(w, band); f(w, tz);
	rCCW(w, band); rCW(w, b); f(w, tz);
	rCCW(w, b);
}

/* swapOp04 with rotation */
static void
flipOppSegments(MballWidget w, int wedge, int band)
{
	rnHalf(w, band);
	swapOp04(w, wedge, band);
	rnHalf(w, band);
}

#ifdef EXTRA
/* Pretty Patterns */
static void
quadrantizedPattern(MballWidget w)
{
/* r3^4*r4^4*f1 *r3^2*r4^2*f2 *r3^2*r4^2*f3 */
	rnHalf(w, 2); rnHalf(w, 3); f(w, 0);
	rnCW(w, 2, 2); rnCW(w, 3, 2); f(w, 7);
	rnCW(w, 2, 2); rnCW(w, 3, 2); f(w, 6);
}

static void
bandedPattern(MballWidget w)
{
/* r1^4*r3^4*f1 *r1^2*r3^2*f2 *r1^2*r3^2*f3 */
	rnHalf(w, 0); rnHalf(w, 2); f(w, 0);
	rnCW(w, 0, 2); rnCW(w, 2, 2); f(w, 7);
	rnCW(w, 0, 2); rnCW(w, 2, 2); f(w, 6);
}

static void
move0(MballWidget w)
{
/* move1=r1*r3*f1 *r1^(-1)*r3^(-1)*f7*f2, */
	rCW(w, 0); rCW(w, 2); f(w, 0);
	rCCW(w, 0); rCCW(w, 2); f(w, 2); f(w, 7);
}

static void
move1(MballWidget w)
{
/* move2=r1*r3*f1 *r1^(-1)*r3^(-1)*f1, */
	rCW(w, 0); rCW(w, 2); f(w, 0);
	rCCW(w, 0); rCCW(w, 2); f(w, 0);
}

static void
move2(MballWidget w)
{
/* move3=r1*r3*f3 *r1^(-1)*r3^(-1)*f4*f5, */
	rCW(w, 0); rCW(w, 2); f(w, 6);
	rCCW(w, 0); rCCW(w, 2); f(w, 5); f(w, 4);
}

static void
move3(MballWidget w)
{
/* move4=r1*r3*f2 *r1^(-1)*r3^(-1)*f2, */
	rCW(w, 0); rCW(w, 2); f(w, 7);
	rCCW(w, 0); rCCW(w, 2); f(w, 7);
}

static void
move4(MballWidget w)
{
/* move5=f3*f4*f5*f6 *f3*f4*f5*f6 *r1*r2*r3*r4 (swaps columns 1,2), */
	f(w, 6); f(w, 5); f(w, 4); f(w, 3);
	f(w, 6); f(w, 5); f(w, 4); f(w, 3);
	rCW(w, 0); rCW(w, 1); rCW(w, 2); rCW(w, 3);
}

static void
move5(MballWidget w)
{
/* move6=f4*f5*f6*f7 *f4*f5*f6*f7 *r1*r2*r3*r4 (swaps columns 2,3) */
	f(w, 5); f(w, 4); f(w, 3); f(w, 2);
	f(w, 5); f(w, 4); f(w, 3); f(w, 2);
	rCW(w, 0); rCW(w, 1); rCW(w, 2); rCW(w, 3);
}

/* 50 moves */
static void
checkeredPattern(MballWidget w)
{
/* checkered=move1*move2*move3*move4*move5*move6 */
	move0(w); move1(w); move2(w); move3(w); move4(w); move5(w);
}

/* 50 moves (5,6,7), not found in rainbow.doc but in rainbo12.log */
static void
long3Cycle(MballWidget w)
{
/*long3Cycle=f2 *r1*f4 *r1^(-2)*f4 *r4^(-1)*f4
  *r1*f4 *r4^(-1)*f4 *r1^(-2)*f4 *r4*f4
  *r1^2*f4 *r4^(-1)*f4 *r1*f4 *r4^2*f4
  *r1^(-1)*f4 *r4^(-2)*f4 *r1^(-1)*f4 *r4*f4
  *r1^2*f4 *r4^(-1)*f4 *r1^(-1)*f4 *r4*f4
  *r1*f4 *r4*r1^(-1)*f2 */
	f(w, 7);
	rCW(w, 0); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCW(w, 3); rCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCCW(w, 3); rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCW(w, 3); rCCW(w, 0); f(w, 7);
}

/* 7 * 44 moves -> 3 out */
static void
long3OutSwap(MballWidget w)
{
	f(w, 7);
	rCW(w, 0); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCCW(w, 3); f(w, 5);
	rCCW(w, 0); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCW(w, 0); f(w, 5);
	rCW(w, 3); rCCW(w, 0); f(w, 7);
}

/* this swaps 1 & 6 small segments on top but
  also swaps wedge 3 upper and lower */
static void
polar2Swap16(MballWidget w)
{
/* polar2swap36=f1 *r3^(-1)*r4^(-1)*f1*f2 *r1*r4^(-1)*f2 *r4^4*f2
  *r1^(-1)*r4*f2 *r4^4*f1 *r3*r4*f1 */
/* (if you replace r3 by r2 both times in this move you get the same
 effect) */
	f(w, 0);
	rCCW(w, 2); rCCW(w, 3); f(w, 0); f(w, 7);
	rCW(w, 0); rCCW(w, 3); f(w, 7);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 7);
	rCCW(w, 0); rCW(w, 3); f(w, 7);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 0);
	rCW(w, 2); rCW(w, 3); f(w, 0);
}

/* this swaps 3 & 4 small segments on top but
  also swaps wedge 6 upper and lower */
static void
polar2Swap34(MballWidget w)
{
/* polar2swap18=f1 *r3^(-1)*r4^(-1)*f3*f4 *r1*r4^(-1)*f4 *r4^4*f4
  *r1^(-1)*r4*f4 *r4^4*f3 *r3*r4*f1 */
	f(w, 0);
	rCCW(w, 2); rCCW(w, 3); f(w, 6); f(w, 5);
	rCW(w, 0); rCCW(w, 3); f(w, 5);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 5);
	rCCW(w, 0); rCW(w, 3); f(w, 5);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 6);
	rCW(w, 2); rCW(w, 3); f(w, 0);
}

static void
equator2Swap16(MballWidget w)
{
/* equator2swap36=f1 *r4^(-1)*r3^(-1)*f1*f2 *r2*r3^(-1)*f2 *r3^4*f2
  *r2^(-1)*r3*f2 *r3^4*f1 *r4*r3*f1 */
	f(w, 0);
	rCCW(w, 3); rCCW(w, 2); f(w, 0); f(w, 7);
	rCW(w, 1); rCCW(w, 2); f(w, 7);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 7);
	rCCW(w, 1); rCW(w, 2); f(w, 7);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 0);
	rCW(w, 3); rCW(w, 2); f(w, 0);
}

static void
equator2Swap34(MballWidget w)
{
/* equator2swap18=f1 *r4^(-1)*r3^(-1)*f3*f4 *r2*r3^(-1)*f4 *r3^4*f4
 *r2^(-1)*r3*f4 *r3^4*f3 *r4*r3*f1 */
	f(w, 0);
	rCCW(w, 3); rCCW(w, 2); f(w, 6); f(w, 5);
	rCW(w, 1); rCCW(w, 2); f(w, 5);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 5);
	rCCW(w, 1); rCW(w, 2); f(w, 5);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 6);
	rCW(w, 3); rCW(w, 2); f(w, 0);
}

/* 2 * 98 moves -> 4 out, correct PDF? */
static void
nsMidSwap(MballWidget w)
{
/* NSmid_swap=r3*r2*f1 *r2*f1 *r3*f1 *r2^(-1)*f1 *r3^(-2)*f1
  *r2*f1 *r3*f1 *r2^(-1)*f1 *r3^4*f1
  *r2*f1 *r3*f1 *r2^(-1)*f1 *r3^(-2)*f1 *r2*f1
  *r3^2*f1 *r2^(-1)*f1 *r3^2*f1 *r2*f1
  *r3^(-1)*f1 *r2^(-1)*f1 *r3^(-1)*f1 *r2*f1
  *r3*f1 *r2^(-1)*f1 *r2*r3^(-2)*f1 *r2^(-1)*f1
  *r3^(-1)*f1 *r2*f1 *r2^(-1)*f1 *r3*f1 *r2*f1
  *r2^(-1)*f1 *r2*f1 *r3^2*f1
  *r2^(-1)*f1 *r2*f1 *r2^(-1)*f1 *r2*r3^(-1)*f1
  *r2^(-1)*f1 *r3*f1 *r2*f1 *r2^(-2)*r3^2 */
	rCW(w, 2); rCW(w, 1); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCCW(w, 2); rCCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCCW(w, 2); rCCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 2); rCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 1); rCCW(w, 2); rCCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCW(w, 2); rCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 1); rCCW(w, 2); f(w, 0);
	rCCW(w, 1); f(w, 0);
	rCW(w, 2); f(w, 0);
	rCW(w, 1); f(w, 0);
	rCCW(w, 1); rCCW(w, 1); rCW(w, 2); rCW(w, 2);
}

/* 2 * 98 moves -> 4 out, correct PDF? */
static void
nsSwap(MballWidget w)
{
/* NS_swap=r4*r1*f1 *r1*f1 *r4*f1 *r1^(-1)*f1 *r4^(-2)*f1
  *r1*f1 *r4*f1 *r1^(-1)*f1 *r4^44*f1
  *r1*f1 *r4*f1 *r1^(-1)*f1 *r4^(-2)*f1 *r1*f1
  *r4^2*f1 *r1^(-1)*f1 *r4^2*f1 *r1*f1
  *r4^(-1)*f1 *r1^(-1)*f1 *r4^(-1)*f1 *r1*f1
  *r4*f1 *r1^(-1)*f1 *r1*r4^(-2)*f1 *r1^(-1)*f1
  *r4^(-1)*f1 *r1*f1 *r1^(-1)*f1 *r4*f1 *r1*f1
  *r1^(-1)*f1 *r1*f1 *r4^2*f1
  *r1^(-1)*f1 *r1*f1 *r1^(-1)*f1 *r1*r4^(-1)*f1
  *r1^(-1)*f1 *r4*f1 *r1*f1 *r1^(-2)*r4^2 */
	rCW(w, 3); rCW(w, 0); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCCW(w, 3); rCCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCCW(w, 3); rCCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 3); rCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 0); rCCW(w, 3); rCCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCW(w, 3); rCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 0); rCCW(w, 3); f(w, 0);
	rCCW(w, 0); f(w, 0);
	rCW(w, 3); f(w, 0);
	rCW(w, 0); f(w, 0);
	rCCW(w, 0); rCCW(w, 0); rCW(w, 3); rCW(w, 3);
}

/* 2 * 152 moves -> 3 out, correct? */
static void
ewSwap(MballWidget w)
{
/* EW_swap=f2*f3*f5 *r2*f5 *r1*r2*r3*r4*f5
  *r2*f5 *r3^(-1)*f5 *r2^(-1)*f5 *r3^(-1)*f5
  *r2*f5 *r3^(-1)*f5 *r2^(-1)*f5 *r3^3*f5
  *r2*f5 *r3^(-1)*f5 *r2^(-1)*f5 *r3^2*f5 *r2*f5
  *r3^(-1)*f5 *r2^(-1)*f5 *r3^2*r2*f5
  *r2^(-1)*f5 *r2*f4 *r4^(-1)*r1^(-1)*f5 *r3^(-1)*f5 *r2^(-1)*f5
  *r3^(-1)*f5 *r2*f5 *r3*f5 *r2^(-1)*f5 *r3^2*f5
  *r2*f5 *r3^(-1)*f5 *r2^(-1)*f5 *r3^(-1)*f5 *r2*f5
  *r3*f5 *r2^(-1)*f5 *r2*f5 *r2^(-1)*f5
  *r3*r2^2*f5 *r2*f5 *r3^2*f5 *r2^(-1)*f5
  *r3^(-3)*f5 *r2*f5 *r3^2*f5
  *r2^(-1)*f5 *r3^(-1)*f5 *r2^(-1)*f5 *r2*f5 *r2^(-1)*f5
  *r2*r3^(-1)*f5 *r2^(-1)*f5 *r3^(-1)*f5 *r2*f5
  *r3*f5 *r2^(-1)*f5 *r3*f5 *r2*f5 *r2^(-1)*f5
  *r2*f5 *r2^(-2)*r3*f5 *r2*f5
  *r2^(-2)*f5 *r2^(-1)*f5*f3*f2 */
	f(w, 7); f(w, 6); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 0); rCW(w, 1); rCW(w, 2); rCW(w, 3); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 1); f(w, 5);
	rCCW(w, 3); rCCW(w, 0); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 1); rCW(w, 1); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); rCCW(w, 2); rCCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 2); rCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 1); rCCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCW(w, 2); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); rCCW(w, 1); rCW(w, 2); f(w, 4);
	rCW(w, 1); f(w, 4);
	rCCW(w, 1); rCCW(w, 1); f(w, 4);
	rCCW(w, 1); f(w, 4); f(w, 6); f(w, 7);
}

/* 5 * 107 moves, 5 out (30 * 107 moves, restored)
  I think this was meant to be from rainbo12.log but rainbo13.log copied here. */
static void
badLong3Cycle(MballWidget w)
{
/*badLong3cycle=r4^(-2)*f3 *r4*f4 *r4*f4 *r4^(-1)*r1^2*f3
  *r4^(-1)*f3 *r1^(-3)*f3 *r4^(-1)*f3
  *r1*f3 *r4^2*f3 *r1*f3 *r4^(-1)*f3
  *r1^(-1)*f3 *r4^2*f3 *r1*f3
  *r4^(-1)*f3 *r1^(-1)*f3 *r4^4*f3
  *r1*f3 *r4*f3 *r1^(-1)*f3 *r4*f3
  *r1^(-2)*f3 *r4^(-1)*f3 *r1*f3 *r4^(-1)*f3 *r1^(-1)*f3
  *r4^2*f3 *r1^4*f3 *r4*f3
  *r1^(-3)*f3 *r4^(-1)*f3 *r1*f3 *r4^2*f3
  *r1^(-1)*f3 *r4*f3 *r1^3*f3 *r4*f3
  *r1^(-3)*f3 *r4^(-1)*f3
  *r1^2*f3 *r4^(-1)*f3 *r1^(-1)*f3
*/
	rCCW(w, 3); rCCW(w, 3); f(w, 6);
	rCW(w, 3); f(w, 5);
	rCW(w, 3); f(w, 5);
	rCCW(w, 3); rCW(w, 0); rCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCCW(w, 0); rCCW(w, 0); rCCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCW(w, 3); rCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
	rCW(w, 3); rCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
	rCW(w, 3); f(w, 6);
	rCCW(w, 0); rCCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
	rCW(w, 3); rCW(w, 3); f(w, 6);
	rCW(w, 0); rCW(w, 0); rCW(w, 0); rCW(w, 0); f(w, 6);
	rCW(w, 3); f(w, 6);
	rCCW(w, 0); rCCW(w, 0); rCCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCW(w, 0); f(w, 6);
	rCW(w, 3); rCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
	rCW(w, 3); f(w, 6);
	rCW(w, 0); rCW(w, 0); rCW(w, 0); f(w, 6);
	rCW(w, 3); f(w, 6);
	rCCW(w, 0); rCCW(w, 0); rCCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCW(w, 0); rCW(w, 0); f(w, 6);
	rCCW(w, 3); f(w, 6);
	rCCW(w, 0); f(w, 6);
}

/* 379 moves, small 3 & 4 wedges swapped */
static void
long2Cycle(MballWidget w)
{
/*long2cycle=f1*f3 *r1^(-1)*f3*f1 *r4^(-2)*f1*f3 *r1*f3*f1
  *r4^(-1)*f1*f3 *r1^(-1)*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1^2*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4*f1*f3 *r1*f3*f1 *r4^(-3)*f1*f3 *r1^(-1)*f3*f1 *r4^(-1)*f1*f3
  *r1^(-1)*f3*f1 *r4^(-1)*f1*f3 *r1^2*f3*f1 *r4^(-3)*f1*f3
  *r1^(-1)*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1*f3*f1 *r4^(-1)*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1^(-2)*f3*f1 *r4*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1*f3*f1 *r4*f1*f3 *r1^(-1)*f3*f1 *r4*f1*f3
  *r1*f3*f1 *r4*f1*f3 *r1^(-2)*f3*f1 *r4*f1*f3
  *r1*f3*f1 *r4*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1^(-1)*f3*f1 *r4^2*f1*f3 *r1*f3*f1
  *r4^(-3)*f1*f3 *r1^(-1)*f3*f1 *r4^(-1)*f1*f3
  *r1^(-1)* f3*f1 *r4^(-1)*f1*f3 *r1^2*f3*f1 *r4^(-3)*f1*f3
  *r1^(-1)*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1*f3*f1 *r4^(-1)*f1*f3 *r1*f3*f1
  *r4*f1*f3 *r1^(-2)*f3*f1 *r4*f1*f3
  *r1*f3*f1 *r4*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1^(-1)*f3*f1 *r4^2*f1*f3 *r1^(-1)*f3*f1
  *r4*f1*f3 *r1*f3*f1 *r4*f1*f3 *r1*f3*f1
  *r4^3*f1*f3 *r1^(-2)*f3*f1 *r4*f1*f3 *r1*f3*f1
  *r4*f1*f3 *r1*f3*f1 *r4^3*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1^(-2)*f3*f1 *r4*f1*f3 *r1*f3*f1 *r4*f1*f3
  *r1*f3*f1 *r4*f1*f3 *r1^(-1)*f3*f1
  *r4^2*f1*f3 *r1*f3*f1 *r4^(-2)*f1*f3 *r1^(-1)*f3*f1
  *r4*f1*f3 *r1*f3*f1 *r4^(-2)*f1*f3
  *r1^(-1)*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1^2*f3*f1 *r4^(-3)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1^(-1)*f3*f1 *r4^(-1)*f1*f3
  *r1^2*f3*f1 *r4^(-1)*f1*f3 *r1^(-1)*f3*f1
  *r4^(-1)*f1*f3 *r1*f3*f1 *r4^2
*/
	f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3); rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); rCCW(w, 3); rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); rCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCCW(w, 0); f(w, 5); f(w, 7);
	rCCW(w, 3); f(w, 7); f(w, 5);
	rCW(w, 0); f(w, 5); f(w, 7);
	rCW(w, 3); rCW(w, 3);
}

static void
solveFirstWedge(MballWidget w)
{
	/* Find yellow */
	int pos = findColor(w, 0, 0);
	int tz = wedgeFromPosition(w, pos);
	int b = bandFromPosition(w, pos);
	int i, lat;

	if (b > 0) {
		fPuzzle(w, 0);
		tz = (3 * w->mball.wedges / 2 - tz - 1) % w->mball.wedges;
	}
	if (tz < w->mball.wedges / 2) {
		for (i = 0; i < tz; i++) {
			rPuzzleCCW(w, 0);
		}
	} else {
		for (i = 0; i < w->mball.wedges - tz; i++) {
			rPuzzleCW(w, 0);
		}
	}
	for (lat = 1; lat < (w->mball.bands + 1) / 2; lat++) {
		pos = findColor(w, 0, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		if (b >= w->mball.bands / 2) {
			if (tz == 0) {
				rCW(w, b);
				tz++;
			}
			if (tz < w->mball.wedges / 2) {
				f(w, 1);
				tz = w->mball.wedges / 2 + 1 - tz;
			} else {
				f(w, w->mball.wedges / 2);
				tz = w->mball.wedges - 1 - tz + w->mball.wedges / 2;
			}
			b = w->mball.bands - 1 - b;
		}
		if (tz < w->mball.wedges / 2) {
			for (i = 0; i < tz; i++) {
				rCCW(w, lat);
			}
		} else {
			for (i = 0; i < w->mball.wedges - tz; i++) {
				rCW(w, lat);
			}
		}
	}
	for (lat = w->mball.bands / 2; lat < w->mball.bands; lat++) {
		pos = findColor(w, 0, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		if (b < w->mball.bands / 2) {
			if (tz < w->mball.wedges / 2) {
				f(w, 1);
				tz = w->mball.wedges / 2 + 1 - tz;
			} else {
				f(w, w->mball.wedges / 2);
				tz = w->mball.wedges - 1 - tz + w->mball.wedges / 2;
			}
			b = w->mball.bands - 1 - b;
		}
		if (tz < w->mball.wedges / 2) {
			for (i = 0; i < tz; i++) {
				rCCW(w, lat);
			}
		} else {
			for (i = 0; i < w->mball.wedges - tz; i++) {
				rCW(w, lat);
			}
		}
	}
}

static void
solveSecondWedge(MballWidget w, int lon)
{
	int pos = findColor(w, lon, 0);
	int tz = wedgeFromPosition(w, pos);
	int b = bandFromPosition(w, pos);
	int lat;

	while (tz > 4) {
		f(w, tz - 3);
		tz = tz - 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 1 || tz == 2) && b >= w->mball.bands / 2) {
		f(w, 1);
		if (tz == 2)
			tz = tz + 1;
		else /* tz == 1 */
			tz = tz + 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 3 || tz == 4) && b >= w->mball.bands / 2) {
		f(w, 1);
		if (tz == 4) {
			tz = tz - 3;
		} else { /* tz == 3 */
			tz = tz - 1;
		}
		b = w->mball.bands - 1 - b;
	}
	/* b < w->mball.bands / 2 */
	if (tz == 3 || tz == 4) {
		f(w, 2);
		f(w, 1);
		tz = tz - 2;
	}
	if (tz == 2) {
		rCCW(w, 0);
		f(w, 1);
		rCW(w, 0);
		f(w, 1);
		tz = 1;
	}
	for (lat = 1; lat < (w->mball.bands + 1) / 2; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 4) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 1 || tz == 2) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 1);
			rNPoleCW(w, lat - 1);
			if (tz == 1)
				tz = 4;
			else
				tz = 3;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 3 || tz == 4) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 1);
			rNPoleCW(w, lat - 1);
			if (tz == 4)
				tz = 1;
			else
				tz = 2;
			b = w->mball.bands - 1 - b;
		}
		/* b < w->mball.bands / 2 */
		if (tz == 2 || tz == 3 || tz == 4) {
			/*rnCCW(w, 1, tz - 1);
			f(w, 1);
			rnCW(w, 1, tz - 1);
			f(w, 1);*/
			f(w, tz);
			rnCW(w, lat, tz - 1);
			f(w, tz);
			rnCCW(w, lat, tz - 1);
			tz = 1;
		}
	}
	for (lat = (w->mball.bands + 1) / 2; lat < w->mball.bands; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 4) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if (tz == 2 && b < w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 1);
			rNPoleCW(w, lat - 1);
			tz = 4;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 3 || tz == 4) && b < w->mball.bands / 2) {
			rCW(w, lat);
			f(w, 2);
			rCCW(w, lat);
			b = w->mball.bands - 1 - b;
			if (tz == 4)
				tz = 2;
		}
		/* b >= w->mball.bands / 2 */
		if (tz == 2 || tz == 3 || tz == 4) {
			f(w, tz);
			rnCW(w, lat, tz - 1);
			f(w, tz);
			rnCCW(w, lat, tz - 1);
			tz = 1;
		}
	}
}

static void
solveThirdWedge(MballWidget w, int lon)
{
	int pos = findColor(w, lon, 0);
	int tz = wedgeFromPosition(w, pos);
	int b = bandFromPosition(w, pos);
	int lat;

	while (tz > 5) {
		f(w, tz - 3);
		tz = tz - 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 2 || tz == 3) && b >= w->mball.bands / 2) {
		f(w, 2);
		if (tz == 3)
			tz = tz + 1;
		else /* tz == 2 */
			tz = tz + 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 4 || tz == 5) && b >= w->mball.bands / 2) {
		f(w, 2);
		if (tz == 5) {
			tz = tz - 3;
		} else { /* tz == 4 */
			tz = tz - 1;
		}
		b = w->mball.bands - 1 - b;
	}
	/* b < w->mball.bands / 2 */
	if (tz == 4 || tz == 5) {
		f(w, 3);
		f(w, 2);
		tz = tz - 2;
	}
	if (tz == 3) {
		rCCW(w, 0);
		f(w, 2);
		rCW(w, 0);
		f(w, 2);
		tz = 1;
	}
	for (lat = 1; lat < (w->mball.bands + 1) / 2; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 5) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 2 || tz == 3) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 2);
			rNPoleCW(w, lat - 1);
			if (tz == 2)
				tz = 5;
			else
				tz = 4;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 4 || tz == 5) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 2);
			rNPoleCW(w, lat - 1);
			if (tz == 5)
				tz = 2;
			else
				tz = 3;
			b = w->mball.bands - 1 - b;
		}
		/* b < w->mball.bands / 2 */
		if (tz == 3 || tz == 4) {
			/*rnCCW(w, lat, tz - 1);
			f(w, 1);
			rnCW(w, lat, tz - 1);
			f(w, 1);*/
			f(w, tz);
			rnCW(w, lat, tz - 2);
			f(w, tz);
			rnCCW(w, lat, tz - 2);
			tz = 1;
		} else if (tz == 5) {
			f(w, 4);
			rnCW(w, lat, 2);
			f(w, 4);
			rnCCW(w, lat, 2);
			f(w, 3);
			rCW(w, lat);
			f(w, 3);
			rCCW(w, lat);
			tz = 1;
		}
	}
	for (lat = (w->mball.bands + 1) / 2; lat < w->mball.bands; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 5) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if (tz == 3 && b < w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 2);
			rNPoleCW(w, lat - 1);
			tz = 5;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 4 || tz == 5) && b < w->mball.bands / 2) {
			rCW(w, lat);
			f(w, 3);
			rCCW(w, lat);
			b = w->mball.bands - 1 - b;
			if (tz == 5)
				tz = 3;
		}
		/* b >= w->mball.bands / 2 */
		if (tz == 3 || tz == 4) {
			f(w, tz);
			rnCW(w, lat, tz - 2);
			f(w, tz);
			rnCCW(w, lat, tz - 2);
			tz = 1;
		} else if (tz == 5) {
			f(w, 4);
			rnCW(w, lat, 2);
			f(w, 4);
			rnCCW(w, lat, 2);
			f(w, 3);
			rCW(w, lat);
			f(w, 3);
			rCCW(w, lat);
			tz = 1;
		}
	}
}

static void
solveForthWedge(MballWidget w, int lon)
{
	int pos = findColor(w, lon, 0);
	int tz = wedgeFromPosition(w, pos);
	int b = bandFromPosition(w, pos);
	int i, lat;

	while (tz > 6) {
		f(w, tz - 3);
		tz = tz - 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 3 || tz == 4) && b >= w->mball.bands / 2) {
		f(w, 3);
		if (tz == 4)
			tz = tz + 1;
		else /* tz == 3 */
			tz = tz + 3;
		b = w->mball.bands - 1 - b;
	}
	if ((tz == 5 || tz == 6) && b >= w->mball.bands / 2) {
		f(w, 3);
		if (tz == 6) {
			tz = tz - 3;
		} else { /* tz == 5 */
			tz = tz - 1;
		}
		b = w->mball.bands - 1 - b;
	}
	/* b < w->mball.bands / 2 */
	if ((tz == 5 || tz == 6)) {
		f(w, 4);
		f(w, 3);
		tz = tz - 2;
	}
	if (tz == 4) {
		rCCW(w, 0);
		f(w, 3);
		rCW(w, 0);
		f(w, 3);
		tz = 1;
	}
	for (lat = 1; lat < (w->mball.bands + 1) / 2; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 6) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 3 || tz == 4) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 3);
			rNPoleCW(w, lat - 1);
			if (tz == 3)
				tz = 6;
			else
				tz = 5;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 5 || tz == 6) && b >= w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 3);
			rNPoleCW(w, lat - 1);
			if (tz == 6)
				tz = 3;
			else
				tz = 4;
			b = w->mball.bands - 1 - b;
		}
		/* b < w->mball.bands / 2 */
		if (tz >= 4 && tz <= 6) {
			for (i = 0; i < tz - 3; i++) {
				f(w, 4);
				rCW(w, lat);
				f(w, 4);
				rCCW(w, lat);
			}
			tz = 1;
		}
	}
	for (lat = (w->mball.bands + 1) / 2; lat < w->mball.bands; lat++) {
		pos = findColor(w, lon, lat);
		tz = wedgeFromPosition(w, pos);
		b = bandFromPosition(w, pos);
		while (tz > 6) {
			f(w, tz - 3);
			tz = tz - 3;
			b = w->mball.bands - 1 - b;
		}
		if (tz == 4 && b < w->mball.bands / 2) {
			rNPoleCCW(w, lat - 1);
			f(w, 3);
			rNPoleCW(w, lat - 1);
			tz = 6;
			b = w->mball.bands - 1 - b;
		}
		if ((tz == 5 || tz == 6) && b < w->mball.bands / 2) {
			rCW(w, lat);
			f(w, 4);
			rCCW(w, lat);
			b = w->mball.bands - 1 - b;
			if (tz == 6)
				tz = 4;
		}
		/* b >= w->mball.bands / 2 */
		if (tz >= 4 && tz <= 6) {
			for (i = 0; i < tz - 3; i++) {
				f(w, 4);
				rCW(w, lat);
				f(w, 4);
				rCCW(w, lat);
			}
			tz = 1;
		}
	}
}
#endif

static void
solveWedgeOppSameLat(MballWidget w, int wedge, int band)
{
	int b = w->mball.bands - 1 - band;

	rCCW(w, b);
	f(w, wedge);
	rCW(w, b);
}

static Boolean
solveOppSameLat(MballWidget w, int band)
{
	int wedge = findOppSameLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveOppSameLat: wedge %d, band %d\n",
			wedge, band);
#endif
		solveWedgeOppSameLat(w, wedge, band);
		return True;
	}
	return False;
}

static Boolean
solveAdjOppLat(MballWidget w, int band)
{
	int wedge = findAdjOppLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveAdjOppLat: wedge %d, band %d\n",
			wedge, band);
#endif
		fo(w, wedge,  w->mball.wedges / 2 + 1);
		return (solveOppSameLat(w, band) ||
			solveOppSameLat(w, w->mball.bands - 1 - band));
	}
	return False;
}

static Boolean
solveNextAdjSameLat(MballWidget w, int band)
{
	int wedge = findNextAdjSameLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveNextAdjSameLat: wedge %d, band %d\n",
			wedge, band);
#endif
		if (w->mball.wedges == 6) {
			flipFor6_4s(w, (wedge + 3) % w->mball.wedges, band);
		} else if (w->mball.wedges == 8) {
			fo(w, wedge, 1);
			fo(w, wedge, 2);
#ifdef DEBUG
		} else {
			(void) printf("solveNextAdjSameLat: need to work out for wedge %d\n",
				wedge);
#endif
		}
		return (solveOppSameLat(w, band) ||
			solveOppSameLat(w, w->mball.bands - 1 - band));
	}
	return False;
}

static Boolean
solveAdjSameLat(MballWidget w, int band)
{
	int wedge = findAdjSameLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveAdjSameLat: wedge %d, band %d\n",
			wedge, band);
#endif
		if (w->mball.wedges == 4) {
			flipFor4d(w, (wedge + 1) % w->mball.wedges,
				w->mball.bands - 1 - band);
			return True;
		} else if (w->mball.wedges == 6) {
			fo(w, wedge, 1);
			fo(w, wedge, 2);
			return (solveOppSameLat(w, band) ||
				solveOppSameLat(w, w->mball.bands - 1 - band));
		} else if (w->mball.wedges == 8) {
			fo(w, wedge, 1);
			rCW(w, w->mball.bands - 1 - band);
			fo(w, wedge, 2);
			rCCW(w, w->mball.bands - 1 - band);
			return (solveNextAdjSameLat(w, band));
		}
#ifdef DEBUG
		else {
			(void) printf("solveAdjSameLat: need to work out for wedge %d\n",
				wedge);
		}
#endif
	}
	return False;
}

static Boolean
solveAdjOppOppLat(MballWidget w, int band)
{
	int wedge = findAdjOppOppLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveAdjOppOppLat: wedge %d, band %d\n",
			wedge, band);
#endif
		if (w->mball.wedges == 4) {
			fo(w, wedge, 2);
			return (solveAdjSameLat(w, band));
		} else if (w->mball.wedges == 6) {
			fo(w, wedge, 2);
			return (solveOppSameLat(w, band) ||
				solveOppSameLat(w, w->mball.bands - 1 - band));
		} else if (w->mball.wedges == 8) {
			fo(w, wedge, 2);
			return (solveOppSameLat(w, band));
#ifdef DEBUG
		} else {
			(void) printf("solveAdjOppOppLat: need to work out for wedge %d\n",
				wedge);
#endif
		}
	}
	return False;
}

static Boolean
solveOppOppLat(MballWidget w, int band)
{
	int wedge = findOppOppLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveOppOppLat: wedge %d, band %d\n",
			wedge, band);
#endif
		f(w, wedge);
		return (solveAdjSameLat(w, w->mball.bands - 1 - band));
	}
	return False;
}

static Boolean
solveAdjOppSameLat(MballWidget w, int band)
{
	int wedge = findAdjOppSameLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveAdjOppSameLat: wedge %d, band %d\n",
			wedge, band);
#endif
		fo(w, wedge, 2);
		return (solveOppOppLat(w, band));
	}
	return False;
}

static Boolean
solveNextAdjOppLat(MballWidget w, int band)
{
	int wedge = findNextAdjOppLat(w, band);

	if (wedge != w->mball.wedges) {
#ifdef DEBUG
		(void) printf("solveNextAdjOppLat: wedge %d, band %d\n",
			wedge, band);
#endif
		if (w->mball.wedges == 6) {
			fo(w, wedge, 1);
			return (solveNextAdjSameLat(w, band));
		} else if (w->mball.wedges == 8) {
			fo(w, wedge, 2);
			return (solveAdjOppSameLat(w, band));
#ifdef DEBUG
		} else {
			(void) printf("solveNextAdjOppLat: need to work out for wedge %d\n",
				wedge);
#endif
		}
	}
	return False;
}

static void
easyFlip(MballWidget w, int refTz, int refB, int slice)
{
	int pos = findColor(w, slice, refB);
	int tz = wedgeFromPosition(w, pos);

#ifdef DEBUG
	(void) printf("easyFlip for %d: tz %d\n", w->mball.wedges, tz);
#endif
	if (w->mball.wedges == 4) {
		if (ringAdd(w, tz, -refTz) == 2 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, -1);
#ifdef DEBUG
			(void) printf("  moving 2 out %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 1 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, -1);
#ifdef DEBUG
			(void) printf("  moving 2 in %d\n", tz);
#endif
		}
	} else if (w->mball.wedges == 6) {
		int d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;

		if (ringAdd(w, tz, -refTz) == 4 + slice) {
			fo(w, tz, -2);
			tz = ringAdd(w, tz, -2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving 2 out %d\n", tz);
#endif
		}
		/* easier to take care of direction now, probably for all cases
			 where (wedges / 2) % 2 == 1 */
		if (ringAdd(w, tz, -refTz) == slice && d == 1) {
			f(w, tz);
			tz = ringAdd(w, tz, 2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  take 2 out so to rotate %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 2 + slice && d == 0) {
			fo(w, tz, -1);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  rotating 2 %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 2 + slice) {
			fo(w, tz, -2);
			tz = ringAdd(w, tz, -2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving 2 in %d\n", tz);
#endif
		}
	} else if (w->mball.wedges == 8) {
		if (ringAdd(w, tz, -refTz) > 4 + slice) {
			fo(w, tz, -3);
			tz = ringAdd(w, tz, -3);
#ifdef DEBUG
			(void) printf("  %d: moving >4 %d\n", slice, tz);
#endif
		}
		if (slice >= 3) {
			if (ringAdd(w, tz, -refTz) == 4 + slice) {
				fo(w, tz, -3);
				tz = ringAdd(w, tz, -3);
#ifdef DEBUG
				(void) printf("  %d e: moving 4 %d\n",
					slice, tz);
#endif
			}
		} else {
			if (ringAdd(w, tz, -refTz) == 4 + slice) {
				fo(w, tz, -2);
				tz = ringAdd(w, tz, -1);
#ifdef DEBUG
				(void) printf("  %d: moving 4 %d\n",
					slice, tz);
#endif
			}
		}
		if (ringAdd(w, tz, -refTz) == 1 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, 1);
#ifdef DEBUG
			(void) printf("  %d: moving 1 %d\n", slice, tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 2 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, 1);
#ifdef DEBUG
			(void) printf("  %d: moving 2 %d\n", slice, tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 3 + slice) {
			fo(w, tz, -3);
			tz = ringAdd(w, tz, -3);
#ifdef DEBUG
			(void) printf("  moving 3 %d\n", tz);
#endif
		}
	} else if (w->mball.wedges == 10) {
		int d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;

		if (ringAdd(w, tz, -refTz) == 8 + slice) {
			fo(w, tz, -4);
			tz = ringAdd(w, tz, -4);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving 2 out %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 6 + slice &&
				slice >= 3) {
			fo(w, tz, -4);
			tz = ringAdd(w, tz, -4);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving out 4 %d\n", tz);
#endif
		} else if (ringAdd(w, tz, -refTz) == 6 + slice) {
			fo(w, tz, -3);
			tz = ringAdd(w, tz, -2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving 2 out small step %d\n", tz);
#endif
		}
		/* easier to take care of direction now, probably for all cases
			 where (wedges / 2) % 2 == 1 */
		if (ringAdd(w, tz, -refTz) == slice && d == 1) {
			f(w, tz);
			tz = ringAdd(w, tz, 4);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  take 2 out so to rotate %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 2 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, 2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  backing up 2 %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 4 + slice &&
				d == 0 && slice >= 4) {
			fo(w, tz, -3);
			fo(w, tz, -4);
			fo(w, tz, -3);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  rotating 5 %d\n", tz);
#endif
		} else if (ringAdd(w, tz, -refTz) == 4 + slice && d == 0) {
			fo(w, tz, -2);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  rotating 2 %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 4 + slice) {
			fo(w, tz, -4);
			tz = ringAdd(w, tz, -4);
			d = (d == 0) ? 1 : 0;
#ifdef DEBUG
			(void) printf("  moving 2 in %d\n", tz);
#endif
		}
	} else if (w->mball.wedges == 12) {
		if (ringAdd(w, tz, -refTz) == 8 && slice < 3) {
			fo(w, tz, -4);
			tz = ringAdd(w, tz, -3);
#ifdef DEBUG
			(void) printf("  %d: moving 8 %d\n", slice, tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) >= 6 + slice) {
			fo(w, tz, -5);
			tz = ringAdd(w, tz, -5);
#ifdef DEBUG
			(void) printf("  %d e: moving 4 %d\n", slice, tz);
#endif
		}
		if (slice >= 5) {
			if (ringAdd(w, tz, -refTz) == 6 + slice) {
				fo(w, tz, -5);
				tz = ringAdd(w, tz, -5);
#ifdef DEBUG
				(void) printf("  %d e: moving 4 %d\n",
					slice, tz);
#endif
			}
		} else {
			if (ringAdd(w, tz, -refTz) == 6 + slice) {
				fo(w, tz, -3);
				tz = ringAdd(w, tz, -1);
#ifdef DEBUG
				(void) printf("  %d: moving 4 %d\n",
					 slice, tz);
#endif
			}
		}
		if (ringAdd(w, tz, -refTz) == 1 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, 3);
#ifdef DEBUG
			(void) printf("  %d: moving 1 %d\n", slice, tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 2 + slice) {
			fo(w, tz, -1);
			tz = ringAdd(w, tz, 3);
#ifdef DEBUG
			(void) printf("  %d: moving 2 %d\n", slice, tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 3 + slice) {
			fo(w, tz, -2);
			tz = ringAdd(w, tz, 1);
#ifdef DEBUG
			(void) printf("  moving 3 %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 4 + slice && slice == 5) {
			fo(w, tz, -3);
			fo(w, tz, -4);
			fo(w, tz, -3);
			fo(w, tz, -4);
			tz = ringAdd(w, tz, -4);
#ifdef DEBUG
			(void) printf("  moving 5 %d\n", tz);
#endif
		} else if (ringAdd(w, tz, -refTz) == 4 + slice) {
			fo(w, tz, -2);
			tz = ringAdd(w, tz, 1);
#ifdef DEBUG
			(void) printf("  moving 4 %d\n", tz);
#endif
		}
		if (ringAdd(w, tz, -refTz) == 5 + slice) {
			fo(w, tz, -5);
			tz = ringAdd(w, tz, -5);
#ifdef DEBUG
			(void) printf("  moving 5 %d\n", tz);
#endif
		}
	}
}

static void
orientWithinWedge(MballWidget w)
{
	int wedge, band;

	/* use for bands > 1 */
	if (w->mball.wedges == 4) {
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1) {
					flipFor4w(w, wedge, band);
				}
			}
		}
	} if (w->mball.wedges == 6) {
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1) {
					flipFor6w(w, (wedge + w->mball.wedges - 1) % w->mball.wedges, band);
				}
			}
		}
		/* if (allTop(w)) */
		for (wedge = 0; wedge < w->mball.wedges; wedge++) {
			int tz;

			for (tz = 0; tz < w->mball.wedges; tz++) {
				for (band = 0; band < w->mball.bands / 2; band++) {
					int pos, pos1, tz1;

					tz1 = (tz + w->mball.wedges - 1) % w->mball.wedges;
					pos1 = w->mball.mballLoc[tz1][band].wedge;
					pos = w->mball.mballLoc[tz][band].wedge;
					if ((pos1 > pos) && (pos != 0)) {
						flipFor6_4(w, tz, band);
					}
				}
			}
		}
	} else if (w->mball.wedges == 8) {
		/* flipping opposite wedges i.e. 4 wedges apart */
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = 0; wedge < w->mball.wedges / 2; wedge++) {
				if (w->mball.mballLoc[wedge][band].direction == 1 &&
						w->mball.mballLoc[ringAdd(w, wedge, w->mball.wedges / 2)][band].direction == 1) {
					flipOppSegments(w, wedge, band);
				}
			}
		}
		/* flipping wedges 3 wedges apart */
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1 &&
						w->mball.mballLoc[ringAdd(w, wedge, 3)][band].direction == 1) {
					fo(w, wedge, 3);
					flipOppSegments(w, wedge, band);
					fo(w, wedge, 3);
				}
			}
		}
		/* flipping wedges 1 wedge apart */
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1 &&
						w->mball.mballLoc[ringAdd(w, wedge, 1)][band].direction == 1) {
					fo(w, wedge, 1);
					flipOppSegments(w, wedge, band);
					fo(w, wedge, 1);
				}
			}
		}
		/* flipping wedges 2 wedges apart, done later as less efficient */
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1 &&
						w->mball.mballLoc[ringAdd(w, wedge, 2)][band].direction == 1) {
					fo(w, wedge, 1);
					fo(w, wedge, 2);
					flipOppSegments(w, wedge, band);
					fo(w, wedge, 2);
					fo(w, wedge, 1);
				}
			}
		}
		/* lone wedges that need flipping, least efficient, so do last, 34 moves */
		for (band = 0; band < w->mball.bands / 2; band++) {
			for (wedge = w->mball.wedges - 1; wedge >= 0; wedge--) {
				if (w->mball.mballLoc[wedge][band].direction == 1) {
					flipWedgeSegment1(w, wedge, band);
				}
			}
		}
	}
}

#ifdef EXTRA
/* 3 approaches to solving */
static void
solveLon(MballWidget w)
{
	/* solve wedges approach, half implemented */
	solveFirstWedge(w);
	solveSecondWedge(w, 1);
	solveThirdWedge(w, 2);
	solveForthWedge(w, 3);
}

static void
solvePoles(MballWidget w)
{
	/* solve top to bottom approach, not implemented */
}
#endif

static void
solveLat(MballWidget w)
{
	/* solve top and bottom segments */
	int iter, wedge, band, lat;

	if (w->mball.wedges == 2) {
		int notWedge, midBand;

		wedge = NRAND(2); /* better to pick most correct one */
		notWedge = (wedge == 0) ? 1 : 0;
		lat = (w->mball.bands - 1) / 2;
		for (band = 0; band < w->mball.bands; band++) {
			if (band != lat &&
					(w->mball.mballLoc[wedge][lat].wedge !=
					w->mball.mballLoc[wedge][band].wedge) &&
					(w->mball.mballLoc[wedge][lat].wedge ==
					w->mball.mballLoc[notWedge][band].wedge)) {
				rCW(w, band);
			}
		}
		if (!checkSolved(w)) {
			f(w, wedge);
		}
		for (band = 0; band < w->mball.bands; band++) {
			if (band != lat &&
					(w->mball.mballLoc[wedge][lat].wedge !=
					w->mball.mballLoc[wedge][band].wedge) &&
					(w->mball.mballLoc[wedge][lat].wedge ==
					w->mball.mballLoc[notWedge][band].wedge)) {
				rCW(w, band);
			}
		}
		if (w->mball.orient && !checkSolved(w)) {
			/*swap half, f, fix, f, swap bottom half */
			rNHalfHalf(w);
			f(w, wedge);
			for (band = 0; band < w->mball.bands; band++) {
				if (w->mball.mballLoc[wedge][band].direction != 1) {
					rCW(w, band);
				}
			}
			f(w, wedge);
			rSHalfHalf(w);
			midBand = w->mball.bands / 2;
			if (w->mball.bands % 2 != 0) {
				if (w->mball.mballLoc[wedge][0].wedge !=
						w->mball.mballLoc[wedge][midBand].wedge) {
					rCW(w, midBand);
				}
				if (w->mball.mballLoc[wedge][midBand].direction !=
						w->mball.mballLoc[wedge][0].direction) {
					rCW(w, midBand);
					f(w, wedge);
					rSHalfHalf(w);
					f(w, wedge);
					rCW(w, midBand);
					rSHalfHalf(w);
					f(w, wedge);
					rSHalfHalf(w);
				}
			}
		}
		return;
	}
	/* Stage 1 and Stage 2, align same sized segments */
	for (band = 0; band < w->mball.bands / 2; band++) {
		int ob = w->mball.bands - 1 - band;
		Boolean fixing = !checkBandSolved(w, band);

		while (fixing) {
			if (solveOppSameLat(w, band))
				continue;
			if (solveOppSameLat(w, ob))
				continue;
			/* How to Make Segments Opposite */
			/* Option 1 */
			if (solveAdjOppLat(w, band))
				continue;
			if (solveAdjOppLat(w, ob))
				continue;
			/* Option 2 */
			if (w->mball.wedges == 4 || w->mball.wedges == 6) {
				if (solveAdjSameLat(w, band))
					continue;
				if (solveAdjSameLat(w, ob))
					continue;
			}
			if (w->mball.wedges == 6) {
				if (solveOppOppLat(w, band))
					continue;
			}
			if (w->mball.wedges == 8) {
				if (solveNextAdjSameLat(w, band))
					continue;
				if (solveNextAdjSameLat(w, ob))
					continue;
			}
			if (w->mball.wedges == 6) {
				if (solveAdjOppOppLat(w, band))
					continue;
				if (solveAdjOppOppLat(w, ob))
					continue;
			}
			if (w->mball.wedges == 8) {
				if (solveAdjOppOppLat(w, band))
					continue;
				if (solveAdjOppOppLat(w, ob))
					continue;
			}
			if (w->mball.wedges == 6) {
				if (solveNextAdjSameLat(w, band))
					continue;
				if (solveNextAdjSameLat(w, ob))
					continue;
			}
			if (w->mball.wedges == 6) {
				if (solveNextAdjOppLat(w, band))
					continue;
				if (solveNextAdjOppLat(w, ob))
					continue;
			}
/*#ifndef UNDERCONSTRUCTION*/
			/* Option 3 */
			if (w->mball.wedges == 8) {
				if (solveAdjSameLat(w, band))
					continue;
				if (solveAdjSameLat(w, ob))
					continue;
			}
			if (w->mball.wedges != 6) {
				if (solveOppOppLat(w, band))
					continue;
			}
			if (w->mball.wedges == 8) {
				if (solveAdjOppSameLat(w, band))
					continue;
				if (solveAdjOppSameLat(w, ob))
					continue;
				if (solveNextAdjOppLat(w, band))
					continue;
				if (solveNextAdjOppLat(w, ob))
					continue;
			}
/*#endif*/
/*#ifdef UNDERCONSTRUCTION
		return;
#endif*/
			fixing = False;
		}
/*#ifdef UNDERCONSTRUCTION*/
		/* working on band 0 */
/*		return;
#endif*/
	}
	/* Stage 3, align the different sized segments to center band,
	   do it this way as there is an odd number of bands.  WSD site
	   moves the larger segments instead, not much difference. */
	for (iter = 0; iter < 2 + ((w->mball.wedges < 8) ? 2 : 0); iter++) {
		/* need to go through again as unsolved wedges may be moving around */
		for (wedge = 0; wedge < w->mball.wedges; wedge++) {
			lat = (w->mball.bands - 1) / 2;
			for (band = lat - 1; band >= 0; band--) {
				int color, pos, tz, diff;
				Boolean bypass = False;

				if (checkSegmentSolved(w, wedge, band, lat)) {
#ifdef DEBUG
					(void) printf("solved wedge %d, band %d\n",
						wedge, band);
#endif
					continue;
				}
				color = w->mball.mballLoc[wedge][lat].wedge;
				pos = findColor(w, color, band);
				tz = wedgeFromPosition(w, pos);
				diff = (w->mball.wedges - wedge + tz + w->mball.wedges / 2) % w->mball.wedges;
#ifdef DEBUG
				(void) printf("wedge %d, band %d\n",
					wedge, band);
				(void) printf("tz %d, diff %d\n", tz, diff);
#endif
				/*if (diff != 0 && wedge == 0) {
					if (diff < w->mball.wedges / 2) {
						rnCCW(w, band, diff);
						rnCCW(w, w->mball.bands - 1 - band, diff);
					} else {
						diff = w->mball.wedges - diff;
						rnCW(w, band, diff);
						rnCW(w, w->mball.bands - 1 - band, diff);
					}
				}*/
				if (diff == 1) {
					if (w->mball.wedges == 6) {
						bypass = True;
						flipFor6_4sm(w, (wedge + w->mball.wedges - 1) % w->mball.wedges, band);
					} else if (w->mball.wedges == 4)
						fo(w, wedge, w->mball.wedges - 2);
					else
						fo(w, wedge, w->mball.wedges / 2 - 1);
				} else if (diff == w->mball.wedges - 1) {
					if (w->mball.wedges == 6) {
						flipFor6_4sm(w, (wedge + 1) % w->mball.wedges, band);
						bypass = True;
					} else
						fo(w, wedge, 2);
				} else if (diff == 2) {
					if (w->mball.wedges == 8) {
						fo(w, wedge, w->mball.wedges / 2);
						fo(w, wedge, w->mball.wedges / 2 - 1);
					} else if (w->mball.wedges == 6) {
						fo(w, wedge, w->mball.wedges / 2);
					} else {
						fo(w, wedge, w->mball.wedges - 1);
						fo(w, wedge, w->mball.wedges - 2);
					}
				} else if (diff == w->mball.wedges - 2) {
					fo(w, wedge, 1);
					if (w->mball.wedges != 6)
						fo(w, wedge, 2);
				} else if (diff == 3) {
					fo(w, wedge, w->mball.wedges / 2);
				} else if (diff == w->mball.wedges - 3) {
					fo(w, wedge, 1);
				}
				if (!bypass) {
					rCCW(w, band);
					fo(w, wedge, w->mball.wedges / 2);
					rCW(w, band);
					rCCW(w, w->mball.bands - 1 - band);
					fo(w, wedge, w->mball.wedges / 2);
					rCW(w, w->mball.bands - 1 - band);
				}
			}
		}
	}
	if (w->mball.orient) {
		int refPos = findColor(w, 0, (w->mball.bands + 1) / 2 - 1);
		int refTz = wedgeFromPosition(w, refPos);
		int refB = bandFromPosition(w, refPos);
		int pos, tz, d;

#ifdef DEBUG
		(void) printf("Orient: wedge %d, band %d\n", refTz, refB);
#endif
		/* put numbers on top, no ordering needed for 2 in a ring,
		 * otherwise need logic because ordering on opposite side
		 * is reversed */
		if (w->mball.wedges > 2 &&
				w->mball.mballLoc[refTz][refB].direction == 1) {
			fPuzzle(w, 0); /* should not have but seems to double the work otherwise */
			if (refTz >= w->mball.wedges / 2)
				refTz = w->mball.wedges - 1 - refTz + w->mball.wedges / 2;
			else
				refTz = w->mball.wedges / 2 - 1 - refTz;
			refB = w->mball.bands - 1 - refB;
#ifdef DEBUG
			(void) printf("righted, wedge %d, band %d\n",
				refTz, refB);
#endif
		}
		/* order wedges, the first half is "easy" */
		for (tz = 1; tz < w->mball.wedges / 2; tz++)
			easyFlip(w, refTz, refB, tz);
#ifdef DEBUG
		(void) printf("%d wedge specific\n", w->mball.wedges);
#endif
		if (w->mball.wedges == 2) {
			if (w->mball.mballLoc[1][0].direction != w->mball.mballLoc[0][0].direction) {
				f(w, w->mball.mballLoc[1][0].wedge);
			}
		} else if (w->mball.wedges == 4) {
			pos = findColor(w, w->mball.wedges / 2, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, -1);
			}
		} else if (w->mball.wedges == 6) {
			pos = findColor(w, w->mball.wedges / 2, refB);
			tz = wedgeFromPosition(w, pos);
		        d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, -2);
				tz = ringAdd(w, tz, -2);
				d = (d == 0) ? 1 : 0;
			}
			if (d == 1) {
				fo(w, tz, -2);
				f(w, tz);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, -2);
				fo(w, tz, -1);
			}
		} else if (w->mball.wedges == 8) {
			int tz4, tz7;

			/* check if we can squeeze out another easy flip */
			pos = findColor(w, w->mball.wedges / 2, refB);
			tz4 = wedgeFromPosition(w, pos);
			pos = findColor(w, w->mball.wedges - 1, refB);
			tz7 = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz4, -refTz) == w->mball.wedges - 1) {
				fo(w, tz4, -3);
				tz = ringAdd(w, tz4, -tz7);
				tz4 = ringAdd(w, tz4, -3);
				tz7 = (tz4 + tz) % w->mball.wedges;
			} else if (ringAdd(w, tz7,  -refTz) == w->mball.wedges / 2) {
				f(w, tz7);
				tz = ringAdd(w, tz7, -tz4);
				tz7 = ringAdd(w, tz7, 3);
				tz4 = ringAdd(w, tz7, tz);
			} else if ((ringAdd(w, tz7, -refTz) == w->mball.wedges - 2) &&
					(ringAdd(w, tz4, -refTz) != w->mball.wedges / 2)) {
				fo(w, tz7, -2);
				tz = ringAdd(w, tz7, -tz4);
				tz7 = ringAdd(w, tz7, -1);
				tz4 = ringAdd(w, tz7, tz);
			}
			/* check if its the 2 pair pattern */
			if ((ringAdd(w, tz7, -refTz) == w->mball.wedges / 2 + 1) &&
					(ringAdd(w, tz4, -refTz) != w->mball.wedges / 2)) {
				saturn2Pair(w, ringAdd(w, tz7, -1));
			}
			/* fix for 3 out */
			if (ringAdd(w, tz4, -refTz) == w->mball.wedges / 2) {
				tz = ringAdd(w, tz7, -refTz);
				if (tz == w->mball.wedges / 2 + 1) {
					saturn3Jump(w, ringAdd(w, tz4, 1));
				} else if (tz == w->mball.wedges - 2) {
					saturn3JumpBack(w, ringAdd(w, tz4, 1));
				}
			} else if (ringAdd(w, tz7, -refTz) == w->mball.wedges - 1) {
				tz = ringAdd(w, tz4, -refTz);
				if (tz == w->mball.wedges / 2 + 1) {
					saturn3Jump(w, ringAdd(w, tz7, -3));
				} else if (tz == w->mball.wedges - 2) {
					saturn3JumpBack(w, ringAdd(w, tz7, -3));
				}
			}
			/* if even, outermost 6 & 7 could be swapped. */
			if (w->mball.bands % 2 == 0) {
				pos = findColor(w, w->mball.wedges / 2 + 1, refB);
				tz = wedgeFromPosition(w, pos);
				if (ringAdd(w, tz, -refTz) != w->mball.wedges / 2 + 1) {
					swapEven(w, ringAdd(w, tz, -1));
				}
			}
		} else if (w->mball.wedges == 10) {
			int d1, d2;
#if 0
			/* check if we can squeeze out another easy flip */
			int tz5, tz9;

			pos = findColor(w, w->mball.wedges / 2, refB);
			tz5 = wedgeFromPosition(w, pos);
			pos = findColor(w, w->mball.wedges - 1, refB);
			tz9 = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz5, -refTz) == w->mball.wedges - 1) {
				fo(w, tz5, -4);
				tz = ringAdd(w, tz5, -tz9);
				tz5 = ringAdd(w, tz5, -4);
				tz9 = ringAdd(w, tz5, tz);
			} else if (ringAdd(w, tz9, -refTz) == w->mball.wedges / 2) {
				f(w, tz9);
				tz = ringAdd(w, tz9, -tz5);
				tz9 = ringAdd(w, tz9,  4);
				tz5 = ringAdd(w, tz9, tz);
			}
#endif
			/* I wrote a program to find these, see puck.c */
			pos = findColor(w, w->mball.wedges / 2, refB);
			tz = wedgeFromPosition(w, pos);
		        d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, -4);
				tz = ringAdd(w, tz, -4);
				d = (d == 0) ? 1 : 0;
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges / 2 + 2) {
				fo(w, tz, -2);
				fo(w, tz, -6);
				fo(w, tz, -2);
				fo(w, tz, -6);
				fo(w, tz, -2);
				fo(w, tz, -6);
				f(w, tz);
				fo(w, tz, -6);
				f(w, tz);
				tz = ringAdd(w, tz, -2);
				d = (d == 0) ? 1 : 0;
			}
			if (d == 1) {
				fo(w, tz, -2);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, 1);
			}
			pos = findColor(w, w->mball.wedges / 2 + 1, refB);
			tz = wedgeFromPosition(w, pos);
		        d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 2) {
				fo(w, tz, -2);
				fo(w, tz, -6);
				fo(w, tz, -2);
				fo(w, tz, -6);
				fo(w, tz, -2);
				fo(w, tz, -6);
				f(w, tz);
				fo(w, tz, -6);
				f(w, tz);
				tz = ringAdd(w, tz, -2);
				d = (d == 0) ? 1 : 0;
			}
			if (d == 1) {
				fo(w, tz, -2);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, 1);
			}
			pos = findColor(w, w->mball.wedges / 2 + 2, refB);
		        d = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			pos = findColor(w, w->mball.wedges - 2, refB);
		        d1 = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			pos = findColor(w, w->mball.wedges - 1, refB);
		        d2 = w->mball.mballLoc[pos % w->mball.wedges][(w->mball.bands + 1) / 2 - 1].direction;
			if (d == 1 && d2 == 1) {
				fo(w, tz, 2);
				fo(w, tz, -4);
				fo(w, tz, 3);
				fo(w, tz, 1);
				fo(w, tz, -5);
				fo(w, tz, -4);
				fo(w, tz, -3);
				fo(w, tz, -1);
				fo(w, tz, 2);
				fo(w, tz, 3);
			} else if (d == 1 && d1 == 1) {
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, 1);
				fo(w, tz, 2);
				f(w, tz);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, -1);
				fo(w, tz, 1);
				fo(w, tz, 2);
			} else if (d1 == 1 && d2 == 1) {
				f(w, tz);
				fo(w, tz, 1);
				fo(w, tz, 2);
				fo(w, tz, 3);
				fo(w, tz, 1);
				f(w, tz);
				fo(w, tz, 1);
				f(w, tz);
				fo(w, tz, 2);
				fo(w, tz, 3);
			}
		} else if (w->mball.wedges == 12) {
#if 0
			/* check if we can squeeze out another easy flip */
			/* TODO: Take into account that C wedge may
			   be solved */
			int tz6, tzc;

			pos = findColor(w, w->mball.wedges / 2, refB);
			tz6 = wedgeFromPosition(w, pos);
			pos = findColor(w, w->mball.wedges - 1, refB);
			tzc = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz6, -refTz) == w->mball.wedges - 1) {
				fo(w, tz6, -5);
				tz = ringAdd(w, tz6, -tzc);
				tz6 = ringAdd(w, tz6, -5);
				tzc = ringAdd(w, tz6, tz);
			} else if (ringAdd(w, tzc, -refTz) == w->mball.wedges / 2) {
				f(w, tzc);
				tz = ringAdd(w, tzc, -tz6);
				tzc = ringAdd(w, tzc, 5);
				tz6 = ringAdd(w, tzc, tz);
			}
#endif
			/* http://www.jaapsch.net/puzzles/puck.htm */
			/* What Jaap calls Segment 6 and down: etc. */
			/* I am solving in order, he solves in reverse. */
/*
6: 6: !
   5: ceacae      -> 8 to 7 f(-2,-4,0,-2,0,-4)
                  -> 8 to 7 f(-4,0,-2,0,-4,-2)
   4: dbcdcd (r?) -> 9 to 7 f(-2,-1,-2,-1,0,-2)
   3: adbcdcd     -> A to 7 f(0,-2,-1,-2,-1,0,-2)
   2: dcdcbd (r?) -> B to 7 f(-2,0,-1,-2,-1,-2)
   1: a           -> C to 7 f(0)
*/
			pos = findColor(w, w->mball.wedges / 2, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, -5);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 2) {
				fo(w, tz, -2);
				fo(w, tz, -4);
				fo(w, tz, -3);
				fo(w, tz, -2);
				fo(w, tz, -3);
				fo(w, tz, -2);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 3) {
				fo(w, tz, -3);
				fo(w, tz, -1);
				fo(w, tz, -2);
				fo(w, tz, -1);
				fo(w, tz, -2);
				fo(w, tz, -3);
				fo(w, tz, -1);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges / 2 + 2) {
				f(w, tz);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, -1);
				fo(w, tz, -2);
				f(w, tz);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges / 2 + 1) {
				if (NRAND(2) == 0) {
					fo(w, tz, 1);
					fo(w, tz, 3);
					fo(w, tz, -1);
					fo(w, tz, 1);
					fo(w, tz, -1);
					fo(w, tz, 3);
				} else {
					fo(w, tz, 3);
					fo(w, tz, -1);
					fo(w, tz, 1);
					fo(w, tz, -1);
					fo(w, tz, 3);
					fo(w, tz, 1);
				}
			}
/*
5: 5: !
   4: eadc deae -> 9 to 8 f(-1,1,-2,-1,0,-1,1,-1) r?
   3: cabcbc    -> A to 8 f(-2 -1 -2 -1,0,-2)
   2: cebc dcec -> B to 8 f(-3,1,-2,-1,-2,-3,1,-3)
   1: cbcbac    -> C to 8 f(-2,0,-1,-2,-1,-2)
*/
			pos = findColor(w, w->mball.wedges / 2 + 1, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, -2);
				fo(w, tz, -4);
				fo(w, tz, -3);
				fo(w, tz, -2);
				fo(w, tz, -3);
				fo(w, tz, -2);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 2) {
				f(w, tz);
				fo(w, tz, -4);
				fo(w, tz, -1);
				fo(w, tz, -2);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, -4);
				f(w, tz);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 3) {
				f(w, tz);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, -1);
				fo(w, tz, -2);
				f(w, tz);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges / 2 + 2) {
				f(w, tz);
				fo(w, tz, 2);
				fo(w, tz, -1);
				f(w, tz);
				fo(w, tz, 1);
				f(w, tz);
				fo(w, tz, 2);
				f(w, tz);
			}
/*
4: 4: !
   3: dfcb abfd -> A to 9 f(-1,-3,0,-1,-2,-1,-3,-1)
   2: bdbc badb -> B to 9 f(-3,-5,-1,0,-1,-2,-5,-3)
   1: bdab cbdb -> C to 9 f(-3,-5,-2,-1,0,-1,-5,-3)
                -> C to 9 f(-1,-3,-1,-2,-1,0,-3,-1)
*/
			pos = findColor(w, w->mball.wedges / 2 + 2, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				if (NRAND(2) == 0) {
					f(w, tz);
					fo(w, tz, 2);
					fo(w, tz, -1);
					fo(w, tz, -2);
					fo(w, tz, -3);
					fo(w, tz, -2);
					fo(w, tz, 2);
					f(w, tz);
				} else {
					fo(w, tz, -2);
					f(w, tz);
					fo(w, tz, -2);
					fo(w, tz, -1);
					fo(w, tz, -2);
					fo(w, tz, -3);
					f(w, tz);
					fo(w, tz, -2);
				}
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 2) {
					fo(w, tz, 1);
					fo(w, tz, 3);
					fo(w, tz, -1);
					fo(w, tz, -2);
					fo(w, tz, -1);
					f(w, tz);
					fo(w, tz, 3);
					fo(w, tz, 1);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 3) {
					f(w, tz);
					fo(w, tz, 2);
					fo(w, tz, -1);
					f(w, tz);
					fo(w, tz, 1);
					f(w, tz);
					fo(w, tz, 2);
					f(w, tz);
			}
/*
3: 3: !
   2: dbdab dbdab (r?)-> B to A f(-1,0,-3,-1,-3,-1,0,-3,-1,-3)
   1: badbd badbd (r?)-> C to A f(-3,-1,-3,0,-1,-3,-1,-3,0,-1)
*/
			pos = findColor(w, w->mball.wedges - 3, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				fo(w, tz, 1);
				fo(w, tz, -1);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, -1);
				fo(w, tz, 1);
				fo(w, tz, -1);
				fo(w, tz, 1);
				fo(w, tz, -2);
				fo(w, tz, -1);
			} else if (ringAdd(w, tz, -refTz) == w->mball.wedges - 2) {
				f(w, tz);
				fo(w, tz, -1);
				fo(w, tz, 2);
				f(w, tz);
				fo(w, tz, 2);
				f(w, tz);
				fo(w, tz, -1);
				fo(w, tz, 2);
				f(w, tz);
				fo(w, tz, 2);
			}
/*
2: 2: !
   1: abace deba eacd -> B to A f(0,-1,0,-2,-4,-3,-4,-1,0,-4,0-2,-3)
*/
			pos = findColor(w, w->mball.wedges - 2, refB);
			tz = wedgeFromPosition(w, pos);
			if (ringAdd(w, tz, -refTz) == w->mball.wedges - 1) {
				if (NRAND(2) == 0) {
					fo(w, tz, 7);
					fo(w, tz, 6);
					fo(w, tz, 7);
					fo(w, tz, 5);
					fo(w, tz, 3);
					fo(w, tz, 4);
					fo(w, tz, 3);
					fo(w, tz, 6);
					fo(w, tz, 7);
					fo(w, tz, 3);
					fo(w, tz, 7);
					fo(w, tz, 5);
					fo(w, tz, 4);
				} else {
					fo(w, tz, 4);
					fo(w, tz, 5);
					fo(w, tz, 7);
					fo(w, tz, 3);
					fo(w, tz, 7);
					fo(w, tz, 6);
					fo(w, tz, 3);
					fo(w, tz, 4);
					fo(w, tz, 3);
					fo(w, tz, 5);
					fo(w, tz, 7);
					fo(w, tz, 6);
					fo(w, tz, 7);
				}
			}
		}
		/* Orient segments within wedges */
		orientWithinWedge(w);
	}
}

/* This procedure coordinates the solution process. */
void
solveSomePieces(MballWidget w)
{
	setPuzzle(w, ACTION_RESET);
	if (solvingFlag)
		return;
#ifdef JMP
	if (!setjmp(solve_env))
#endif
	{
		solvingFlag = True;
#if 0
#ifdef EXTRAGROUP
		quadrantizedPattern(w);
		bandedPattern(w);
		checkeredPattern(w);
		simpleSwap(w);
		nsMidSwap(w);
		nsSwap(w);
		ewSwap(w);
		swapAdj34(w);
		swapOp04(w, 0, 0);
		polar2Swap16(w); /* non-oriented */
		polar2Swap34(w);
		equator2Swap16(w);
		equator2Swap34(w);
		long3OutSwap(w);
		long2Cycle(w);
		long3Cycle(w);
		threeOut(w, 1, 1);
		twoOut(w, 0, 1);
		flipOppSegments(w, 1, 1);
		flipWedgeSegment(w, 2, 2);
		flipWedgeSegment1(w, 0, 0);
		saturn2Pair(w, 0);
		saturn3Jump(w, 5);
		saturn3JumpBack(w, 4);
		swapEven(w, 0);
		swap4by4d(w);
		swap4by4(w);
		swap2by4(w);
		flipFor4w(w, 0, 0);
		flipFor4d(w, 0, 0);
		flipFor4a(w, 0, 0);
		flipFor4_3(w, 0, 0);
		swap4by4(w);
		swap4by4op(w, 0, 0);
		flipFor6_4(w, 0, 0);
		flipFor6_4sm(w, 1, 0);
		flipFor6_4s(w, 3, 0);
		flipFor6_3f(w, 0, 0);
		flipFor6d(w, 0, 0);
		flipFor6w(w, 0, 0);
		flipFor6_3(w, 0, 0);
		flipFor6_3r(w, 0, 0);
#endif
#else
		if (!checkSolved(w)) {
			solveLat(w);
		}
#endif
	}
#ifdef JMP
	abortSolvingFlag = False;
#endif
	solvingFlag = False;
	w->mball.cheat = True; /* Assume the worst. */
	setPuzzle(w, ACTION_COMPUTED);
}
