Saturday, August 20, 2011

Hint for sudoku

I keep playing sudoku at http://www.websudoku.com Most of the time I solve the puzzle easily. There are situation where it is difficult to make any logical move. We get stuck without able to post numbers in any of the cells.

In such cases, I usually fill all the empty cells with the probable numbers that can fit in that cell. For eg, I place the numbers 278 if these three numbers have a chance of being placed in a cell. With all empty cells having such probable numbers, it is easy to apply some deduction logic to narrow down the correct numbers.

Filling in the probable numbers is a tedious task. I came up with a simple java code that would help in filling the numbers (just the hint, not the actual answers).

Instruction to use the code:
  • Install watij as mentioned at http://watij.com/webspec-api/
  • Copy the java code I had placed in the comment section (placed in 3 comments due to comment size restriction)
  • run the java code along with the classpath pointing to watij class and jars
  • This will open a window and websudoku site is opened
  • Settings page is accessed automatically and few settings are tweaked
  • once you get the puzzle page, play it as you would do in normal manner
  • When you get stuck, click on the 'Done' button in the top panel. The button name is marked as 'pauseUntil'
  • we should have numbers filled now. Once that happens, continue with the game

Happy sudoku.

6 comments:

Jeya Balaji said...

package open.sudoku.hint;

import org.watij.webspec.dsl.Tag;
import org.watij.webspec.dsl.WebSpec;



/**
* @author Jeya Balaji
* jeya.balaji@gmail.com
*
* 18th Jul 2011
*/

/**
* purpose : to open up a browser with http://www.websudoku.com
* and if required, fill the blank cells with possible numbers
*/

