I got an assignment to write a program that fills an empty sudoku board and prints it out.
The tools that we have are only functions, arrays and pointers. No recursion, no search and sort algorithms to improve the time complexity.
So far I thought to use two dimension array for the board and go over every row in a nested "for" loop.
Every time I fetch a number with a random function and check a row, a column and a square (3X3), and if all of them pass then I fill the number.
My problem is that, that way it takes the code a very long time to solve, and I don't know if I'm doing it right. I didn't see a solution of my code yet, even after leaving it to run more than 5 minutes. I thought maybe somehow to use a histogram of numbers from 1-9 that maps which numbers already used to somehow change the use of fetching random numbers, but I'm not really sure how to use it and if it's even right to do so. Basically I'm stuck.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#define MATRIX_SIZE 9
#define MAX_NUM 9
void solve_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE]);
void print_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE]);
int rowCheck(int num, int board[][MATRIX_SIZE], int row);
int columnCheck(int num, int board[][MATRIX_SIZE], int row);
int squareCheck(int num, int board[][MATRIX_SIZE], int row, int col);
int giveNum(void);
void main()
{
srand(time(NULL));
int board[MATRIX_SIZE][MATRIX_SIZE];
/*{
0,0,0,0,0,4,0,0,0,
0,6,8,0,0,0,5,0,0,
0,2,0,0,0,0,0,7,6,
6,0,0,0,0,0,8,9,0,
0,0,5,2,6,0,0,0,0,
0,0,0,9,0,0,1,0,0,
0,0,0,0,0,7,0,5,0,
0,4,0,0,0,0,0,0,1,
0,0,0,0,5,1,4,0,0
};*/
for (int row = 0; row < MATRIX_SIZE; row++)
for (int col = 0; col < MATRIX_SIZE; col++)
board[row][col] = -1;
solve_sudoku(board);
print_sudoku(board);
}
void solve_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE])
{
int rowCh, colCh, sqrCh, num, square = 0;
for (int row = 0; row < MATRIX_SIZE; row++)
{
for (int col = 0; col < MATRIX_SIZE; col++)
{
if (square > 2)
square = 0;
while(1)
{
num = giveNum();
rowCh = rowCheck(num, board, row, col);
if (!rowCh)
continue;
colCh = columnCheck(num, board, row, col);
if (!colCh)
continue;
sqrCh = squareCheck(num, board, row, col-square);
if (!sqrCh)
continue;
break;
} //while (!rowCh || !colCh || !sqrCh);
square++;
board[row][col] = num;
}
}
}
void print_sudoku(int board[MATRIX_SIZE][MATRIX_SIZE])
{
printf("Sudoku solution:\n");
for (int i = 0; i < MATRIX_SIZE; i++)
{
for (int j = 0; j < MATRIX_SIZE; j++)
printf("%d ", board[i][j]);
printf("\n");
}
}
int giveNum(void)
{
int num = rand() % MATRIX_SIZE + 1;
return num;
}
int rowCheck(int num, int board[][MATRIX_SIZE], int row)
{
for (int col = 0; col < MATRIX_SIZE; col++)
{
if (num == board[row][col])
return 0;
}
return 1;
}
int columnCheck(int num, int board[][MATRIX_SIZE], int col)
{
for (int row = 0; row < MATRIX_SIZE; row++)
{
if (num == board[row][col])
return 0;
}
return 1;
}
int squareCheck(int num, int board[][MATRIX_SIZE], int row, int col)
{
for (int i = row; i < row + sqrt(MATRIX_SIZE); i++)
for (int j = col; j < col + sqrt(MATRIX_SIZE); j++)
if (board[i][j] == num)
return 0;
return 1;
}
I strongly doubt that you will have much luck with a pure random approach. There are so many combinations so that chance of hitting a valid solution is very little. Instead you'll most likely end in a dead-lock where there is no valid number to put in current position... then you just have an endless loop.
Anyway... here is a bug:
For the squareCheck function to work, it's required that col and row identifies the upper-left corner. For col you ensure that using square but for row you don't.
In other words, your check isn't correct.
Instead of using "the square method" consider to put these lines in the start of the function:
row = row - (row % 3);
col = col - (col % 3);
There's a loop while(1) where you pick a random number and determine if it is valid in the current position.
It's quite possible to get to a dead end here.
You can have easily filled in numbers that while valid individually leave the puzzle insoluble.
You need some method of backtracking if you get 'stuck' or detecting that it will get stuck.
The 'common' approach is to hold a 9x9 matrix of sets holding a subset of 1-9 which are the untried values. When a value is set (at start) or tried (during solve) you check the constraints and remove the value being tried from its column, row and square.
Start with a 9x9 grid all cells initialised to the full range [1-9].
If you set a cell to (say) 5 remove 5 from all cells in that column, row and sub-square.
If that leaves any cell with the empty set, the puzzle is insoluble.
When solving only pick from the set of 'remaining possible values' rather than rand [1-9].
However it still may be that a trial makes the puzzle insoluble and needs to go back a cell (or more) to come forward again.
The easy way to do that would be recursion. But that's ruled out by the Exercise.
So it looks like some kind of Undo stack is required.
Here is a way to generate a random suduko.
// Check that no number 1..9 is present twice in a column
int colok(int s[][9])
{
for (int col=0; col<9; ++col)
{
for (int n=1; n<=9; ++n)
{
int cnt = 0;
for (int i=0; i<9; ++i)
{
if (s[i][col] == n)
{
if (cnt > 0) return 0;
cnt = 1;
}
}
}
}
return 1;
}
// Check that no number 1..9 is present twice in a 3x3 block
int blockok(int s[][9])
{
for (int row=0; row<9; row += 3)
{
for (int col=0; col<9; col +=3)
{
for (int n=1; n<=9; ++n)
{
int cnt = 0;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
if (s[i + row][j + col] == n)
{
if (cnt > 0) return 0;
cnt = 1;
}
}
}
}
}
}
return 1;
}
void p(int s[][9])
{
for (int i=0; i<9; ++i)
{
for (int j=0; j<9; ++j)
{
printf("%d ", s[i][j]);
}
puts("");
}
}
#define MAX_LOOP 10000000
void makerow(int s[][9], int r)
{
int loops = 0;
while(1)
{
++loops;
// FY Shuffle row (this ensures that rows are always valid)
int a[] = {1,2,3,4,5,6,7,8,9};
int max = 8;
while(max)
{
int t = rand() % (max + 1);
int tmp = a[t];
a[t] = a[max];
a[max] = tmp;
--max;
}
// Save row
for (int i=0; i<9; ++i)
{
s[r][i] = a[i];
}
// Check whether it's valid
if (colok(s) && blockok(s))
{
// It's valid so stop here
break;
}
// Stop if too many loops
if (loops > MAX_LOOP)
{
puts("I'm so tired...");
exit(1);
}
}
printf("loops %d\n", loops);
}
int main(void)
{
srand((int)time(0));
int s[9][9] = { 0 };
for (int i=0; i<9; ++i)
{
printf("Make row %d\n", i);
makerow(s, i);
}
p(s);
return 0;
}
Possible output:
Make row 0
loops 1
Make row 1
loops 27
Make row 2
loops 1090
Make row 3
loops 3
Make row 4
loops 1019
Make row 5
loops 5521
Make row 6
loops 96
Make row 7
loops 66727
Make row 8
loops 498687
7 5 2 4 6 8 3 1 9
3 4 6 9 1 7 8 2 5
8 1 9 3 2 5 7 6 4
9 6 3 8 7 4 2 5 1
1 8 5 2 9 3 6 4 7
2 7 4 1 5 6 9 8 3
6 9 7 5 4 2 1 3 8
5 2 8 7 3 1 4 9 6
4 3 1 6 8 9 5 7 2
But notice... it happens that no solution can be generated.. then the output is:
Make row 0
loops 1
Make row 1
loops 37
Make row 2
loops 2957
Make row 3
loops 16
Make row 4
loops 2253
Make row 5
I'm so tired...
In order to avoid recursion you can try to navigate the solution space by levels. That requires a Queue, in which you add the next possible states from a given one (just extracted from the queue) and you mark the already visited ones (e.g. with the selected numbers) In this way you only build a single loop (no nested loops required) and you can generate all the possible solutions (but you can stop at the first that just generates a valid position)
Thanks for all of your responses. There is an update: I found a bug that made me a lot of problems, The bug was that I defined : columnCheck function that receives variable row and I called the function this way: " columnCheck(num, board, row, col); ", so the bug is that in the definition I need to give only 3 arguments, when I called the function accidently with 4 and also gave the columCheck the row instead the column. Also rowCheck was called with 4 arguments instead of 3 as defined. Can someone explain why the debugger didn't warn me about that ?
Also I changed the giveNum() function to this one:
int giveNum(void)
{
int static num = 1;
if (num > 9)
num = 1;
return num++;
}
Now it's not random but it fills the sudoku.
Since a lot of people asked the instructor how to do it, he replied that this kind of solution will be fine for now, However I will take the challenge to solve it with your suggestions.
I have written this C code to find a minimum number of wires required to switch on all the bulbs.
The problem is that there is x number of computers, some of which are On and some are Off and the distance between these bulb from the first bulb is given. The computer can be switched ON by connecting it to its nearby ON the bulb.
So the inputs are as follows:
X = 6 (number of bulbs)
1 0 1 1 0 1(1 means the bulb is ON and 0 means the bulb is OFF)
2 4 8 36 37 40 (distance between one bulb from the first bulb)
and the output will be:
3 (Reason: 4 - 2 = 2, 37 - 36 = 1, 2 + 1 = 3)
#include <stdio.h>
int main(){
int n,pre,post,sum = 0;
scanf("%d",&n);
int arr[n],dist[n];
for(int i =0;i<n;i++){
scanf("%d ",&arr[i]);
}
for(int i =0;i<n;i++){
scanf("%d ",&dist[i]);
}
for(int i =0;i<6;i++){
if(arr[i] == 0){
pre = dist[i]-dist[i-1];
post = dist[i+1]-dist[i];
if(pre>post){
sum +=post;
}
else{
sum+=pre;
}
}
}
printf("\n %d",sum);
}
It keeps on taking the inputs. Please tell me what is the error in this code?
Thanks in advance.
Edited: I missed that scanf("%d",n) by mistake. It was there in my original code and the problem still persists.
As Sandrin mentioned, n is not defined.
Assuming your input file is:
6
1 0 1 1 0 1
2 4 8 36 37 40
You need to add code to set n:
scanf("%d ",&n);
And, you need to insert this before the definitions of your matrix
Here's the refactored code:
#include <stdio.h>
int
main(void)
{
int n, pre, post, sum = 0;
#if 1
scanf("%d ",&n);
#endif
int arr[n], dist[n];
for (int i = 0; i < n; i++)
scanf("%d ", &arr[i]);
for (int i = 0; i < n; i++)
scanf("%d ", &dist[i]);
for (int i = 0; i < 6; i++) {
if (arr[i] == 0) {
pre = dist[i] - dist[i - 1];
post = dist[i + 1] - dist[i];
if (pre > post) {
sum += post;
}
else {
sum += pre;
}
}
}
printf("\n %d", sum);
return 0;
}
Putting a side technical errors (e.g. n not initialized), the algorithms assumes that all problems can be solved by single pass. This is not true for cases like:
1 0 0 0 0 1
0 1 3 4 6 7
Where the code will choose to connect bulbs [0,1], [2,3], and [4,5], based on pre/post distances. However, bulbs 2 and 3 will remain disconnected.
A better algorithm will attempt to find, for each sequence of off bulbs, which is the most expensive connection, and avoid it.
I have come up with this solution for my code and I have tried to consider all the test cases. If you find any test case that won't run feel free to tell.
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av){
int n,pre,post,sum = 0;
scanf("%d",&n);
int *input,*distance;
input = malloc(n * sizeof(int));
for (int i=0; i < n; i++)
{
scanf("%d", &input[i]);
}
distance = malloc(n * sizeof(int));
for (int i=0; i < n; i++)
{
scanf("%d", &distance[i]);
}
for(int i =0;i<6;i++){
if(input[i] == 0){
pre = distance[i]-distance[i-1];
if(input[i+1]==1){
post = distance[i+1]-distance[i];
input[i] =1;
if(pre>post){
sum +=post;
}
else{
sum+=pre;
}
}
else{
sum = sum+pre;
}
printf("%d.....%d....%d\n",pre,post,sum); //Debugging
}
}
printf("\n %d",sum);
free(input);
free(distance);
}
I wanna create all possible 5 digit numbers that can be created from the numbers (0-7).
The code below achieves this, but is there any way to make this depend on user input?
The number of loops equals the number of digits I want and each individual loop must be:
for(1st number;condition<=last number;1st number++)
So, for five digits, I have:
for(i=0;i<8;i++){
for(j=0;j<8;j++){
for(k=0;k<8;k++){
for(m=0;m<8;m++){
for(n=0;n<8;n++){
printf("%d %d %d %d %d\n",i,j,k,m,n);
}
}
}
}
}
Keep iterators in an array and increment them manually.
#include <assert.h>
#include <stdio.h>
#include <string.h>
void callback(unsigned n, int i[n]) {
assert(n == 5);
printf("%d %d %d %d %d\n", i[0], i[1], i[2], i[3], i[4]);
}
void iterate(unsigned n, unsigned max, void (*callback)(unsigned n, int i[n])) {
// VLA, use *alloc in real code
int i[n];
memset(i, 0, sizeof(i));
while (1) {
for (int j = 0; j < n; ++j) {
// increment first number, from the back
++i[n - j - 1];
// if it didn't reach max, we end incrementing
if (i[n - j - 1] < max) {
break;
}
// if i[0] reached max, return
if (j == n - 1) {
return;
}
// if the number reaches max, it has to be zeroed
i[n - j - 1] = 0;
}
// call the callback
callback(n, i);
}
}
int main() {
// iterate with 5 numbers to max 8
iterate(5, 8, callback);
}
The beginning and ending of what the code prints:
0 0 0 0 0
0 0 0 0 1
...
...
7 7 7 7 6
7 7 7 7 7
If you want variable numbers of loops, you generally need to use recursion.
Say if you want n digits, with the ith digit be in the range of a[i],b[i], then you will do the following:
/* whatever */
int n;
int *a,*b,*number;
void recursion(int whichdigit){
if (whichdigit==n){
/* Say you managed to output number */
return;
}
for (int i=a[whichdigit];i<=b[whichdigit];i++){
number[whichdigit]=i;
recursion(whichdigit+1);
}
return;
}
int main(){
/* Say somehow you managed to obtain n */
a=malloc(n*sizeof(int));
b=malloc(n*sizeof(int));
number=malloc(n*sizeof(int))
if (!a||!b||!number){
/* unable to allocate memory */
}
/* Say somehow you managed to read a[i],b[i] for all i in 0..n-1 */
recursion(0);
return 0;
}
Warning: if you tries to have too many digits, you will likely get a segmentation fault or stack overflow error.
I'm currently going through CS50 through edx and doing problem set 1, Mario.
The objective is to create a print out using pound signs. With the help of some videos I got the code for the first one but I don't understand fundamentally how the math works/ what the computer is understanding.
So I figure if I don't learn I'm crippling myself later.
if n= 5
Then i has 1 added to it until it is not less than 5 which means 5 times yes?
Take a look at this line for the space loop >
for (int j = 0; j < n -1 - i; j++)
If n is 5, then it ends up being j(0) < 3...
So why on the first line are there four spaces and not three spaces?
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int n;
do
{
n = get_int("Pyramid Height: ");
}
while (n < 0 || n >= 24);
//print out this many rows
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n -1 - i; j++)
{
printf(" ");
}
// print out this many columns
for (int j = 0; j < i + 2; j++)
{
printf("#");
}
printf("\n");
}
}
I get the correct pyramid yet i don't understand the logic behind the spacing and prints
if n=5 then n-1-j would be equal 5-1-0 i.e. 4 for the first time executing the loop that is the reason why you are seeing four spaces. The first loop condition should be n-2-j if you want the number of spaces to be three because total no of columns is 5 and the pounds expected in the first row are 2, therefore you should be subtracting 2 from n.
That looks way too complicated.
Here's a simple version I whipped up:
#include <stdio.h>
int main(void) {
int height = 5;
char blocks[height];
memset(blocks,'#',height);
for(int i=0; i<height; ++i)
{
printf("%*.*s\n", height, i+1, blocks );
}
return 0;
}
Output:
Success #stdin #stdout 0s 9424KB
#
##
###
####
#####
Let us try to figure out the pattern here. Like for the left pyramid if the height of the pyramid is 8, check the pattern of spaces and hashes from top to bottom. In this case we need 8 lines, every line has same characters and no of spaces decreases and no of hashes increases from top to bottom.
Now we have the pattern for the left half, the right half is the same, mirror image. So now we can write down the loop as we know the no of spaces and hashes from top to bottom. In programming we need to understand the underlying principle. Plug in the code afterwards becomes easy.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int h;
do
{
h = get_int("Pyramid height: ");
}
while (h<1 || h>8);
int n = 8, i, j;
for (i=0; i<h;++i)
{
// left half
for (j=0;j<h-1-i;++j)
printf(" ");
for (j=0;j<i+1;++j)
printf("#");
// two spaces in middle
printf(" ");
// right half, we have omitted the space code as it is not required.
for (j=0;j<i+1;++j)
printf("#");
printf("\n");
}
return 0;
I have worked for a sudoku puzzle in C but I'm stuck in one problem: Checking every 3x3 grid for not having duplicate values.
Here is my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int v[10][10];
//Matrix start from 1 and end with 9
//So everywhere it should be i=1;i<=9 not from 0 to i<9 !!!
//Display function ( Display the results when it have)
void afisare()
{
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++)
printf("%2d",v[i][j]);
printf("\n");
}
printf("\n");
}
//Function to check the valability of value
int valid(int k, int ii, int jj)
{
int i;
//Check for Row/Column duplicate
for(i = 1; i <= 9; ++i) {
if (i != ii && v[i][jj] == k)
return 0;
if (i != jj && v[ii][i] == k)
return 0;
}
//Returns 0 if duplicate found return 1 if no duplicate found.
return 1;
}
void bt()
{
int i,j,k,ok=0;
//Backtracking function recursive
for(i=1;i<=9;i++){
for(j=1;j<=9;j++)
if(v[i][j]==0)
{
ok=1;
break;
}
if(ok)
break;
}
if(!ok)
{
afisare();
return;
}
for(k=1;k<=9;k++)
if(valid(k,i,j))
{
v[i][j]=k;
bt();
}
v[i][j]=0;
}
int main()
{
//Reading from the file the Matrix blank boxes with 0
int i,j;
freopen("sudoku.in","r",stdin);
for(i=1;i<=9;i++)
for(j=1;j<=9;j++)
scanf("%d",&v[i][j]);
bt();
system("pause");
return 0;
}
I know in function Valid I should have the condition to check every 3x3 grid but I don't figure it out: I found those solution to create some variables start and end
and every variable get something like this:
start = i/3*3;
finnish = j/3*3;
i and j in my case are ii and jj.
For example found something like this:
for (int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++)
for (int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++)
if (row != i && col != j && grid[row][col] == grid[i][j])
return false;
I tryed this code and it doesn't work.
I don't understand this: I have the next matrix for sudoku:
1-1 1-2 1-3 1-4 1-5 1-6
2-1 2-2 2-3 2-4 2-5 2-6
3-1 3-2 3-3 3-4 3-5 3-6
If my code put's a value on 3-2 how he check in his grid for duplicate value, that formula may work for 1-1 or 3-3 but for middle values doesn't work, understand ?
If my program get's to 2-5 matrix value It should check if this value is duplicate with 1-4 1-5 1-6 2-4 2-6 ... untill 3-6.
Since you are using index arrays starting with 1 and not zero, you have to correct for that when calculating the sub-grid indexes.
start = (i - 1) / 3 * 3 + 1;
finish = (j - 1) / 3 * 3 + 1;