Peter’s solutions: week 101 — 22 February 2021
THE WEEKLY CHALLENGE
Spiral triangle
You are given an array @A of items (integers say, but they can be anything).
Your task is to pack that array into an MxN matrix spirally counterclockwise, as tightly as possible.
‘Tightly’ means the absolute value |M-N| of the difference has to be as small as possible.
Input: @A = (1,2,3,4) Output: 4 3 1 2
Since the given array is already a 1x4 matrix on its own, but that's not as tight as possible. Instead, you'd spiral it counterclockwise. 4 3 1 2 Example 2: Input: @A = (1..6) Output: 6 5 4 1 2 3 or 5 4 6 3 1 2
Either will do as an answer, because they're equally tight. Example 3: Input: @A = (1..12) Output: 9 8 7 6 10 11 12 5 1 2 3 4 or 8 7 6 9 12 5 10 11 4 1 2 3
This is a challenge which is easy to explain but not so easy to translate into Perl.
My best attempt goes like this:
First search the factors of @A to find the closest
together $factor and (scalar @A) / $factor; these will be
the height and width of the matrix. If scalar @A is prime,
those will be 1 and scalar @A.
First, as instructed, put $A[0] in the bottom left
corner of the matrix.
Proceed straight ahead ('east') filling cells until you hit either the edge of the matrix, or a filled cell, in which case turn left and continue until all the cells are filled.
That sounds easy, but both 'straight ahead' and 'turn left' imply keeping track of the current and previous filled cells to know which direction is straight ahead. which in turn calls for a choice among 8 cases. In production code I might try to optimise that, but for even a 10,000 member array my solution completes in milliseconds.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2021-02-22 use utf8; # Week 101 - task 1 - Pack a spiral use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; use Encode; pack_a_spiral(1..6); pack_a_spiral(1..13); pack_a_spiral(1..50); pack_a_spiral(1..99); pack_a_spiral(1..169); sub pack_a_spiral { my (@z, $w, $h, $count, $width, $height, @factors, $diff, $x, $y, @matrix, $j, $cw, $mov); # initialise @z = @_; $count = @z; # deduce closest height and width for $j (1 .. $count) { push @factors, $j if $count / $j == int($count / $j); } $diff = 1e6; for $h (@factors) { $w = $count / $h; last if $h > $w; if (abs($w - $h) < $diff) { $width = $w; $height = $h; $diff = abs($w - $h); } } # insert values in spiral $x = 0; $y = $height - 1; $cw = 0; $mov = 'E'; B: for $j (0 .. $width * $height - 1) { $matrix[$x][$y] = $z[$j]; $cw = length($z[$j]) if length($z[$j]) > $cw; last unless @z; # cases where spiral continues in same direction if ($mov eq 'E' and $x != $width - 1 and not defined $matrix[$x + 1][$y]) { $x ++; # keep moving east } elsif ($mov eq 'N' and $y != 0 and not defined $matrix[$x][$y - 1]) { $y --; # keep moving north } elsif ($mov eq 'W' and $x != 0 and not defined $matrix[$x - 1][$y]) { $x --; # keep moving west } elsif ($mov eq 'S' and $y != $height - 1 and not defined $matrix[$x][$y + 1]) { $y ++; # keep moving south # cases where it turns a corner } elsif ($x != $width - 1 and not defined $matrix[$x + 1][$y]) { $x ++; $mov = 'E'; # move east } elsif ($y != 0 and not defined $matrix[$x][$y - 1]) { $y --; $mov = 'N'; # move north } elsif ($x != 0 and not defined $matrix[$x - 1][$y]) { $x --; $mov = 'W'; # move west } else { $y ++; $mov = 'S'; # move south } } # display say qq[\nInput: $count]; say qq[Output: dimensions $width × $height]; for $y (0 .. $height - 1) { for $x (0 .. $width - 1) { printf (qq[%${cw}s ], $matrix[$x][$y]); } say ''; } }
44 lines of code
Completed after the closing date and not submitted to GitHub
Input: 6 Output: dimensions 3 × 2 6 5 4 1 2 3 Input: 13 Output: dimensions 13 × 1 1 2 3 4 5 6 7 8 9 10 11 12 13 Input: 50 Output: dimensions 10 × 5 23 22 21 20 19 18 17 16 15 14 24 43 42 41 40 39 38 37 36 13 25 44 45 46 47 48 49 50 35 12 26 27 28 29 30 31 32 33 34 11 1 2 3 4 5 6 7 8 9 10 Input: 99 Output: dimensions 11 × 9 29 28 27 26 25 24 23 22 21 20 19 30 59 58 57 56 55 54 53 52 51 18 31 60 81 80 79 78 77 76 75 50 17 32 61 82 95 94 93 92 91 74 49 16 33 62 83 96 97 98 99 90 73 48 15 34 63 84 85 86 87 88 89 72 47 14 35 64 65 66 67 68 69 70 71 46 13 36 37 38 39 40 41 42 43 44 45 12 1 2 3 4 5 6 7 8 9 10 11 Input: 169 Output: dimensions 13 × 13 37 36 35 34 33 32 31 30 29 28 27 26 25 38 79 78 77 76 75 74 73 72 71 70 69 24 39 80 113 112 111 110 109 108 107 106 105 68 23 40 81 114 139 138 137 136 135 134 133 104 67 22 41 82 115 140 157 156 155 154 153 132 103 66 21 42 83 116 141 158 167 166 165 152 131 102 65 20 43 84 117 142 159 168 169 164 151 130 101 64 19 44 85 118 143 160 161 162 163 150 129 100 63 18 45 86 119 144 145 146 147 148 149 128 99 62 17 46 87 120 121 122 123 124 125 126 127 98 61 16 47 88 89 90 91 92 93 94 95 96 97 60 15 48 49 50 51 52 53 54 55 56 57 58 59 14 1 2 3 4 5 6 7 8 9 10 11 12 13
Any content of this website which has been created by Peter Campbell Smith is in the public domain