Skip to content

Commit

Permalink
[bugs & docs] lots of documentation and bug fixes (TheAlgorithms#554)
Browse files Browse the repository at this point in the history
* sudoku - lots of documentation and bug fixes

Signed-off-by: Krishna Vedala <[email protected]>

* fix uint8_t format specifier

* fix format specifiers

* fix space in doc

* fix doc for get_next_unknown

* fix docs and lgtm alert in euler problem 19

* fix docs & lgtm error fibonacci_fast

* fix docs & lgtm alert merge_sort

* free dynamic memory
  • Loading branch information
kvedala authored Jul 4, 2020
1 parent b693440 commit 6072e3b
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 100 deletions.
24 changes: 14 additions & 10 deletions misc/fibonacci_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,28 @@
#include <stdlib.h>

/**
Returns the \f$n^{th}\f$ and \f$n+1^{th}\f$ Fibonacci number.
The return variables are C & D respectively.
* Get the \f$n^{th}\f$ and \f$n+1^{th}\f$ Fibonacci number using recursive
* half-interval decimation.
* \param [in] n index of Fibonacci number to get
* \param [out] C left half interval value - end result here. Cannot be NULL
* \param [out] D right half interval can be discarded at end and can be NULL
*/
void fib(unsigned long n, unsigned long *C, unsigned long *D)
{
// Out of Range checking
if (n < 0)
{
printf("\nNo Such term !\n");
exit(0);
}
// commented out since `n` is unsigned integer
// if (n < 0)
// {
// printf("\nNo Such term !\n");
// exit(0);
// }

unsigned long a, b, c, d;

if (n == 0)
{
C[0] = 0;
if (D)
if (D) /* if D is not NULL */
D[0] = 1;
return;
}
Expand All @@ -50,7 +54,7 @@ void fib(unsigned long n, unsigned long *C, unsigned long *D)

/**< If n is odd */
C[0] = b;
if (D)
if (D) /* if D is not NULL */
D[0] = a + b;
return;
}
Expand Down Expand Up @@ -78,4 +82,4 @@ int main(int argc, char *argv[])
printf("The nth term is : %'lu \n", result);

return 0;
}
}
299 changes: 238 additions & 61 deletions misc/sudoku_solver.c
Original file line number Diff line number Diff line change
@@ -1,93 +1,270 @@
// recursion problem : Sudoku Solver
/*You are given an incomplete N*N Sudoku and asked to solve it using the
following recursive algorithm: (1) Scan the Sudoku from left to right row-wise
to search for an empty cell. (2) If there are no empty cells, print the Sudoku.
Go to step 5. (3) In the empty cell, try putting numbers 1 to N while ensuring
that no two numbers in a single row, column, or box are same. Go back to step 1.
(4) Declare that the Sudoku is Invalid.
(5) Exit.*/

/**
* @file
* @brief Sudoku Solver using recursive implementation of brute-force algorithm
*
* @details
* Given an incomplete N*N Sudoku and asked to solve it using the
* following recursive algorithm:
* 1. Scan the Sudoku from left to right row-wise to search for an empty cell.
* 2. If there are no empty cells, print the Sudoku. Go to step 5.
* 3. In the empty cell, try putting numbers 1 to N
* while ensuring that no two numbers in a single row, column, or box are same.
* Go back to step 1.
* 4. Declare that the Sudoku is Invalid.
* 5. Exit.
*
* @authors [Anuj Shah](https://github.com/anujms1999)
* @authors [Krishna Vedala](https://github.com/kvedala)
*/
#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M 144
int N, R, C;
/** @addtogroup sudoku Sudoku solver
* @{
*/
/** Structure to hold the matrix and dimensions
*/
struct sudoku
{
uint8_t *a; /**< matrix as a flattened 1D row-major array */
uint8_t N; /**< number of elements */
uint8_t N2; /**< block of elements */
};

