# RabbitFarm

### 2021-01-03

#### Perl Weekly Challenge 093

## Part 1

*You are given set of co-ordinates @N. Write a script to count maximum points on a straight line when given co-ordinates plotted on 2-d plane.*

### Solution

```
use strict;
use warnings;
##
# You are given set of co-ordinates @N.
# Write a script to count maximum points
# on a straight line when given co-ordinates
# plotted on 2-d plane.
##
sub triangle_area{
my($i, $j, $k) = @_;
return ($i->[0] * ($j->[1] - $k->[1]))
+ ($j->[0] * ($k->[1] - $i->[1]))
+ ($k->[0] * ($i->[1] - $j->[1]));
}
sub collinear_points{
my(@points) = @_;
my @collinear;
for my $i (@points){
for my $j (@points){
for my $k (@points){
if(triangle_area($i, $j, $k) == 0){
my $i_string = join(",", @{$i});
my $j_string = join(",", @{$j});
my $k_string = join(",", @{$k});
if(($i_string ne $j_string) && ($i_string ne $k_string) && ($j_string ne $k_string)){
my $has_i = grep { $i_string eq join(",", @{$_}) } @collinear;
push @collinear, $i if !$has_i;
my $has_j = grep { $j_string eq join(",", @{$_}) } @collinear;
push @collinear, $j if !$has_j;
my $has_k = grep { $k_string eq join(",", @{$_}) } @collinear;
push @collinear, $k if !$has_k;
}
}
}
}
}
return @collinear;
}
MAIN:{
my @N;
@N = ([5,3], [1,1], [2,2], [3,1], [1,3]);
my @collinear = collinear_points(@N);
print "There are a maximum of " . @collinear . " collinear points.\n"
}
```

### Sample Run

```
$ perl perl/ch-1.pl
There are a maximum of 3 collinear points.
```

### Notes

Keep in mind that any two points determine a line. Therefore to consider all possible non-trivial lines we need to review all triples of points. This method will work in the most general case when the starting data may contain multiple lines with a larger number of points.

In determining collinearity I calculate the area of a triangle using the triple of points. If the area is zero we know that all the points lay on the same line.

## Part 2

*You are given a binary tree containing only the numbers 0-9. Write a script to sum all possible paths from root to leaf.*

### Solution

```
use strict;
use warnings;
##
# You are given a binary tree containing
# only the numbers 0-9.
# Write a script to sum all possible paths
# from root to leaf.
##
use Graph;
sub travserse_sum{
my($tree) = @_;
my @paths = build_paths($tree);
my $path_sum = 0;
for my $path (@paths){
$path_sum += unpack("%32C*", pack("C*", @{$path}));
}
return $path_sum;
}
sub build_paths {
my ($graph) = @_;
my @paths;
local *_helper = sub{
my $v = $_[-1];
my @successors = $graph->successors($v);
if(@successors){
_helper(@_, $_) for @successors;
}
else{
push @paths, [@_];
}
};
_helper($_) for $graph->source_vertices();
return @paths;
}
MAIN:{
my $Tree;
$Tree = new Graph();
$Tree->add_vertices(1, 2, 3, 4);
$Tree->add_edge(1, 2);
$Tree->add_edge(2, 3);
$Tree->add_edge(2, 4);
print travserse_sum($Tree) . "\n";
$Tree = new Graph();
$Tree->add_vertices(1, 2, 3, 4, 5, 6);
$Tree->add_edge(1, 2);
$Tree->add_edge(1, 3);
$Tree->add_edge(2, 4);
$Tree->add_edge(3, 5);
$Tree->add_edge(3, 6);
print travserse_sum($Tree) . "\n";
}
```

### Sample Run

```
$ perl perl/ch-2.pl
13
26
```

### Notes

This is straightforward enough, at a high level anyway: (1) Get all paths and then (2) sum all the nodes on the paths.

- I am always happy to have a chance to use the Graph module!
- The Graph module has a bunch of nice algorithms implemented but what we want here is not a
*shortest path*but*all paths*. The Graph module doesn’t have anything for us to use for that. Implementing a recursive*Depth First Search*and collecting all the paths is not such a hard thing to do, but in the**Holiday Spirit**(i.e. laziness) I just re-used Ikegami’s code. See the References section. - I first used the pack/unpack trick for summing array back in Challenge 007.

## References

posted at: 16:37 by: Adam Russell | path: /perl | permanent link to this entry

The Weekly Challenge 093 (Prolog Solutions)

## Part 1

