//CHECKJS  C:\temp\sudoku\sudoku.js 11/6/2005 12:30:20 PM  11:23 PM 8/18/2007


//Sudoku Assistant Sudoku Solver http://www.stolaf.edu/people/hansonr/sudoku
//VERY efficient JavaScript analysis, except for block range check

//Bob Hanson hansonr@stolaf.edu http://www.stolaf.edu/people/hanson 8:24 AM 11/4/2005


// entries:

// starting (fixed) puzzle:
// ?48.3............71.2.......7.5....6....2..8.............1.76...3.....4......5.... where "." can be "0"

// partially solved:
// ?-9,1,,1t3,,       where (-) implies fixed;(+) implies solved;missing implies unknown, and t means "three commas"

// full marks: (brackets around single numbers optional)
// ?MARKS=[[4],[8,9],[3,7,8,9],[2],[1],[5,8],[3,5],[6],[7,9],[1,9],[1,6,9],[3,6,9],[3,5,9],[7],[4,5],[1,3,4,5],[8],[2],[1,7,8,9],[5],[2],[3,8,9],[6],[4,8],[1,3,4],[1,3],[7,9],[5],[2,8],[1],[6],[3,8],[9],[7],[2,3],[4],[6],[7],[4,8],[1,3,4,8],[3,8],[2],[1,3],[9],[5],[3],[2,9],[4,9],[1,4],[5],[7],[8],[1,2],[6],[1,7,8,9],[1,6,8,9],[6,7,8,9],[1,7,8],[4],[1,6,8],[2],[5],[3],[1,7],[3],[5,6,7],[1,5,7],[2],[1,5,6],[9],[4],[8],[2],[4],[5,8],[5,8],[9],[3],[6],[7],[1]]
// ?MARKS=[4,8,[6,7,9],3,[1,2,6,9],[1,2,5,7,9],[2,5,6,9],[2,5,9],[2,5,6,9],[5,6,9],[3,5,6,9],[3,6,9],[4,5,6,8,9],[2,4,6,8,9],[2,4,5,8,9],[2,3,5,6,9],7,1,[1,5,6,9],2,[3,6,7,9],[1,4,5,6,7,8,9],[1,4,6,8,9],[1,4,5,7,8,9],[3,5,6,9],[3,4,5,8,9],[3,4,5,6,8,9],7,[1,3,4,9],5,[1,4,8,9],[1,3,4,8,9],[1,3,4,8,9],[1,2,3,9],6,[2,3,4,9],[1,6,9],[1,3,4,6,9],[3,4,6,9],2,[1,3,4,6,9],[1,3,4,5,7,9],8,[1,3,4,5,9],[3,4,5,7,9],[1,2,6,8,9],[1,3,4,6,9],[2,3,4,6,8,9],[1,4,5,6,7,8,9],[1,3,4,6,8,9],[1,3,4,5,7,8,9],[1,2,3,5,7,9],[1,2,3,4,5,9],[2,3,4,5,7,9],[2,5,8,9],[4,5,9],1,[4,8,9],7,6,[2,3,5,9],[2,3,5,8,9],[2,3,5,8,9],3,[5,6,7,9],[2,6,7,8,9],[1,8,9],[1,2,8,9],[1,2,8,9],4,[1,2,5,8,9],[2,5,6,7,8,9],[2,6,8,9],[4,6,7,9],[2,4,6,7,8,9],[1,4,8,9],5,[1,2,3,4,8,9],[1,2,3,6,7,9],[1,2,3,8,9],[2,3,6,7,8,9]]
// ?MARKS=[[4],[8],[679],...
// ?MARKS=4,8,679,3,1269,...

// ?DONTSHOWWEAKLINKS
// ?COLORONLY
// ?ALSX
// ?ALSY
// ?ALS
// ?HINGE
// ?YCYCLESONLY
// ?STRONG
// ?WEAK
// ?EDGESONLY
// ?NOALSCOLUMNS
// ?ALSONLY
// ?NOSASHIMI
// ?ALSLARGE
// ?TRANSPOSE
// ?NOGLYPHS

// demo only (these specific marks -- no solving!):
// ?DEMO=[row,col:mark,mark,mark],[row,col:mark,mark,mark],[row,col:mark,mark,mark]...
// ?EDGES=

