Java – KenKen Puzzle Solver

import java.util.HashMap;

public class KenKen {

    static int[][] table;//2-dimensional array to represent matrix
    static int width = 4;//this means 4x4 table

    // this hashmap stores contraints like 16x, 7+, 2-, 4
    static HashMap<String, String> constraints = new HashMap<>();

    public static void main(String[] args) {

        table = getEmptyTable();
        fillConstraints();

        int r = 0;//row index
        int c = 0;//column index

        // check all combinations while row index and column index not more than index
        while (r<width && c<width) {
            if (table[r][c] < width) {// if cell value less than max value
                table[r][c]++; // increment cell value by 1
                if (isValid(r, c)) { // check cell value
                    c++; // if cell value is valid move to next cell
                    if (c == width) {//if there is no more column, move to
                        c = 0;//first column
                        r++;//of next line
                    }
                }
            } else {//if cell value more than max value
                table[r][c] = 0;//make it 0
                c--;//because we move to previous column
                if (c < 0) {//if there is no column on the left, move to
                    c = width - 1;//the last column
                    r--;//of previous row
                }
            }
        }
       
        printTable();//print result

    }
   
    // kenken constraints
    private static void fillConstraints() {
        constraints.put("0-0 0-1 1-1", "16 *"); //cell(row:0,column:0) * cell(row:0,column:1) * cell(row:1,column:1) = 16
        constraints.put("0-2 0-3 1-2", "7 +"); // cell(row:0,column:2) + cell(row:0,column:3) + cell(row:1,column:2) = 7
        constraints.put("1-0 2-0", "2 -"); // cell(row:1,column:0) - cell(row:2,column:0) = 2
        constraints.put("2-1 3-0 3-1", "12 *"); // cell(row:2,column:1) * cell(row:3,column:0) * cell(row:3,column:1) = 12
        constraints.put("2-2 2-3", "2 /"); // cell(row:2,column:2) / cell(row:2,column:3) = 2
        constraints.put("3-2 3-3", "2 /"); // cell(row:3,column:2) / cell(row:3,column:3) = 2
        constraints.put("1-3", "4 ="); // cell(row:1,column:3) = 4
    }


    private static boolean isValid(int r, int c) {
        // this method checks cell value validity by its row index and column index

        // check row validity
        for (int i = 0; i < width; i++) {
            if (i != c && table[r][c] == table[r][i])
                return false;
        }

        // check column validity
        for (int i = 0; i < width; i++) {
            if (i != r && table[r][c] == table[i][c])
                return false;
        }

        // check constraints validity
        for (String key : constraints.keySet()) { // loop each key(cell positions)
           
            if (key.contains(r + "-" + c)) {
                //if key(cell positions) has needed position

                String constraint = constraints.get(key); // get contraint like "16 *" which means multiply of cells equals 16

                String operator = constraint.substring(constraint.indexOf(" ") + 1);//get operator. eg "*" from "16 *"
                int num = Integer.parseInt(constraint.substring(0, constraint.indexOf(" ")));//get number. eg 16 from "16 *"
                double result = 0;//using this variable we will check contstraint

                String[] positions = key.split(" ");//split cell positions "0-0 0-1 1-1" to "0-0","0-1","1-1"
                for (int i = 0; i < positions.length; i++) {
                    // loop each position like "0-0" from "0-0 0-1 1-1"
                   
                    int posR = Integer.parseInt(positions[i].substring(0, positions[i].indexOf("-"))); //get row. eg 1 from "1-2"
                    int posC = Integer.parseInt(positions[i].substring(positions[i].indexOf("-") + 1)); //get column eg 2 from "1-2"
                   
                    if (table[posR][posC] == 0) return true;//if cell value equals 0, we cannot make sure this is valid or not, so return true which means valid

                    if (operator.equals("="))
                        return (table[posR][posC] == num);//if constraint "=", let's check equality of cell value and constraint number
                    else if (operator.equals("+"))
                        result = result + table[posR][posC];//if "+", add cell value to sum, in order to compare it in the end of check
                    else if (operator.equals("*")) {
                        if (result == 0)
                            result = 1;// if multiplication of 0 is 0, that's why let's start with 1
                        result = result * table[posR][posC];//multiply result by cell value
                    } else if (operator.equals("-")) {
                        result = result - table[posR][posC];//minus cell value from another value
                        if (result < 0)
                            result = result * -1;//if result is negative, make it positive :)
                    } else if (operator.equals("/")) {
                        if (result == 0) {
                            result = 1;// same as multiplication, 0/x=0
                        } else {
                            if (result % table[posR][posC] != 0 && table[posR][posC] % result != 0)
                                return false;// if we cannot devide value by cell value, it is not divisible (not valid)
                        }
                        result = result / table[posR][posC];//devide one value by another
                        if (result < 1) {// image we have 2 and 4. 2/4=0.5 so we convert this to 1/0.5=2 like 4/2=2
                            result = 1 / result;
                        }

                    }

                }

                return result == num;//check constraint value
                // for example c1=2, c2=4, c3=2
                // contraint "16 *"
                // c1 * c2 * c3 = 16
                // 2 * 4 * 2 = 16 valid

            }
        }

        return true;

    }

   
   
    /*
        method to get empty matrix table with 0s
        0 means empty
        if width = 3;
        matrix will look like this:
        0 0 0
        0 0 0
        0 0 0
     */

    private static int[][] getEmptyTable() {
        int[][] table = new int[width][];

        for (int i = 0; i < width; i++) {
            table[i] = new int[width];
            for (int num : table[i]) {
                num = 0;
            }
        }
        return table;
    }
   
   
   
   
    // print table on console
    private static void printTable() {
       
        for (int i = 0; i < table.length; i++) {
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < width; j++) {
                if (sb.toString().length() > 0)
                    sb.append(" ");
                sb.append(table[i][j]);
            }
            System.out.println(sb.toString());
        }

    }
   
   

}