*You are given set of co-ordinates @N. Write a script to count maximum points on a straight line when given co-ordinates plotted on 2-d plane.*

### Solution

```
:-initialization(main).
triangle_area(Points, Area):-
[[X1, Y1], [X2, Y2], [X3, Y3]] = Points,
Area is (X1 * (Y2 - Y3)) + (X2 * (Y3 - Y1)) + (X3 * (Y1 - Y2)).
collinear_points(Points, CollinearPoints):-
member(A, Points),
member(B, Points),
member(C, Points),
A \== B, A \== C, B \== C,
triangle_area([A, B, C], Area),
Area == 0,
CollinearPoints = [A, B, C].
main:-
N = [[5,3], [1,1], [2,2], [3,1], [1,3]],
collinear_points(N, CollinearPoints),
write(CollinearPoints), nl,
halt.
```

### Sample Run

```
$ gplc ch-1.p
$ ch-1
[[2,2],[3,1],[1,3]]
```

### Notes

Keep in mind that any two points determine a line. Therefore to consider all possible non-trivial lines we need to review all triples of points.

In determining collinearity I calculate the area of a triangle using the triple of points. If the area is zero we know that all the points lay on the same line.

## Part 2

*You are given a binary tree containing only the numbers 0-9. Write a script to sum all possible paths from root to leaf.*

### Solution

```
:-initialization(main).
dfs(Node, Graph, [Node|Path]):-
dfs(Node, Graph, Path, []).
dfs(_, _, [], _).
dfs(Node, Graph, [AdjNode|Path], Seen) :-
member(r(Node, Adjacent), Graph),
member(AdjNode, Adjacent),
\+ memberchk(AdjNode, Seen),
dfs(AdjNode, Graph, Path, [Node|Seen]).
sum_paths(Paths, Sum):-
sum_paths(Paths, 0, Sum).
sum_paths([], Sum, Sum).
sum_paths([H|T], PartialSum, Sum):-
sum_list(H, ListSum),
S is PartialSum + ListSum,
sum_paths(T, S, Sum).
path_lengths([], _).
path_lengths([H|T], [L|Lengths]):-
length(H, L),
path_lengths(T, Lengths).
partial_path(_, _, []).
partial_path(Path, MaxPathLength, [H|T]):-
length(Path, PathLength),
length(H, HLength),
(PathLength < MaxPathLength ; (subtract(Path, H, Remaining), length(Remaining, 0))),
partial_path(Path, MaxPathLength, T).
partial_path(Path, MaxPathLength, [H|_]):-
length(Path, PathLength),
length(H, HLength),
PathLength =< MaxPathLength,
subtract(Path, H, Remaining),
\+ length(Remaining, 0),
fail.
complete_paths(Paths, CompletePaths):-
path_lengths(Paths, PathLengths),
max_list(PathLengths, MaxPathLength),
complete_paths(Paths, Paths, MaxPathLength, [], CompletePaths).
complete_paths([], _, _, CompletePaths, CompletePaths).
complete_paths([H|T], Paths, MaxPathLength, CompletePathsAccum, CompletePaths):-
\+ partial_path(H, MaxPathLength, Paths),
complete_paths(T, Paths, MaxPathLength, [H|CompletePathsAccum], CompletePaths).
complete_paths([H|T], Paths, MaxPathLength, CompletePathsAccum, CompletePaths):-
partial_path(H, MaxPathLength, Paths),
complete_paths(T, Paths, MaxPathLength, CompletePathsAccum, CompletePaths).
main:-
findall(Path0, dfs(1,[r(1,[2]),r(2,[3,4])], Path0), Paths0),
complete_paths(Paths0, CompletePaths0),
sum_paths(CompletePaths0, Paths0Sum),
write(Paths0Sum), nl,
findall(Path1, dfs(1,[r(1,[2,3]), r(3,[5,6]), r(2,[4])], Path1), Paths1),
complete_paths(Paths1, CompletePaths1),
sum_paths(CompletePaths1, Paths1Sum),
write(Paths1Sum), nl, halt.
```

### Sample Run

```
$ gplc ch-2.p
$ prolog/ch-2
13
26
```

### Notes

The depth first search is pretty idiomatic Prolog and the `dfs/3`

code was something I grabbed from SO (see references). That code is straightforward enough, it finds all paths in a depth first manner. We are only concerned with the complete *root to leaf* paths and so a bit of effort goes into filtering out the partial paths. Once that is done the paths are summed and we are done.

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

## References

posted at: 16:36 by: Adam Russell | path: /prolog | permanent link to this entry