// queen - solve the queens on a chess board problem for n x n sized board
// one command line argument, n, defaults to 8

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

class Queen {

private:

puzzle::Puzzle puzzle;

search::Server<search::PosVariable> searchserver;

int nsqr, ndiag, offset[5];

Maps getmaps(void)
{
	Maps maps(2);
	Map map(offset[4]);

	maps[0] = map.rev(offset[1], nsqr).
				rot(ndiag, offset[2], offset[4] - offset[2]);
	maps[1] = map.rev(offset[3], ndiag).
				rot(nsqr, offset[0], offset[2] - offset[0]);
	return (maps);
}

void printsolution(int n, const PartIds &s, const Parts &parts)
{
	PartIds::const_iterator si;
	int i, j, *tab;
	Pos p;

	tab = new int[nsqr];
	for (si = s.begin(); si != s.end(); si++) {
		p = parts[*si].pos;
		tab[p[0]] = p[1] - nsqr;
	}
	std::cout << std::endl << "Solution " << n << ":" << std::endl;
	for (i = 0; i < nsqr; i++) {
		for (j = 0; j < nsqr; j++) std::cout << (tab[i] == j? "o ": ". ");
		std::cout << std::endl;
	}
	delete tab;
}

Shapes getshapes(void)
{
	Shapes shapes(1);
	Shape shape;
	Pos pos(4);
	int i, j;

	for (i = 0; i < (nsqr+1)/2; i++)
		for (j = i; j < (nsqr+1)/2; j++) {
			pos[0] = offset[0] + i;
			pos[1] = offset[1] + j;
			pos[2] = offset[2] + i + j;
			pos[3] = offset[3] + i + nsqr - 1 - j;
			shape.poss.push_back(pos);
		}
	shape.n = nsqr;
	shapes[0] = shape;
	return (shapes);
}

void setsol(const PartIdss &s, const Parts &parts)
{
	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);
}

public:

Queen(int ansqr) : nsqr(ansqr), puzzle(6*ansqr-2)
{
	nsqr = ansqr;
	ndiag = nsqr + nsqr - 1;
	offset[0] = 0;
	offset[1] = offset[0] + nsqr;
	offset[2] = offset[1] + nsqr;
	offset[3] = offset[2] + ndiag;
	offset[4] = offset[3] + ndiag;
}

void run(void)
{
	puzzle.setmaps(getmaps());
	puzzle.setshapes(getshapes());
	puzzle.search(searchserver);
	setsol(puzzle.getsolutions(), puzzle.getparts());
}

}; // end of class Queen

int main(int argc, char **argv)
{
	int n;

	if (argc > 2) {
		std::cerr << "Usage: " << argv[0] << " [len]" << std::endl;
		exit(1);
	}
	Queen(argc > 1? atoi(argv[1]): 8).run();
	return (0);
}