// start with 3D:
// ?MODE=3D (OK with either MARKS or DEMO)
// Show only a certain digit (3, for example):
// ?SHOWONLY=3
// in general here, i is row 0-8, j is col 0-8, and k is candidate value 0-8, coordinates of a cube

//first implementation 7:24 AM 10/6/2005
//added STRONG edges 11:11 PM 10/10/2005
//added BINARY edges 9:02 AM 10/14/2005
//merged STRONG and BINARY 8:20 AM 10/15/2005
//Medusa, with strong and weak instead of strong and binary 1:55 PM 10/16/2005
//checked against top95 -- solves 47/95.
//All types of X-constraint and Y-constraint now accounted for 4:57 PM 10/16/2005

//Medusa, with weak field check 1:19 AM 10/17/2005
//checked against top95 -- solves 48/95.  10:48 PM 10/18/2005
//Full Medusa with "vertical" weak nodes 11:37 PM 10/23/2005
//checked against top95 -- solves 54/95. 11:48 PM 10/23/2005
//added field check for "forcing weak corners" see http://www.setbb.com/phpbb/viewtopic.php?t=252&mforum=sudoku 10:43 AM 10/24/2005
//added full weak field check for logic chain analysis 10:36 AM 10/26/2005
//checked against top95 -- solves 59/95. 10:41 AM 10/26/2005
//added reverse logic -- chains only -- along the lines of 12:47 AM 10/30/2005
//checked against top95 -- solves 65/95 12:48 AM 10/30/2005.
//added FULL reverse logic including chains and
//checked against top95 -- solves 87/95 4:25 PM 10/31/2005.
//fixed weak by abandoning forcing corners -- must be a mistake in the algorithm 9:04 AM 11/01/2005
//checked against top95 -- solves ALL 95 :)  9:04 AM 11/01/2005
//cleaned up logic analysis and added useraction.js::doShowLogicTable() 10:27 PM 11/2/2005
//checked against Mark Becker's impossible520 solves ALL 3:08 PM 11/4/2005
//added table generation 8:09 AM 11/4/2005
//added MARKS entry 8:13 AM 11/4/2005
//added forward logic 1:00 AM 11/5/2005
//checked against top870 -- no problem -- all solved 6:37 AM 11/5/2005

// forward and reverse logic found identical

// added "edges only" because it is so human 12:56 PM 11/08/2005
// improved Y-Cycle handling; improved automatic run 6:39 AM 11/26/2005
// improved chain table display 5:23 AM 11/29/2005

// implemented almost-locked sets 12/7/2005
// slight improvements on almost-locked-sets 10:02 AM 12/16/2005
// 11:21 AM 10/25/2008 added DONTSHOWEAKLINKS option

thisdatafile="http://magictour.free.fr/top870"


