/*
Copyright 2005 Vegard Hanssen, Vegard@menneske.no
http://www.menneske.no/sudokuto/
*/

function populateGrid() {
    var grid, r, c;
    grid = new Array(size);
    for(r=0;r<size;r++) {
	grid[r] = new Array(size);
    }
    for(r=0;r<size;r++) {
	for (c=0;c<size;c++) {
	    grid[r][c] = getCellNumber(r,c);
	}
    }
    return grid;
}

function getCellNumber(r, c) {
    el = document.getElementById("IP"+r+c);
    if(el.value>0) {
	return el.value;
    } else {
	return 0;
    }
}

function setCellNumber(r, c, num) {
    el = document.getElementById("IP"+r+c);
    el.value = num;
    el.style.backgroundColor = "rgb(200,200,200)";
}

function resetBackground() {
    for(var r=0;r<size;r++) {
	for(var c=0;c<size;c++) {
	    el = document.getElementById("IP"+r+c);
	    el.style.backgroundColor = "rgb(255,255,255)";
	}
    }
}

function compareGrids(m1, m2) {
    var count=0,r,c, resr, resc;
    for(r=0;r<size;r++) {
	for(c=0;c<size;c++) {
	    if (m1[r][c] != m2[r][c]) {
		count++;
		resr = r;
		resc = c;
	    }
	}
    }
    return new Array(count, resr, resc);
}

function clearGrid() {
    resetBackground();
    for(r=0;r<size;r++) {
	for(c=0;c<size;c++) {
	    el=document.getElementById("IP"+r+c);
	    el.value="";
	}
    }
    won = 0;
    lose = 0;
    oldgrid = populateGrid();
}

function showThinkingText(text) {
    el = document.getElementById("idthink");
    el.innerHTML = text;
}

function removeThinkingText() {
    el = document.getElementById("idthink");
    el.innerHTML = "";
}

function postTurn() {
    //    showThinkingText();
    resetBackground();
    var newgrid;
    if (lose==1) {
	alert(message[1]);
	return;
    }
    if (won==1) {
	alert(message[2]);
	return;
    }

    newgrid = populateGrid();
    var comp = compareGrids(newgrid, oldgrid);
    if (comp[0]>1) {
	alert(message[3]);
	lose = 1;
    } else if (comp[0]==1) {
	if (checkLegalGrid()==0) {
	    alert(message[4]);
	    lose = 1;
	    return;
	}
	if (checkFullRCB()==1) {
	    won = 1;
	    alert(message[5]);
	} else {
	    if(doComputerTurn()==1) {
		if (checkFullRCB()==1) {
		    lose = 1;
		    alert(message[7]);
		} else if(getAllAvailableCoords().length==0) {
		    lose = 1;
		    alert(message[7]);
		} else {
		    oldgrid = populateGrid();
		}
	    } else {
		won = 1;
		alert(message[5]);
	    }
	}
    } else {
	alert(message[6]);
	lose = 1;
    }
    //        removeThinkingText();
}

function doComputerTurn() {
    var coord = findNextSpot();
    if (coord[0] == -1) {
	return 0;
    }
    var nums = getPossibleNumbers(coord[0], coord[1]);
    var rand = Math.floor(Math.random()*(nums.length/2));
    setCellNumber(coord[0], coord[1], nums[rand]);
    return 1;
}

function findNextSpot() {
    if (difficultlvl>1) {
	var coord = findSingleCell();
	if (coord[0] != -1) {
	    return coord;
	}
    }
    var found = 0;
    var coords;
    if (difficultlvl>2) {
	coords = getCellsWithThreeOrMoreCoords();
	if (coords[0] != -1) {
	    found = 1;
	}
    }
    if(found == 0) {
	coords = getAllAvailableCoords();
	if (coords[0] == -1) {
	    return new Array(-1,-1);
	}
    }
    var rand = Math.floor(Math.random()*(coords.length/2));
    coord = new Array(2);
    coord[0] = coords[rand*2];
    coord[1] = coords[(rand*2)+1];
    return coord;
}