int OKrow(int a[M], int x, int y, int v)
/**
* Check if `x`^th row is valid
* @param a ::sudoku to check
* @param x row to check
* @param y ignored column
* @param v value to check if it repeats
* @returns `true` if valid
* @returns `false` if in-valid
*/
bool OKrow(const struct sudoku *a, int x, int y, int v)
{
int j;
for (j = 0; j < N; j++)
if (a[x * N + j] == v)
return 0;
return 1;
int offset = x * a->N;
for (int j = 0; j < a->N; j++)
if (a->a[offset + j] == v)
// if the value is found in the row
return false;
return true;
}
int OKcol(int a[M], int x, int y, int v)

/**
* Check if `y`^th column is valid
* @param a ::sudoku to check
* @param x ignored row
* @param y column to check
* @param v value to check if it repeats
* @returns `true` if valid
* @returns `false` if in-valid
*/
bool OKcol(const struct sudoku *a, int x, int y, int v)
{
int i;
for (i = 0; i < N; i++)
if (a[i * N + y] == v)
return 0;
return 1;
for (int i = 0; i < a->N; i++)
if (a->a[i * a->N + y] == v)
// if the value is found in the column
return false;
return true;
}
int OKbox(int a[M], int x, int y, int v)

/**
* Check if a 3x3 box is valid
* @param a matrix to check
* @param x row index of the element to check
* @param y column index of the element to check
* @param v value to check if it repeats
* @returns `true` if valid
* @returns `false` if in-valid
*/
bool OKbox(const struct sudoku *a, int x, int y, int v)
{
int bi = x / R, bj = y / C, i, j;
for (i = 0; i < R; i++)
for (j = 0; j < C; j++)
if (a[(i + bi * R) * N + (j + bj * C)] == v)
return 0;
return 1;
/* get start indices of the box that the current (x,y) lies in
remember that in C/C++, division operation always rounds towards
-infinity for signed integers and towards 0 for unsigned integers
*/
int bi = x - x % a->N2, bj = y - y % a->N2;
// printf("Checking box: (%d,%d)\n", bi, bj);

for (int i = bi; i < (bi + a->N2); i++)
for (int j = bj; j < (bj + a->N2); j++)
if (a->a[i * a->N + j] == v)
// if the value is found in the box
return false;
return true;
}
int OK(int a[M], int x, int y, int v)

/**
* Check if element `v` is valid to place at (x,y) location.
* @param a ::sudoku to check
* @param x row to place value
* @param y column to place value
* @param v value to check if it is valid
* @returns `true` if valid
* @returns `false` if in-valid
*/
bool OK(const struct sudoku *a, int x, int y, int v)
{
return OKrow(a, x, y, v) && OKcol(a, x, y, v) && OKbox(a, x, y, v);
bool result = OKrow(a, x, y, v);
if (result)
result = OKcol(a, x, y, v);
if (result)
result = OKbox(a, x, y, v);

return result;
}

void print(int a[M])
/**
* Print the matrix to stdout
* @param [in] a array to print
*/
void print(const struct sudoku *a)
{
int i, j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
printf("%d%c", a[i * N + j], (j == N - 1 ? '\n' : ' '));
for (i = 0; i < a->N; i++)
for (j = 0; j < a->N; j++)
printf("%" SCNu8 "%c", a->a[i * a->N + j],
(j == a->N - 1 ? '\n' : ' '));
}

int solve(int a[M])
/**
* @brief Find and get the location for next empty cell.
*
* @param [in] a pointer to sudoku instance
* @param [out] x pointer to row index of next unknown
* @param [out] y pointer to column index of next unknown
* @returns `true` if an empty location was found
* @returns `false` if no more empty locations found
*/
bool get_next_unknown(const struct sudoku *a, int *x, int *y)
{
int i, j, v, rem = 0;
for (i = 0; i < N; i++)
for (int i = 0; i < a->N; i++)
{
for (j = 0; j < N; j++)
for (int j = 0; j < a->N; j++)
{
if (a[i * N + j] == 0)
if (a->a[i * a->N + j] == 0)
{
rem = 1;
for (v = 1; v <= N; v++)
{
if (OK(a, i, j, v))
{
a[i * N + j] = v;
if (solve(a))
return 1;
a[i * N + j] = 0;
}
}
*x = i;
*y = j;
return true;
}
}
}
if (rem == 0)
return 1;
return 0;

/* no unknown locations found */
return false;
}