DEFAULTEASY="-5,-3,,,-7,,,,,-6,,,-1,-9,-5,,,,,-9,-8,,,,,-6,,-8,,,,-6,,,,-3,-4,,,-8,,-3,,,-1,-7,,,,-2,,,,-6,,-6,,,,,-2,-8,,,,,-4,-1,-9,,,-5,,,,,-8,,,-7,-9"
DEFAULTPUZZLE="-9,,,-2,,,,-5,,,-7,-6,,,-8,,-4,,,,,-4,,,,,-3,,-6,,-1,,,,,-4,,,-4,,-9,,-5,,,-2,,,,,-6,,-7,,-3,,,,,-4,,,,,-2,,-8,,,-4,-3,,,-8,,,,-5,,,-2"
DEFAULTFIVESTAR=",-9,-8,,-1,-2,,-4,,-5,-6,-2,-3,,,,,,,,,,,-9,,,,,,,,,,-6,,-1,,-3,-6,,,,-5,-9,,-1,,-7,,,,,,,,,,-2,,,,,,,,,,,-6,-4,-5,-3,,-4,,-5,-7,,-8,-2"
DEFAULTFIVEPLUS=",,-1,-7,,-4,-8t,-8t1t-4,7,-5,7,4,,-9t-2,1t-8,-5,,-3,-1t-1t,-4t,-8t-3,-9,8,-1,-2t,-9t-6,,4,1,-3,,-1,,4t,-5t,-6,-1,,-9,-7,8,2"
MEDUSASTRONG="MARKS=59,6,2,3,-1,-4,8,59,7,14589,-3,4589,58,6789,5679,-2,16,59,1589,-7,589,2,689,569,4,16,3,4578,2458,4578,-9,24678,12567,57,-3,16,-6,589,-1,58,378,357,579,4,2,34579,2459,34579,14,2467,12567,579,-8,16,-2,58,578,6,39,39,-1,57,-4,3479,49,3479,14,-5,12,-6,279,8,459,1,6,-7,24,-8,3,259,59"
MEDUSASTRONGWEAK="MARKS=-4,89,3789,-2,-1,58,35,-6,79,19,16,369,39,-7,45,45,-8,-2,789,-5,-2,39,-6,48,134,13,79,-5,28,-1,-6,38,-9,-7,23,-4,-6,-7,48,14,38,-2,13,-9,-5,-3,29,49,14,-5,-7,-8,12,-6,789,16,789,78,-4,16,-2,-5,-3,17,-3,567,57,-2,16,-9,-4,-8,-2,-4,58,58,-9,-3,-6,-7,-1"
LEVEL6C="MARKS=-4,-8,7,-3,12,12,56,9,56,59,359,39,6,48,48,2,-7,-1,1,-2,6,57,9,57,3,8,4,-7,34,-5,89,348,489,1,-6,2,69,13469,349,-2,1346,57,-8,34,57,28,1346,28,57,1346,14,57,34,9,58,45,-1,48,-7,-6,9,2,3,-3,67,89,1,28,289,-4,5,67,269,4679,249,49,-5,3,67,1,8"
LEVEL6B="MARKS=-1,-9,67,-3,-4,-2,678,78,-5,-2,678,-5,78,-1,-9,-4,-3,67,-4,78,-3,578,56,67,-2,-1,-9,68,36,-1,-2,3789,-5,36789,78,-4,568,356,-9,-1,378,-4,3678,-2,367,-7,-4,-2,-6,389,38,389,-5,-1,-9,-1,-8,57,356,367,357,-4,-2,56,-2,67,-4,358,378,-1,-9,37,-3,57,-4,-9,-2,-1,57,-6,-8"//from Davidjan43@aol.com
DEFAULTPROOF_OLD="100050009000100030008000200050004000400060008000300010002000500030005000700090002"
    DEFAULTALS="SHHALSMARKS=14,-2,-3,-7,5,9,148,148,-6,-8,7,14,2,-6,134,-5,-9,134,-9,56,56,138,138,1348,-7,2,134,26,156,12568,1358,-4,138,-9,-7,158,-3,145,-7,158,-9,-6,148,1458,-2,14,1459,14589,158,2,7,36,36,1458,-5,1369,1269,-4,-7,138,12368,1368,189,67,13469,1469,69,138,-2,13468,134568,145789,267,-8,12469,69,13,5,12346,1346,1479" //top95.19
    DEFAULTPROOF="MARKS=-7,126,-8,459,4569,4569,-3,1456,1259,469,36,3469,-2,34569,-1,4679,45678,5789,-5,1236,123469,78,3469,78,12469,146,129,189,-4,1579,3579,59,3579,178,-2,-6,-3,1267,12679,479,-8,24679,147,1457,157,268,25678,2567,-1,2456,24567,478,-9,3,128,-9,12357,-6,125,2358,127,1378,-4,12468,12368,12346,3489,-7,23489,-5,1368,1289,12468,1235678,1234567,34589,12459,234589,12679,13678,12789"
ALMOSTIMPOSSIBLE="700000400020070080003008009000500300060020090001007006000300900030040060009001035"
     CANNOTSOLVE="100000089000009002000000450007600000030040000900002005004070000500008010060300000"
    CANNOTSOLVE2="MARKS=1,2457,2356,2457,2356,3467,367,8,9,3467,4578,3568,4578,3568,9,1,367,2,367,289,289,128,128,367,4,5,367,248,1258,7,6,1589,135,289,2349,1348,268,3,1258,1589,4,157,289,2679,1678,9,148,168,178,138,2,367,3467,5,238,1289,4,1259,7,156,2589,2369,368,5,279,239,249,269,8,367,1,3467,278,6,1289,3,1259,145,2589,2479,478"