function findSingleCell() {
    for(var r=0;r<size;r++) {
	var count=0,posc;
	for(var c=0;c<size;c++) {
	    if (getCellNumber(r,c)==0) {
		count++;
		posc = c;
	    }
	}
	if (count==1) {
	    if (getPossibleNumbers(r,posc).length>0) {
		return new Array(r,posc);
	    }
	}
    }

    for(var c=0;c<size;c++) {
	var count=0,posr;
	for(var r=0;r<size;r++) {
	    if (getCellNumber(r,c)==0) {
		count++;
		posr = r;
	    }
	}
	if (count==1) {
	    if (getPossibleNumbers(posr,c).length>0) {
		return new Array(posr,c);
	    }
	}
    }

    for(var i=0;i<size;i++) {
	var list = getBoxCoords(i);
	var count=0, posr, posc;
	for(var y=0;y<list.length;y+=2) {
	    if (getCellNumber(list[y], list[y+1])==0) {
		count++;
		posr = list[y];
		posc = list[y+1];
	    }
	}
	if (count==1) {
	    if (getPossibleNumbers(posr,posc).length>0) {
		return new Array(posr,posc);
	    }
	}
    }
    return new Array(-1,-1);
}

function checkLegalGrid() {
    var grid, numbers;
    grid = populateGrid();
    for(var r=0;r<size;r++) {
	if(checkLegalCoords(getRowCoords(r))==0) { return 0; }
    }

    for(var c=0;c<size;c++) {
	if(checkLegalCoords(getColumnCoords(c))==0) { return 0; }
    }

    for(var i=0;i<size;i++) {
	if(checkLegalCoords(getBoxCoords(i))==0) { return 0; }
    }
    return 1;
}

function checkLegalCoords(coords) {
    var numbers = getBooleanList(size, 0);
    for(var i=0;i<coords.length;i+=2) {
	var num = getCellNumber(coords[i], coords[i+1])-1;
	if (num>=size) { return 0; }
	if (num == -1) {
	    continue;
	}
	if (numbers[num]==1) { return 0; }
	numbers[num] = 1;
    }
    return 1;
}

function getBooleanList(nums, init) {
    var list = new Array(nums);
    for(var i=0;i<nums;i++) {
	list[i] = init;
    }
    return list;
}

function getRowCoords(r) {
    var list = new Array(size*2);
    for(var c=0;c<size;c++) {
	list[c*2] = r;
	list[(c*2)+1] = c;
    }
    return list;
}

function getColumnCoords(c) {
    var list = new Array(size*2);
    for(var r=0;r<size;r++) {
	list[r*2] = r;
	list[(r*2)+1] = c;
    }
    return list;
}

function getBoxCoords(box) {
    var list = new Array(size*2);
    var rstart = Math.floor(box/sizer)*sizer;
    var cstart = (box-rstart)*sizec;
    var pos = 0;
    for(var r=rstart;r<rstart+sizer;r++) {
	for(var c=cstart;c<cstart+sizec;c++) {
	    list[pos++] = r;
	    list[pos++] = c;
	}
    }
    return list;
}

function getBoxCoordsRC(r, c) {
    var list = new Array(size*2);
    var rstart = Math.floor(r/sizer)*sizer;
    var cstart = Math.floor(c/sizec)*sizec;
    var pos = 0;
    for(var r=rstart;r<rstart+sizer;r++) {
	for(var c=cstart;c<cstart+sizec;c++) {
	    list[pos++] = r;
	    list[pos++] = c;
	}
    }
    return list;
}

function getPossibleNumbers(r, c) {
    var numbers = getBooleanList(size, 1);
    coords = getRowCoords(r);
    for(var i=0;i<coords.length;i+=2) {
	var num = getCellNumber(coords[i], coords[i+1])-1;
	numbers[num] = 0;
    }
    coords = getColumnCoords(c);
    for(var i=0;i<coords.length;i+=2) {
	var num = getCellNumber(coords[i], coords[i+1])-1;
	numbers[num] = 0;
    }
    coords = getBoxCoordsRC(r, c);
    for(var i=0;i<coords.length;i+=2) {
	var num = getCellNumber(coords[i], coords[i+1])-1;
	numbers[num] = 0;
    }
    var count = 0;
    for(var i=0;i<size;i++) {
	if (numbers[i] == 1) {
	    count++;
	}
    }
    var list = new Array(count);
    var pos = 0;
    for(var i=0;i<size;i++) {
	if (numbers[i] == 1) {
	    list[pos++] = i+1;
	}
    }
    return list;
}