public class SudokuHint {

public static final int NUM_COLS = 9;
public static final int NUM_ROWS = 9;
public static final int MATRIX_SIZE = 9;
public static final int GRID_SIZE = 3;
public static final int MAX_HINT_SIZE = 5;

public static final int MAX_TRY = 5;


private void openBrowser() {
WebSpec spec = new WebSpec().mozilla();
// WebSpec spec = new WebSpec().ie();
changeSettings(spec);

waitForUserRequest(spec);
}

private void changeSettings(WebSpec spec) {
spec.open("http://view.websudoku.com/?select=1&level=4");
spec.find().input().with().name("goto").click();
spec.find().input().with().name("showopts").click();

spec.find().input().with().type("radio").with().name("options1").at(0).set.checked(true);
spec.find().input().with().type("checkbox").with().name("options3").set.checked(true);
spec.find().input().with().name("saveopts").click();
}


/*
* user need to press 'Done' button to get sudoku hints
*/
private void waitForUserRequest(WebSpec spec) {
while(true)
{
spec.pauseUntilDone();
fillHints(spec);
}
}



private void fillHints(WebSpec spec) {
int[][] givenMatrix = captureMatrix(spec);
String[][] hintMatrix = prepareHints(givenMatrix);
displayHint(spec, hintMatrix);
}



/*
* collect numbers from the webpage
*/
private int[][] captureMatrix(WebSpec spec) {

System.out.println("Capturing matrix");

int[][] matrix = new int[NUM_COLS][NUM_ROWS];
for(int col=0; col < NUM_COLS; col++)
{
for(int row=0; row < NUM_ROWS; row++)
{
String val = getValue(spec, col, row);
if(val == null || "".equals(val))
val = "0";
try
{
matrix[col][row] = Integer.parseInt(val);
}
catch(Exception ex)
{
matrix[col][row] = 0;
}
System.out.print(".");
}
}

System.out.println("");

return matrix;
}


private void displayHint(WebSpec spec, String[][] hintMatrix) {
System.out.println("display hints");

for(int col=0; col < NUM_COLS; col++)
{
for(int row=0; row < NUM_ROWS; row++)
{
if(hintMatrix[col][row] == null || "".equals(hintMatrix[col][row])) continue;
setValue(spec, col, row, hintMatrix[col][row]);
}
}
}



private String[][] prepareHints(int[][] givenMatrix) {
System.out.println("Preparing hints");

String[][] hintMatrix = new String[NUM_COLS][NUM_ROWS];

for(int col=0; col < NUM_COLS; col++)
{
for(int row=0; row < NUM_ROWS; row++)
{
if(givenMatrix[col][row] == 0)
hintMatrix[col][row] = prepateHint(givenMatrix, col, row);
}
}

return hintMatrix;
}

Jeya Balaji said...

/*
* generate the hint for a particular empty cell
*/
private String prepateHint(int[][] givenMatrix, int col, int row) {
String hint = "";
for(int num = 1; num <= MATRIX_SIZE; num++)
{
if(! hasOccured(givenMatrix, col, row, num))
hint += num;
}

// if(hint.length() > MAX_HINT_SIZE) hint = "X";
return hint;
}

/*
* checks if a number has occurred in the col or row or in the grid
*/
private boolean hasOccured(int[][] givenMatrix, int givenCol, int givenRow, int givenNum) {

for(int col = 0; col < NUM_COLS; col++)
{
if(col != givenCol && givenMatrix[col][givenRow] == givenNum)
return true;
}

for(int row = 0; row < NUM_ROWS; row++)
{
if(row != givenRow && givenMatrix[givenCol][row] == givenNum)
return true;
}

int startCol = (givenCol / GRID_SIZE) * GRID_SIZE;
int startRow = (givenRow / GRID_SIZE) * GRID_SIZE;

for(int col = startCol; col < startCol + GRID_SIZE; col++)
{
for(int row = startRow; row < startRow + GRID_SIZE; row++)
{
if(col == givenCol && row == givenRow) continue;
if(givenMatrix[col][row] == givenNum) return true;
}
}

return false;
}


private String getValue(WebSpec spec, int col, int row) {
String id = composeId(col, row);

for(int i=0; i < MAX_TRY; i++)
{
try
{
return spec.findWithId(id).get().value();

}
catch(Exception ex)
{
//
// ex.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {

}
System.out.println("Attempting again " + i);
}

System.out.println("Error while getting value from col=" + col + ", row=" + row);
return "";
}


private void setValue(WebSpec spec, int col, int row, String value) {
String id = composeId(col, row);

for(int i=0; i < MAX_TRY; i++)
{
try
{
Tag cell = spec.findWithId(id);
cell.set().value(value);
cell.call().onKeyUp();
return;
}
catch(Exception ex)
{
//
// ex.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {

}
System.out.println("Attempting again " + i);
}

System.out.println("Error while setting value at col=" + col + ", row=" + row);


}

Jeya Balaji said...

/*
private String getValue(WebSpec spec, int col, int row) {
String id = composeId(col, row);
try
{
return spec.findWithId(id).get().value();
}
catch(Exception ex)
{
// System.out.println("Error while checking col=" + col + ", row=" + row);
// ex.printStackTrace();
}

return "";
}


private void setValue(WebSpec spec, int col, int row, String value) {
String id = composeId(col, row);
Tag cell = spec.findWithId(id);
cell.set().value(value);
cell.call().onKeyUp();

// for(int i = 0; i < value.length(); i++)
// {
// spec.findWithId(id).set().value(spec.findWithId(id).get().value() +
// value.charAt(i));
// }
}
*/

private String composeId(int col, int row) {
return "f" + col + row;
}

/**
* @param args
*/
public static void main(String[] args) {
SudokuHint sudokuHint = new SudokuHint();
sudokuHint.openBrowser();
// sudokuHint.testing();
}



public void testing()
{
WebSpec spec = new WebSpec().mozilla();
// WebSpec spec = new WebSpec().ie();

spec.open("http://www.websudoku.com/?select=1&level=4");
// System.out.println(spec.source());

Tag src = spec.find().frameset().find().frame();
System.out.println(src.exists());
System.out.println(src.get("src"));
System.out.println(src.find().html().toString());


src.find().input().with().name("goto").click();
src.find().input().with().name("showopts").click();
//
// spec.find().input().with().type("radio").with().name("options1").at(0).set.checked(true);
// spec.find().input().with().type("checkbox").with().name("options3").set.checked(true);
// spec.find().input().with().name("saveopts").click();
}

}

Cari said...

Whoo-hooo! I love sudokus! Thanks!

Anam said...

WoW! That's really great I will say. I am sure you quite worked hard to get this on place. Just tweeted to my twitter. Please do keep up this work.

Regards,
Anam

rugged breed said...

sudoku makes me crazy, I didn't even recognize the time while I am playing with this game, takes for the hints!


Zero Dramas