/******************************************************************
 *						Author:	Zhou Yundong
 *						Time: 20090219 20:49
 ******************************************************************/
#include "Stdafx.h"
#include "Think.h"

int idx2uniq[81];
int actualSum[81];
int cntFinishPare;
int finishPare[288];
int cntFinishKilpare;
int finishKilpare[288];
int cntFinishKilequal;
int finishKilequal[288];
int finishSaw[81];
int finishExtra[81];

///////////////////以下是取得Finish的数据///////////////////
// get idx2uniq based on leftUniq[81], leftIdx[81]
void getIdx2uniq()
{
	int i, j;
	for(i=0; i<81; i++)
	{
		idx2uniq[i] = -1;
	}
	for(i=0; i<81; i++)
	{
		if(leftHead[i] != 0 && leftUniq[i])
		{
			for(j=i; j<81; j++)
			{
				if(leftIdx[j] == leftHead[i])
				{
					idx2uniq[j] = i;
				}
			}
		}
	}
}

void getFinishSum()
{
	int i, j;
	getIdx2uniq();
	for(i=0; i<81; i++)
	{
		actualSum[i] = 0;
	}
	for(i=0; i<81; i++)
	{
		if(leftUniq[i])
		{
			for(j=0; j<81; j++)
			{
				if(idx2uniq[j] == i)
				{
					actualSum[i] += leftBoard[j];
				}
			}
		}
	}
}

// get cntFinishPare, finishPare[288] based on leftPare[144]
void getFinishPare()
{
	int i;
	cntFinishPare = 0;
	for(i=0; i<72; i++)
	{
		if(leftPare[i] == 1)
		{
			finishPare[cntFinishPare] = i+(i>>3);
			finishPare[cntFinishPare+1] = i+(i>>3)+1;
			cntFinishPare += 2;
		}
		else if(leftPare[i] == 2)
		{
			finishPare[cntFinishPare] = i+(i>>3)+1;
			finishPare[cntFinishPare+1] = i+(i>>3);
			cntFinishPare += 2;
		}
	}
	for(i=0; i<72; i++)
	{
		if(leftPare[i+72] == 1)
		{
			finishPare[cntFinishPare] = i;
			finishPare[cntFinishPare+1] = i+9;
			cntFinishPare += 2;
		}
		else if(leftPare[i+72] == 2)
		{
			finishPare[cntFinishPare] = i+9;
			finishPare[cntFinishPare+1] = i;
			cntFinishPare += 2;
		}
	}
}

// get cntFinishKilpare, finishKilpare[288] based on kilpare[144]
// get cntFinishKilequal, finishKilequal[288] based on kilpare[144]
void getFinishKilpare()
{
	int i;
	cntFinishKilpare = 0;
	cntFinishKilequal = 0;
	for(i=0; i<72; i++)
	{
		if(leftKilpare[i] == 0) continue;
		if(leftKilpare[i] == 1)
		{
			finishKilpare[cntFinishKilpare] = idx2uniq[i+(i>>3)];
			finishKilpare[cntFinishKilpare+1] = idx2uniq[i+(i>>3)+1];
			cntFinishKilpare += 2;
		}
		else if(leftKilpare[i] == 2)
		{
			finishKilpare[cntFinishKilpare] = idx2uniq[i+(i>>3)+1];
			finishKilpare[cntFinishKilpare+1] = idx2uniq[i+(i>>3)];
			cntFinishKilpare += 2;
		}
		else if(leftKilpare[i] == 3)
		{
			finishKilequal[cntFinishKilequal] = -idx2uniq[i+(i>>3)+1];
			finishKilequal[cntFinishKilequal+1] = -idx2uniq[i+(i>>3)];
			cntFinishKilequal += 2;
		}
	}
	for(i=0; i<72; i++)
	{
		if(leftKilpare[i+72] == 0) continue;
		if(leftKilpare[i+72] == 1)
		{
			finishKilpare[cntFinishKilpare] = idx2uniq[i];
			finishKilpare[cntFinishKilpare+1] = idx2uniq[i+9];
			cntFinishKilpare += 2;
		}
		else if(leftKilpare[i+72] == 2)
		{
			finishKilpare[cntFinishKilpare] = idx2uniq[i+9];
			finishKilpare[cntFinishKilpare+1] = idx2uniq[i];
			cntFinishKilpare += 2;
		}
		else if(leftKilpare[i+72] == 3)
		{
			finishKilequal[cntFinishKilequal] = -idx2uniq[i+9];
			finishKilequal[cntFinishKilequal+1] = -idx2uniq[i];
			cntFinishKilequal += 2;
		}
	}
}

