Implement sudoku puzzle 9x9 by Graph - java

I have a sudoku puzzle 9x9 in a text file and I wondering how can we create a Graph from sudoku puzzle.Sudoku puzzle is a int[][] Example puzzle
0 0 0 0 9 8 0 4 5
0 0 4 3 2 0 7 0 0
7 9 0 5 0 0 0 3 0
0 0 0 9 0 0 4 0 0
0 4 5 0 0 2 8 0 0
8 7 9 6 0 4 0 1 0
0 3 0 0 7 9 0 6 4
4 5 0 2 1 3 9 0 8
0 8 7 4 6 5 0 0 0
and class Graph
class Graph
{
private int V;
private LinkedList<Integer> adj[];
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList();
}
void addEdge(int v,int w)
{
adj[v].add(w);
adj[w].add(v);
}
public int getV()
{
return V;
}
public LinkedList<Integer> getListAdj(int u)
{
return adj[u];
}
I write a function to read puzzle from a text file and implement it to graph
public boolean readGraph(String input_name, int result[])
{
return true;
}
But I stuck in this step.

Here goes:
First, I already know that the puzzle is 9x9, so the newlines in the text file are meaningless to me. I can ignore them. Also, I know that each element of the puzzle is only ever going to be a single character long so (after getting the text file into memory like so: Reading a plain text file in Java):
I get my String puzzle which is that text file into memory. Now I want to iterate over that String like so:
Graph graph = new Graph(81); //9x9 graph with 81 verticies
int whichVertextAreWeOn = 0;
for (int i = 0; i < puzzle.length(); i++){
char c = puzzle.charAt(i);
if(c>'0' && c > '9'){
int integer = Integer.parseInt(c);
//now I need to add this to my Graph... Saving my work now, comments are appreciated
//Turns out you simply add edges to each vertex in a graph, the vertex itself has no value...
//so I'm going to keep track of which vertex I'm on, this is starting to seem like a bad data structure for this purpose, but I shall carry on. -Adding an iterator to keep track of which vertex I'm on.
for(int w = 0; w < graph.V(); w++;){
if(vertextIsLinked(whichVertextAreWeOn, w))
graph.addEdge(whichVertextAreWeOn, w);
}
//hum... from here I need to add an edge to this vertex for each connected vertex...
}
}
private boolean vertextIsLinked(int vertexWeAreOn, int possibleVertext){
//use rules of Sukdoku to figure out if these two verticies should be linked. This would return true for any vertex in horizontal or vertical alignment to the vertexWeAreOn.
}

Related

Making a island large leetcode - spotting mistake Java

