# Pragmatic Bookshelf Brain Teaser

Saw a challenge from the Pragmatic Bookshelf on Mastodon

Fill each column with the digits 1 through 6 without repeating or omitting digits so the sums in the right column are the total of each row. A digit may appear more than one across rows.

Because putting that matrix into alt-text is weird, here’s a table!

C1 | C2 | C3 | C4 | C5 | TOTAL |
---|---|---|---|---|---|

6 | 5 | 2 | 19 | ||

1 | 3 | 10 | |||

1 | 3 | 11 | |||

4 | 5 | 24 | |||

3 | 2 | 4 | 18 | ||

6 | 5 | 4 | 23 |

#### Let’s Talk About It

This …

I suppose I have to say it.

**This** looks like a **job** for *Recursion!*

We’re placing a digit into a place in a matrix, proceeding, then testing at the end. We’re returning arrayrefs, and if we have the answer, it’ll be a full one. If not, `[]`

.

I expand my habitual use of List::Util, adding `first`

and `any`

to my bag of tricks. `any`

is a boolean, checking an array for anything. Here, `any { /x/ } @flatten`

tests if any of the elements in `@flatten`

contain the letter `x`

. Within my code, I’m using `x`

as the placeholder for unfilled elements, so we can tell if the matrix has unfilled spots.

We then fill the spots in the array, and I use `first`

to find the indexes we need to fill, with `$row = first { 'x' eq $matrix->[$_][$col] } 1 .. 6`

.

We’re supposed to have each column use the numbers 1 through 6, so I use hashes and `grep`

to discern the numbers in each column not already used, and then only use those numbers to fill in the column. Because of this, I don’t have to test if the column are correct, because they can’t not be. I test by sum, which is kinda halfhearted.

I feel I should mention that you don’t *need* to make a program to solve this. After being hung up a bit, I put the numbers into a spreadsheet, used a few `=SUM()`

lines because I didn’t want to do simple addition if I could get the computer to do it, and was able to discern the numbers by hand, then use that as a test set to make sure my recursion was working.

#### Show Me The Code!

```
#!/usr/bin/env perl
use strict;
use warnings;
use experimental qw{ say signatures state fc };
use List::Util qw{ any first sum0 };
my $array = [
[qw{ 6 x 5 2 x }],
[qw{ 1 x 3 x x }],
[qw{ x x 1 3 x }],
[qw{ 4 5 x x x }],
[qw{ 3 2 x 4 x }],
[qw{ x 6 x 6 4 }],
];
my @totals = qw{19 10 11 24 18 23};
my $matrix = fill_matrix( $array, \@totals );
say 'OUTPUT';
say join "\n", map { join ' ', $_->@* } $matrix->@*;
exit;
sub fill_matrix ( $matrix, $totals, $col = 0 ) {
my @flat = map { $_->@* } $matrix->@*;
if ( any { $_ eq 'x' } @flat ) {
no warnings;
my @column = map { $_->[$col] } $matrix->@*;
if ( !any { /x/ } @column ) {
return fill_matrix( $matrix, $totals, $col + 1 );
}
my $row = first { 'x' eq $matrix->[$_][$col] } 1 .. 6;
my %list;
my @list = 1 .. 6;
$list{$_}++ for @column;
my @needed = grep { !$list{$_} } @list;
my $copy;
for my $i ( 0 .. -1 + scalar $matrix->@* ) {
my @row = $matrix->[$i]->@*;
push $copy->@*, \@row;
}
for my $n (@needed) {
$copy->[$row][$col] = $n;
my $return = fill_matrix( $copy, $totals, $col );
return $return if scalar $return->@*;
}
return [];
}
else {
for my $i ( 0 .. -1 + scalar $matrix->[0]->@* ) {
my @col = map { $matrix->[$_][$i] } 0 .. 5;
my $sum = sum0 @col;
return [] if $sum != 21;
}
for my $i ( 0 .. 5 ) {
my $t = $totals->[$i];
my $sum = sum0 $matrix->[$i]->@*;
if ( $sum ne $totals->[$i] ) {
return [];
}
}
return $matrix;
}
}
```

```
$ ./prag_array.pl
OUTPUT
6 1 5 2 5
1 3 3 1 2
2 4 1 3 1
4 5 4 5 6
3 2 6 4 3
5 6 2 6 4
```