//CHECKJS  C:\temp\sudoku\strong.js 11/6/2005 12:29:56 PM
//strong.js hansonr@stolaf.edu 7:00 AM 10/28/2005
// handles all strong chain creation and checking
//for nodeData:
DATA=0
K=1
CHAIN=2
PARITY=3
INFO=4
ALLCOORD=5
SHORTINFO=6
SHOWINFO=7
NDATA=8
CHAINPARITY=9
COORDLIST=10
CHAINCODE=11
FULLCHAINCODE=12

StrongEdges=[]
StrongEdgePtr={}
StrongNodes=[]
StrongNodePtr={}
StrongNodeList=[]
StrongChains=[]
WeakNodes={}
AssociatedWeakNodes=[]
tempnodelist=""
ChainSense=[]
ChainXRef={}
WeakXRows=[]
WeakXCols=[]
WeakXBlocks=[]

function chainCodeSet(i,pi,j,pj){
	if(i==j && pi!=pj)return
	var aiscaps=(ALPHABET.indexOf(chainCode(i,pi))>=0)
	var biscaps=(ALPHABET.indexOf(chainCode(j,pj))>=0)
//too complicated!	if(!ChainSense[j][2]&&aiscaps==biscaps)ChainSense[j]=[ChainSense[j][1],ChainSense[j][0]]
	ChainSense[i][2]=1
	ChainSense[j][2]=1
}

function chainCode(ichain,iparity,isfull,withmarks){
	var ch=""
	if(!iparity)iparity=0
	if(!ChainSense[ichain]){
		ch=ALPHABET.charAt((ichain-1)%26)
		ChainSense[ichain]=[ch,ch.toLowerCase(),0]	
	}
	iparity=(iparity<=0?0:1)
	ch=ChainSense[ichain][iparity]
	if(!isfull)return ch
	ch=ichain+"("+ch+")"
	chainlist+=";"+ch
	//yellowlist+=getChainSrc(ichain)
	if (withmarks)weakmarks+=getAssociatedNodeSet(ichain)
	return ch
}

