/*

File PlainSquare.m

Squares are the variables that guide the search.  This file implements simple squares for plain depth first search.

*/

#import <appkit/appkit.h>

#import "Plain.h"
#import "Puzzle.h"
#import "Crossword.h"
#import "CrosswordSquare.h"
#import "Inspector.h"


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


#define position(i)		((wordPosition *) [words  elementAt: i])
#define forword(c)		((c) == WILDCARD ? (c):(c) + 'a')
#define forcell(c)		((c) == WILDCARD ? EMPTY:(c) + 'A')


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


@implementation PlainSquare

- (float) efficiency	{	return efficiency;	}


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


- initPuzzle: (id) thePuzzle  cell: (id) theCell
{
	[super  init];
	
	puzzle = thePuzzle;
	cell = theCell;
	letter = WILDCARD;
	tried = 0;
	words = [[Storage  alloc]
				initCount: 0  elementSize: sizeof(wordPosition)  description: ""];
	
	return self;
}


- free
{
	[words  free];
	[super  free];
	
	return self;
}


- addToWord: (id) word  at: (int) i
{
	wordPosition	position;
	
	position.word = word;
	position.i = i;
	[words  addElement: &position];
	
	return self;
}


- startOver
{
	return self;
}


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


- setStatus: (int) flag
{
	status |= flag;
	[self  adjustColor];
	
	return self;
}


- clearStatus: (int) flag
{
	status &= ~flag;
	[self  adjustColor];
	
	return self;
}


- hilight
{
	[self  setStatus: HILIGHT];
	[[puzzle  getCrossword]  drawCellInside: cell];
	
	return self;
}


- unhilight
{
	[self  clearStatus: HILIGHT];
	[[puzzle  getCrossword]  drawCellInside: cell];
	
	return self;
}


- adjustColor
{
	int		i, n;
	
	n = status & ~(status - 1);
	i = 0;
	while (n > 0)
	{
		i++;
		n >>= 1;
	}
	
	[cell  setColor: [[puzzle  getInspector]  getColor: i]];
	return self;
}


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


- (BOOL) fillNext
{
	char	choice;
	
	if ((choice = [self  chooseLetter]) == WILDCARD) [self  clear];
	[[self  setLetter: choice]  show];
	
	return (letter == WILDCARD) ? NO:YES;
}


- erase
{
	[[[self  clear]  setLetter: WILDCARD]  show];
	return self;
}


- clear
{
	letter = WILDCARD;
	tried = 0;
	
	return self;
}


- show
{
	[[puzzle  getCrossword]  putLetter: forcell(letter)  inSquare: cell];
	DPSFlush();
	
	return self;
}


- setLetter: (char) theLetter
{
	wordPosition	* position;
	int				i;
	
	if ((letter = theLetter) != WILDCARD) tried |= (1 << letter);
	i = [words  count];
	
	while (i--)
	{
		position = position(i);
		[position->word  changeLetter: position->i  to: forword(letter)];
	}
	
	return self;
}


- (char) chooseLetter
{
	int		i, max;
	char	best;
	BOOL	findbest;
	
	best = WILDCARD;
	findbest = [[puzzle  getInspector]  getOption: BESTLETTER];
	
	for (max = 0, i = 0; i < LETTERS; i++)
	if ((count[i] > max) && !(tried & (1 << i)))
	{
		max = count[i];
		best = i;
		if (!findbest) break;
	}
	
	return best;
}


/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行  */


- update
{
	wordPosition	* position;
	countTable		table;
	int				i, j;
	
	if (letter == WILDCARD)
	{
		for (j = 0; j < LETTERS; j++) count[j] = 1;
		i = [words  count];
		
		while (i--)
		{
			position = position(i);
			table = [position->word  getCount];
			for (j = 0; j < LETTERS; j++) count[j] *= table[position->i][j];
		}
		
		for (i = 0, j = 0; j < LETTERS; j++) i += (count[j] != 0);
		if ([[puzzle  getInspector]  getOption: BESTSQUARE])
		
				efficiency = 1.0 / (i + 1.0);	else
				efficiency = (i == 0) + 1.0;
	}
	
	return self;
}


@end