// get finishSaw[81] 注：这里省略了finishSaw的越界检查，因为绝对不会出界
bool getFinishSaw()
{
	int i, j;
	int count;
	for(i=1; i<=9; i++)
	{
		count = 0;
		for(j=0; j<81; j++)
		{
			if(leftSaw[j] == i)
			{
				finishSaw[mult9[i-1]+count] = j;
				count++;
			}
		}
		if(count != 9) return false;
	}
	return true;
}

bool getFinishExtra()
{
	int i, j;
	int count;
	for(i=1; i<=maxExtra; i++)
	{
		count = 0;
		for(j=0; j<81; j++)
		{
			if(leftExtra[j] == i)
			{
				finishExtra[mult9[i-1]+count] = j;
				count++;
			}
		}
		if(count != 9) return false;
	}
	return true;
}

bool getFinishAll()
{
	switch(gameKind)
	{
		case 0:
			break;
		case 1:
			getFinishSum();
			break;
		case 2:
			getFinishPare();
			break;
		case 3:
			getFinishSum();
			getFinishPare();
			getFinishKilpare();
			if(!getFinishSaw()) return false;
			if(!getFinishExtra()) return false;
			break;
		case 4:
			if(!getFinishSaw()) return false;
			break;
		case 5:
			if(!getFinishExtra()) return false;
			break;
	}
	return true;
}

///////////////////以下是编辑合法检查///////////////////
// 数独规定每个组的数都不能重复
int legalCheckSodoku()
{
	int i, j, temp;
	int bitSum;
	// each row
	for(i=0; i<81; i+=9)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			if(leftBoard[i+j] == 0) continue;
			temp = 1<<leftBoard[i+j];
			if(bitSum & temp) return 0;
			bitSum |= temp;
		}
	}
	// each column
	for(i=0; i<9; i++)
	{
		bitSum = 0;
		for(j=0; j<81; j+=9)
		{
			if(leftBoard[i+j] == 0) continue;
			temp = 1<<leftBoard[i+j];
			if(bitSum & temp) return 0;
			bitSum |= temp;
		}
	}
	return -1;
}

int legalCheckSodoku2()
{
	int i, j, temp;
	int bitSum;
	// each palace
	for(i=0; i<9; i++)
	{
		bitSum = 0;
		for(j=0; j<81; j++)
		{
			if(squareNoTbl[j] == i)
			{
				if(leftBoard[j] == 0) continue;
				temp = 1<<leftBoard[j];
				if(bitSum & temp) return 0;
				bitSum |= temp;
			}
		}
	}
	return -1;
}

// 数和规定必须和小于指定和
int legalCheckSum()
{
	int i, j;
	for(i=0; i<81; i++)
	{
		if(actualSum[i] != 0 && actualSum[i] >= leftSum[i] && leftSum[i] != 0)
		{
			return 1;
		}
	}
	for(i=0; i<81; i++)
	{
		if(leftUniq[i])
		{
			for(j=0; j<81; j++)
			{
				if(idx2uniq[j] == i && leftBoard[j] == 0)
				{
					break;
				}
			}
			if(j == 81) return 1;
		}
	}
	return -1;
}