function getAllAvailableCoords() {
    var count = 0;
    var grid = getEmptyGrid();
    for(var r=0;r<size;r++) {
	for(var c=0;c<size;c++) {
	    if ((getCellNumber(r,c) == 0) && (getPossibleNumbers(r,c).length>0)) {
		count++;
		grid[r][c] = 1;
	    }
	}
    }
    if (count==0) {
	return new Array(-1,-1);
    }
    var list = new Array(count*2);
    var pos = 0;
    for(var r=0;r<size;r++) {
	for(var c=0;c<size;c++) {
	    if (grid[r][c] == 1) {
		list[pos++] = r;
		list[pos++] = c;
	    }
	}
    }
    return list;
}

function getCellsWithThreeOrMoreCoords() {
    var grid = getEmptyGrid();
    var count = 0;
    for(var r=0;r<size;r++) {
	for(var c=0;c<size;c++) {
	    if (getCellNumber(r,c)!=0) { continue; }
	    if (getPossibleNumbers(r,c).length==0) { continue; }
	    if (getCountOnIllegalCells(getRowCoords(r))==0 && getCountOnFreeCells(getRowCoords(r))<3) { continue; }
	    if (getCountOnIllegalCells(getColumnCoords(c))==0 && getCountOnFreeCells(getColumnCoords(c))<3) { continue; }
	    if (getCountOnIllegalCells(getBoxCoords(r,c))==0 && getCountOnFreeCells(getBoxCoords(r,c))<3) { continue; }
	    count++;
	    grid[r][c] = 1;
	}
    }
    if (count == 0) {
	return new Array(-1,-1);
    }
    var list = new Array(count*2);
    var pos = 0;
    for(var r=0;r<size;r++) {
	for(var c=0;c<size;c++) {
	    if (grid[r][c] == 1) {
		list[pos++] = r;
		list[pos++] = c;
	    }
	}
    }
    return list;
}

function getEmptyGrid() {
    var grid = new Array(size);
    for(r=0;r<size;r++) {
	grid[r] = new Array(size);
    }
    for(r=0;r<size;r++) {
	for (c=0;c<size;c++) {
	    grid[r][c] = 0;
	}
    }
    return grid;
}

function getCountOnFreeCells(list) {
    var count = 0;
    for(var i=0;i<list.length;i+=2) {
	if ((getCellNumber(list[i], list[i+1]) == 0) &&
	    (getPossibleNumbers(list[i], list[i+1]).length>0)) {
	    count++;
	}
    }
    return count;
}

function getCountOnIllegalCells(list) {
    var count = 0;
    for(var i=0;i<list.length;i+=2) {
	if ((getCellNumber(list[i], list[i+1]) == 0) &&
	    (getPossibleNumbers(list[i], list[i+1]).length==0)) {
	    count++;
	}
    }
    return count;  
}

function checkFullRCB() {
    for(var r=0;r<size;r++) {
	var count = 0;
	for(var c=0;c<size;c++) {
	    if (getCellNumber(r, c)>0) {
		count++;
	    }
	}
	if (count==size) { return 1; }
    }

    for(var c=0;c<size;c++) {
	var count = 0;
	for(var r=0;r<size;r++) {
	    if (getCellNumber(r, c)>0) {
		count++;
	    }
	}
	if (count==size) { return 1; }
    }

    for(var i=0;i<size;i++) {
	var list = getBoxCoords(i);
	var count = 0;
	for(var y=0;y<list.length;y+=2) {
	    if (getCellNumber(list[y], list[y+1])>0) {
		count++;
	    }
	}
	if (count==size) { return 1; }
    }

}
