Posts Tagged ‘grid’

Problem 11 of PE’s website says:

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.

img1

What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?

I provided a general solution in C. My program allocates dynamically any type of matrix, with any size you want, with any length of adjacent numbers you want the program to analize (this is the only extra data you provide as a parameter of the program from the CLI). It also provides some error management (i.e. if both sizes of the grid are less than the length of the adjacent numbers you want to find the product).

My program works this way:

1. Open your command line interpreter and execute the program providing the length of adjacent numbers you want to evaluate. For example, in this problem it is 4, therefore:

$ name_of_program 4

2. Now the program is waiting so that the user provides a matrix to the standard input (the program accepts any size!) and press Enter. In order that the program “catches” that you are done, it is to say, that the EOF of stdin is reached, press CTRL-D (but before of this, don’t forget to press Enter, this step is important).

3. It stores the grid in a new (temporal) file. At this point the width (= the amount of numbers of each line) and the height (= the number of lines of the file) of the grid are calculated and a new grid with that right size is created.

4. All the data stored in the file is saved in the grid.

5. All the required calculations inside the grid are performed.

6. The result is printed out on the standard output and the temporal file created by the program is removed from your computer.

Here is the C code:

#include <stdio.h>
#include <stdlib.h>

int **newGrid (unsigned int rows, unsigned int columns);
/* It returns a pointer to a 2D (rows x columns) matrix. */

void freeGrid (int **grid, unsigned int columns);
/* It frees the memory used for grid. */

void recordStdinToFileOpen (FILE * file);
/* Entering user's input is stored in a (temporal) file. */

unsigned int countElementsForGrid (FILE * file, int index_of_array);
/* After the grid is saved in a file, this function returns the width
and the height of the matrix, depending on whether the value of the 
"index_of_array" argument is 0 or 1, respectively. */

void recordFileOpenToGrid (FILE * from_file, int **grid, 
	unsigned int width, unsigned int height);
/* This functions enters the file we are using to allocate dinamically
the data and save it in a grid whose size has been previously calculated. */

unsigned long int getLargestProduct (int **grid, unsigned int width, 
	unsigned int height, unsigned int adjacent);
	
/* This function carries out the largest product of any "adjacent" length of adjacent 
numbers of the "grid" argument, whose size is "width"x"height", and returns the result.
For this problem in particular, adjacent = 4, height = 20, width = 20. */
	
unsigned long int doTheStuff (FILE * file, unsigned int adjacent);

/* It gathers all the functions above and returns the return value of the
getLargestProduct() function. */

unsigned long int openFileForGrid (unsigned int adjacent);
/* It opens a temporal file, does all the stuff described above, and
returns the result of doTheSuff() function.
When all the work is done, it removes physically that temporal file 
of your computer. */


int **newGrid (unsigned int rows, unsigned int columns){
    
    int **grid = NULL;
    unsigned int j = 0;

    grid = (int **) malloc (columns * sizeof (int *));

    for (j = 0; j < columns; j++){
		grid[j] = (int *) malloc (rows * sizeof (int));
    }

    return grid;
}

void freeGrid (int **grid, unsigned int columns){

    int j = 0;

    for (j = 0; j < columns; j++){
		free (grid[j]);
    }
    free (grid);
}

void recordStdinToFileOpen (FILE * file){

    int num;

    fseek (file, 0L, SEEK_SET);
    
    while (!feof (stdin)){
		fscanf (stdin, "%d", &num);
		if (!feof (stdin)){
			fprintf (file, "%d ", num);
			if (getchar () == '\n'){
				fprintf (file, "\n");
			}
		}
    }
}

unsigned int countElementsForGrid (FILE * file, int index_of_array){
    
    unsigned int result = 0;
    unsigned int i = 0, j = 0; /* During the execution time, press Enter
				  				after you paste your grid */
    unsigned int measures[2] = {i, j};
    int first_line_done = 0; 
    int c;

    fseek (file, 0L, SEEK_SET);
    
    while ((c = fgetc (file)) != EOF){
		if ((c == ' ') && first_line_done == 0){
			i++;
		}
		if (c == '\n'){
			j++;
			first_line_done = 1;
		}
		else {
			continue;
		}
    }

    measures[0] = i;
    measures[1] = j;

    result = measures[index_of_array];

    return result;
}