TESTINGMARKS_OLD=".7,.1,5,6;,.4,5,6;,2,.4,5,8;,.1,4,6;,3,.4,5,8;,9,.1,9;,3,.4,5,9;,.1,4,5,8,9;,7,.1,4,9;,2,.4,5,8;,6,.2,6,9;,.2,6,9;,8,3,.4,5;,.6,9;,.1,4;,7,.1,5;,3,.2,6,7,8;,.2,6,7;,.1,4,7,8;,9,.1,2,4,7;,5,.1,2,4,6;,.1,2,8;,.2,6,8,9;,4,.2,5,6,7,9;,.1,5,7,8;,.2,5,8;,.1,2,7;,.1,6,8,9;,3,.1,2,8;,.2,8,9;,.2,5,8,9;,1,.4,5,8;,6,3,.4,9;,.2,4,9;,7,.1,2,6,8,9;,.1,2,6,8,9;,.2,6,9;,.4,6,9;,.2,4;,5,7,.1,2,6,9;,3,4,.2,6,7,9;,3,.6,7,9;,1,.2,7,9;,.6,8,9;,.2,5,6,9;,.2,5,8;,5,.1,2,6,7,9;,.2,6,7,9;,.6,7,9;,3,8,.1,6,9;,.1,2,6,9;,4;"
    TESTINGMARKS=".7,.1,5,6;,.4,5,6;,2,.4,8;,.1,6;,3,.4,5,8;,9,.1,9;,3,.4,5;,.1,4,5,8;,7,.1,4,9;,2,.5,8;,6,.2,6,9;,.2,6,9;,8,3,.4,5;,.6,9;,.1,4;,7,.1,5;,3,.2,6,7,8;,.2,6,7;,.1,4,7,8;,9,.1,2,4,7;,5,.1,2,6;,.1,2,8;,.2,6,8,9;,4,.2,5,6,7,9;,.1,5,7,8;,.2,5,8;,.1,2,7;,.1,6,9;,3,.1,2,8;,.2,8,9;,.2,5,8;,1,.5,8;,6,3,.4,9;,.2,4,9;,7,.1,6,8,9;,.1,6,8,9;,.2,6,9;,.4,6,9;,.2,4;,5,7,.1,2,6,9;,3,4,.6,7,9;,3,.6,7,9;,1,.2,7;,8,.2,5,6,9;,.2,5;,5,.1,2,6,7,9;,.2,6,7,9;,.6,7,9;,3,8,.1,6,9;,.1,2,6,9;,4;"
//CANTSOLVEWITHOUTSUBSETS=",-4,,-7t,-6t,-3,-9tttt,-5,-7tt,,-3,,-2t,-8tt-1,-9t,-5,-7,,-6t,-4tt-5,,-1tt,-2t,-6,,-8,-4"

testcell="r5c3 " //remove space for activating this

firsttry=1
nnodes=0
nchains=0
nweaklinks=0
nweakcorners=0
nalmostlockedb=0
nalmostlockedx=0
nalmostlockedy=0

ncellssolved=0
ntidbits=0
Logic_level=0
Wing_level=0

isdemo=0

icheckcross=1
icheckranges=0
ichecksubs=0
icheckgrids=0
icheckmedusa=0
icheckweaklinks=0
icheckreverselogic=0
icheckforwardlogic=0
icheckhinge=0
icheckmagic=0
isedgesonly=0
idostronggroups=1
ichecklockedcandidates=1
ichecklogicsubsets=1
idosashimi=1
idoalslarge=0
idoalscolumns=1
idoalsonly=0
ijustcolor=0
itransposemarks=0
igetalmostlockedy=0  //new 9:00 AM 12/07/2005
igetalmostlockedx=0
igetalmostlockedb=0  //new 7:47 PM 1/2/2009
idoglyphs=1
ishowtimings=0
idonotstop=0
iseliminated=0
iclearlog=1
isautorun=0
istoprun=0
ihaveset=0
ihavechecked=0
ihavemarks=0
nautosolved=0
nautorun=0

tableid="~"
FullMsgs = new Array()
lastmsg=""
eliminationmsg=""
ref0=""

numberformat=1
userdisallowslist=""
LinearData=new Array()
HintTable=new Array()
MethodsUsed=new Array()
chainlist=""

theref="index.htm"
lastdisplay=""
ishint=0
greenlist=""
bluelist=""
redlist=""
redlistk=""
yellowlist=""
pointlist=""
showingthisn=0
solving=0
nsteps=0
MAXSOLVERSTEPS=100
isbad=0
onlythisn=0
isdone=0
isstuck=0
//smsg=""
ishowchain=0
ishowchain2=0
idontshowchain=0
idolog=1
testchain=0
thisStepRef=""
thisPt = 2
thisslicen=0
ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

