// nuts - solve "Drive Ya Nuts" (Copyright 1997 Milton Bradley) puzzle

#include "search.hpp"
#include "puzzle.h"

class Nuts {

private:

puzzle::Puzzle puzzle;

search::Server<search::PosFixed<48> > searchserver;

int *getnut(int i)
{
	static int nuttab[7][6] = {
		{ 1, 4, 3, 6, 5, 2 },
		{ 1, 2, 3, 4, 5, 6 },
		{ 1, 6, 4, 2, 5, 3 },
		{ 1, 6, 5, 4, 3, 2 },
		{ 1, 4, 6, 2, 3, 5 },
		{ 1, 6, 5, 3, 2, 4 },
		{ 1, 6, 2, 4, 5, 3 } };
	return (nuttab[i]);
}

Shape getshape(int *tab)
{
	static int codes[][2] = { {0,1}, {2,3}, {0,2}, {1,3}, {0,3}, {1,2} };
	int i, j, k, l, p;
	Poss poss(37);
	Pos in(6), out(12);
	Pos::iterator ipos;
	Poss::iterator iposs;

	iposs = poss.begin();
	for (i = 0; i < 6; i++) for (j = 0; j < 6; j++, *iposs++ = sort(in))
		for (k = 0, ipos = in.begin(); k < 3; k++) for (l = 0; l < 2; l++)
				p = (i+k+2)%6,
				*ipos++ = codes[(p&1)^(tab[(p+j)%6]-1)][l] + (2*i-k+13)%12*4;
	for (k = 0, ipos = out.begin(); k < 6; k++)	for (l = 0; l < 2; l++)
		*ipos++ = codes[(k&1)^(tab[k]-1)][l] + k*8;
	*iposs++ = sort(out);
	return (Shape(1, poss));
}

Shapes getshapes(void)
{
	Shapes shapes(7);
	int i;

	for (i = 0; i < 7; i++) shapes[i] = getshape(getnut(i));
	return (shapes);
}

void printsolution(int n, const PartIds &s, const Parts &parts,
		const Shapes &shapes)
{
	static int row[] = { -2, -1, 1, 2, 1, -1, 0 };
	static int col[] = { 0, 3, 3, 0, -3, -3, 0 };
	char tab[13][21];
	int i, j, k, shapeid, r, c;
	Poss poss;
	Pos pos;

	for (i = 0; i < 13; i++) for (j = 0; j < 21; j++) tab[i][j] = ' ';
	for (i = 0; i < 7; i++) {
		pos = parts[s[i]].pos;
		shapeid = parts[s[i]].shapeid;
		poss = shapes[shapeid].poss;
		j = std::find(poss.begin(), poss.end(), pos) - poss.begin();
		tab[r = row[j/6]*2+6][c = col[j/6]*2+10] = '*';
		if (j < 36) for (k = 0; k < 6; k++)
			tab[r+row[k]][c+col[k]] = getnut(shapeid)[(j+k)%6] + '0';
	}
	std::cout << std::endl << "Solution " << n << ":" << std::endl;
	for (i = 0; i < 13; i++) {
		for (j = 0; j < 21; j++) std::cout << tab[i][j];
		std::cout << std::endl;
	}
}

void setsol(const PartIdss &s, const Parts &parts, const Shapes &shapes)
{
	PartIdss::const_iterator si;
	int n;

	std::cout << "Number of solutions: " << s.size() << std::endl;
	n = 0;
	for (si = s.begin(); si != s.end(); si++)
		printsolution(++n, *si, parts, shapes);
}

public:

Nuts(void) : puzzle(48)
{
}

void run(void)
{
	Shapes shapes;

	shapes = getshapes();
	puzzle.setshapes(shapes);
	puzzle.search(searchserver);
	setsol(puzzle.getsolutions(), puzzle.getparts(), shapes);
}

}; // end of class Nuts

int main(void)
{
	Nuts().run();
	return (0);
}
