Related
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'm trying to solve one problem, which I found on website https://open.kattis.com/problems/coast. Tl;dr version of problem is, that for given map of landscape, I should print out length of coastline (without inner islands).
I receive 0/26 mark, but I have no idea why, I've tested, and as far as i checked, it worked. I assume it doesn't compile, but if that is the case, why is that? It compiles for me perfectly fine.
#include <stdio.h>
int edgeCount(int, int, char*);
int topToBottomCount(int, int, char*);
int leftToRightCount(int, int, char*);
int removingInsides(int, int, char*);
int main()
{
int n = 0; // number of strings
int m = 0; // strings lenghts
//printf("Enter N(number of strings) x M(strings lenght): ");
scanf("%d", &n);
scanf("%d", &m);
char coast[1024];
for(int i = 0; i < n; i++){
scanf("%s", coast+i*m); // adding strings to char coast[1024], making array of ones and zeroes // e.g we are adding 3x4 strings - 111100001111
} // it can also be looked as 1111
// 0000 - matrix
int coasts = edgeCount(n, m, coast); // 1111
coasts += topToBottomCount(n, m, coast);
coasts += leftToRightCount(n, m, coast);
coasts -= removingInsides(n, m, coast);
printf("%d - coasts\n", coasts);
return 0;
}
int edgeCount(int n, int m, char *coast){ // if 1 is placed at the edge of the "map", it is 1 coast (2 if it is at corner)
int edgeCoast = 0;
for(int i = 0; i < m; i++){ // top edges
if(coast[i] == '1')
edgeCoast++;
}
for(int i = m*n - m; i < m*n; i++){ // bottom edges (m*n - m = first char in the last string, it can be also looked as the last row in matrix)
if(coast[i] == '1')
edgeCoast++;
}
for(int i = 0; i <m*n; i+=m){ // left side edges (first column in matrix)
if(coast[i] == '1')
edgeCoast++;
}
for(int i = m-1; i < m*n; i+=m){ // right side edges (last column in matrix)
if(coast[i] == '1')
edgeCoast++;
}
return edgeCoast;
}
int topToBottomCount(int n, int m, char *coast){
int coasts = 0;
for(int i = 0; i < m*n - m; i++){ // we start from first char in "matrix", and move to the (m*n - m = 2nd last "row")
if(coast[i] ^ coast[i+m]) // we are checking if zero is placed above one or via versa
coasts++;
}
return coasts;
}
int leftToRightCount(int n, int m, char* coast){
int coasts = 0;
int p = m-1;
for(int i = 0; i < n*m; i++){ // we start from the first charr, and we are going trough whole matrix, but the last column
if(i == p){ // p = m - 1 (last char in first row)
p+=m; // p+=m (last char in next column, and so on)
continue; // we move to next iteration
}
if(i == m*n - 1) //if we are at last char in matrix, we break out from loop
break;
if(coast[i] ^ coast[i+1])
coasts++;
}
return coasts;
}
int removingInsides(int n, int m, char* coast){ // Lakes and islands in lakes are not contributing to the sea coast. we are checking if they exist.
int innerCoasts = 0;
for(int i = m + 1; i < n*m - m - 1; i ++){
if( coast[i] == '0' && coast[i] ^ coast[i-1] && coast[i] ^ coast[i+1] && coast[i] ^ coast[i-m] && coast[i] ^ coast[i+m]) // char has to be 0, and to hist left, right, above and under there has to be 1
innerCoasts++;
}
return innerCoasts * 4; // *4 because we added 4 coasts before for each island.
}
I tried compiling your code using the GCC C++ compiler (4.9.2). It compiled fine and I tested it using the sample problem in the link you provided. It spit out the right answer.
However, when I tried compiling using the GCC C compiler (also v 4.9.2), it fails with 'for' loop initial declarations are only allowed in C99 or C11 mode, which is explained by this SO question. I think your assignment was graded using a C compiler and the compilation of your program failed due to this error.
The problem starts near the very bottom of the array. I print percent[x] values to make sure they are there, and then after the sort, three of them are filled with zeros. I've been looking around for awhile but I can't find anything.
#include <stdio.h>
int main()
{
int votes[5][4]={192,48,206,37,
147,90,312,21,
186,12,121,38,
114,21,408,39,
267,13,382,29};
char cand[4]={'A','B','C','D'};
int row_totals[5];
int col_totals[4]; //This is left for you to do
//see code below to see how
//row_totals were calculated.
int total_votes;
//use a for loop to calculate
//using either row_totals or col_totals
float percent[4]; //use a for loop to calculate based on
int swap; //total_votes and col_totals
//be sure to print the totals for the candidates
//at the end, you will need to sort the percent array
//bringing along the values from the cand array. That is
//if a swap is made in the percent array, do the same
//swap in the cand array.
//then if percent[3] is greater than 50, declare cand[3] the winner
//if percent[3] is not greater than 50, declare a run-off
//between cand[2] and cand[3]
int row,col;
for(row=0;row<=4;row++) // used to find the row total
{
row_totals[row]=0;
for(col=0;col<=3;col++)
{
row_totals[row] += votes[row][col];
}
}
for(col=0; col <=3; col++)
{
col_totals[col]=0;
for(row =0; row <= 4; row++) // used to find the column total
{
col_totals[col] += votes[row][col];
}
}
for(row =0; row<=4; row++)
{
total_votes += row_totals[row]; //finds the total amount of the votes
}
printf(" Candidate Candidate Candidate Candidate Total\n");
printf(" Precinct: A B C D Votes\n");
for(row=0;row<=4;row++)
{
printf("%6d",row+1);
for(col=0;col<=3;col++)
{
printf("%12d",votes[row][col]);
}
printf("%11d\n",row_totals[row]);
}
printf("Total\nVotes:");
for(col=0; col<=3; col++)
{
printf("%12d", col_totals[col]);
}
printf(" %d", total_votes);
printf("\nPrecentage:");
for(col=0; col <= 3; col++)
{
percent[col] = (col_totals[col] / (double)total_votes); //calculates percentages
printf("%11f", percent[col]);
}
int x,y;
for(x=0; x<=3; x++)
{
printf("\n%f", percent[x]);
}
for(x=0; x<3; x++)
{
for(y=0;y<(3-x); y++)
{
if(percent[y] > percent[y+1])
{
swap = percent[y];
percent[y] = percent[y+1];
percent[y+1]= swap;
}
}
}
for(col=0; col<4; col++)
{
printf("\n%f", percent[col]);
}
return 0;
Your temporary variable for swapping is an integer, but the values you swap are floats between 0 and 1, which will become zero on conversion to int.
The error is hard to spot, because the temporary variable in declared at the top of the long main function, far away from the actual swapping code. You could make the temporary variable a local variable to the swapping scope:
for (x = 0; x < 3; x++) {
for (y = 0; y < (3 - x); y++) {
if (percent[y] > percent[y + 1]) {
float swap = percent[y];
percent[y] = percent[y + 1];
percent[y + 1] = swap;
}
}
}
Other issues:
Your total_votes isn't initialised to zero.
Please consider writing your loops as
for (row = 0; row < nrows; row++) ...
instead of
for (row = 0; row <= nrows - 1; row++) ...
This is a common C idiom. Your loops use hard-coded values, but later you might want to have variable limits as in the two examples above, where the "less than the number of items" variant is more readable.
When you print, new-lines should be at the end of your print formats, not at the beginning. This is the natural way of printing. It also has the benefit that the output buffer will be flushed when printing a newline to the console.
This is minor, but pick one floating-point type. You use float, but calculate your percentage with double. I recommend double, which is the standard floating-point type on modern machines.
Hello I am trying to populate an array with random values between 0 and 10000, display each to the screen with their location then calculate max, min, and average value in addition to thier locations. I am having trouble displaying the results. Can someone please help?
Thank you!
#include <stdio.h>
#include<time.h>
#include<math.h>
int array [3][5];
int practice_array;
int i, row, col, max, min, sum, avg;
srand(time(NULL));
for ( row = 0; row < 2; row = row + 1){
for ( col = 0; col < 4; col = col +1){
array[row][col] = rand()%10000;
practice_array = array[row][col];
sum = array[row][col];
avg = sum / 15;
for(i =0; i< 8; i++){
printf("The value in row %d col %d is %d\n",row, col,practice_array);
}
}
}
for (i = 0; i < 8; i++){
max = array[0];
min = array[0];
if (array[i] > max)
{
max = array[i];
}
else if (array[i] < min)
{
min = array [i];
}
}
printf("The max value is %d in row %d, col %d\n", max, row,col);
printf("The min value is %d in row %d, col %d \n", min, row,col);
return (0);
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 3
#define COL 5
int main(){
int array[ROW][COL];
int practice_array;
int i, row, col, max, min, sum, avg;
srand(time(NULL));
for ( row = 0; row < ROW; row = row + 1){
for ( col = 0; col < COL; col = col +1){
array[row][col] = rand()%(10000+1);
practice_array = array[row][col];
sum += practice_array;
printf("The value in row %d col %d is %d\n",row, col,practice_array);
}
}
avg = sum / (ROW*COL);//unused
int *pv = &array[0][0];
max = min = 0;
for (i = 1; i < ROW*COL; ++i){
if (pv[i] > pv[max])
max =i;
if (pv[i] < pv[min])
min = i;
}
printf("The max value is %d in row %d, col %d\n", pv[max], max/COL, max%COL);
printf("The min value is %d in row %d, col %d\n", pv[min], min/COL, min%COL);
return 0;
}
First you should really use defines for constants (array sizes, ...) like I've shown to you on the other thread otherwise your code is mess with magic numbers everywhere (for example in this code: 3, 5, 2, 4, 8, ...). And if you've to change a value, you need to change it everywhere; with a define you change it only once at one place.
Also, when it prints each values & location, they are duplicated 5 times before printing the next value this is because of this (completely useless) loop, just delete it and keep only the printf:
for(i =0; i< 8; i++){
printf("The value in row %d col %d is %d\n",row, col,practice_array);
}
For everything else, as far as I can see, you don't have fully understood how loops are working. I suggest you to learn the basics of the loops before trying to use them with arrays.
Also try to use step wise development by first building an array with simple numbers and printing it out. Then try adding random numbers to a specific location in each array position and so on with 2d stuff. It seems like you wrote down a bunch of code without stepping back and trying to run it a few times
After looking through you code I could see a few things that you still need to work on.
Don't forget all of that needs to be inside of the main method or the compiler will not know where to start. you will also need "#include <stdlib.h>" to get your srand to work.
If you try to find examples online on a simple srand being used, you will see what I mean. The variable sum is not finding the sum. You need to loop though all the locations and add them to the sum. It would then be easy to find the average using your method.
If you are looking to print out all of them, remember to also use that for loop and loop through every single location and print them out.
Alright so I thought my code was working and it seems to do so, it allows the user to choose the size of a magic square where the number one is the start point and starts in the center of the first row. The pattern goes along this line....go up one and over one, if you go up above the first row.....move back to the last row or if you run off the end of the right side of the column than go back to the start of the column...in a magic square if your not familiar with it, all sides are equal when the numbers on that side or diagonal are counted.
An odd number must be entered for this to be written out as a magic square (example: 3x3, 5x5, 7x7, etc..) the problem is it works until I enter 11x11....when done, it comes back around and when the program runs into a slot that has already been filled it is supposed to enter the next number below the last one that was entered into the array...but when 11x11 is entered it overwrites the 1 with a 13 which breaks the cycle and ruins the pattern....I would appreciate it if someone helped me with this, I think maybe the problem has to do with the equation I use to choose the starting point. This works all the way up to 11x11, every odd number entered after that seems to overwrite the starting point.
// Chapter 8 Programming Project #17
#include <stdio.h>
#define N_squared (N * N)
#define MOVE (--row, ++column)
#define RW_SIZE ((int) (sizeof(magic_square) / sizeof(magic_square[0])))
void create_magic_square(int N, int magic_square[N][N], int ROW_SIZE);
void print_magic_square(int N, int magic_square[N][N], int ROW_SIZE);
int main(void)
{
int N, row, column;
printf("This program creates a magic square of a specified size\n");
printf("The size must be an odd number between 1 and 99.\n");
printf("Enter size of magic square: ");
scanf("%d", &N);
int magic_square[N][N];
for (row = 0; row < N; row++) {
for (column = 0; column < N; column++) {
magic_square[row][column] = 0;
}
}
// Create magic square
create_magic_square(N, magic_square, RW_SIZE);
// Print magic square
print_magic_square(N, magic_square, RW_SIZE);
return 0;
}
void create_magic_square(int N, int magic_square[N][N], int ROW_SIZE)
{
printf("Size of N*N = %d\nSize of ROW_SIZE = %d\n", N_squared, ROW_SIZE);
// Here I iterate through the numbers, rows, and columns
int i = 1, row = 0;
int column = (((ROW_SIZE + 1) / 2) - 1);
while (i != N_squared + 1){
// if new position is empty place next number
if (magic_square[row][column] == 0) {
magic_square[row][column] = i;
i++;
// If new position is filled then move back and down
} else if (row + 2 < ROW_SIZE &&
column - 1 >= 0) {
row += 2;
column -= 1;
} else if (row + 2 > ROW_SIZE - 1 &&
column - 1 < 0) {
row = 1;
column = ROW_SIZE - 1;
}
// If current position has been set then move
if (magic_square[row][column] != 0)
MOVE;
// If row runs off the board reset
if (row < 0)
row = ROW_SIZE - 1;
// if column runs off the board reset
if (column > ROW_SIZE - 1)
column = 0;
}
}
void print_magic_square(int N, int magic_square[N][N], int ROW_SIZE)
{
int row, column;
printf("\n");
for (row = 0; row < ROW_SIZE; row++) {
for (column = 0; column < ROW_SIZE; column++) {
if (N > 9)
printf(" %3d ", magic_square[row][column]);
else
printf(" %2d ", magic_square[row][column]);
}
printf("\n\n");
}
}