function showMarks(TF){
	if (TF) {
		getNextStep(0,0,1)
	} else {
		createTable(1)
		showRef()
	}
}

function getNextStep(isstep,iscontinuation,idonochecks,withmarks){
	var isOK=1
	var n=0
	var m=0
	var s=""
	var s2=""
	var D=new Array()

	showingthisn=0
	if(!ishint)HintTable=new Array()


	//isstep: 0 indicates just loading new -- don't save the old reference and don't reveal anything

	//iscontinuation: 1 for continuation of previous, from DoStep(1) only -- Step or Solve pressed or Autorun

	//idonochecks: 1 for just get the basic info -- chains mostly


	logMessage("",idonochecks||!iscontinuation)

	if(!iscontinuation)iscontinuation=0
	if(!idonochecks)idonochecks=0

	if(!ihaveset)setPuzzle()
	if(ishint)iscontinuation=0
	if(!iscontinuation && !isautorun){
		isautorun=0
		AutoMsgs = []
	}

	if(isstep)saveRef()

	checkOptions()

	itestlogic=(idonotstop && !icheckranges && !ichecksubs && !icheckgrids)

	if(itestlogic)logAddMessage("ONLY logic checking. "+(new Date()))

	isdone=0
	isstuck=0
	ishowchain=0
	ishowchain2=0
	iseliminated=0
	ncellssolved=0
	ntidbits=0
	idontshowchain=0

	lastmsg=""
	greenlist=yellowlist=bluelist=redlist=redlistk=pointlist=""
	getValues(0)
	chainlist=""
	StrongChains=[]
	AlsChains = []

	WeakLinks=new Array()
	Sets=new Array()
	NodeGroups=new Array()

	//the Possible array is set in crossCheckAll()
	setUserEdges(userEdgeList)

	isdone=checkAllDone()

	s=(81-ncellssolved)+" cell"+(ncellssolved==80?"":"s")+" left to solve; "

	if(!isdemo && !idonochecks)logAddMessage((solving?(solving>1?"":"")
		+"<b>Step "+solving+"</b> "+addAutoMsg("?")+"<br />":"")+"Cross checking",0,1)
	for(var i=0;i<9;i++)for(var j=0;j<9;j++){
		D=Data[i][j]
		if(!withmarks)
			for(var k=0;k<9;k++)
				D.Allowed[k]=(ihavechecked && iscontinuation && D.Impossible[k]?0
						:iscontinuation||isdemo?D.Allowed[k]
						:userdisallowslist.indexOf(coordOf(D,k))>=0?0
						:k+1)
		D.Impossible=new Array()
		D.Eliminated=new Array()
		D.onlypossible=0
		D.isOK=1
		D.Parity=new Array()
		D.flagged=0
	}
	crossCheckAll() //set the Possible[] array
	countTidBits()
	s+=ncellssolved+" clues; "+ntidbits+" tidbits of information<br>"
	var A=["3x3 block","row","column"]

	if(isdemo || idonochecks){
		getStrongChains(0)
		if(igetalmostlockedx||igetalmostlockedy||igetalmostlockedb){
			getAlmostLocked(1)
			if (igetalmostlockedy) {
				checkSubsets(A,1)
			}
			if (igetalmostlockedx) {
				checkGrids(1)
			}
		}
		//dumpChains(0,0)
		logAddMessage(s)
		s=logGetMessage()
		createTable(0)
		showChainSelect()
		logMessage(s,1,0,"isdemo")
		AutoMsgs.push(s+"<br />")
		return
	}
	logAddMessage(s)

	//hint: sometimes subsets first, sometimes block ranges

	var dorangesfirst=(firsttry || !ihavechecked || !ishint?1:coinflip())
	var dogridsfirst= (firsttry || !ihavechecked || !ishint?0:coinflip())			

	for(var istop=0;istop<1;istop++){
		n=markOnlyOnePossible(1)
		isdone=checkAllDone()
		ihavechecked=1
		if(isdone||n)break

		if(ishint && !firsttry){
			//just for variation
			for(var i=0;i<10;i++){
				n=Math.floor(Math.random()*3)
				m=(n+1)%3
				s=A[n]
				A[n]=A[m]
				A[m]=s
			}

		}

		firsttry=0

		if(igetalmostlockedx||igetalmostlockedy||igetalmostlockedb)getAlmostLocked()

		if(icheckranges && dorangesfirst || igetalmostlockedb){
			logAddMessage("Checking block ranges")
			isOK&=!checkRanges(solving)
			isOK&=!markOnlyOnePossible(0)
			icheckranges=0
			if(iseliminated||isdone||!isOK)break
			if(igetalmostlockedb)logAddMessage(nalmostlockedb + " almost-locked ranges")
		}

		if(ichecksubs){
			isOK&=!checkSubsets(A)
			if(!itestlogic && isOK && igetalmostlockedy)isOK&=!checkAlmostLockedSetsY(A)
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
		}
		//hint: sometimes grid first, sometimes block ranges, but not on FIRST hint try

		if(icheckgrids && dogridsfirst || igetalmostlockedx){
			isOK&=!checkGrids()
			icheckgrids=0
			if(!itestlogic && isOK && igetalmostlockedx)isOK&=!checkAlmostLockedSetsX()
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
		}


		if(icheckranges){
			logAddMessage("Checking block ranges")
			isOK&=!checkRanges(solving)
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
			if(!itestlogic && igetalmostlockedb)logAddMessage(nalmostlockedb + " almost-locked ranges")
		}

		if(icheckgrids){
			isOK&=!checkGrids()
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
		}

		if(icheckmedusa && !itestlogic){
			isOK=!checkStrongConstraints()
			doShowStrongChains()
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break

		}

		if(icheckhinge && !itestlogic){
			isOK=!checkForHinge(false)
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
		}

		if(icheckweaklinks && !itestlogic){
			isOK=!checkWeakConstraints(solving)
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break

			if(icheckhinge && !itestlogic){
				isOK=!checkForHinge(true)
				isOK&=!markOnlyOnePossible(0)
				if(iseliminated||isdone||!isOK)break
			}


		}

		if(!idonotstop && (icheckreverselogic||icheckforwardlogic||icheckmagic)){
			
			if(itestlogic){
				getStrongChains(1) //skip parity checking
				getWeakNodes(1)    //skip parity checking
				getWeakLinks(1)    //skip weak link checking (I think)
			}
			if(icheckmagic && !icheckreverselogic && !icheckforwardlogic){
				if(StrongChains.length==0){
					getStrongChains(1)
					getWeakNodes(1)
				}
				if(WeakLinks.length==0)getWeakLinks(1)
				isOK=!checkLogic(0,1)
			}else{
				isOK=!checkLogic(icheckreverselogic,0)
			}
			isOK&=!markOnlyOnePossible(0)
			if(iseliminated||isdone||!isOK)break
		}
		isstuck=!isdone
	}

	if(solving)updateAllowed(1)

	if(!isdone && !icheckmedusa){
		getStrongChains(0)
		if(igetalmostlockedx||igetalmostlockedy||igetalmostlockedb)getAlmostLocked()
	}
	//logAddMessage(getMarkLink("[snapshot "+(solving?solving:"")+"]"))

	if(isstep==0)greenlist="NOSHOW"
	var fullchainlist = ""
	if (iShowAnswers || ishowdetail){
		logAddMessage(dumpChainList(chainlist))
		fullchainlist = chainlist
	}
	
	showChainSelect()
	var smsg = logGetMessage()
	logMessage(smsg,1,0,"stepping")

	if(solving)FullMsgs[FullMsgs.length]=smsg
	chainlist=""
	createTable(0)
}