I am working on LeetCode problem 827. Making A Large Island:
You are given an n x n binary matrix grid. You are allowed to change at most one 0 to be 1.
Return the size of the largest island in grid after applying this operation.
An island is a 4-directionally connected group of 1s.
Example 1:
Input: grid = [[1,0],[0,1]]
Output: 3
Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
My solution fails for the following test case:
[[1,1,0],[0,0,0], [1,1,0]]
The output of my code is 3, but 5 is expected.
Here is my code:
class Solution {
public int largestIsland(int[][] grid) {
int n=grid.length;
int max=0;
boolean hasZero=false;
boolean[][] visited = new boolean[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(grid[i][j]==0){
grid[i][j]=1;
max=Math.max(max,area(grid,n,i,j,visited));
grid[i][j]=0;
// visited[i][j]=false;
hasZero=true;
}
}
}
return hasZero?max:n*n;
}
private int area(int[][] grid, int n, int i, int j, boolean[][] visited){
if(i<0 || i>n-1 || j>n-1 || j<0 || grid[i][j]==0 || visited[i][j])
return 0;
visited[i][j]=true;
int a1 = area(grid,n,i+1,j,visited);
int a2 = area(grid,n,i,j+1,visited);
int a3 = area(grid,n,i-1,j,visited);
int a4 = area(grid,n,i,j-1,visited);
return 1+a1+a2+a3+a4;
}
}
This solution is O(N^4) and I know other, more efficient working solutions, but I'm not able to spot what's wrong with my attempt.
Could someone spot what is wrong?
The problem is that after you have marked an island as visited, it can no longer play a role in a better connection.
For instance, your failing test case:
[[1, 1, ],[0, 0, 0],[1, 1, 0]]
...can be depicted as:
1 1 0
0 0 0
1 1 0
Your code will first try this (changing the value in brackets):
1 1(1)
0 0 0
1 1 0
... and mark those as visited (I'll mark those with "v"):
v v v
0 0 0
1 1 0
...and so it finds 3 for max.
Then it will continue with finding the following:
v v v
(1)0 0
1 1 0
This will lead to a value of 3, which does not improve the previous value for max. But this is wrong, because it really connects with another island that you had marked visited. It should have found this:
1 1 0
(1)0 0
1 1 0
... which is 5.
As you already found working algorithms, I suppose this answers your question.

How to create a 2D array by scanning a file

I'm trying to read a file and generate a 2D Array. So I believe my constructor will create the correct dimensions, I just don't know how to input the actual values into the arrays.
File format:
6
1 4 2 2 2 3
4 2 2 4 1 2
2 1 3 4 3 2
1 3 3 2 6 2
0 0 0 2 0 0
3 4 0 0 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 0 0 6
5 0 1 0 0 4
The file input is on the left, and the board result should look like the right :
6 | 1 4 2 2 2 3
1 4 2 2 2 3 | -----------
4 2 2 4 1 2 | 1|. . . 2 . .|4
2 1 3 4 3 2 | 3|3 4 . . . .|2
1 3 3 2 6 2 | 3|. . . 1 . .|2
0 0 0 2 0 0 | 2|. 1 . . . .|4
3 4 0 0 0 0 | 6|. . . . . 6|1
0 0 0 1 0 0 | 2|5 . 1 . . 4|2
0 1 0 0 0 0 | -----------
0 0 0 0 0 6 | 2 1 3 4 3 2
5 0 1 0 0 4 |
this first line of the file is the size of the board (6x6).
The second line is the "North to South(NS)" facing values
The third line is the "East to West(EW)" facing values
The fourth line is the "South to North(SN)" facing values
The fifth line is the "West to East(WE)" facing values.
And the rest of the lines will populate the board. A 0 will put nothing in.
public static final int EMPTY = 0;
int[][] board;
int dim;
int[] NS, SN, EW, WE; //the outter arrays
public SkyscraperConfig(Scanner f){
while(f.hasNextLine()){
if(f.nextLine().length() == 1){
dim = f.nextInt();
}
else{
outterArrays = f.nextLine().length();
}
}
this.board = new int[dimension+1][dimension+1];//I made the dimension +1 to hold the outter arrays that hold the NS, SN, EW, and WE values
this.NS = new int[outterArrays+1];
this.SN = new int[outterArrays+1];
this.EW = new int[outterArrays+1];
this.WE = new int[outterArrays+1];
}
My Idea was to create a 2D Array that is the size of the first line in the file. Then for the outer values, create four arrays which will represent the outside. I don't know how to put those outer arrays into my 2D array though.
As with all file reading, try to separate each task distinct task. Ask yourself "What do I need to know before I do , and what do I have to do in order to complete ?" Hopefully the tasks are listed in order (each task only requires information above it in the file), which is the case for your problem.
Your task seems to involve three sub tasks:
Figure out how large the arrays and matrix need to be (1 line)
Read in the side arrays (4 lines)
Read in the matrix (N lines)
So let's work with that:
int[][] board;
int dim;
int[] NS, SN, EW, WE; //the outter arrays
public SkyscraperConfig(Scanner f){
//First line should be dimension line
int dim = Integer.parseInt(f.nextLine());
//Initalize data structures based off of this dimension
this.NS = new int[dim];
this.SN = new int[dim];
this.EW = new int[dim];
this.WE = new int[dim];
this.board = new int[dim][dim];
//Read in side arrays
//...
//Read in the board
//...
}
Here we can guess that we're going to have a lot of duplicated code in reading the lines - probably time to start designing helper methods. One thing we seem to be doing a lot of is reading in a line and parsing all of the ints in it. So let's write a method for that
private static int[] parseIntLine(String line){
String[] arr = line.trim().split(' '); //Split on the space character
int[] intArr = new int[arr.length];
for(int i = 0; i < arr.length; i++){
intArr[i] = Integer.parseInt(arr[i]);
}
return intArr;
}
Now we can use this method to finish up our implementation, letting the reading take care of the array length:
public SkyscraperConfig(Scanner f){
//First line should be dimension line
int dim = Integer.parseInt(f.nextLine());
//Only actual initialization we have to do is for the matrix's outer array
board = new int[dim][];
//Read in side arrays
NS = parseIntLine(f.nextLine());
EW = parseIntLine(f.nextLine());
SN = parseIntLine(f.nextLine());
WE = parseIntLine(f.nextLine());
//Read in the board - dim rows to read
for(int i = 0; i < dim; i++){
board[i] = parseIntLine(f.nextLine());
}
f.close();
}
Now there's a lot of things that could go wrong that you should probably account for. What if the first line contains more than just one number? What if the first line contains a non-integer value? What if one of the side arrays or one of the board rows is of the wrong length? What if there aren't enough rows to fill the board? What if there are too many rows? For each of these questions you should either handle the case within the method (via try/catch or if-else logic) or if it's an unfixable problem throw some kind of exception.

Is there a predefined method to padarray in java by a given no of rows and columns with a number

How to padarray in java that is add row and column to a existing array in front and back with a given number.
For example :-
let x = 1 2 3
4 5 6
7 8 9
and now want to 2 rows and columns of zeros in this:
x = 0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 2 3 0 0
0 0 4 5 6 0 0
0 0 7 8 9 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
So, i want to know that is there a existing method or way to do this in java like it is available in matlab using the predefined method called padarray(x,[r,c]).
You can never add rows or columns to 2 dimensional arrays at all. Arrays are fixed size. You could use a dynamic data structure such as List<List<Integer>>.
What you also can do is create a new array (that is bigger or smaller than your current one) using the Arrays.copyOf(int[] original, int newLength); method.
You array x is like:
int[][] x = new int[][]{{1,2,3}, {4,5,6}, {7,8,9}};
There is no one-liner (I know of) to transform it to your desired format. You have to create a method that creates a new 2 dimensional array and place your values at the correct indexes.
Here is some code that takes the 2D array you want padded, what you want it to be padded with, and how many pads to surround the array with (yours would be 2 because you want your array surrounded with 2 layers of 0's).
public static int[][] padArray(int[][] arr, int padWith, int numOfPads) {
int[][] temp = new int[arr.length + numOfPads*2][arr[0].length + numOfPads*2];
for (int i = 0; i < temp.length; i++) {
for (int j = 0; j < temp[i].length; j++) {
temp[i][j] = padWith;
}
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
temp[i+numOfPads][j+numOfPads] = arr[i][j];
}
}
return temp;
}

How can I loop through a Sudoku board?

For example, say we have a Sudoku board like this:
0 0 6 5 8 9 7 4 3
0 5 0 0 0 0 0 6 0
7 0 9 0 6 0 1 0 0
0 3 0 0 0 2 0 8 7
0 0 1 0 0 0 4 0 0
8 9 0 6 0 0 0 5 0
0 0 2 0 5 0 3 0 6
0 7 0 0 0 0 0 9 0
3 1 8 4 9 6 5 0 0
I want to store it into one array such that the first 9 elements of the array are the first sub block, i.e. the values {0 0 6 0 5 0 7 0 9} and followed by {5 8 9 0 0 0 0 6 0}.
I've tried finding a solution but I always get an array index out of bounds error and it is too brute force. Something similar to this:
while(st.hasMoreTokens()) {
if(ctr == 27) {
c.addSubBlock(sb1);
c.addSubBlock(sb2);
c.addSubBlock(sb3);
sb1 = new SubBlock();
sb2 = new SubBlock();
sb3 = new SubBlock();
ctr = 0;
}
sb1.addElement(Integer.parseInt(st.nextToken()));
sb1.addElement(Integer.parseInt(st.nextToken()));
sb1.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
ctr+=9;
}
Please give me some tips. Code snippets would also be a great help.
EDIT: This thread somehow helped me figured it out. And yes, this is part of the Sudoku where I'm trying to encode the board into an array.
What I did was to transform first the input String into a 2d array (9x9) and use int block = (row/3)*3 + (col/3); to compute exactly which sub block each element belongs.
Create a 3x3 array of sub blocks
Use 2 counters (x & y) for tracking the position in the full board of each element read
Add the values at (x,y) into sub block (x/3,y/3)
Something like this:
SubBlock board[][] = new SubBlock[3][3];
int x, y;
for ( y=0; y<9; y++ )
for ( x=0; x<9; x++ )
board[y/3][x/3].addElement(Integer.parseInt(st.nextToken()));
board[0][0] will be the top-left SubBlock, board[2][2] the bottom-right one.
Store everything in a two dimension array. E.g.
int[] board = {
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}};
//looping
public static void Main(string[] args){
for(int i = 0; i < 9; i++)
{
System.out.println("SubBlock number"+i);
for(int j = 0; j < 9; j++){
System.out.println(board[i][j]);
}
}
}
Assuming that you are reading input left to right, top to bottom, try a set of 4 nested loops like this:
int board[] = new int[81];
for (int outY = 0; outY < 3; outY++)
{
for (int outX = 0; outX < 3; outX++)
{
for (int inY = 0; inY < 3; inY++)
{
for (int inX = 0; inX < 3; inX++)
{
board[27*outY + 9*outX + 3 * inY + inX] = //parse an int from your input here
}
}
}
}
It would be great if we knew why you are trying to loop through the board.
If you want to check if you can enter a number, I recommend you use maps for each of the 3x3 squares.
Then check if the item is in the map already or not. For the rows and columns, you can either loop over the 2D array and check each element, or -again- use a map for each column and a map for each row.
I'm not entirely sure if you want an answer for a single-dimension array or if you're willing to make it a two-dimensional array (as you mention each nine element set with curly braces), but if two-dimensional is OK...
The OP in this Code Review posting used a 'fancy' way of sifting through the subgrids by using the math (i % 3) + rowStart inside one of the square brackets and (i / 3) + colStart inside the other. One commenter noted this modulo method to be a bit obscure, and I'm prone to agree, but for how clean it is and the fact that it works, I think it's a solid solution. So, paired with the iteration of the for loop, we can sift through each 'subgrid' cell, as well as each element of row + col.
for(i=0; i<9; ++i)
{
if (puzzle[row][i] == num) return 0;
if (puzzle[i][col] == num) return 0;
if (puzzle[rowStart + (i%3)][colStart + (i/3)] == num) return 0;
}
If we find a number in one of the cells that matches, it's a duplicate, and we exit the function as 'false', or, 0.
EDIT:
Now that I think of it, you could use this same trick for a single-dimension array by using i % 9 instead of 3. You could then determine which 'row' we're on by doing i / 9 and trusting that, since we're dealing with type ints, we'll truncate the unnecessary decimals.
This does verify that this trick is a bit prone towards N-1 indexed data, as someone would assume 'go to the 81st element' would mean go to the 9th column of the 9th row, but using 81 % 9 would yield 0, and 81 / 9 would yield 9, so we'd go to the 0th place at row 9.