// 数比规定两边不允许都是已知数，另外还有一些条件
int legalCheckPare()
{
	int i;
	for(i=0; i<cntFinishPare; i+=2)
	{
		if(leftBoard[finishPare[i]] != 0 && leftBoard[finishPare[i+1]] != 0
			|| leftBoard[finishPare[i]] == 1
			|| leftBoard[finishPare[i+1]] == 9
			|| leftBoard[finishPare[i]] <= leftBoard[finishPare[i+1]] && leftBoard[finishPare[i]] != 0)
		{
			return 2;
		}
	}
	return -1;
}

// 紫比规定两边必须都是和形式，并且不允许两边都是给定和，等号时两边和都必须未指定
int legalCheckKilpare()
{
	int i;
	for(i=0; i<72; i++)
	{
		if(leftKilpare[i] != 0 && (leftIdx[i+(i>>3)] == 0 || leftIdx[i+(i>>3)+1] == 0)) return 3; // 不是和形式
		if(leftKilpare[i+72] != 0 && (leftIdx[i] == 0 || leftIdx[i+9] == 0)) return 3; // 不是和形式
	}
	for(i=0; i<cntFinishKilpare; i+=2)
	{
		if(leftSum[finishKilpare[i]] != 0 && leftSum[finishKilpare[i+1]] != 0
			|| idx2uniq[finishKilpare[i]] == idx2uniq[finishKilpare[i+1]])
		{
			return 3;
		}
	}
	for(i=0; i<cntFinishKilequal; i+=2)
	{
		if(leftSum[-finishKilequal[i]] != 0 || leftSum[-finishKilequal[i+1]] != 0
			|| idx2uniq[-finishKilpare[i]] == idx2uniq[-finishKilpare[i+1]])
		{
			return 3;
		}
	}
	return -1;
}

// 数扭内检查是否重复
int legalCheckSaw()
{
	int i, j, temp;
	int bitSum;
	// each saw
	for(i=0; i<81; i+=9)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			if(leftBoard[finishSaw[i+j]] == 0) continue;
			temp = 1<<leftBoard[finishSaw[i+j]];
			if(bitSum & temp) return 0;
			bitSum |= temp;
		}
	}
	return -1;
}

// 数超内检查是否重复
int legalCheckExtra()
{
	int i, j, temp;
	int bitSum;
	// each extra
	for(i=0; i<maxExtra; i++)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			if(leftBoard[finishExtra[mult9[i]+j]] == 0) continue;
			temp = 1<<leftBoard[finishExtra[mult9[i]+j]];
			if(bitSum & temp) return 0;
			bitSum |= temp;
		}
	}
	return -1;
}

int legalCheckAll()
{
	int result;
	switch(gameKind)
	{
		case 0:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSodoku2()) != -1) return result;
			break;
		case 1:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSodoku2()) != -1) return result;
			if((result=legalCheckSum()) != -1) return result;
			break;
		case 2:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSodoku2()) != -1) return result;
			if((result=legalCheckPare()) != -1) return result;
			break;
		case 3:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSum()) != -1) return result;
			if((result=legalCheckPare()) != -1) return result;
			if((result=legalCheckKilpare()) != -1) return result;
			if((result=legalCheckSaw()) != -1) return result;
			if((result=legalCheckExtra()) != -1) return result;
			break;
		case 4:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSaw()) != -1) return result;
			break;
		case 5:
			if((result=legalCheckSodoku()) != -1) return result;
			if((result=legalCheckSodoku2()) != -1) return result;
			if((result=legalCheckExtra()) != -1) return result;
			break;
	}
	return -1;
}

///////////////////以下是解成立检查///////////////////
int finishCheckZero()
{
	int i;
	for(i=0; i<81; i++)
	{
		if(rightBoard[i] == 0) return 6;
	}
	return -1;
}