/**
* @brief Function to solve a partially filled sudoku matrix. For each unknown
* value (0), the function fills a possible value and calls the function again
* to check forvalid solution.
*
* @param [in,out] a sudoku matrix to solve
* @return `true` if solution found
* @return `false` if no solution found
*/
bool solve(struct sudoku *a)
{
static uint32_t counter = 0;
int i, j;
static char prefix[100] = ""; // enough memory

if (!get_next_unknown(a, &i, &j))
{
/* no more empty location found
implies all good in the matrix
*/
return true;
}

/* try all possible values for the unknown */
for (uint8_t v = 1; v <= a->N; v++)
{ /* try all possible values 1 thru N */
printf("%sTry (%d,%d) = %" SCNu8 "... ", prefix, i, j, v);
counter++;
if (OK(a, i, j, v))
{
/* if assignment checks satisfy, set the value and
continue with remaining elements */
printf("passed (counter=%" SCNu32 ")\n", counter);
a->a[i * a->N + j] = v;
strcat(prefix, " ");
if (solve(a))
{
/* solution found */
return true;
}

printf("%sBacktrack (%d,%d) <- %" SCNu8 " (counter=%" SCNu32 ")\n",
prefix, i, j, a->a[i * a->N + j], counter);

prefix[strlen(prefix) - 2] = '\0'; // truncate the prefix
a->a[i * a->N + j] = 0;
}
else
{
printf("\r");
}
}

return false;
}

/** @} */

void test()
{
printf("Test begin...\n");

uint8_t test_array[] = {3, 0, 6, 5, 0, 8, 4, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0,
0, 0, 8, 7, 0, 0, 0, 0, 3, 1, 0, 0, 3, 0, 1, 0, 0,
8, 0, 9, 0, 0, 8, 6, 3, 0, 0, 5, 0, 5, 0, 0, 9, 0,
6, 0, 0, 1, 3, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0,
0, 0, 7, 4, 0, 0, 5, 2, 0, 6, 3, 0, 0};
struct sudoku a = {.N = 9, .N2 = 3, .a = test_array};
assert(solve(&a)); // ensure that solution is obtained

uint8_t expected[] = {3, 1, 6, 5, 7, 8, 4, 9, 2, 5, 2, 9, 1, 3, 4, 7, 6,
8, 4, 8, 7, 6, 2, 9, 5, 3, 1, 2, 6, 3, 4, 1, 5, 9,
8, 7, 9, 7, 4, 8, 6, 3, 1, 2, 5, 8, 5, 1, 7, 9, 2,
6, 4, 3, 1, 3, 8, 9, 4, 7, 2, 5, 6, 6, 9, 2, 3, 5,
1, 8, 7, 4, 7, 4, 5, 2, 8, 6, 3, 1, 9};
for (int i = 0; i < a.N; i++)
for (int j = 0; j < a.N; j++)
assert(a.a[i * a.N + j] == expected[i * a.N + j]);

printf("Test passed\n");
}

/** \brief Main function */
int main()
{
scanf("%d%d%d", &N, &R, &C);
int a[M], i, j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++) scanf("%d", &a[i * N + j]);
test();

struct sudoku a; // store the matrix as a 1D array
scanf("%" SCNu8, &(a.N));
a.a = (uint8_t *)malloc(a.N * a.N * sizeof(uint8_t));
a.N2 = (uint8_t)sqrt(a.N);

if (solve(a))
print(a);
for (int i = 0; i < a.N; i++)
for (int j = 0; j < a.N; j++) scanf("%" SCNu8, &(a.a[i * a.N + j]));

printf("Entered a %udx%ud matrix with block size: %" SCNu8 "\n", a.N, a.N,
a.N2);
// print(&a);
printf("\n\n");
if (solve(&a))
printf("Valid solution found!\n");
else
printf("Invalid\n");
print(&a);

free(a.a);
return 0;
}
Loading

0 comments on commit 6072e3b

Please sign in to comment.