diff --git a/DroidSudSolve.iml b/DroidSudSolve.iml
new file mode 100644
index 0000000..4df0d25
--- /dev/null
+++ b/DroidSudSolve.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 51cfdae..f04b4cd 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,7 @@
-# droidsudsolve
\ No newline at end of file
+Sudoku solver for Android (open source)
+
+This sudoku solver is written by Ashik (ashik@ashikslab.in)
+using the libexact software library for solving exact cover problems.
+
+libexact was developed by Petteri Kaski and Olli Pottonen
+at the Helsinki University of technology.
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 0000000..650b8e7
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..0500367
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 17
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ applicationId "com.oldestmonk.droidsudsolve"
+ minSdkVersion 8
+ targetSdkVersion 17
+
+ ndk {
+ moduleName "exactcaller"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+ externalNativeBuild {
+ ndkBuild {
+ path '../../../Dropbox/workspace/DroidSudSolve/jni/Android.mk'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:gridlayout-v7:18.0.0'
+ compile 'com.android.support:support-v4:18.0.0'
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..be62e1f
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/oldestmonk/droidsudsolve/MainActivity.java b/app/src/main/java/com/oldestmonk/droidsudsolve/MainActivity.java
new file mode 100644
index 0000000..87257de
--- /dev/null
+++ b/app/src/main/java/com/oldestmonk/droidsudsolve/MainActivity.java
@@ -0,0 +1,495 @@
+package com.oldestmonk.droidsudsolve;
+
+import android.R.color;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.text.style.EasyEditSpan;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Gravity;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+import android.view.ViewGroup.LayoutParams;
+import java.util.TreeSet;
+import java.util.TreeSet;
+
+import com.oldestmonk.droidsudsolve.R;
+
+public class MainActivity extends Activity {
+ private static final int MENU_CLEARALL = 1;
+ private static final int MENU_EXITAPP = 2;
+ private TextView[][] tvarray;
+ private Button[] numbtns;
+ int curposinmatrix;
+ protected static final int[] bresids={
+ R.drawable.back1,
+ R.drawable.back2,
+ R.drawable.back3,
+ R.drawable.back8,
+ R.drawable.back9,
+ R.drawable.back4,
+ R.drawable.back7,
+ R.drawable.back6,
+ R.drawable.back5
+ };
+ public MainActivity() {
+ tvarray = new TextView[9][9];
+ numbtns = new Button[10];
+ curposinmatrix = -1;
+
+ }
+ public native int[] exactcaller(int[] jproblem);
+ static {
+ System.loadLibrary("exactcaller");
+ }
+ protected void setTvBack(int i, int j) {
+
+ int ii = i%3;
+ int jj = j%3;
+ int cresid = bresids[ii+jj*3];
+ tvarray[i][j].setBackgroundResource(cresid);
+ }
+ protected void deactivatePreviousTv(int cpinmat) {
+ int i = cpinmat/9;
+ int j = cpinmat%9;
+ tvarray[i][j].setBackgroundColor(Color.WHITE);
+ curposinmatrix = -1;
+ }
+ protected boolean alContainsVal(TreeSet al, int val) {
+ for( int x : al )
+ {
+ if(x==val)
+ return true;
+ }
+ return false;
+ }
+ protected void activateTv(int i, int j) {
+ if(curposinmatrix!=-1) {
+ deactivatePreviousTv(curposinmatrix);
+ }
+ tvarray[i][j].setBackgroundColor(Color.YELLOW);
+ curposinmatrix = i*9+j;
+ for(int u=0; u<9; u++) {
+ for(int v=0; v<9; v++) {
+ setTvBack(u,v);
+ }
+ }
+ tvarray[i][j].setBackgroundColor(Color.YELLOW);
+ }
+ int getValAt(int i, int j) {
+ String str = tvarray[i][j].getText().toString();
+ if(str.equals("")) {
+ return 0;
+ }
+ else {
+ return Integer.parseInt(str);
+ }
+ }
+ TreeSet getErrors() {
+ TreeSet retval = new TreeSet();
+ int[][] curvalues = new int[9][9];
+ for(int i=0; i<9; i++) {
+ for(int j=0; j<9; j++) {
+ curvalues[i][j] = getValAt(i, j);
+ }
+ }
+ // row and column checks are done by the following for loop
+ for(int i=0; i<9; i++) {
+ //check for row i and column i
+ for(int j=0; j<9; j++) {
+ for(int k=j+1; k<9; k++) {
+ if(curvalues[i][j]!=0 && (curvalues[i][j]== curvalues[i][k])){
+ retval.add(i*9+j);
+ retval.add(i*9+k);
+ }
+ if(curvalues[j][i]!=0 && (curvalues[j][i]== curvalues[k][i])){
+ retval.add(j*9+i);
+ retval.add(k*9+i);
+ }
+ }
+ }
+ }
+ for(int ci=0; ci<3; ci++) {
+ for(int cj=0; cj<3; cj++) {
+ int cbegini = ci*3;
+ int cbeginj = cj*3;
+ for(int iti=cbegini; iti al = getErrors();
+ for (Integer val : al)
+ {
+ int i = val/9;
+ int j = val%9;
+ tvarray[i][j].setTextColor(Color.RED);
+ }
+ if(alContainsVal(al, curi*9+curj)) {
+ activateTv(curi, curj);
+ }
+ }
+ protected void changeValueAt(int curposi, int curposj, int val) {
+ if(val==0) {
+ tvarray[curposi][curposj].setText("");
+ }
+ else {
+ tvarray[curposi][curposj].setText(String.valueOf(val));
+ }
+ curposinmatrix = -1;
+ checkValuesAndWarn(curposi, curposj);
+ }
+ protected void handleBtnPress(int i) {
+ if(curposinmatrix==-1) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Please click on a cell to select it, then click on a value to enter that value to the cell!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ else {
+ int curposi = curposinmatrix/9;
+ int curposj = curposinmatrix%9;
+ changeValueAt(curposi, curposj, i);
+ }
+ }
+ void fillSolution(int[] solution, boolean[] wasempty) {
+ for(int n=0; n<81; n++) {
+ int i = n/9;
+ int j = n%9;
+ tvarray[i][j].setText(String.valueOf(solution[n]));
+ if(wasempty[n]) {
+ tvarray[i][j].setTextColor(Color.GREEN);
+ }
+ setTvBack(i, j);
+ }
+ }
+ void fillCell(int i, int j, int val) {
+ tvarray[i][j].setText(String.valueOf(val));
+ tvarray[i][j].setBackgroundColor(Color.GREEN);
+ }
+ boolean isGoodSol(int[] sol) {
+ if(sol[0]==100)
+ return false;
+ for(int i=0; i<81; i++) {
+ if(sol[i]==0)
+ return false;
+ }
+ return true;
+ }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ setContentView(R.layout.activity_main);
+
+ TableLayout tl = (TableLayout) findViewById(R.id.sudokutable);
+
+ for (int j = 0; j < 9; j++) {
+ TableRow tr = new TableRow(this);
+// tr.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
+// LayoutParams.WRAP_CONTENT));
+ tr.setLayoutParams(new TableRow.LayoutParams(
+ LayoutParams.MATCH_PARENT,0,0.1f));
+ for (int i = 0; i < 9; i++) {
+ TextView tView = new TextView(this);
+
+ tView.setLayoutParams(new TableRow.LayoutParams(0,
+ LayoutParams.WRAP_CONTENT, 1f));
+ //tView.setBackgroundResource(R.drawable.back);
+ tView.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
+// tView.setLayoutParams(new LayoutParams(
+// LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+ //set it's height = width
+
+ tr.addView(tView);
+ tvarray[i][j] = tView;
+
+ int cellht = getResources().getDisplayMetrics().widthPixels/11;
+ tView.setHeight(cellht);
+ setTvBack(i,j);
+ final int finali = i;
+ final int finalj = j;
+ tvarray[i][j].setOnClickListener(new TextView.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ activateTv(finali,finalj);
+ }
+ });
+
+ }
+ tl.addView(tr);
+ }
+ TableLayout tnt = (TableLayout) findViewById(R.id.numtable);
+ TableRow tr2 = new TableRow(this);
+ tr2.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ int bside = getResources().getDisplayMetrics().widthPixels/10;
+ for(int i=1; i<6; i++) {
+ Button numbtn = new Button(this);
+
+ numbtn.setText(String.valueOf(i));
+ tr2.addView(numbtn);
+ numbtns[i] = numbtn;
+ }
+ tnt.addView(tr2);
+ TableRow tr3 = new TableRow(this);
+ tr3.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ for(int i=6; i<10; i++) {
+ Button numbtn = new Button(this);
+
+ numbtn.setText(String.valueOf(i));
+ tr3.addView(numbtn);
+ numbtns[i] = numbtn;
+ }
+
+ Button numbtn = new Button(this);
+
+ numbtn.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
+ numbtn.setText("X");
+ numbtn.setBackgroundColor(Color.RED);
+ tr3.addView(numbtn);
+ numbtns[0] = numbtn;
+ tnt.addView(tr3);
+
+ for(int i=0; i<10; i++) {
+ final int finali = i;
+ numbtns[i].setOnClickListener(new TextView.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ handleBtnPress(finali);
+ }
+ });
+ }
+ TableRow tr4 = new TableRow(this);
+ tr4.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.MATCH_PARENT));
+ Button hintbtn = new Button(this);
+ hintbtn.setText("Hint");
+ final Activity factivity = this;
+ hintbtn.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ TreeSet el = getErrors();
+ if(!el.isEmpty()) {
+ //show alertdialog
+ AlertDialog.Builder builder = new AlertDialog.Builder(factivity);
+ builder.setMessage("Error in your input. Please correct values marked in red!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ if(curposinmatrix==-1 || getValAt(curposinmatrix/9, curposinmatrix%9)!=0) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(factivity);
+ builder.setMessage(
+ "First click on an empty cell to select it," +
+ " then click on the Hint Button." +
+ " I will fill that cell with a correct value!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ int ci = curposinmatrix/9;
+ int cj = curposinmatrix%9;
+ final int[] jproblem = new int[81];
+ for(int i=0; i<9; i++) {
+
+ for(int j=0; j<9; j++) {
+ jproblem[i*9+j] = getValAt(i, j);
+ }
+ }
+
+ int[] solution = exactcaller(jproblem);
+ if(isGoodSol(solution)) {
+ fillCell(ci, cj, solution[ci*9+cj]);
+ }
+ else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(factivity);
+ builder.setMessage("The puzzle you entered has no solutions!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ }
+ });
+ tr4.addView(hintbtn);
+
+ Button solvebtn = new Button(this);
+ solvebtn.setText("SOLVE!");
+ //final Activity factivity = this;
+ solvebtn.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ TreeSet el = getErrors();
+ if(!el.isEmpty()) {
+ //show alertdialog
+ AlertDialog.Builder builder = new AlertDialog.Builder(factivity);
+ builder.setMessage("Error in your input. Please correct values marked in red!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ final int[] jproblem = new int[81];
+ for(int i=0; i<9; i++) {
+
+ for(int j=0; j<9; j++) {
+ jproblem[i*9+j] = getValAt(i, j);
+ }
+ }
+ final boolean[] wasempty = new boolean[81];
+ for(int i=0; i<81; i++) {
+ if(jproblem[i]==0) {
+ wasempty[i] = true;
+ }
+ else {
+ wasempty[i] = false;
+ }
+ }
+ int[] solution = exactcaller(jproblem);
+ if(isGoodSol(solution)) {
+ fillSolution(solution, wasempty);
+ }
+ else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(factivity);
+ builder.setMessage("The puzzle you entered has no solutions!")
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ return;
+ }
+ }
+ });
+ tr4.addView(solvebtn);
+ TableLayout abtnt = (TableLayout) findViewById(R.id.actionbtntable);
+ abtnt.addView(tr4);
+
+ }
+ protected void clearAllCells() {
+ for(int i=0; i<9; i++) {
+ for(int j=0; j<9;j++) {
+ tvarray[i][j].setTextColor(Color.BLACK);
+ tvarray[i][j].setText("");
+ //tvarray[i][j].setBackgroundResource(R.drawable.back);
+ setTvBack(i, j);
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ menu.add(0, MENU_CLEARALL, 0, "Clear All");
+ menu.add(0, MENU_EXITAPP, 0, "Exit App");
+ //getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ case MENU_CLEARALL:
+ clearAllCells();
+ return true;
+
+ case MENU_EXITAPP:
+ AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
+ this);
+ // set title
+ alertDialogBuilder.setTitle("Quit?!");
+
+ alertDialogBuilder
+ .setMessage("Do you really want to quit?")
+ .setCancelable(false)
+ .setPositiveButton("Yes",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ // if this button is clicked, close
+ // current activity
+ MainActivity.this.finish();
+ }
+ })
+ .setNegativeButton("No", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ // create alert dialog
+ AlertDialog alertDialog = alertDialogBuilder.create();
+
+ // show it
+ alertDialog.show();
+
+ return true;
+ }
+ return false;
+ }
+
+
+}
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
new file mode 100644
index 0000000..675e07f
--- /dev/null
+++ b/app/src/main/jni/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := exactcaller
+LOCAL_SRC_FILES := exactcaller.c exact.c util.c
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/app/src/main/jni/exact.c b/app/src/main/jni/exact.c
new file mode 100644
index 0000000..fb6cbaf
--- /dev/null
+++ b/app/src/main/jni/exact.c
@@ -0,0 +1,1013 @@
+/*
+ * libexact v1.0 --- a software library for solving combinatorial
+ * exact covering problems
+ *
+ * Copyright (C) 2008 Petteri Kaski
+ * Olli Pottonen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+/*************************************************** Library implementation. */
+
+#include
+#include
+#include "exact.h"
+#include "util.h"
+
+/****************************************************** Internal structures. */
+
+struct exact_rchead_struct;
+
+typedef struct exact_lrudrc_struct
+{
+ struct exact_lrudrc_struct *left;
+ struct exact_lrudrc_struct *right;
+ struct exact_lrudrc_struct *up;
+ struct exact_lrudrc_struct *down;
+ struct exact_rchead_struct *row;
+ struct exact_rchead_struct *col;
+} exact_lrudrc_t;
+
+typedef struct exact_rchead_struct
+{
+ exact_lrudrc_t links;
+ int id;
+ int count;
+ int b;
+} exact_rchead_t;
+
+struct exact_struct
+{
+ /* Root element of the dancing link data structure. */
+ exact_rchead_t root;
+
+ /* Memory management for the dancing link data structure. */
+ exact_chunk_t * lrudrc_chunk;
+ exact_chunk_t * rchead_chunk;
+
+ /* Key--value maps for elements of the data structure. */
+ exact_map_t * rowid_to_rowhead;
+ exact_map_t * colid_to_colhead;
+ exact_map_t * entry_to_lrudrc;
+
+ /* Counts etc. */
+ int num_cols;
+ int num_rows;
+ int sum_b; /* Sum of the entries b_i in the vector b.
+ * Used as an upper bound for
+ * the size of any solution. */
+ int simple; /* Nonzero if b_i == 1 for all i,
+ * or equivalently, every row must
+ * be covered exactly once. */
+
+ /* Modes of operation. */
+ int can_declare;
+ int iteration_in_progress;
+ int lock;
+
+ /* The search stack. */
+ int level;
+ int * soln_stack;
+ int soln_stack_capacity;
+ int num_push;
+ exact_lrudrc_t ** col_stack;
+ int * filter_pos;
+ exact_lrudrc_t ** filter_stack;
+ int filter_stack_capacity;
+
+ /* Cache for a row with the minimum branching factor. */
+ exact_rchead_t * cache;
+ int cache_branching_factor;
+
+ /* Search control functions and their user parameters. */
+ exact_level_t * level_f;
+ void * level_p;
+ exact_filter_t * filter_f;
+ void * filter_p;
+};
+
+/************************************************ Link/unlink/relink macros. */
+
+#define lrreset(entry) \
+{ (entry)->left = entry; \
+ (entry)->right = entry; }
+
+/* Unused macro
+#define lrlinkright(to, entry) \
+{ (entry)->right = (to)->right; \
+ (entry)->left = to; \
+ (to)->right->left = entry; \
+ (to)->right = entry; }
+*/
+
+#define lrlinkleft(to, entry) \
+{ (entry)->left = (to)->left; \
+ (entry)->right = to; \
+ (to)->left->right = entry; \
+ (to)->left = entry; }
+
+#define lrunlink(entry) \
+{ (entry)->left->right = (entry)->right; \
+ (entry)->right->left = (entry)->left; }
+
+#define lrrelink(entry) \
+{ (entry)->left->right = entry; \
+ (entry)->right->left = entry; }
+
+#define udreset(entry) \
+{ (entry)->up = entry; \
+ (entry)->down = entry; }
+
+/* Unused macro
+#define udlinkdown(to, entry) \
+{ (entry)->down = (to)->down; \
+ (entry)->up = to; \
+ (to)->down->up = entry; \
+ (to)->down = entry; }
+*/
+
+#define udlinkup(to, entry) \
+{ (entry)->up = (to)->up; \
+ (entry)->down = to; \
+ (to)->up->down = entry; \
+ (to)->up = entry; }
+
+#define udunlink(entry) \
+{ (entry)->up->down = (entry)->down; \
+ (entry)->down->up = (entry)->up; }
+
+#define udrelink(entry) \
+{ (entry)->up->down = entry; \
+ (entry)->down->up = entry; }
+
+/******************** Structures & comparison functions for key--value maps. */
+
+static int int_cmp(const void *a, const void *b)
+{
+ const int *aa = (const int *) a;
+ const int *bb = (const int *) b;
+ return (*aa > *bb) - (*aa < *bb);
+}
+
+typedef struct exact_rcid_struct
+{
+ int row;
+ int col;
+} exact_rcid_t;
+
+static int rcid_cmp(const void *a, const void *b)
+{
+ const exact_rcid_t *aa = (const exact_rcid_t *) a;
+ const exact_rcid_t *bb = (const exact_rcid_t *) b;
+ return 2*((aa->row > bb->row) - (aa->row < bb->row)) +
+ (aa->col > bb->col) - (aa->col < bb->col);
+}
+
+/************************************* Initialization and release functions. */
+
+static void enlarge_soln_stack(exact_t *e, int size)
+{
+ EXACT_FREE(e->soln_stack);
+ EXACT_FREE(e->col_stack);
+ EXACT_FREE(e->filter_pos);
+
+ e->soln_stack = EXACT_ALLOC(sizeof(int)*size);
+ e->col_stack = EXACT_ALLOC(sizeof(exact_lrudrc_t *)*size);
+ e->filter_pos = EXACT_ALLOC(sizeof(int)*(size+1));
+ e->soln_stack_capacity = size;
+}
+
+static void enlarge_filter_stack(exact_t *e, int size)
+{
+ EXACT_FREE(e->filter_stack);
+ e->filter_stack = EXACT_ALLOC(sizeof(exact_lrudrc_t *)*size);
+ e->filter_stack_capacity = size;
+}
+
+#define SOLN_STACK_START_SIZE 128
+#define FILTER_STACK_START_SIZE 128
+#define EXACT_CHUNK_SIZE 256
+
+static void exact_init(exact_t *e)
+{
+ e->num_cols = 0;
+ e->num_rows = 0;
+ e->num_push = 0;
+ e->sum_b = 0;
+ e->simple = 1;
+ e->soln_stack_capacity = SOLN_STACK_START_SIZE;
+ e->soln_stack = EXACT_ALLOC(sizeof(int)*e->soln_stack_capacity);
+ e->col_stack = EXACT_ALLOC(sizeof(exact_lrudrc_t *)*
+ e->soln_stack_capacity);
+ e->filter_pos = EXACT_ALLOC(sizeof(int)*
+ (e->soln_stack_capacity+1));
+ e->filter_stack_capacity = FILTER_STACK_START_SIZE;
+ e->filter_stack = EXACT_ALLOC(sizeof(exact_lrudrc_t *)*
+ e->filter_stack_capacity);
+ e->lrudrc_chunk = exact_chunk_alloc(sizeof(exact_lrudrc_t),
+ EXACT_CHUNK_SIZE);
+ e->rchead_chunk = exact_chunk_alloc(sizeof(exact_rchead_t),
+ EXACT_CHUNK_SIZE);
+ e->rowid_to_rowhead = exact_map_alloc(sizeof(int), &int_cmp);
+ e->colid_to_colhead = exact_map_alloc(sizeof(int), &int_cmp);
+ e->entry_to_lrudrc = exact_map_alloc(sizeof(exact_rcid_t),
+ &rcid_cmp);
+ e->can_declare = 1;
+ e->iteration_in_progress = 0;
+ e->lock = 0;
+
+ e->level_f = NULL;
+ e->level_p = NULL;
+ e->filter_f = NULL;
+ e->filter_p = NULL;
+
+ exact_lrudrc_t *l = &e->root.links;
+ l->row = &e->root;
+ l->col = &e->root;
+ lrreset(l);
+ udreset(l);
+}
+
+static void exact_release(exact_t *e)
+{
+ exact_map_free(e->rowid_to_rowhead);
+ exact_map_free(e->colid_to_colhead);
+ exact_map_free(e->entry_to_lrudrc);
+ exact_chunk_free(e->lrudrc_chunk);
+ exact_chunk_free(e->rchead_chunk);
+ EXACT_FREE(e->filter_stack);
+ EXACT_FREE(e->filter_pos);
+ EXACT_FREE(e->col_stack);
+ EXACT_FREE(e->soln_stack);
+}
+
+exact_t *exact_alloc(void)
+{
+ exact_t *e = (exact_t *) EXACT_ALLOC(sizeof(exact_t));
+ exact_init(e);
+ return e;
+}
+
+void exact_free(exact_t *e)
+{
+ exact_release(e);
+ EXACT_FREE(e);
+}
+
+/*********************************************************** Number of rows. */
+
+int exact_num_rows(exact_t *e)
+{
+ return e->num_rows;
+}
+
+/******************************************************** Number of columns. */
+
+int exact_num_cols(exact_t *e)
+{
+ return e->num_cols;
+}
+
+/*********************************** Check whether declarations are allowed. */
+
+int exact_can_declare(exact_t *e)
+{
+ return e->can_declare;
+}
+
+/************************************************************ Declare a row. */
+
+void exact_declare_row(exact_t *e, int i, int b)
+{
+ if(!e->can_declare)
+ EXACT_ERROR("not in DECLARE mode, operation not permitted");
+ if(exact_map_find(e->rowid_to_rowhead, &i))
+ EXACT_ERROR("row already exists (i = %d)", i);
+ if(b <= 0)
+ EXACT_ERROR("parameter b must be positive (b = %d)", b);
+
+ exact_rchead_t *rh = exact_chunk_get(e->rchead_chunk);
+ rh->id = i;
+ rh->count = 0;
+ rh->b = b;
+ exact_map_associate(e->rowid_to_rowhead, rh);
+
+ exact_lrudrc_t *r = &rh->links;
+ r->row = rh;
+ r->col = &e->root;
+ lrreset(r);
+
+ exact_lrudrc_t *rl = &e->root.links;
+ udlinkup(rl, r);
+
+ e->num_rows++;
+ e->sum_b = e->sum_b + b;
+ e->simple = e->simple && (b == 1);
+ if(e->sum_b > e->soln_stack_capacity)
+ enlarge_soln_stack(e, 2*e->sum_b);
+}
+
+/*********************************************** Check whether a row exists. */
+
+int exact_is_row(exact_t *e, int i)
+{
+ return exact_map_find(e->rowid_to_rowhead, &i);
+}
+
+/********************************************************* Declare a column. */
+
+void exact_declare_col(exact_t *e, int j, int u)
+{
+ if(!e->can_declare)
+ EXACT_ERROR("not in DECLARE mode, operation not permitted");
+ if(exact_map_find(e->colid_to_colhead, &j))
+ EXACT_ERROR("column already exists (j = %d)", j);
+ if(u <= 0)
+ EXACT_ERROR("parameter u must be positive (u = %d)", u);
+
+ exact_rchead_t *ch = exact_chunk_get(e->rchead_chunk);
+ ch->id = j;
+ ch->count = 0;
+ ch->b = u;
+ exact_map_associate(e->colid_to_colhead, ch);
+
+ exact_lrudrc_t *c = &ch->links;
+ c->row = &e->root;
+ c->col = ch;
+ udreset(c);
+
+ exact_lrudrc_t *rl = &e->root.links;
+ lrlinkleft(rl, c);
+
+ e->num_cols++;
+ if(e->num_cols > e->filter_stack_capacity)
+ enlarge_filter_stack(e, 2*e->num_cols);
+}
+
+/******************************************** Check whether a column exists. */
+
+int exact_is_col(exact_t *e, int j)
+{
+ return exact_map_find(e->colid_to_colhead, &j);
+}
+
+/****************************** Declare a 1-entry to the coefficient matrix. */
+
+void exact_declare_entry(exact_t *e, int i, int j)
+{
+ if(!e->can_declare)
+ EXACT_ERROR("not in DECLARE mode, operation not permitted");
+
+ if(!exact_map_find(e->rowid_to_rowhead, &i))
+ EXACT_ERROR("nonexistent row (i = %d)", i);
+ exact_rchead_t *rh = exact_map_value(e->rowid_to_rowhead);
+
+ if(!exact_map_find(e->colid_to_colhead, &j))
+ EXACT_ERROR("nonexistent column (j = %d)", j);
+ exact_rchead_t *ch = exact_map_value(e->colid_to_colhead);
+
+ exact_rcid_t rcid = { i, j };
+ if(exact_map_find(e->entry_to_lrudrc, &rcid))
+ EXACT_ERROR("entry already exists (i = %d, j = %d)", i, j);
+
+ rh->count++;
+ ch->count++;
+ exact_lrudrc_t *r = &rh->links;
+ exact_lrudrc_t *c = &ch->links;
+ exact_lrudrc_t *t = exact_chunk_get(e->lrudrc_chunk);
+ t->row = rh;
+ t->col = ch;
+ lrlinkleft(r, t);
+ udlinkup(c, t);
+
+ exact_map_associate(e->entry_to_lrudrc, t);
+}
+
+/********************************************* Return the value of an entry. */
+
+int exact_is_entry(exact_t *e, int i, int j)
+{
+ if(!exact_map_find(e->rowid_to_rowhead, &i))
+ EXACT_ERROR("nonexistent row (i = %d)", i);
+ if(!exact_map_find(e->colid_to_colhead, &j))
+ EXACT_ERROR("nonexistent column (j = %d)", j);
+ int k[2] = { i, j };
+ if(exact_map_find(e->entry_to_lrudrc, k))
+ return 1;
+ return 0;
+}
+
+/*********************************** Output identifiers of unsatisfied rows. */
+
+int exact_get_rows(exact_t *e, int *id)
+{
+ int n = 0;
+ exact_lrudrc_t *r;
+ for(r = e->root.links.down;
+ r != &e->root.links;
+ r = r->down)
+ id[n++] = r->row->id;
+ return n;
+}
+
+/********************************** Output identifiers of available columns. */
+
+int exact_get_cols(exact_t *e, int *id)
+{
+ int n = 0;
+ exact_lrudrc_t *c;
+ for(c = e->root.links.right;
+ c != &e->root.links;
+ c = c->right)
+ id[n++] = c->col->id;
+ return n;
+}
+
+/*********** Subroutines for manipulating the "dancing link" data structure. */
+
+/*
+
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ up | up | up |
+-------###########right------###########right------###########right-- COLUMN
+ ## ROOT ## ## col ## ## col ## LIST
+---left###########-------left###########-------left###########-------
+ | down | down | down
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ up | | | up |
+-------###########right-------+-------+------------###########right--
+ ## row ## | | ## entry ##
+---left###########------------+-------+--------left###########-------
+ | down | | | down
+ | | | | | |
+ | | | | | |
+ up | up | | |
+-------###########right------###########right-------+-------+--------
+ ## row ## ## entry ## | |
+---left###########-------left###########------------+-------+--------
+ | down | down | |
+ | | | | | |
+
+ ROW LIST
+
+*/
+
+/* Left--right unlink routine for a vertical interval. */
+
+static int lrunlink_interval(exact_t *e,
+ exact_lrudrc_t *a,
+ const exact_lrudrc_t *b,
+ int skip)
+{
+ /* Start from a, go down until (but not including) b. */
+ exact_lrudrc_t *d;
+ for(d = a; d != b; d = d->down) {
+ if(--d->row->count == 0) {
+ /* The row of d is not covered, and
+ * has no intersecting columns available for covering it.
+ * We can backtrack immediately. */
+ skip = 1;
+ }
+ /* Update minimum branching row cache. */
+ if(d->row->count < e->cache_branching_factor) {
+ e->cache_branching_factor = d->row->count;
+ e->cache = d->row;
+ }
+ lrunlink(d);
+ }
+ return skip;
+}
+
+
+/* Left--right relink routine for a vertical interval. */
+
+static void lrrelink_interval(exact_lrudrc_t *a,
+ const exact_lrudrc_t *b)
+{
+ /* Start from a, go up until (but not including) b. */
+ exact_lrudrc_t *d;
+ for(d = a; d != b; d = d->up) {
+ lrrelink(d);
+ d->row->count++;
+ }
+}
+
+
+/* Updates the data structure to reflect the fact that
+ * the column of c was just pushed to the solution stack. */
+
+static int push_col_update(exact_t *e, exact_lrudrc_t *c, int use_cache)
+{
+ /* Initialize minimum branching row cache. */
+ e->cache_branching_factor = use_cache ? (c->row->count + 1) : 0;
+ e->cache = NULL;
+
+ /* Initialize control variables. */
+ int skip = 0; /* Force backtrack upon return? */
+ int unlink_c = (--c->col->b == 0); /* Unlink the column of c if
+ * the column bound is met. */
+
+ /* Check whether any rows intersecting the column of c
+ * got covered as a result of the push. */
+
+ /* Ensure that c is a column header. */
+ c = &c->col->links;
+
+ /* Traverse down the list at the column of c,
+ * starting from the entry below the column header.
+ * All entries except the column header are traversed. */
+ exact_lrudrc_t *d;
+ for(d = c->down; d != c ; d = d->down) {
+ if(--d->row->b == 0) {
+ /* The row of d just got covered.
+ * Proceed to unlink all columns intersecting the row of d. */
+
+ /* In particular, remember to unlink the column of c
+ * once this loop is done. */
+ unlink_c = 1;
+
+ /* Unlink the row header of the row of d from the row list. */
+ exact_lrudrc_t *rhd = &d->row->links;
+ udunlink(rhd);
+ /* Reminder:
+ * Do not decrease d->row->count in this loop, but do so
+ * in the following loop (which will be executed since
+ * unlink_c == 1); otherwise the calls to lrunlink_interval
+ * in this loop can incorrectly force a backtrack. */
+
+ /* Traverse right the list at the row of d.
+ * All entries except the entry d are traversed,
+ * including the row header (rhd). */
+ exact_lrudrc_t *dr;
+ for(dr = d->right; dr != d; dr = dr->right) {
+ if(dr != rhd) { /* Ignore the row header. */
+ /* Unlink the column of dr. */
+ exact_lrudrc_t *a = dr->down;
+ exact_lrudrc_t *b = &dr->col->links;
+ skip = lrunlink_interval(e, a, b, skip);
+ lrunlink(b); /* Unlink the column header. */
+ a = b->down;
+ b = dr;
+ skip = lrunlink_interval(e, a, b, skip);
+ }
+ }
+ }
+ }
+ if(unlink_c) {
+ /* Unlink the column of c.
+ * The entry c must be a column header. */
+ lrunlink(c); /* Unlink header. */
+ exact_lrudrc_t *d;
+ for(d = c->down; d != c; d = d->down) {
+ /* Caching is used only if all rows have b == 1. In that case,
+ * the row d considered here is covered and should not be cached
+ * even id d->row->count < e->cache_branching_factor.
+ */
+ d->row->count--;
+ /* Reminder:
+ * Cannot backtrack here on d->row->count == 0 alone
+ * because the row of d may be covered
+ * (that is, d->row->b == 0).
+ */
+ lrunlink(d);
+ }
+ }
+ return skip;
+}
+
+
+/* Rewinds the data structure to reflect the fact that
+ * the column of c was just popped off the solution stack. */
+
+static void pop_col_update(exact_lrudrc_t *c)
+{
+
+ /* Ensure that c is a column header. */
+ c = &c->col->links;
+
+ /* Relink the column of c if it was unlinked. */
+ if(c->right->left != c) {
+ /* Relink the column of c.
+ * The entry c must be a column header. */
+ exact_lrudrc_t *d;
+ for(d = c->up; d != c; d = d->up) {
+ lrrelink(d);
+ d->row->count++;
+ }
+ lrrelink(c); /* Relink header. */
+ }
+
+ /* Check whether any rows intersecting the column of c are uncovered
+ * as a result of the pop. */
+
+ /* Traverse up the list at the column of c,
+ * starting from the entry above the column header.
+ * All entries except the column header are traversed. */
+ exact_lrudrc_t *d;
+ for(d = c->up ; d != c ; d = d->up) {
+ if(d->row->b == 0) {
+ /* The row of d just got uncovered.
+ * Proceed to relink all columns intersecting the row of d. */
+
+ /* Traverse left the list at the row of d.
+ * All entries except the entry d are traversed,
+ * including the row header (rhd). */
+ exact_lrudrc_t *rhd = &d->row->links;
+ exact_lrudrc_t *dr;
+ for(dr = d->left; dr != d; dr = dr->left) {
+ if(dr != rhd) { /* Ignore row header. */
+ /* Relink the column of dr. */
+ exact_lrudrc_t *a = dr->up;
+ exact_lrudrc_t *b = &dr->col->links;
+ lrrelink_interval(a, b);
+ lrrelink(b); /* Relink the column header. */
+ a = b->up;
+ b = dr;
+ lrrelink_interval(a, b);
+ }
+ }
+ /* Relink the row header of the row of d to the row list. */
+ udrelink(rhd);
+ }
+ d->row->b++;
+ }
+ c->col->b++;
+}
+
+static int filter(exact_t *e, int lvl)
+{
+ /* Evaluate filter function on candidate columns and
+ unlink accordingly. */
+ int skip = 0;
+ int i = e->filter_pos[lvl-1];
+
+ /* Traverse right the column list.
+ * All entries except the root are traversed. */
+ exact_lrudrc_t *c;
+ for(c = e->root.links.right;
+ c != &e->root.links;
+ c = c->right) {
+ if(!e->filter_f(e->filter_p,
+ lvl,
+ e->soln_stack,
+ c->col->id)) {
+ /* Unlink the column of c. */
+ exact_lrudrc_t *a = c->down;
+ exact_lrudrc_t *b = c;
+ skip = lrunlink_interval(e, a, b, skip);
+ lrunlink(c); /* Unlink the column header. */
+ /* Save data for unfiltering. */
+ e->filter_stack[i++] = c;
+ }
+ }
+ /* Record the position for unfiltering. */
+ e->filter_pos[lvl] = i;
+
+ return skip;
+}
+
+static void unfilter(exact_t *e, int lvl)
+{
+ /* Relink any columns unlinked by the filter function. */
+ int i = e->filter_pos[lvl];
+ while(i > e->filter_pos[lvl-1]) {
+ exact_lrudrc_t *c = e->filter_stack[--i];
+ /* Relink the column of c. */
+ lrrelink(c); /* Relink the column header. */
+ exact_lrudrc_t *a = c->up;
+ exact_lrudrc_t *b = c;
+ lrrelink_interval(a, b);
+ }
+}
+
+/********************** Check whether forcing a partial solution is allowed. */
+
+int exact_can_push(exact_t *e)
+{
+ if(e->iteration_in_progress)
+ return 0;
+ return 1;
+}
+
+/************************************************************ Push a column. */
+
+void exact_push(exact_t *e, int j)
+{
+ if(e->iteration_in_progress)
+ EXACT_ERROR("operation not permitted in ITERATE mode");
+
+ /* Find the column. */
+ if(!exact_map_find(e->colid_to_colhead, &j))
+ EXACT_ERROR("nonexistent column (j = %d)", j);
+ exact_rchead_t *ch = exact_map_value(e->colid_to_colhead);
+ exact_lrudrc_t *c = &ch->links;
+
+ /* Check that column has not been unlinked. */
+ if(c->left->right != c)
+ EXACT_ERROR("cannot push an unlinked column (j = %d)", j);
+
+ /* Check that the column is not empty. */
+ if(ch->count == 0)
+ EXACT_ERROR("pushing a column of zeroes (j = %d)", j);
+
+ e->soln_stack[e->num_push++] = j;
+ push_col_update(e, c, 0);
+ e->can_declare = 0;
+}
+
+/************************************************************* Pop a column. */
+
+void exact_pop(exact_t *e)
+{
+ if(e->iteration_in_progress)
+ EXACT_ERROR("operation not permitted in ITERATE mode");
+ if(e->num_push == 0)
+ EXACT_ERROR("nothing to pop");
+ int j = e->soln_stack[--e->num_push];
+
+ /* Find the column. */
+ exact_map_find(e->colid_to_colhead, &j);
+ exact_rchead_t *ch = exact_map_value(e->colid_to_colhead);
+ exact_lrudrc_t *c = &ch->links;
+
+ pop_col_update(c);
+ if(e->num_push == 0)
+ e->can_declare = 1;
+}
+
+/************************************************* Check validity of a push. */
+
+int exact_pushable(exact_t *e, int j)
+{
+ if(e->iteration_in_progress)
+ EXACT_ERROR("operation not permitted in ITERATE mode");
+
+ /* Find the column. */
+ if(!exact_map_find(e->colid_to_colhead, &j))
+ EXACT_ERROR("nonexistent column (j = %d)", j);
+ exact_rchead_t *ch = exact_map_value(e->colid_to_colhead);
+ exact_lrudrc_t *c = &ch->links;
+
+ /* Check that column has not been unlinked. */
+ if(c->left->right != c)
+ return 0;
+
+ /* Check that the column is not empty. */
+ if(ch->count == 0)
+ return 0;
+ return 1;
+}
+
+/************************************************* Number of pushed columns. */
+
+int exact_num_push(exact_t *e)
+{
+ return e->num_push;
+}
+
+/************************************* Output identifiers of pushed columns. */
+
+int exact_get_push(exact_t *e, int *id)
+{
+ int n = e->num_push;
+ int i;
+ for(i = 0; i < n; i++)
+ id[i] = e->soln_stack[i];
+ return n;
+}
+
+/******************************************************* Set level function. */
+
+void exact_level(exact_t *e, exact_level_t *l, void *p)
+{
+ if(e->iteration_in_progress)
+ EXACT_ERROR("operation not permitted in ITERATE mode");
+ e->level_f = l;
+ e->level_p = p;
+}
+
+/****************************************************** Set filter function. */
+
+void exact_filter(exact_t *e, exact_filter_t *f, void *p)
+{
+ if(e->iteration_in_progress)
+ EXACT_ERROR("operation not permitted in ITERATE mode");
+ e->filter_f = f;
+ e->filter_p = p;
+}
+
+/******************** Data structure consistency check (for test code only). */
+
+void exact_check(exact_t *e);
+
+void exact_check(exact_t *e)
+{
+ exact_lrudrc_t *d = &e->root.links;
+ do {
+ int s = 0;
+ exact_lrudrc_t *r = d;
+ do {
+ if(r->left->right != r ||
+ r->right->left != r)
+ EXACT_INTERNAL_ERROR("invalid left/right link");
+ if(r->row != d->row)
+ EXACT_INTERNAL_ERROR("invalid row link");
+ s++;
+ int t = 0;
+ exact_lrudrc_t *dr = r;
+ do {
+ if(dr->down->up != dr ||
+ dr->up->down != dr)
+ EXACT_INTERNAL_ERROR("invalid up/down link");
+ if(dr->col != r->col)
+ EXACT_INTERNAL_ERROR("invalid column link");
+ if(dr->row == &e->root)
+ t++;
+ dr = dr->down;
+ } while(dr != r);
+ if(t != 1)
+ EXACT_INTERNAL_ERROR("missing/repeated entry in column list");
+ r = r->right;
+ } while(r != d);
+ if(d->row != &e->root && s != d->row->count + 1) {
+ EXACT_INTERNAL_ERROR("invalid row count");
+ }
+ d = d->down;
+ } while(d != &e->root.links);
+}
+
+/************************************************** Reset solution iterator. */
+
+void exact_reset_solve(exact_t *e)
+{
+ if(e->lock)
+ EXACT_ERROR("re-entry while call on instance in progress");
+ if(e->iteration_in_progress) {
+ int lvl = e->level;
+ while(lvl > e->num_push) {
+ if(e->filter_f != NULL)
+ unfilter(e, lvl);
+ lvl--;
+ exact_lrudrc_t *c = e->col_stack[lvl];
+ pop_col_update(c);
+ }
+ e->iteration_in_progress = 0;
+ if(e->num_push == 0)
+ e->can_declare = 1;
+ }
+}
+
+/******************************************************** Solution iterator. */
+
+const int *exact_solve(exact_t *e, int *size)
+{
+ int lvl;
+
+ if(e->lock)
+ EXACT_ERROR("re-entry while call on instance in progress");
+ e->lock = 1;
+
+ if(e->iteration_in_progress) {
+ lvl = e->level;
+ goto lvl_down;
+ }
+ e->can_declare = 0;
+ e->iteration_in_progress = 1;
+ lvl = e->num_push;
+ e->filter_pos[lvl] = 0;
+ e->cache = NULL;
+lvl_up:
+ /* Call level function. */
+ if(e->level_f != NULL)
+ if(!e->level_f(e->level_p, lvl, e->soln_stack))
+ goto lvl_down;
+
+ /* Report if solution found. */
+ if(e->root.links.down == &e->root.links) {
+ /* Solution found. Return to caller for reporting. */
+ e->level = lvl;
+ *size = lvl;
+ e->lock = 0;
+ return e->soln_stack;
+ /* Will backtrack upon next entry to exact_solve. */
+ }
+
+ {
+ exact_lrudrc_t *r, *c;
+ if(lvl <= e->num_push ||
+ e->col_stack[lvl-1]->row->b == 0) {
+ /* Select a new row to cover. */
+
+ /* Selection heuristic:
+ * Select a row that leads to the minimum branching factor
+ * for the search. Put otherwise, select a row with the
+ * minimum number of columns currently intersecting it.
+ */
+
+ /* See if we have such a row cached.
+ * Note: must check that the cached row has not been unlinked
+ * after it has been cached; an unlinked row has
+ * e->cache->b == 0.
+ */
+ if(e->cache != NULL && e->cache->b != 0) {
+ /* Yes. Use the cached row. */
+ r = &e->cache->links;
+ } else {
+ /* No. Find a row with the minimum branching factor. */
+ int record_count = e->num_cols + 1;
+ r = NULL;
+ exact_lrudrc_t *t;
+ for(t = e->root.links.down;
+ t != &e->root.links;
+ t = t->down) {
+
+ int count = t->row->count;
+ if(count < record_count) {
+ r = t;
+ record_count = count;
+ }
+ }
+ }
+
+ /* Start with the first column at this row. */
+ c = r->right;
+ } else {
+ /* The row selected at a preceding level is not yet covered,
+ * proceed to cover it further. */
+
+ /* Start with the first available column that is
+ * not to the left of the column pushed at the previous level.
+ * Note: any columns to the left will be considered as the search
+ * branches at the preceding level(s).
+ */
+ c = e->col_stack[lvl-1];
+ while(c->right->left != c) {
+ /* This is an unlinked column,
+ * proceed to the next column on the right. */
+ c = c->right; /* Left--right links in an unlinked column
+ * can still be traversed. This however
+ * may lead to traversing repeated
+ * unlinked columns. */
+ if(c == &c->row->links) {
+ /* Row header encountered.
+ * This row has no available columns, but
+ * the row is not yet covered; can backtrack. */
+ goto lvl_down;
+ }
+ }
+ }
+
+ /* Branch the search:
+ * Push one column at a time until the row header is encountered. */
+ for(; c != &c->row->links; c = c->right) {
+ /* Push the column of c and save backtrack data. */
+ e->soln_stack[lvl] = c->col->id;
+ e->col_stack[lvl] = c;
+ /* Update data structure. */
+ if(push_col_update(e, c, e->simple))
+ goto lvl_skip; /* Update signals that we can backtrack. */
+ lvl++;
+ if(e->filter_f != NULL)
+ if(filter(e, lvl))
+ goto lvl_down; /* Filtering signals that we can backtrack. */
+ goto lvl_up;
+ /* Simulated recursive invocation here. */
+ lvl_down:
+ /* Backtrack and rewind data structure. */
+ if(lvl == e->num_push)
+ goto finished;
+ if(e->filter_f != NULL)
+ unfilter(e, lvl);
+ lvl--;
+ c = e->col_stack[lvl];
+ lvl_skip:
+ pop_col_update(c);
+ }
+ goto lvl_down;
+ }
+ finished:
+ e->iteration_in_progress = 0;
+ if(e->num_push == 0)
+ e->can_declare = 1;
+ e->lock = 0;
+ return NULL;
+}
diff --git a/app/src/main/jni/exact.h b/app/src/main/jni/exact.h
new file mode 100644
index 0000000..a6df5c0
--- /dev/null
+++ b/app/src/main/jni/exact.h
@@ -0,0 +1,76 @@
+/*
+ * libexact v1.0 --- a software library for solving combinatorial
+ * exact covering problems
+ *
+ * Copyright (C) 2008 Petteri Kaski
+ * Olli Pottonen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+/******************************************************** Library interface. */
+
+#ifndef EXACT_READ
+#define EXACT_READ
+
+struct exact_struct;
+typedef struct exact_struct exact_t;
+typedef int exact_level_t (void *, int, const int *);
+typedef int exact_filter_t (void *, int, const int *, int);
+
+/* Initializing and releasing an instance. */
+
+exact_t * exact_alloc (void);
+void exact_free (exact_t *e);
+
+/* Declaring an instance. */
+
+void exact_declare_row (exact_t *e, int i, int b);
+void exact_declare_col (exact_t *e, int j, int u);
+void exact_declare_entry (exact_t *e, int i, int j);
+int exact_can_declare (exact_t *e);
+
+/* Iterating through the solutions. */
+
+const int * exact_solve (exact_t *e, int *n);
+void exact_reset_solve (exact_t *e);
+
+/* Examining an instance. */
+
+int exact_is_row (exact_t *e, int i);
+int exact_is_col (exact_t *e, int j);
+int exact_is_entry (exact_t *e, int i, int j);
+int exact_num_rows (exact_t *e);
+int exact_num_cols (exact_t *e);
+int exact_get_rows (exact_t *e, int *i);
+int exact_get_cols (exact_t *e, int *j);
+
+/* Forcing a partial solution. */
+
+void exact_push (exact_t *e, int j);
+void exact_pop (exact_t *e);
+int exact_pushable (exact_t *e, int j);
+int exact_can_push (exact_t *e);
+int exact_num_push (exact_t *e);
+int exact_get_push (exact_t *e, int *j);
+
+/* Controlling the search. */
+
+void exact_level (exact_t *e, exact_level_t *l, void *p);
+void exact_filter (exact_t *e, exact_filter_t *f, void *p);
+
+#endif
diff --git a/app/src/main/jni/exactcaller.c b/app/src/main/jni/exactcaller.c
new file mode 100644
index 0000000..61b4e52
--- /dev/null
+++ b/app/src/main/jni/exactcaller.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include
+#include
+#include "exact.h"
+
+/* This is a trivial JNI example where we use a native method
+ * to return a new VM String. See the corresponding Java source
+ * file located at:
+ *
+ * apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
+ */
+
+#define UNDEF -1
+static void solve_sudoku(int *a)
+{
+ exact_t *e = exact_alloc();
+
+ /* Row--column */
+ int r, v, c, s;
+ for(r = 0; r < 9; r++)
+ for(c = 0; c < 9; c++)
+ exact_declare_row(e, 9*r+c, 1);
+ /* Row--value */
+ for(r = 0; r < 9; r++)
+ for(v = 0; v < 9; v++)
+ exact_declare_row(e, 81+9*r+v, 1);
+ /* Column--value */
+ for(c = 0; c < 9; c++)
+ for(v = 0; v < 9; v++)
+ exact_declare_row(e, 162+9*c+v, 1);
+ /* Subsquare--value */
+ for(s = 0; s < 9; s++)
+ for(v = 0; v < 9; v++)
+ exact_declare_row(e, 243+9*s+v, 1);
+ /* Row--column--value */
+ for(r = 0; r < 9; r++) {
+ for(c = 0; c < 9; c++) {
+ s = 3*(r/3)+c/3;
+ for(v = 0; v < 9; v++) {
+ exact_declare_col(e, 9*9*r+9*c+v, 1);
+
+ /* Row--column */
+ exact_declare_entry(e, 9*r+c, 9*9*r+9*c+v);
+
+ /* Row--value */
+ exact_declare_entry(e, 81+9*r+v, 9*9*r+9*c+v);
+
+ /* Column--value */
+ exact_declare_entry(e, 162+9*c+v, 9*9*r+9*c+v);
+
+ /* Subsquare--value */
+ exact_declare_entry(e, 243+9*s+v, 9*9*r+9*c+v);
+ }
+ }
+ }
+
+ /* Push the columns corresponding to the given partial solution. */
+ for(r = 0; r < 9; r++) {
+ for(c = 0; c < 9; c++) {
+ if(a[9*r+c] != UNDEF) {
+ int j = 9*9*r+9*c+a[9*r+c];
+ if(!exact_pushable(e, j)) {
+ /* The partial solution is conflicting. */
+ a[0]=100;
+ goto solve_done;
+ }
+ exact_push(e, j);
+ }
+ }
+ }
+
+ /* List all complete solutions. */
+ int n, i;
+ const int *b;
+ while((b = exact_solve(e, &n)) != NULL) {
+ /* Put the solution into matrix form. */
+ for(i = 0; i < n; i++) {
+ int r = b[i]/81;
+ int c = b[i]/9; c = c%9;
+ int v = b[i]%9;
+ a[9*r+c] = v;
+ }
+ return; /*added by ashik- since i need only one soltion */
+ /* Rewind the matrix. */
+ /* for(int i = exact_num_push(e); i < n; i++) { */
+ /* int r = b[i]/81; */
+ /* int c = b[i]/9; c = c%9; */
+ /* a[9*r+c] = UNDEF; */
+ /* } */
+ }
+solve_done:
+ exact_free(e);
+}
+
+jintArray
+Java_com_oldestmonk_droidsudsolve_MainActivity_exactcaller( JNIEnv* env,
+ jobject thiz,
+ jintArray jproblem )
+{
+ jintArray result;
+ int size = 81;
+ jint cproblem[81];
+ (*env)->GetIntArrayRegion(env, jproblem, 0, size, cproblem);
+ result = (*env)->NewIntArray(env, size);
+ if (result == NULL) {
+ return NULL; /* out of memory error thrown */
+ }
+
+ int a[81];
+ int i;
+ for(i=0; i<81; i++) {
+ a[i] = cproblem[i]-1;
+ }
+ solve_sudoku(a);
+ for(i=0; i<81; i++) {
+ cproblem[i] = a[i]+1;
+ }
+
+ // fill a temp structure to use to populate the java int array
+ jint fill[81];
+ for (i = 0; i < size; i++) {
+ fill[i] = cproblem[i]; // put whatever logic you want.
+ }
+ // move from the temp structure to the java structure
+ (*env)->SetIntArrayRegion(env, result, 0, size, fill);
+ return result;
+}
diff --git a/app/src/main/jni/util.c b/app/src/main/jni/util.c
new file mode 100644
index 0000000..88ea9ae
--- /dev/null
+++ b/app/src/main/jni/util.c
@@ -0,0 +1,377 @@
+/*
+ * libexact v1.0 --- a software library for solving combinatorial
+ * exact covering problems
+ *
+ * Copyright (C) 2008 Petteri Kaski
+ * Olli Pottonen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+/*********************************************** Internal utility functions. */
+
+#include
+#include
+#include
+#include "util.h"
+
+int exact_mem_alloc_balance = 0;
+
+void *exact_mem_alloc(size_t size)
+{
+ exact_mem_alloc_balance++;
+ void *p = malloc(size);
+ if(p == NULL)
+ EXACT_ERROR("malloc fails");
+ return p;
+}
+
+void exact_mem_free(void *p)
+{
+ exact_mem_alloc_balance--;
+ free(p);
+}
+
+struct exact_chunk_struct
+{
+ int num_entries;
+ int num_alloc;
+ size_t entry_size;
+ void *data;
+ struct exact_chunk_struct *next;
+};
+
+exact_chunk_t *exact_chunk_alloc(size_t entry, int entries)
+{
+ exact_chunk_t *c = (exact_chunk_t *) EXACT_ALLOC(sizeof(exact_chunk_t));
+ c->num_entries = entries;
+ c->num_alloc = 0;
+ c->entry_size = entry;
+ c->data = EXACT_ALLOC(c->entry_size * c->num_entries);
+ c->next = NULL;
+ return c;
+}
+
+void exact_chunk_free(exact_chunk_t *c)
+{
+ while(c != NULL) {
+ exact_chunk_t *t = c->next;
+ EXACT_FREE(c->data);
+ EXACT_FREE(c);
+ c = t;
+ }
+}
+
+void *exact_chunk_get(exact_chunk_t *c)
+{
+ if(c->num_alloc >= c->num_entries) {
+ exact_chunk_t *n =
+ (exact_chunk_t *) EXACT_ALLOC(sizeof(exact_chunk_t));
+ n->num_entries = c->num_entries;
+ n->num_alloc = c->num_alloc;
+ n->entry_size = c->entry_size;
+ n->data = c->data;
+ n->next = c->next;
+ c->next = n;
+ c->num_entries = 2*c->num_entries;
+ c->data = EXACT_ALLOC(c->entry_size * c->num_entries);
+ c->num_alloc = 0;
+ }
+ return ((char *) c->data) + c->entry_size*c->num_alloc++;
+}
+
+void exact_error(const char *fn, int line, const char *func,
+ const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ fprintf(stderr,
+ "ERROR [detected by libexact interface; file = %s, line = %d]\n"
+ "%s: ",
+ fn,
+ line,
+ func);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ abort();
+}
+
+void exact_internal_error(const char *fn, int line, const char *func,
+ const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ fprintf(stderr,
+ "ERROR [libexact internal error; file = %s, line = %d]\n"
+ "%s: ",
+ fn,
+ line,
+ func);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ abort();
+}
+
+/******************** Map from keys to values -- implemented as an AVL tree. */
+
+struct avl_node_struct;
+
+typedef struct avl_node_struct
+{
+ void * key;
+ void * value;
+ struct avl_node_struct * left;
+ struct avl_node_struct * right;
+ int height;
+} avl_node_t;
+
+struct exact_map_struct
+{
+ avl_node_t * root;
+ exact_chunk_t * node_chunk;
+ exact_chunk_t * key_chunk;
+ size_t key_size;
+ exact_map_cmp_t * cmp_f;
+
+ void * active_key;
+ void ** active_value_p;
+ int path_length;
+ int path_capacity;
+ avl_node_t *** path;
+};
+
+#define AVL_CHUNK_SIZE 128
+#define PATH_CAPACITY_START 32
+
+static void enlarge_path(exact_map_t *m, int capacity)
+{
+ EXACT_FREE(m->path);
+ m->path_capacity = capacity;
+ m->path = EXACT_ALLOC(sizeof(avl_node_t **)*m->path_capacity);
+}
+
+static void exact_map_init(exact_map_t *m, size_t key, exact_map_cmp_t *f)
+{
+ m->key_size = key;
+ m->root = NULL;
+ m->active_value_p = NULL;
+ m->node_chunk = exact_chunk_alloc(sizeof(avl_node_t), AVL_CHUNK_SIZE);
+ m->key_chunk = exact_chunk_alloc(m->key_size, AVL_CHUNK_SIZE);
+ m->path_capacity = PATH_CAPACITY_START;
+ m->path = EXACT_ALLOC(sizeof(avl_node_t **)*m->path_capacity);
+ m->path_length = 0;
+ m->active_key = EXACT_ALLOC(m->key_size);
+ m->cmp_f = f;
+}
+
+static void exact_map_release(exact_map_t *m)
+{
+ EXACT_FREE(m->active_key);
+ EXACT_FREE(m->path);
+ exact_chunk_free(m->key_chunk);
+ exact_chunk_free(m->node_chunk);
+}
+
+exact_map_t *exact_map_alloc(size_t key, exact_map_cmp_t *f)
+{
+ exact_map_t *m = (exact_map_t *) EXACT_ALLOC(sizeof(exact_map_t));
+ exact_map_init(m, key, f);
+ return m;
+}
+
+void exact_map_free(exact_map_t *m)
+{
+ exact_map_release(m);
+ EXACT_FREE(m);
+}
+
+static int height(avl_node_t *n)
+{
+ if(n == NULL)
+ return -1;
+ return n->height;
+}
+
+int exact_map_find(exact_map_t *m, void *key)
+{
+ memcpy(m->active_key, key, m->key_size);
+ avl_node_t *n = m->root;
+ int t = height(n)+2;
+ if(t > m->path_capacity)
+ enlarge_path(m, 2*t);
+ m->path_length = 1;
+ m->path[0] = &m->root;
+ while(n != NULL) {
+ t = m->cmp_f(n->key, m->active_key);
+ if(t == 0) {
+ m->active_value_p = &n->value;
+ return 1;
+ }
+ if(t > 0) {
+ m->path[m->path_length++] = &n->left;
+ n = n->left;
+ } else {
+ m->path[m->path_length++] = &n->right;
+ n = n->right;
+ }
+ }
+ m->active_value_p = NULL;
+ return 0;
+}
+
+void *exact_map_value(exact_map_t *m)
+{
+ void **av = m->active_value_p;
+ if(av == NULL)
+ EXACT_INTERNAL_ERROR("no value available");
+ return *av;
+}
+
+static int max(int a, int b)
+{
+ return a > b ? a : b;
+}
+
+/* AVL outer rotation:
+ *
+ * d b
+ * / \ <--- left --- / \
+ * b E A d
+ * / \ --- right --> / \
+ * A C C E
+ *
+ */
+
+static avl_node_t *rotate_outer_right(avl_node_t *d)
+{
+ avl_node_t *b = d->left;
+ d->left = b->right;
+ b->right = d;
+
+ d->height = max(height(d->left), height(d->right)) + 1;
+ b->height = max(height(b->left), height(b->right)) + 1;
+
+ return b;
+}
+
+static avl_node_t *rotate_outer_left(avl_node_t *b)
+{
+ avl_node_t *d = b->right;
+ b->right = d->left;
+ d->left = b;
+
+ b->height = max(height(b->left), height(b->right)) + 1;
+ d->height = max(height(d->left), height(d->right)) + 1;
+
+ return d;
+}
+
+/* AVL inner rotation right:
+ *
+ * f f d
+ * / \ / \ / \
+ * b G --- b left --> d G -- f right --> / \
+ * / \ / \ b f
+ * A d b E / \ / \
+ * / \ / \ A C E G
+ * C E A C
+ *
+ */
+
+static avl_node_t *rotate_inner_right(avl_node_t *f)
+{
+ f->left = rotate_outer_left(f->left);
+ return rotate_outer_right(f);
+}
+
+/* AVL inner rotation left:
+ *
+ * b b d
+ * / \ / \ / \
+ * A f -- f right --> A d --- b left --> / \
+ * / \ / \ b f
+ * d G C f / \ / \
+ * / \ / \ A C E G
+ * C E E G
+ *
+ */
+
+static avl_node_t *rotate_inner_left(avl_node_t *b)
+{
+ b->right = rotate_outer_right(b->right);
+ return rotate_outer_left(b);
+}
+
+void exact_map_associate(exact_map_t *m, void *v)
+{
+ void **av = m->active_value_p;
+ if(av != NULL) {
+ *av = v;
+ return;
+ }
+ if(m->path_length == 0)
+ EXACT_INTERNAL_ERROR("no query issued");
+
+ avl_node_t *n = exact_chunk_get(m->node_chunk);
+ n->left = NULL;
+ n->right = NULL;
+ n->height = 0;
+ n->key = exact_chunk_get(m->key_chunk);
+ n->value = v;
+ memcpy(n->key, m->active_key, m->key_size);
+
+ m->active_value_p = &n->value;
+ avl_node_t **p = m->path[--m->path_length];
+ *p = n;
+
+ while(m->path_length > 0) {
+ p = m->path[--m->path_length];
+ avl_node_t *nn = n;
+ n = *p;
+ /* A child of n was updated to the value nn. */
+ if(n->left == nn) {
+ /* Left child of n was updated. */
+ if(height(n->left) - height(n->right) == 2) {
+ /* Left subtree is too high after update, must rebalance. */
+ if(height(n->left->left) + 1 == n->left->height) {
+ /* The cause is the left--left subtree. */
+ n = rotate_outer_right(n);
+ } else {
+ /* The cause is the left--right subtree. */
+ n = rotate_inner_right(n);
+ }
+ }
+ } else {
+ /* Right child of n was updated. */
+ if(height(n->right) - height(n->left) == 2) {
+ /* Right child is too high after update, must rebalance. */
+ if(height(n->right->right) + 1 == n->right->height) {
+ /* The cause is the right--right subtree. */
+ n = rotate_outer_left(n);
+ } else {
+ /* The cause is the right--left subtree. */
+ n = rotate_inner_left(n);
+ }
+ }
+ }
+ n->height = max(height(n->left),
+ height(n->right)) + 1;
+ *p = n;
+ }
+}
diff --git a/app/src/main/jni/util.h b/app/src/main/jni/util.h
new file mode 100644
index 0000000..9b39a6e
--- /dev/null
+++ b/app/src/main/jni/util.h
@@ -0,0 +1,70 @@
+/*
+ * libexact v1.0 --- a software library for solving combinatorial
+ * exact covering problems
+ *
+ * Copyright (C) 2008 Petteri Kaski
+ * Olli Pottonen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+/************************************ Internal utility functions and macros. */
+
+#ifndef EXACT_UTIL_READ
+#define EXACT_UTIL_READ
+
+#include
+#include
+
+void * exact_mem_alloc (size_t size);
+void exact_mem_free (void *p);
+
+#define EXACT_ALLOC(s) exact_mem_alloc(s)
+#define EXACT_FREE(p) exact_mem_free(p)
+
+struct exact_chunk_struct;
+typedef struct exact_chunk_struct exact_chunk_t;
+
+exact_chunk_t * exact_chunk_alloc (size_t entry, int entries);
+void exact_chunk_free (exact_chunk_t *c);
+void * exact_chunk_get (exact_chunk_t *c);
+
+struct exact_map_struct;
+typedef struct exact_map_struct exact_map_t;
+typedef int exact_map_cmp_t (const void *, const void *);
+
+exact_map_t * exact_map_alloc (size_t key, exact_map_cmp_t *f);
+void exact_map_free (exact_map_t *m);
+int exact_map_find (exact_map_t *m, void *k);
+void * exact_map_value (exact_map_t *m);
+void exact_map_associate (exact_map_t *m, void *v);
+
+void exact_error (const char *fn,
+ int line,
+ const char *func,
+ const char *format, ...);
+
+void exact_internal_error (const char *fn,
+ int line,
+ const char *func,
+ const char *format, ...);
+
+#define EXACT_ERROR(...) exact_error(__FILE__,__LINE__,__func__,__VA_ARGS__);
+#define EXACT_INTERNAL_ERROR(...) \
+ exact_internal_error(__FILE__,__LINE__,__func__,__VA_ARGS__);
+
+#endif
diff --git a/app/src/main/res/drawable/back1.xml b/app/src/main/res/drawable/back1.xml
new file mode 100644
index 0000000..acc2b23
--- /dev/null
+++ b/app/src/main/res/drawable/back1.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back2.xml b/app/src/main/res/drawable/back2.xml
new file mode 100644
index 0000000..f8062e2
--- /dev/null
+++ b/app/src/main/res/drawable/back2.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back3.xml b/app/src/main/res/drawable/back3.xml
new file mode 100644
index 0000000..72ae7fd
--- /dev/null
+++ b/app/src/main/res/drawable/back3.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back4.xml b/app/src/main/res/drawable/back4.xml
new file mode 100644
index 0000000..0e04558
--- /dev/null
+++ b/app/src/main/res/drawable/back4.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back5.xml b/app/src/main/res/drawable/back5.xml
new file mode 100644
index 0000000..20970a1
--- /dev/null
+++ b/app/src/main/res/drawable/back5.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back6.xml b/app/src/main/res/drawable/back6.xml
new file mode 100644
index 0000000..e06a52e
--- /dev/null
+++ b/app/src/main/res/drawable/back6.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back7.xml b/app/src/main/res/drawable/back7.xml
new file mode 100644
index 0000000..bbaea51
--- /dev/null
+++ b/app/src/main/res/drawable/back7.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back8.xml b/app/src/main/res/drawable/back8.xml
new file mode 100644
index 0000000..78e6d1b
--- /dev/null
+++ b/app/src/main/res/drawable/back8.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back9.xml b/app/src/main/res/drawable/back9.xml
new file mode 100644
index 0000000..1db2979
--- /dev/null
+++ b/app/src/main/res/drawable/back9.xml
@@ -0,0 +1,18 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher.png b/app/src/main/res/drawable/ic_launcher.png
new file mode 100644
index 0000000..5966d4e
Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher.png differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..f245b9e
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
new file mode 100644
index 0000000..d227c49
--- /dev/null
+++ b/app/src/main/res/menu/main.xml
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..1ba777d
--- /dev/null
+++ b/app/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sw720dp-land/dimens.xml b/app/src/main/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..eee741a
--- /dev/null
+++ b/app/src/main/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+
+
+
+ 128dp
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..541752f
--- /dev/null
+++ b/app/src/main/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v14/styles.xml b/app/src/main/res/values-v14/styles.xml
new file mode 100644
index 0000000..f20e015
--- /dev/null
+++ b/app/src/main/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..a6dd140
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+
+ 16dp
+ 16dp
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4c81f50
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+
+
+ Monk\'s Sudoku Solver
+ Settings
+ Hello India!
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4a10ca4
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..f6627fc
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,15 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.2'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'