function setData(){
	ihaveset=0
	var C=new Array()
	Blocks=new Array()
	var p=0
	var isfixed=(LinearData.join().indexOf("-")<0)
	for(var i=0;i<9;i++){
		Data[i]=new Array()
		for(var j=0;j<9;j++){
			C=Data[i][j]=new Array()
			C.fixed=0
			C.N=LinearData[p++]
			C.N=(C.N?parseInt(C.N):0)
			if(C.N<0||C.N && isfixed){
				C.fixed=1
				C.N=Math.abs(C.N)
			}
			if(C.fixed)ihaveset=1
			C.isopen=0
			C.isOK=1
			C.row=i
			C.col=j
			C.block=(Math.floor(i/3)*3+Math.floor(j/3))
			C.bptr=(i*3)%9+j%3
			C.flagged=0
			C.xrcb=Pwr2[i]+Pwr2[9+j]+Pwr2[C.block+18]
			C.showinfo="r"+(C.row+1)+"c"+(C.col+1)
			C.nodeinfo=[C,C.showinfo]//last for human readability only
			C.xiskstrong=0
			C.onlypossible=0
			C.npossible=0
			C.Allowed=new Array()
			C.AllowedByCross=new Array()
			C.Impossible=new Array()
			C.Eliminated=new Array()
			C.Parity=new Array()
			for(var k=0;k<9;k++)C.Allowed[k]=1
			if(!Blocks[C.block])Blocks[C.block]=new Array()
			Blocks[C.block][C.bptr]=C
		}
	}
	Possible=new Array()
	initXArray(Possible)
	userdisallowslist=""
	logMessage("",0,0,"clearing")
}