function chainCode2(weaklinkindex){ 
	var s=weaklinkindex
	if(!s)return ""
	var W=WeakLinks[s]
	var how=W[0][0]
	if(how.indexOf("via")<0)how=W[0][5][4]
	s=s.replace(/\_|\//g,",")
	//n_m,1/0
	var S=s.split(",")
	for(var i=0;i<4;i++)S[i]=parseInt(S[i])
	return(S[0]==S[1]&&S[2]!=S[3]?[]:[chainCode(S[0],S[2],1),chainCode(S[1],1-S[3],1),how,chainCode(S[1],1-S[3])])
}




function addEdge(slist,A,B,type,n){
	var s=A+B
	if(slist.indexOf(s)>=0)return ""
	if(!type)type="xy"
	var i=StrongEdges.length
	StrongEdges[i]=[A,B]
	var s1=nodeData([A],COORDLIST)
	var s2=nodeData([B],COORDLIST)
	StrongEdgePtr[s1+","+s2]=StrongEdgePtr[s2+","+s1]=i
	return s+A+"\n"
}

function addEdge2(slist,irowcol,k,sXRowCol,sXSubset){
	//two block subsets of a row or column
	var s=sXRowCol+irowcol+"_"+k+"_"+Possible[sXSubset][irowcol][k]
	if(slist.indexOf(s)>=0)return ""
	var A=[[k],[k]]
	var i1=-1
	var i=0
	var b=0
	var S=xList(Possible[sXRowCol][irowcol][k])
	for(var ii=0;ii<S.length;ii++){
		i=S[ii]
		b=i-(i%3)
		if(i1<0)i1=b
		A[i1==b?0:1].push(sXRowCol=="XRow"?Data[irowcol][i].nodeinfo:Data[i][irowcol].nodeinfo)		
	}
	return s+addEdge(slist,A[0],A[1],s,2)
}

function addEdge3(slist,iblock,k,stype,sXSubset){
	//two parallel rows or columns in a block 
	var s=sXSubset+iblock+"_"+k+"_"+Possible[sXSubset][iblock][k]
	if(slist.indexOf(s)>=0)return ""
	var A=[[k],[k]]
	var i=0
	var b=0
	S=xList(Possible[sXSubset][iblock][k])
	for(var i=0;i<9;i++)if(Possible.XBlock[iblock][k]&Pwr2[i]){
		if(Blocks[iblock][i][stype]==S[0])A[0].push(Blocks[iblock][i].nodeinfo)
		if(Blocks[iblock][i][stype]==S[1])A[1].push(Blocks[iblock][i].nodeinfo)
	}
	return s+addEdge(slist,A[0],A[1],s,3)
}

function addEdge4(slist,iblock,k){
	//looking for special row/col mix
	var s="BlockRC"+iblock+"_"+k
	if(slist.indexOf(s)>=0)return ""
	var A=[[k],[k]]
	var X=[]
	var i=0
	var b=0
	var imin=0
	var x=0
	var i1=iblock-iblock%3
	var i2=i1+3
	for(var i=i1;i<i2;i++){
		X=xList(Possible.XRow[i][k]&Possible.XBlockCol[iblock][k])
		if(X.length==2){
			A[0][1]=Data[i][X[0]].nodeinfo
			A[0][2]=Data[i][X[1]].nodeinfo
		}else if(X.length==1){
			x=X[0] //a single column -- values in 2 rows?
			X=xList(Possible.XCol[x][k]&Possible.XBlockRow[iblock][k])
			if(X.length==1)return s //wrong arrangment; not [x x .  . . X  . . X]
			A[1][1]=Data[X[0]][x].nodeinfo
			A[1][2]=Data[X[1]][x].nodeinfo
		}
	}
	return s+addEdge(slist,A[0],A[1],s)
}

function addNode(iedge){

	//A and B are arrays [k,D.nodeinfo,D.nodeinfo,D.nodeinfo,...], where D.nodeinfo =[D,D.showinfo]

	//Node will be [A,+/-ichain]

	var A=StrongEdges[iedge][0]
	var B=StrongEdges[iedge][1]
	var sa=A+""
	var sb=B+""
	var isa=StrongNodeList[sa]
	var isb=StrongNodeList[sb]
	var c=0
	var iparity=1
	var ithis=0
	if(!isa && !isb){ //create new chain, alternating parity
		nchains++
		StrongNodes[++nnodes]=[A,nchains,"new"]
		StrongNodeList[sa]=nnodes
		StrongNodes[++nnodes]=[B,-nchains,"new"]
		StrongNodeList[sb]=nnodes
	}else if(isedgesonly){
	}else if(isa && isb){ //merge chain b into chain a, correcting parity
		iparity=((StrongNodes[isa][1]^StrongNodes[isb][1])>=0?-1:1)
		ithis=nodeData(StrongNodes[isb],CHAIN)
		for(var i=1;i<StrongNodes.length;i++)if(nodeData(StrongNodes[i],CHAIN)==ithis){
			StrongNodes[i][1]=nodeData(StrongNodes[isa],CHAIN)*iparity*(StrongNodes[i][1]>0?1:-1)
		}
	}else if(isa){ //append to a, with parity switch
		StrongNodes[++nnodes]=[B,-StrongNodes[isa][1],"appended",isa]
		StrongNodeList[sb]=nnodes
	}else{ //append to b, with parity switch
		StrongNodes[++nnodes]=[A,-StrongNodes[isb][1],"appended",isb]
		StrongNodeList[sa]=nnodes
	}
}

function addWeakNode(D,ichain,k,iparity,type,TheNode,issetup,iskipcheck){

//logAddMessage("addWeakNode" + iskipcheck + "  " + D.showinfo + " ichain=" + ichain + " k=" + k + " iparity=" + iparity + " " + type + " " + TheNode)

	// idea here is that "cycles" are really just incompatible forces from two different directions
	// incompatible parities leads to an elimination.

	var p=0
	var coord=coordOf(D,k)
	var i=0
	var x=0
	var s=""
	if(D.N||!D.Allowed[k]||D.Impossible[k])return 1

	if(!D.Parity[ichain])D.Parity[ichain]=[0,0,0,0,0,0,0,0,0]

	//check for problems WITHIN this chain only
	if(D.Parity[ichain][k] && !iskipcheck){
		p=D.Parity[ichain][k][0]
		var FirstNode=D.Parity[ichain][k][1]

//logAddMessage("p/iparity:" + p + " " + iparity + " " + ((p^iparity)))

		if((p^iparity)>=0){
			//new idea -- allow this to be a new node if the previous assignment was 1-long
			if(nodeData(FirstNode,NDATA)==1)return 1 //ok -- same parity 1^-1=-1;1^1=0;1^2=1
		}else{
			//we've already got the connection; no need to track a second :)
			//NOT OK -- elimination stuff here
			//this could be a chain end wrap or a non-chain position "weak edge cell"/"weak corner"
			greenlist+=getChainSrc(ichain)
			s=" involving node "+getNodeInfo(FirstNode)+" when trying to add "+coord+" as a weak node to "+getNodeInfo(TheNode)+" "+type
			if(FirstNode[1]==TheNode[1] && nodeData(FirstNode,NDATA)==1){ //same chain and parity -- must be end wrap
				s=chainCode(ichain,p,1)+" can be eliminated -- incompatible strong "+(isjustycycles?"Y":ijustcolor?"X":"M")+"-cycle "+s
				eliminateChainParity(ichain,p,s,(type.indexOf("ALS")>=0?"A2":"Ms"))
			}else{
				s=coord+" is incompatibly weakly linked to "+chainCode(ichain,p,1)+s
				ishowchain=ichain
				eliminateK(D,k,s)
				addAutoMsg((type.indexOf("ALS")>=0?"A2":"Ms"),s)
			}
			ishowchain=ichain
			return idonotstop
		}
	}

	D.Parity[ichain][k]=[iparity,TheNode,type]
//logAddMessage("addWeakNode D.Parity[ichain][k] = " + D.Parity[ichain][k])
	//knock out that parity -- develops the PARITY FIELD. If this value goes to 0, then all values of k are
	//invalidated for THAT chain, and we know the chain's parity -- we know ALL the values for that chain!
	//and if chains can be weakly linked.... :)

	if(issetup)return 1
	p=(iparity<0?1:0)

	WeakXRows[p]|=Pwr2[D.row]
	WeakXCols[p]|=Pwr2[D.col]
	WeakXBlocks[p]|=Pwr2[D.block]

	if(!WeakNodes[coord])WeakNodes[coord]=[]
	if(tempnodelist.indexOf(coord+k+TheNode)<0){
		tempnodelist+=coord+k+TheNode
		i=WeakNodes[coord].length
		WeakNodes[coord][i]=[D,TheNode,k,StrongNodeList[[k,D.nodeinfo]],type]
		if(!AssociatedWeakNodes[p][ichain])AssociatedWeakNodes[p][ichain]=[]
		AssociatedWeakNodes[p][ichain][AssociatedWeakNodes[p][ichain].length]=WeakNodes[coord][i]
//logAddMessage(ichain+": added WeakNode "+coord)
	}
	return 1	
}

function chainOf(i,j,k){
	var n=ptrStrongNode(i,j,k)
	if(!n)return 0
	return nodeData(StrongNodes[n],CHAIN)
}

function checkStrongConstraints(){

	// All the odd/even cycle business is just measuring alternating parity.
	// Strong chains are between cells in the same row, cell, or block set having the same
	// candidate possibilities, where only two such possibilities exist in their common set

	// If an ODD-numbered strong chain "targets" the ends in the same block, row, or cell,
	// one cell will have to be that number, the other not. So one will be the
	// number for sure, and no OTHER possibility of this in the same block, row, or
	// cell will be allowed. If an EVEN-numbered strong chain ends in the same
	// block, row, or cell, then NEITHER of those two endpoints is a possibility,
	// because they can't be both Y, so they have to be both N.

	// note that this follows all 3D paths, not just of a certain k-value

	logAddMessage("Checking strong chains")

	getStrongChains(0)

	return getWeakNodes()
}

function createChains(){
	//may be empty chain numbers -- clean this up
	//create chains from node list

	var n=0
	var ChainPtr=[]
	for(var i=1;i<StrongNodes.length;i++){
		ichain=nodeData(StrongNodes[i],CHAIN)
		if(!ChainPtr[ichain])ChainPtr[ichain]=(++n)
		StrongNodes[i][1]=ChainPtr[ichain]*(StrongNodes[i][1]>0?1:-1)
		ichain=ChainPtr[ichain]
		if(!StrongChains[ichain])StrongChains[ichain]=[]
		StrongChains[ichain][StrongChains[ichain].length]=i
		StrongNodePtr[nodeData(StrongNodes[i],ALLCOORD)]=i
	}
	for(var i=1;i<StrongChains.length;i++){
		ChainXRef["_"+i]=[]
		ChainXRef["_-"+i]=[]
		WeakXRows[i]=[0,0]
		WeakXCols[i]=[0,0]
		WeakXBlocks[i]=[0,0]
	}

}

function dumpChains(isalert,isdetail,msg){
        if (!isalert && !iReportChains)return;
	var s=""
	var n=0
	if(!msg)msg=""
	for(var i=1;i<StrongChains.length;i++){
		s+="<b><a href=javascript:doShowChain("+i+")>"+(isdetail?"<br />Chain ":"&nbsp;")+i+"</a></b> "
		if(isdetail)for(var j=0;j<StrongChains[i].length;j++)s+="<br />"+StrongChains[i][j]+" "+getNodeInfo(StrongNodes[StrongChains[i][j]])
		n++
	}
	if(isalert){alert(s.replace(/\<br\>/g,"\n"))}else if(n){logAddMessage(s,"<br />"+msg+"Strong Chains")}
}

function getChainSelect() {
        if (!iReportChains)return;
	var s="<select id='chainselect' onkeyup=\"setTimeout('doShowChain()',100)\" onchange=doShowChain()><option value='0'>chains</option>"
	var n=0
	for(var i=1;i<StrongChains.length;i++){
		s+="<option value='"+i+"'>Chain "+i+"</option>"
		n++
	}
	return s + "</select>"
}

function dumpChainList(chainlist){
	var s=""
	if (arguments.length==0)
		s="<br /><br /><b>Medusa Strong Chain List</b>"
		+"<br /><br />The first step in Medusa Strong Chain Compatibility Analysis is to identify the \"strong chains\". When there are exactly two possibilities (\"nodes\" or \"marks\") for a given digit in a row, column, or block, or there are only two possibilities for a given cell, we have a \"strong edge\" -- a link in a strong chain. Any two strong edges with a common node are in the same strong chain. Strong chains may branch; they are not always linear sequences of nodes. These nodes alternate in parity -- if one is TRUE then the next is FALSE. Thus, if any one node of a chain can be proven either TRUE or FALSE, all nodes in the chain are determined simultaneously.<br />"
	if(!chainlist)chainlist=""
	for(var i=1;i<StrongChains.length;i++)if(chainlist=="" || chainlist.indexOf(";"+i+"(")>=0){
		s+="<br /><b>Chain "+i+"</b>: "
		for(var j=0;j<StrongChains[i].length;j++)s+=" "+getNodeInfo(StrongNodes[StrongChains[i][j]],"short")
	}
	return s
}

function eliminateChainParity(ichain,iparity,s,type){
	var N=[]
	var n=0
	var k=0
	ishowchain=ichain
	if(!iparity)iparity=-1
	for(var inode=0;inode<StrongChains[ichain].length;inode++){
		N=StrongNodes[StrongChains[ichain][inode]]
		if((N[1]^iparity)>=0){
			n=nodeData(N,NDATA)
			k=nodeData(N,K)
			for(var j=1;j<=n;j++)eliminateK(nodeData(N,DATA,j),k,s)
		}
	}
	addAutoMsg(type,s)
	return 1  //error found
}

function getAssociatedNodes(ichain,p,NotList){
	if (ichain < 0) return alsGetAssociatedNodes(-ichain)
	var W=[]
	var coord=""
	var List=[]
	if(!AssociatedWeakNodes[p][ichain])return []
	for(var i=0;i<AssociatedWeakNodes[p][ichain].length;i++){
		W=AssociatedWeakNodes[p][ichain][i]
		coord=coordOf(W[0],W[2])
		if(!NotList[coord]){
			List[List.length]=[coord,W]
			NotList[coord]=coord
		}
	}
	return List
}

function getAssociatedNodeSet(ichain){
	if (ichain < 0) return alsGetAssociatedNodeSet(-ichain)
	var s=""
	var N=[]
	for(var i=0;i<StrongChains[ichain].length;i++){
		N=StrongNodes[StrongChains[ichain][i]]
		s+=", "+nodeData(N,ALLCOORD)
	}
	var List = getAssociatedNodes(ichain,0,{})
	if (List.length == 0) {
		getStrongChains(1)
		getWeakNodes(1)
		getWeakLinks(1)
		List = getAssociatedNodes(ichain,0,{})
	}
	var sw="CHAIN " + ichain+ "::" 
	for(var i=0;i<List.length;i++)
		if (s.indexOf(List[i][0])<0)
			sw+=", "+List[i][0]+"0"
	var List = getAssociatedNodes(ichain,1,{})
	for(var i=0;i<List.length;i++)
		if (s.indexOf(List[i][0])<0)
			sw+=", "+List[i][0]+"1"
	return sw
}


function getChainListing(ichain,iparity){
	var s=""
	var N=[]
	var icheckparity=(arguments.length==1?0:1)
	for(var i=0;i<StrongChains[ichain].length;i++){
		N=StrongNodes[StrongChains[ichain][i]]
		if(!icheckparity||nodeData(N,PARITY)==iparity)s+=", "+nodeData(N,icheckparity?ALLCOORD:SHORTINFO)
	}
	return s.substring(2,s.length)
}


function getChainSrc(ichain){
	var s=""
	for(var i=0;i<StrongChains[ichain].length;i++)s+=nodeData(StrongNodes[StrongChains[ichain][i]],SHOWINFO)
	return s
}

function getStrongChains(iskipcheck){
	var iparity=0
	var N=[]
	var D={}
	var k=0
	var n=0

	if(!iskipcheck)iskipcheck=0

	getStrongEdges()
	StrongNodes=new Array()
	StrongNodeList=new Array()
	StrongNodePtr=new Array()
	StrongChains=new Array()
	AssociatedWeakNodes=new Array([],[])
	WeakNodes=new Array()
	WeakLinks=new Array()
	WeakCorners=new Array()
	WeakXRows = new Array()
	WeakXCols = new Array()
	WeakXBlocks = new Array()
	ChainSense=new Array()
	ChainXRef={}
	nnodes=0
	nchains=0
	nweakcorners=0
	nweaklinks=0

	for(var i=0;i<9;i++)for(var j=0;j<9;j++){
		Data[i][j].Parity=new Array()
		Data[i][j].xiskstrong=0
	}

	//create node list from EdgeArray edges
	for(var i=0;i<StrongEdges.length;i++)addNode(i)

	createChains()

	//mark all chain nodes for parity


	for(var i=1;i<StrongNodes.length;i++){
		N=StrongNodes[i]	// [[k,[D,D.showinfo],[D,D.showinfo],[D,D.showinfo]...],+-ichain]
		iparity=N[1]
		n=nodeData(N,NDATA)
		k=nodeData(N,K)
		if(n==1){
			D=nodeData(N,DATA)
			D.xiskstrong|=Pwr2[k]
		}
		for(j=1;j<=n;j++)addWeakNode(nodeData(N,DATA,j),Math.abs(iparity),k,(iparity>0?1:-1),"chain construction",N,1,iskipcheck||j>1)
	}
}

function dataNode(r,c,v) {
	return [v-1,Data[r-1][c-1].nodeinfo]
}

function getStrongEdges(){

	//	strong edges are row, columns, block, or cells with exactly only two possibilities

	//	StrongEdges will be array of pairs of [row,col,k-value,block]

	var slist=""
	var A=new Array()
	StrongEdges=new Array()
	StrongEdgePtr=new Array()
	var x=0
	for (var i=0; i < userDefinedEdges.length; i++) {
		var N1 = userDefinedEdges[i][0][1][0]
		var N2 = userDefinedEdges[i][1][1][0]
		var k1 = userDefinedEdges[i][0][0]
		var k2 = userDefinedEdges[i][1][0]
//alert(userDefinedEdges[i]+" "+N1.Impossible + " " + N2.Impossible)
//TODO -- not quite right - doesn't allow 

		if(!N1.N && !N2.N && !N1.Impossible[k1] && !N2.Impossible[k2])
			slist+=addEdge(slist,userDefinedEdges[i][0],userDefinedEdges[i][1])
	}
	for(var i=0;i<9;i++)for(var k=0;k<9;k++){
		if(!isjustycycles){
			if(xNum(Possible.XRow[i][k])==2){
				A=xList(Possible.XRow[i][k])
				slist+=addEdge(slist,[k,Data[i][A[0]].nodeinfo],[k,Data[i][A[1]].nodeinfo])
			}else if(idostronggroups && xNum(Possible.XRowSubset[i][k])==2){
				slist+=addEdge2(slist,i,k,"XRow","XRowSubset")
			}
			if(xNum(Possible.XCol[i][k])==2){
				A=xList(Possible.XCol[i][k])
				slist+=addEdge(slist,[k,Data[A[0]][i].nodeinfo],[k,Data[A[1]][i].nodeinfo])
			}else if(idostronggroups && xNum(Possible.XColSubset[i][k])==2){
				slist+=addEdge2(slist,i,k,"XCol","XColSubset")
			}
//why?			if(idostronggroups){
				x=xNum(Possible.XBlock[i][k])
				if(x==2){
					A=xList(Possible.XBlock[i][k])
					slist+=addEdge(slist,[k,Blocks[i][A[0]].nodeinfo],[k,Blocks[i][A[1]].nodeinfo])
				}else if(idostronggroups && x>=3){
					if(xNum(Possible.XBlockRow[i][k])==2)slist+=addEdge3(slist,i,k,"row","XBlockRow")
					if(xNum(Possible.XBlockCol[i][k])==2)slist+=addEdge3(slist,i,k,"col","XBlockCol")
					if(x==4 && xNum(Possible.XBlockRow[i][k])==3 && xNum(Possible.XBlockCol[i][k])==3)slist+=addEdge4(slist,i,k)
				}
//			}
		}
		if(!ijustcolor && xNum(Possible.XCell[i][k])==2){
			A=xList(Possible.XCell[i][k])
			slist+=addEdge(slist,[A[0],Data[i][k].nodeinfo],[A[1],Data[i][k].nodeinfo])
		}
	}
}

function getWeakNodes(iskipcheck){

	// returns TRUE if found problem
	var A=new Array()
	var D=new Array()
	var r=0
	var c=0
	var k=0
	var b=0
	var p=0
	var n=0
	var x=0
	var iparity=0
	var isOK=1
	var coord=""
	var icheckalmostlocked=(igetalmostlockedx||igetalmostlockedy||igetalmostlockedb)

	tempnodelist=""
	globalWeakList = ""


//dumpALSWeakNodes()

	if(!iskipcheck)iskipcheck=0

	//mark all cells for parity -- exit on problem
	//if not isall, then this is just node-to-node
	var N
	for(var ichain=1;ichain<StrongChains.length;ichain++)for(var inode=0;inode<StrongChains[ichain].length;inode++){
		A=StrongNodes[StrongChains[ichain][inode]]
		n=nodeData(A,NDATA)
		D=nodeData(A,DATA)
		b=D.block
		k=nodeData(A,K)
		iparity=-(A[1]>0?1:-1)
		if(n==1){
			r=D.row
			c=D.col
			p=D.bptr
			coord=coordOf(D,k)

			for(var i=0;i<9;i++){
				if(i!=c)isOK&=addWeakNode(Data[r][i],ichain,k,iparity,"row "+(r+1),A,0,iskipcheck)
				if(i!=r &&isOK)isOK&=addWeakNode(Data[i][c],ichain,k,iparity,"col "+(c+1),A,0,iskipcheck)
				if(i!=p &&isOK)isOK&=addWeakNode(Blocks[b][i],ichain,k,iparity,"block "+(b+1),A,0,iskipcheck)
				if(!ijustcolor && i!=k &&isOK)isOK&=addWeakNode(Data[r][c],ichain,i,iparity,Data[r][c].showinfo,A,0,iskipcheck)
				if(!isOK)return 1
			}
			if(icheckalmostlocked && (N=ALSWeakNodes[coord])){
				for(var i=0;i<N.length;i++){
					isOK&=addALSWeakChainNode(coord,N[i],ichain,k,iparity,A,iskipcheck)
					if(!isOK)return 1
				}
			}
		}
	}


	for(var ichain=1;ichain<StrongChains.length;ichain++)for(var inode=0;inode<StrongChains[ichain].length;inode++){
		A=StrongNodes[StrongChains[ichain][inode]]
		n=nodeData(A,NDATA)
		D=nodeData(A,DATA)
		b=D.block
		k=nodeData(A,K)
		iparity=-(A[1]>0?1:-1)
		if(n>1){ //just include all similar k in this block
			x=Possible.XBlock[b][k]
			for(var i=1;i<=n;i++){
				x^=Pwr2[nodeData(A,DATA,i).bptr]
			}
			for(var i=0;i<9;i++)if(x&Pwr2[i]){
				isOK&=addWeakNode(Blocks[b][i],ichain,k,iparity,"block "+(b+1),A,0,iskipcheck)
				if(!isOK)return 1
			}			
		}
	}

	return 0
}

function getNodeInfo(N,info){
	// [[k,D.nodeinfo,D.nodeinfo,D.nodeinfo...],+-ichain]; D.nodeinfo=[D,D.showinfo]
	var ichain=nodeData(N,CHAIN)
	var iparity=nodeData(N,PARITY)
	if(info=="short")return nodeData(N,ALLCOORD)+"("+chainCode(ichain,iparity)+")"
	return nodeData(N,ALLCOORD)+" chain "+chainCode(ichain,iparity,1)
}

function nodeData(N,iwhat,iwhich,msg){
	//Node will be [[k,D.nodeinfo,D.nodeinfo,D.nodeinfo...],+/-ichain,xblocklist (for multidim)] where D.nodeinfo=[D,D.showinfo]
	//document.title=N[0].join("------")+iwhat
	if(iwhat==ALLCOORD||iwhat==SHORTINFO||iwhat==COORDLIST){
		var s=""
		var sep=(iwhat==COORDLIST?",":"-")
		for(var i=1;i<N[0].length;i++)s+=sep+coordOf(N[0][i][0],N[0][0])
		s=s.substring(1,s.length)
		if(iwhat!=COORDLIST && N[0].length>2)s="{"+s+"}"
		return s+(iwhat==SHORTINFO?chainCode(Math.abs(N[1]),N[1]):"")
	}else if(iwhat==SHOWINFO){
		var s=""
		for(var i=1;i<N[0].length;i++)s+="-"+N[0][i][1]
		if(N[0].length>2)s="{"+s+"}"
		s=s.substring(1,s.length)
		return s
	}else if(iwhat==DATA){
		if(!iwhich)iwhich=1
		return N[0][iwhich][0]
	}else{
//if (!N)alert("nodeData" + N + " " + iwhat+  " " + iwhich + " " + msg)
		return(
			iwhat==NDATA?N[0].length-1
			:iwhat==K?N[0][0]
			:iwhat==CHAIN?Math.abs(N[1])
			:iwhat==CHAINCODE?chainCode(Math.abs(N[1]),N[1])
			:iwhat==FULLCHAINCODE?chainCode(Math.abs(N[1]),N[1],1)
			:iwhat==PARITY?(N[1]>0?1:0)
			:iwhat==CHAINPARITY?N[1]
			:iwhat==INFO?getNodeInfo(N)
			:error_in_nodeData
		)
	}
}

function ptrStrongNode(i,j,k){
	var n=StrongNodeList[[k,Data[i][j].nodeinfo]]
	return(n?n:0)
}

