So i have this program that should solve a futoshiki puzzle in C
wich is loaded from a text file having this formatting :
5 0 | 0 | 0 | 0 | 0 - - - - v - - - - 0 > 0 | 0 | 0 | 3 - - - - - - - - - 0 | 0 < 2 | 0 | 0 - - - - v - - - - 0 | 0 | 0 | 0 | 4 ^ - v - - - - - - 0 | 0 | 0 | 0 | 0
where 5 is the size of the matrix, and the numbers adjcent to the operators <, >, ^, v must satisfy the condition imposed by them, from the file all the characters on rows are divided by spaces
eg 0 |…
So I’ve managed to load the file, to check if it satisfies the math operators conditions, but I’m stuck on the recursive function
What I’d like to know:
Did i choose the right way to store the matrix or I’ve should have divided the numbers from the logical operators ?
How could I perform an recursive expansion on the matrix and how could I track the used number in a certain step(in case I would have to backtrack)?
eg. let’s say I arrive at index[j][j] where j<n (size of matrix) , starting from there I would have to decrement j (“touching”) only numbers and check if the sub-matrix satisfies the conditions
Here’s what I’ve managed to code so far.
where :
char **readmat(int *n); //reads the matrix from the file eliminating the spaces between chars
void print(char **mat,int n); //prints the stored matrix
int check(char **mat,int n); //checks if items of a matrix of size n satisfies the math operators
int expand (char **mat,int n,int i); //this should be the recursive functions that gets an element at a time and checks if there’s any condition to be satisfied, if so, increments it
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **readmat(int *n);
void print(char **mat,int n);
int check(char **mat,int n);
int expand (char **mat,int n,int i);
int main(int argc, char *argv[])
{
char **mat;
int n, j;
mat=readmat(&n);
if(mat == NULL)
return 1;
if(check(mat,n)){
print(mat,n);
}
else if(expand(mat,n,0)==1){
print(mat,n);
}
else {
printf("Nessuna soluzione trovata.\n");
}
for(j=0; j<=n;j++)
free(mat[j]);
free(mat);
system("PAUSE");
return 0;
}
char **readmat(int *n){
FILE *fp;
char *line,nome[100];
int i,j,k;
char **mat;
printf("Inserire il nome del file: ");
scanf("%s",nome);
fp=fopen(nome,"r");
if(fp==NULL){
printf("Errore apertura file");
return NULL;
}
if(fgets(nome,100,fp)==NULL){
printf("Formato file non valido\n");
fclose(fp);
return NULL;
}
if(sscanf(nome,"%d",n)!=1){
printf("Errore nei parametri del file\n");
fclose(fp);
return NULL;
}
(*n)=(((*n)*2)-1);
mat=(char**)malloc((*n)*sizeof(char*));
for(i=0;i<=(*n);i++)
mat[i]=(char*)malloc((*n)*sizeof(char));
line=(char*)malloc(2*(*n)*sizeof(char));
i=0;
while(i<=2*(*n) && fgets(line,2*(*n)+2,fp)!=NULL){
j=0;
k=0;
while(j<=2*(*n)){
if(line[j]!=' '){
mat[i][k]=line[j];
k++;
}
j++;
}
i++;
}
return mat;
//print(mat, (*n));
}
void print(char **mat,int n){
int i=0,j=0;
for (i=0; i<n; i++) {
for (j=0; j<n; j++) {
printf("%c", mat[i][j]);
}
printf("\n");
}
}
int check(char **mat,int n) {
int i,j;
int k=1;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(mat[i][j]=='<'){
if(mat[i][j-1] >= mat[i][j+1])
k=0;
}
else if(mat[i][j]=='>'){
if(mat[i][j-1] <= mat[i][j+1])
k=0;
}
else if(mat[i][j]=='^'){
if(mat[i-1][j] >= mat[i+1][j])
k=0;
}
else if(mat[i][j]=='v'){
if(mat[i-1][j] <= mat[i+1][j])
k=0;
}
}
}
return k;
}
int expand (char **mat,int n,int i){
int j=i/n;
int k=i%n;
int p;
if(i>=n*n){
return 1;
}
else{
if((mat[j][k]>47)&&(mat[j][k]<58)){
if(mat[j][k]=='0'){
expand(mat,n,i+2);
}
for (p=(mat[j][k]-48); p<(10-(mat[j][k]-48)); p++) {
mat[j][k]=48+p;
if (check(mat,i)) {
if (expand(mat, n, i+2)) {
return 1;
}
}
}
i-=2;
mat[j][k]='0';
}
}
return 0;
}
solution of the example : As you can see the logical conditions area clearly satisfied
0 | 0 | 1 | 0 | 0
- - - - v - - - -
1 > 0 | 0 | 0 | 3
- - - - - - - - -
0 | 0 < 2 | 0 | 0
- - - - v - - - -
0 | 1 | 0 | 0 | 4
^ - v - - - - - -
1 | 0 | 0 | 0 | 0
The way you store the matrix shouldn’t matter too much. You can store it however you like, as long as you can easily get/set the numerical value of each spot, and evaluate whether the operators are satisfied.
Very broadly, you can solve problems of this type by using an algorithm like this:
This algorithm does a brute-force recursive search, trying every possible value for each spot, and backtracking if it enters an illegal state. In the super-worst case, it runs in exponential time, but in practice, the
isValid()call at the beginning will short-circuit any obviously infeasible branches, so it should finish reasonably quickly for a 5×5 input.Implementation of isValid, isComplete, getEmptySpot, and setValue will depend on how you defined gameData.
isValidshould check to see that the game data isn’t in an illegal state – in your case, it should check that all the greater-than comparisons are correct, and check that every number appears only once in each row and column. These checks should ignore spots whose value is 0, since they are just a placeholder meaning “not filled in yet”.isCompleteshould check to see that no spots have a “not filled in yet” placeholder.(isValid(gameData) && isComplete(gameData))implies that gameData is solved.getEmptySpotshould find a spot that hasn’t been filled in yet. If you’re concerned about speed, it should find a spot with the least number values that can be legally entered. This will reduce the width of the search tree pretty considerably.Finally,
setValueshould set the given spot to the given value.