function setMarks(T){
	var x=0
	for(var i=0;i<9;i++)for(var j=0;j<9;j++){
		for(var k=0;k<9;k++){
			x=T[k+j*9+i*81]
			Data[i][j].Allowed[k]=(x?k+1:0)
			if(x)Possible.XCell[i][j]|=Pwr2[k]
		}
	}
	checkAllDone()
	countTidBits()
	var s="<br>" + (81-ncellssolved)+" cell"+(ncellssolved==80?"":"s")+" left to solve; "
		+ncellssolved+" clues; "+ntidbits+" tidbits of information"
	logMessage(s,0,1,"setmarks")
}

function countTidBits(){
	ntidbits=9*9*9
	for(var i=0;i<9;i++)for(var j=0;j<9;j++)ntidbits-=(Data[i][j].N?1:xNum(Possible.XCell[i][j]))
	return ntidbits
}

function setPuzzle(){
	ihaveset=0
	ihavechecked=0
	nsteps=0
	Possible=new Array()
	initXArray(Possible)
	getValues(1)
	ihaveset=1	
}

function clearData() {
	nsteps=0
	ihavechecked=0
	for(var i=0;i<9;i++)for(var j=0;j<9;j++){
		if(!Data[i][j].fixed)Data[i][j].N=0
		Data[i][j].isopen=0
		Data[i][j].onlypossible=0
		Data[i][j].Allowed=new Array()
		Data[i][j].AllowedByCross=new Array()
		Data[i][j].Impossible=new Array()
		Data[i][j].Eliminated=new Array()
	}
	userdisallowslist=""
	greenlist="NOSHOW"
	bluelist=yellowlist=""
	ishowchain=""
	ishowchain2=""
}

function  getRowColumnLabels(n, r_or_c, RowLabels, ColLabels) {
	var asString = (arguments.length < 4)
	if (asString) {
		RowLabels = []
		ColLabels = []
	}
	var prefix = (asString ? "" : r_or_c > 0 ? "c" : r_or_c < 0 ? "r" : "")
	for(var i=0;i<9;i++)for(var j=0;j<9;j++){
		if (Data[i][j].N)continue
		for(var k=0;k<9;k++){
			if(k==Data[i][j].N-1||!Data[i][j].Allowed[k]
			  || n<0 && (r_or_c<0 && j!=-r_or_c-1 || r_or_c>0 && i!=r_or_c-1) 
			  || n>0 && k!=n-1) continue
			var p = n > 0 ? i : r_or_c > 0 ? k : k
			if (!RowLabels[p])RowLabels[p] = prefix
			RowLabels[p] += (n > 0 ? j + 1 : r_or_c > 0 ? j + 1 : i + 1)
			p = n > 0 ? j : r_or_c > 0 ? j : i
			if (!ColLabels[p])ColLabels[p] = ""
			ColLabels[p] += (n > 0 ? i + 1 : r_or_c > 0 ? k + 1 : k + 1)
		}
	}
	if (!asString) return
	for (var i = 0; i < 9; i++) {
		if (RowLabels[i] && RowLabels[i].length == 1) RowLabels[i] = ""
		if (ColLabels[i] && ColLabels[i].length == 1) ColLabels[i] = ""
	}
	return ("columns: { "+ColLabels.join(" ") + " }").replace(/\s+/g," ")
		+ (" rows: { "+RowLabels.join(" ") + " }").replace(/\s+/g," ")
}