int finishCheckSodoku()
{
	int i, j, bitSum;
	for(i=0; i<81; i++)
	{
		if(leftBoard[i] != 0 && leftBoard[i] != rightBoard[i])
		{
			return 0;
		}
	}
	// each row
	for(i=0; i<81; i+=9)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			bitSum |= 1<<rightBoard[i+j];
		}
		if(bitSum != 1022) return 0;
	}
	// each column
	for(i=0; i<9; i++)
	{
		bitSum = 0;
		for(j=0; j<81; j+=9)
		{
			bitSum |= 1<<rightBoard[i+j];
		}
		if(bitSum != 1022) return 0;
	}
	return -1;
}

int finishCheckSodoku2()
{
	int i, j, bitSum;
	// each palace
	for(i=0; i<9; i++)
	{
		bitSum = 0;
		for(j=0; j<81; j++)
		{
			if(squareNoTbl[j] == i)
			{
				bitSum |= 1<<rightBoard[j];
			}
		}
		if(bitSum != 1022) return 0;
	}
	return -1;
}

void regetActualSum()
{
	int i, j;
	// 重新用右盘取得actualSum[81]
	for(i=0; i<81; i++)
	{
		actualSum[i] = 0;
	}
	for(i=0; i<81; i++)
	{
		if(leftUniq[i])
		{
			for(j=0; j<81; j++)
			{
				if(idx2uniq[j] == i)
				{
					actualSum[i] += rightBoard[j];
				}
			}
		}
	}
}

int finishCheckSum()
{
	int i;
	for(i=0; i<81; i++)
	{
		if(leftSum[i] != 0 && actualSum[i] != leftSum[i])
		{
			return 1;
		}
	}
	return -1;
}

int finishCheckPare()
{
	int i;
	for(i=0; i<cntFinishPare; i+=2)
	{
		if(rightBoard[finishPare[i]] <= rightBoard[finishPare[i+1]])
		{
			return 2;
		}
	}
	return -1;
}

int finishCheckKilpare()
{
	int i;
	for(i=0; i<cntFinishKilpare; i+=2)
	{
		if(actualSum[finishKilpare[i]] <= actualSum[finishKilpare[i+1]])
		{
			return 3;
		}
	}
	for(i=0; i<cntFinishKilequal; i+=2)
	{
		if(actualSum[-finishKilequal[i]] != actualSum[-finishKilequal[i+1]])
		{
			return 3;
		}
	}
	return -1;
}

int finishCheckSaw()
{
	int i, j, bitSum;
	// each saw
	for(i=0; i<81; i+=9)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			bitSum |= 1<<rightBoard[finishSaw[i+j]];
		}
		if(bitSum != 1022) return 4;
	}
	return -1;
}

int finishCheckExtra()
{
	int i, j, bitSum;
	// each extra
	for(i=0; i<maxExtra; i++)
	{
		bitSum = 0;
		for(j=0; j<9; j++)
		{
			bitSum |= 1<<rightBoard[finishExtra[mult9[i]+j]];
		}
		if(bitSum != 1022) return 5;
	}
	return -1;
}

int finishCheckAll()
{
	int result;
	if(finishCheckZero() != -1) return 6;
	if((result=finishCheckSodoku()) != -1) return result;
	switch(gameKind)
	{
		case 0:
			if((result=finishCheckSodoku2()) != -1) return result;
			break;
		case 1:
			if((result=finishCheckSodoku2()) != -1) return result;
			regetActualSum();
			if((result=finishCheckSum()) != -1) return result;
			break;
		case 2:
			if((result=finishCheckSodoku2()) != -1) return result;
			if((result=finishCheckPare()) != -1) return result;
			break;
		case 3:
			regetActualSum();
			if((result=finishCheckSum()) != -1) return result;
			if((result=finishCheckPare()) != -1) return result;
			if((result=finishCheckKilpare()) != -1) return result;
			if((result=finishCheckSaw()) != -1) return result;
			if((result=finishCheckExtra()) != -1) return result;
			break;
		case 4:
			if((result=finishCheckSaw()) != -1) return result;
			break;
		case 5:
			if((result=finishCheckSodoku2()) != -1) return result;
			if((result=finishCheckExtra()) != -1) return result;
			break;
	}
	return -1;
}
