diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-11-29 20:13:19 +0000 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-11-29 20:13:19 +0000 |
| commit | 3ceb28b64003e9d414a5efe5bc8f0a1e4c533ae6 (patch) | |
| tree | fd5e8d76ab7695122400bb419e8b07dc56a6978b /challenge-088 | |
| parent | d433b6e28a4d15e724a423272ded765b7d4eebc8 (diff) | |
| parent | 15c864f39b1bef0ad6aa2ab433ec14400df97e3e (diff) | |
| download | perlweeklychallenge-club-3ceb28b64003e9d414a5efe5bc8f0a1e4c533ae6.tar.gz perlweeklychallenge-club-3ceb28b64003e9d414a5efe5bc8f0a1e4c533ae6.tar.bz2 perlweeklychallenge-club-3ceb28b64003e9d414a5efe5bc8f0a1e4c533ae6.zip | |
Merge branch 'master' of https://github.com/manwar/perlweeklychallenge-club
Diffstat (limited to 'challenge-088')
| -rw-r--r-- | challenge-088/abigail/blog1.txt | 1 | ||||
| -rw-r--r-- | challenge-088/abigail/c/ch-2.c | 151 | ||||
| -rw-r--r-- | challenge-088/abigail/node/ch-2.js | 96 | ||||
| -rw-r--r-- | challenge-088/abigail/perl/ch-2.pl | 118 |
4 files changed, 284 insertions, 82 deletions
diff --git a/challenge-088/abigail/blog1.txt b/challenge-088/abigail/blog1.txt new file mode 100644 index 0000000000..ab782c48d9 --- /dev/null +++ b/challenge-088/abigail/blog1.txt @@ -0,0 +1 @@ +https://wp.me/pcxd30-8Z diff --git a/challenge-088/abigail/c/ch-2.c b/challenge-088/abigail/c/ch-2.c new file mode 100644 index 0000000000..91f52233f9 --- /dev/null +++ b/challenge-088/abigail/c/ch-2.c @@ -0,0 +1,151 @@ +# include <stdlib.h> +# include <stdio.h> + +/* + * Challenge + * + * You are given m x n matrix of positive integers. + * + * Write a script to print spiral matrix as list. + */ + +/* + * We solve this by keeping track of the boundaries (min_x, min_y, max_x, + * max_y) of the part of the matrix which still needs to be processed. + * Initially, min_x and min_y are 0, max_x is the index of the bottom row, + * and max_y is the index of the right most column. + * + * We then process the matrix side by side, first going east (top row), + * south (left column), west (bottom row), then north (left row). After + * doing a side, we update the corresponding min/max value. That is, + * after doing the top row, we increment min_x; right column, decrement + * max_y; bottom row, decrement max_x; left column, increment min_y. + * + * We're done when min_x > max_x, or min_y > max_y. + */ + +typedef long long number; +enum dirs {EAST, SOUTH, WEST, NORTH}; + +int main (void) { + char * text = NULL; /* Complete input */ + size_t buf_len = 0; /* Allocated buffer size */ + ssize_t str_len; /* Number of characters read */ + size_t rows = 0; /* Number of rows in matrix */ + size_t columns = 0; /* Number of columns in matrix */ + size_t elements = 0; /* Total number of elemenst in matrix */ + + number element; /* Element read */ + int offset; /* Offset when scanning input */ + char * ptr; /* Pointer into text */ + number ** matrix; /* Matrix we're using */ + + enum dirs direction; /* Direction of movement */ + + + /* Read all the input (this assumes the input doesn't contain * + * a NUL character. */ + str_len = getdelim (&text, &buf_len, 0, stdin); + + /* First, count the number of rows */ + ptr = text; + while (*ptr) { + if (*ptr == '\n') { + rows ++; + } + ptr ++; + } + + /* Count the number of elements */ + ptr = text; + while (sscanf (ptr, "%lld%n", &element, &offset) == 1) { + elements ++; + ptr += offset; + } + + /* We can now calculate the number of columns */ + columns = elements / rows; + + /* Check whether we have any elements left over; * + * if so, we exit with an error. */ + if (elements != rows * columns) { + fprintf (stderr, "That doesn't look like a proper matrix\n"); + exit (1); + } + + /* Allocate memory */ + if ((matrix = (number **) calloc (rows, sizeof (number *))) == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + + for (size_t x = 0; x < rows; x ++) { + if ((matrix [x] = (number *) calloc (columns, + sizeof (number))) == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + } + + /* Scan the text again, but now fill in the array */ + ptr = text; + for (int x = 0; x < rows; x ++) { + for (int y = 0; y < columns; y ++) { + if (sscanf (ptr, "%lld%n", &matrix [x] [y], &offset) != 1) { + fprintf (stderr, "Something really weird happened!\n"); + exit (1); + } + ptr += offset; + } + } + + /* Now it's time to do the real work */ + /* Note that we're using ssize_t for the min/max values; if we use * + * unsigned values, we're running into problems if we use a loop * + * counting down to zero. We would expect the loop to terminate if * + * the iterand is -1, but that cannot happen for an unsigned value. */ + ssize_t min_x = 0; + ssize_t max_x = rows - 1; + ssize_t min_y = 0; + ssize_t max_y = columns - 1; + + direction = EAST; /* We start off heading East */ + + size_t printed = 0; /* Each printed number will be preceeded by a * + * comma, except the first. */ + while (min_x <= max_x && min_y <= max_y) { + if (direction == EAST) { + for (ssize_t y = min_y; y <= max_y; y ++) { + printf (printed ++ ? ", %lld" : "%lld", matrix [min_x] [y]); + } + min_x ++; + } + if (direction == SOUTH) { + for (ssize_t x = min_x; x <= max_x; x ++) { + printf (", %lld", matrix [x] [max_y]); + } + max_y --; + } + if (direction == WEST) { + for (ssize_t y = max_y; y >= min_y; y --) { + printf (", %lld", matrix [max_x] [y]); + } + max_x --; + } + if (direction == NORTH) { + for (ssize_t x = max_x; x >= min_x; x --) { + printf (", %lld", matrix [x] [min_y]); + } + min_y ++; + } + direction = (direction + 1) % (NORTH + 1); + } + printf ("\n"); + + /* Clean up the allocated memory */ + for (size_t x = 0; x < rows; x ++) { + free (matrix [x]); + } + free (matrix); + free (text); +} diff --git a/challenge-088/abigail/node/ch-2.js b/challenge-088/abigail/node/ch-2.js new file mode 100644 index 0000000000..ee99a7cf07 --- /dev/null +++ b/challenge-088/abigail/node/ch-2.js @@ -0,0 +1,96 @@ +// +// Challenge +// +// You are given m x n matrix of positive integers. +// +// Write a script to print spiral matrix as list. +// + +// +// We solve this by keeping track of the boundaries (min_x, min_y, max_x, +// max_y) of the part of the matrix which still needs to be processed. +// Initially, min_x and min_y are 0, max_x is the index of the bottom row, +// and max_y is the index of the right most column. +// +// We then process the matrix side by side, first going east (top row), +// south (left column), west (bottom row), then north (left row). After +// doing a side, we update the corresponding min/max value. That is, +// after doing the top row, we increment min_x; right column, decrement +// max_y; bottom row, decrement max_x; left column, increment min_y. +// +// We're done when min_x > max_x, or min_y > max_y. +// + +// +// Read STDIN. Split on newlines, then on white space. +// +let matrix = require ("fs") + . readFileSync (0) // Read all. + . toString () // Turn it into a string. + . split ("\n") // Split on newlines. + . filter (_ => _ . length) // Filter empty lines. + . map (_ => _ . trim () // Trim white space. + . split (/\s+/)) // Split on whitespace. +; + +// +// Check if all rows are the same length +// +matrix . forEach (row => { + if (row . length != matrix [0] . length) { + throw "Not all rows are of equal length"; + } +}); + +// +// Set some variables +// +let EAST = 0; +let SOUTH = 1; +let WEST = 2; +let NORTH = 3; + +let direction = EAST; // Initial direction + +let min_x = 0; +let max_x = matrix . length - 1; +let min_y = 0; +let max_y = matrix [0] . length - 1; + +// +// Spiral down the matrix, putting the results into the string output. +// +let output = ""; +while (min_x <= max_x && min_y <= max_y) { + if (direction == EAST) { + for (let y = min_y; y <= max_y; y ++) { + output = output + ", " + matrix [min_x] [y]; + } + min_x ++; + } + if (direction == SOUTH) { + for (let x = min_x; x <= max_x; x ++) { + output = output + ", " + matrix [x] [max_y]; + } + max_y --; + } + if (direction == WEST) { + for (let y = max_y; y >= min_y; y --) { + output = output + ", " + matrix [max_x] [y]; + } + max_x --; + } + if (direction == NORTH) { + for (let x = max_x; x >= min_x; x --) { + output = output + ", " + matrix [x] [min_y]; + } + min_y ++; + } + + direction = (direction + 1) % (NORTH + 1); +} + +// +// Print the result, without the leading ", ". +// +process . stdout . write (output . slice (2) + "\n"); diff --git a/challenge-088/abigail/perl/ch-2.pl b/challenge-088/abigail/perl/ch-2.pl index 5455a70ed6..16f6c6f801 100644 --- a/challenge-088/abigail/perl/ch-2.pl +++ b/challenge-088/abigail/perl/ch-2.pl @@ -21,32 +21,15 @@ use experimental 'lexical_subs'; # We solve this by keeping track of the boundaries (min_x, min_y, max_x, # max_y) of the part of the matrix which still needs to be processed. # Initially, min_x and min_y are 0, max_x is the index of the bottom row, -# and max_y is the index of the right most column. The boundaries are -# stored in an array @boundaries, using indices $MIN_X, $MIN_Y, $MAX_X, -# $MAX_Y. +# and max_y is the index of the right most column. # -# We also keep track of the current position, that is, the position -# of the value which should be printed next. This starts off as (0, 0), -# the index of the top left corner. +# We then process the matrix side by side, first going east (top row), +# south (left column), west (bottom row), then north (left row). After +# doing a side, we update the corresponding min/max value. That is, +# after doing the top row, we increment $min_x; right column, decrement +# $max_y; bottom row, decrement $max_x; left column, increment $min_y. # -# Next thing we keep track of is the direction of travel, the change in -# (x, y) coordinate we take at each step. This will be initialized as -# (0, 1), as we start off moving to the right. -# -# We now move through the matrix in the direction of travel, printing -# the current value. If we hit the end of the yet-to-be-printed matrix, -# we rotate the direction of movement by 90 degrees, and update one of -# the boundaries: -# - If we have travelled the top row, we increment $min_x; -# - If we have travelled the right column, we decrement $max_y; -# - If we have travelled the bottom row, we decrement $max_x; -# - If we have travelled the left column, we increment $min_y. -# -# Note that we always travel the edges in the same order: -# top row (left to right), right edge (top to bottom), -# bottom row (right to left), left edge (bottom to top), and then repeat. -# -# We stop if $min_x > $max_x, or $min_y > $max_y. +# We're done when $min_x > $max_x, or $min_y > $max_y. # my @matrix = map {[/[1-9][0-9]*/g]} <>; @@ -56,71 +39,42 @@ my @matrix = map {[/[1-9][0-9]*/g]} <>; # die "Not a matrix" if grep {@$_ != @{$matrix [0]}} @matrix; -# -# Boundaries -# -my @boundaries; - $boundaries [my $MIN_X = 0] = 0; - $boundaries [my $MAX_Y = 1] = $#{$matrix [0]}; - $boundaries [my $MAX_X = 2] = $#matrix; - $boundaries [my $MIN_Y = 3] = 0; -my $boundary_change = 0; +my $EAST = 0; +my $SOUTH = 1; +my $WEST = 2; +my $NORTH = 3; -my $X = 0; -my $Y = 1; +my $direction = $EAST; -# -# Current pointer and direction. -# -my (@position, @direction); - @position [$X, $Y] = (0, 0); - @direction [$X, $Y] = (0, 1); +my $min_x = 0, +my $max_x = $#matrix; +my $min_y = 0; +my $max_y = $#{$matrix [0]}; -my $comma = ""; -while ($boundaries [$MIN_X] <= $boundaries [$MAX_X] && - $boundaries [$MIN_Y] <= $boundaries [$MAX_Y]) { - # - # Print the value at the current position. - # - print $comma, $matrix [$position [$X]] [$position [$Y]]; - $comma = ", "; - - # - # Where would we end up if we move one step. - # - my @next_position = ($position [$X] + $direction [$X], - $position [$Y] + $direction [$Y]); - - # - # Next if we're still in bounds. - # - if ($boundaries [$MIN_X] <= $next_position [$X] && - $next_position [$X] <= $boundaries [$MAX_X] && - $boundaries [$MIN_Y] <= $next_position [$Y] && - $next_position [$Y] <= $boundaries [$MAX_Y]) { - @position = @next_position; - next; +my @out; +while ($min_x <= $max_x && $min_y <= $max_y) { + if ($direction == $EAST) { + push @out => map {$matrix [$min_x] [$_]} $min_y .. $max_y; + $min_x ++; + } + elsif ($direction == $SOUTH) { + push @out => map {$matrix [$_] [$max_y]} $min_x .. $max_x; + $max_y --; + } + elsif ($direction == $WEST) { + push @out => reverse map {$matrix [$max_x] [$_]} $min_y .. $max_y; + $max_x --; + } + elsif ($direction == $NORTH) { + push @out => reverse map {$matrix [$_] [$min_y]} $min_x .. $max_x; + $min_y ++; } - # - # We're running off of the matrix, change direction, and - # update or decrement a minimum or maximum value. - # Note that we always hit boundaries in the same order. - # - $boundaries [$boundary_change] += ($boundary_change == 0 || - $boundary_change == 3) ? 1 : -1; - $boundary_change = ($boundary_change + 1) %4; - - # - # Rotate the movement direction 90 degrees clockwise, - # and update the position. - # - @direction = ($direction [$Y], -$direction [$X]); - @position = ($position [$X] + $direction [$X], - $position [$Y] + $direction [$Y]); + $direction = ($direction + 1) % ($NORTH + 1); } -print "\n"; +$, = ", "; +say @out; __END__ |
