#ifndef BOARD_H_INC
#define BOARD_H_INC

#include "common.h"


#define BOARD_SIZE		9				// horizontal/vertical size of the board
#define BOARD_SQRT_SIZE	3					// sqrt size of board
#define NUM_PATHS		(BOARD_SIZE*3)			// number of paths in the board (for scanning)

// board item structure (16bit unsigned short)	........ ........
//						15     8 7      0
// a board item can:
//
// 1. be empty (NONE)				00000000 00000000	all zeros
//						15     8 7      0
//
// 2. contain a selected number (FIXED)		........ ....xxxx	bit 0..3 represent the number (1..9)
//						15     8 7      0	the user chose to place in this place
//
// 3. contain several 'possible' items (OPTION) 1..98765 4321xxxx	the last bit is ON to indicate this status,
//						15     8 7      0	bits 4..12 tell us what optional numbers are on 
//

#define	BOARD_ITEM_OPTION_BIT			15					// bit where 'OPTION on/off' is stored
#define	BOARD_ITEM_OPTION_BIT_MASK		(1<<BOARD_ITEM_OPTION_BIT)		// mask of the 'OPTION on/off' bit
#define BOARD_ITEM_FIXED_MASK			0x000f					// mask of the 'FIXED' number
#define BOARD_ITEM_OPTIONS_MASK			0x1ff0					// mask of the 'OPTIONS' numbers
#define BOARD_ITEM_OPTIONS_START_BIT	4						// bit where 'OPTIONS' numbers start

#define IS_NONE(x)	((x) == 0)
#define IS_OPTION(x)	((x) & BOARD_ITEM_OPTION_BIT_MASK)				// does this item contain 'OPTIONS'
#define GET_FIXED(x)	((x) & BOARD_ITEM_FIXED_MASK)					// get the value of the 'FIXED' number in this item (1..9,0)
#define	HAS_FIXED(x)	GET_FIXED(x)
#define	NO_FIXED(x)	(GET_FIXED(x) == 0)
#define GET_OPTIONS(x)	(((x) & BOARD_ITEM_OPTIONS_MASK) >> BOARD_ITEM_OPTIONS_START_BIT) // option 1 returned at bit 0
#define GET_OPTION(x,o)	((GET_OPTIONS(x) >> ((o)-1)) & 1)

// describe the status of a board
enum BoardStatusType
{
	BS_INCOMPLETE	=	0,
	BS_ERROR		=	1,
	BS_COMPLETE		=	2
};

// describes the type of solution found for a certain board
enum SolutionType
{
	SOLUTOIN_NONE		=	0,
	SOLUTOIN_SINGLE		=	1,
	SOLUTOIN_MULTPLE	=	2,
};

// a point
struct Point
{
	uint32	u, v;
};

// a scanning path
typedef Point	Path[BOARD_SIZE];

class CBoard
{
public:
	CBoard(void);
	~CBoard(void);

	// calculate scanning-paths
	void			PreCalcPaths		();

	// clear the board
	void			ClearBoard			();

	// retrieves the current status of the board
	BoardStatusType	GetBoardStatus		();

	// set the value of an item in the board, isOptions tells us if this is an option-mark
	// or the final number. use '0' for val to clear the FIXED value. use 'onOff' to toggle
	// OPTIONS values
	void			SetItem				(int u, int v, int val, bool isOption = false, bool onOff = false);
	
	// get the value of an item
	uint16			GetItem				(int u, int v);

	// scans the board and fills-in the options for all items
	void			FillPencilMarks		();


	// apply solving rule #1 - http://www.simes.clara.co.uk/programs/sudokutechnique1.htm
	// find if there's a cell who has only 1 option. if so, it must be that option
	int				ApplyRule1			();

	// apply solving rule #2 - http://www.simes.clara.co.uk/programs/sudokutechnique2.htm
	// find if there's a number that can be in only 1 place in a certain row/column/box. kind of inverse of rule 1
	int				ApplyRule2			();

	// solve the board
	SolutionType	Solve				(bool determineIfMultiple = false);

	// determine what type of solution is available (none, single, multiple)
	SolutionType	IsSolveable			();

	// generate a new board
	void			Generate			(uint16 seed, int difficulty);

private:
	// da' board
	uint16	m_board[BOARD_SIZE][BOARD_SIZE];	// [Y][X]

	// the 9*3 paths on the board (9 rows, 9 columns, 9 boxes)
	Path	m_paths[NUM_PATHS];
};

#endif // BOARD_H_INC