void recordFileOpenToGrid (FILE * from_file, int **grid, 
			   unsigned int width, unsigned int height){

    int i = 0, j = 0;

    fseek (from_file, 0L, SEEK_SET);

    for (j = 0; j < height; j++){
		for (i = 0; i < width; i++){
			fscanf (from_file, "%d", &grid[j][i]);
		}
    }
}

unsigned long int getLargestProduct (int **grid, unsigned int width,
				     unsigned int height, unsigned int adjacent){

    unsigned long int result = 1L;
    unsigned long int i = 0L, j = 0L, i_temp = i, j_temp = j;
    unsigned long int max = 1L;

    for (j = 0L; j < height; j++){
		for (i = 0L; i < width; i++){
			i_temp = i;
			j_temp = j;
			
			if (width - i_temp >= adjacent){  /* Move left-to-right (horitzontally) */ 
				for (i_temp = i; i_temp < adjacent + i; i_temp++){
					result *= (unsigned int) grid[j][i_temp];
				}
				if (result >= max) max = result;
				result = 1L;
			}
			
			if (height - j >= adjacent){ /* Move up-to-down (vertically) */
				for (j_temp = j; j_temp < adjacent + j; j_temp++){
					result *= (unsigned int) grid[j_temp][i];
				}
				if (result >= max) max = result; 
				result = 1L;
			}
			
			if ((height - j >= adjacent) && (width - i_temp >= adjacent)){ 
				/* Move up-to-down diagonally (\) */
				for (j_temp = j, i_temp = i; (j_temp < adjacent + j) 
					 && (i_temp < adjacent + i); j_temp++, i_temp++){
					result *= (unsigned int) grid[j_temp][i_temp];
				}
				if (result >= max) max = result;
				result = 1L;
			}
			
			if ((height - j >= adjacent) && (i_temp >= adjacent - 1)){ 
				/* Move up-to-down diagonally (/) */
				for (j_temp = j, i_temp = i; (j_temp < adjacent + j)
					 && (i_temp + 1 > i - adjacent + 1); j_temp++, i_temp--){
					result *= (unsigned int) grid [j_temp][i_temp];
				}
				if (result >= max) max = result;
				result = 1L;
			}
		}
    }

    result = max;

    return result;
}

unsigned long int doTheStuff (FILE * file, unsigned int adjacent){

    unsigned long int result = 1;
    unsigned int width = 0, height = 0;
    int **grid;

    recordStdinToFileOpen (file);
    width = countElementsForGrid (file, 0);
    height = countElementsForGrid (file, 1);
    
    if ((adjacent > width) && (adjacent > height)){
		fprintf (stderr, "Error: the parameter must be equal or less than, at least, one side of the grid.\n");
		exit (1);
    }

    grid = newGrid (width, height);
    recordFileOpenToGrid (file, grid, width, height);
    result = getLargestProduct (grid, width, height, adjacent);
    freeGrid (grid, height);
    
    return result;
}

unsigned long int openFileForGrid (unsigned int adjacent){
    
    unsigned long int escape = 0L;
    FILE * temp_file;
    
    temp_file = fopen ("temp.txt", "w+");
    if (temp_file != NULL){
		escape = doTheStuff (temp_file, adjacent);
    } else{
		fprintf (stderr, "Error: There were a problem when opening a new file.\n");
		exit (1);
    }

    fclose (temp_file);
    system ("rm -r temp.txt"); /* Windows users: replace "rm -r temp.txt" by "DEL temp.txt". */

    return escape;
}

int main (int argc, char *argv[]){

    char * endptr;
    const unsigned int adjacent = (unsigned int) strtol (argv[1], &endptr, 10);
    unsigned long int result;

    if (argc < 2 || (int) adjacent <= 0){
		fprintf (stderr, "Error: A positive integer as parameter is required.\n");
		exit (1);
    }
    
    result = openFileForGrid (adjacent);
    
    fprintf (stdout, "\n%lu\n", result);

    return 0;
}

I’m going to show you some examples of its use:

$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out 2
1 2
3 4

12
$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out 3
1 2 9
1 8 4
9 3 3
7 7 7

648
$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out 2
1 6 7 2 3

42

Examples of bad inputs:

$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out 5
3 5
5 3
Error: the parameter must be equal or less than, at least, one side of the grid.

$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out -1
Error: A positive integer as parameter is required.

In particular, for this problem:

$ (gcc -Wall -Wconversion -g prob11.c) && ./a.out 4
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

70600674

This is the requested answer.