How can I make this method end its recursion and reach a maximum?

I ran into a StackOverflowError when running a solution I wrote to an assignment.
These are the exact instructions from the book Java Methods: A & AB:
Write a program in which Cookie Monster finds the optimal path from the upper left corner (0,0) to the lower right corner(SIZE-1,SIZE-1) in a cookie grid (a 2-D array). The elements of the grid contain cookies (a non-negative number) or barrels (-1). On each step, Cookie Monster can only go down or to the right. He is not allowed to step on barrels. The optimal path contains the largest number of cookies.
The program reads the cookie grid from a file and reports the number of cookies on the optimal path. (The path itself is not reported.) A sample data file is provided in JM\Ch19\Exercises\cookies.dat.
Hint: Use a stack. If there is only one way to proceed from the current position, then go there and update the total accumulated number of cookies. If there are two ways to proceed, save one of the possible two points (and its total) on the stack and proceed to the other point. If you have reached the lower-right corner, update the maximum. If there is nowhere to go, examine the stack: pop a saved point, if any, and resume from there.
The goal is to give my teacher the best possible path (the one with the most "cookies" on it).
Okay. so the mentioned cookie map file is this:
1 3 0 5 -1 7 -1 -1 0 4 2 1
-1 3 2 1 -1 4 -1 5 3 -1 1 0
5 4 8 -1 3 2 2 -1 4 -1 0 0
2 1 0 4 1 -1 8 0 2 -1 2 5
1 4 0 1 -1 0 3 2 2 4 1 4
0 1 4 1 1 6 1 4 5 2 1 0
3 2 5 2 0 7 -1 2 1 0 -1 3
0 -1 4 -1 -1 3 5 1 4 2 1 2
5 4 8 -1 3 2 2 -1 4 -1 0 0
2 1 0 4 1 -1 8 0 2 -1 2 5
1 3 0 5 -1 7 -1 -1 0 4 2 1
0 0 3 1 5 2 1 5 4 1 3 3
And this is the class I use to get a 2-D array of the numbers (I know this part works.) Using A BlueJ debugger, the 2-D array seems to be what I want it to be.
import java.util.*;
import java.io.*;
public class MapReader
{
public static int[][] grid;
public static Scanner gridscanner = null;
public static int[][] getMap()
{
File file = new File("cookies.dat");
try
{
gridscanner = new Scanner(file);
}
catch (FileNotFoundException ex)
{
System.out.println("*** Cannot open cookis.dat ***");
System.exit(1);
}
int row = 12;
grid = new int[row][row];
for(int r = 0; r < row; r++)
{
for(int c = 0; c < row; c++)
{
grid[r][c] = gridscanner.nextInt();
}
}
return grid;
}
}
And here is a class I use to keep track of saved positions, their values, and their locations for when I'm traversing this "cookie map":
import java.util.*;
public class Point
{
int row;
int col;
int total;
public Point(int r, int c, int t)
{
row = r;
col = c;
total = t;
}
public int getRow() { return row; }
public int getCol() { return col; }
public int getValue() { return MapReader.getMap()[row][col]; }
public int getTotal() { return total; }
}
And finally, here is the class that I use to recursively travel through the 2D array. You'll notice that I prefer to go right when two paths are available but then go down when I pop a Point from the "saved" Stack. The problem lies in this class as far as I know: How can I make the method end its recursion and reach a maximum?
import java.util.*;
public class CookieMonster
{
private static int[][] map = MapReader.getMap();
private static int max = 11;
private static int total, maximum;
private static Stack<Point> saved = new Stack<Point>();
public static void main(String[] args)
{
System.out.println(move(0,0));
}
public static int move(int r, int c)
{
int right = 0;
int down = 0;
boolean isright = true;
boolean isdown = true;
if (c < max)
{
right = map[r][c + 1];
}
else
isright = false;
if (r < max)
{
down = map[r + 1][c];
}
else
isdown = false;
if (right == -1)
isright = false;
if (down == -1)
isdown = false;
if (isright && isdown)
{
saved.push(new Point(r + 1, c, total + down));
total += right;
move(r, c + 1);
}
else if (isright)
{
total += right;
move(r, c + 1);
}
else if (isdown)
{
total += down;
move(r + 1, c);
}
else
{
if (r == max && c == max)
{
if (maximum < total)
maximum = total;
}
if (!saved.isEmpty())
{
Point sd = saved.pop();
total = sd.getTotal();
move(sd.getRow(), sd.getCol());
}
}
return maximum;
}
}
I know the hint suggests to use a stack, but this problem can be solved much more efficiently using dynamic programming. It is basically recursion with a memory of previously visited paths to avoid recomputation.
Assuming you index the matrix starting at 1, Your cost function should be as follows:
c(i, j) = -INF if i == 0 or j == 0 or data(i, j) < 0
data(1, 1) if i == 1 and j == 1
data(i, j) + min(c(i, j - 1), c(i - 1, j))
You can iterate in the usual nested i-j loop from left to right and up to down.
c(n, n) will give you the result of the optimal path.
This seems np-complete. Using a stack and writing the logic to return to a former path if you run into a dead-end seems like wasted effort. You are going to have to use a lot of brute force even with the stack and logic. It seems easier to just use a primitive to store the number of cookies and just write some logic to move down and right at random. If you hit a dead end, just throw that result out and start over. If you hit the end, save that value and check to see if it is larger than a previous path. It if it is, keep it until you find a larger one. If you run it enough times, you will find the best path. I can't imagine it would take more than a few seconds to find the most cookies.

Categories

Resources