RabbitFarm
2023-12-03
The Weekly Challenge 245 (Prolog Solutions)
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
Part 1
You are given two array of languages and its popularity. Write a script to sort the language based on popularity.
Solution
make_pairs(K, V, K-V).
sort_language(Languages, Popularity, SortedLanguages):-
maplist(make_pairs, Popularity, Languages, PopularityLanguages),
keysort(PopularityLanguages, SortedPopularityLanguages),
findall(Language, member(_-Language, SortedPopularityLanguages), SortedLanguages).
Sample Run
% gprolog --consult-file prolog/ch-1.p
| ?- sort_language([2, 1, 3], [perl, c, python], SortedLanguages).
SortedLanguages = [1,2,3]
yes
| ?-
Notes
A pretty standard Prolog convention is the -
separated Pair. So here
all we need do is generate the pairs of popularity and language, and
then use keysort/2
to get everything in the right order.
Part 2
You are given an array of integers >= 0. Write a script to return the largest number formed by concatenating some of the given integers in any order which is also multiple of 3. Return -1 if none found.
Solution
largest_of_three(Numbers, LargestOfThree):-
findall(Number,(
sublist(SubList, Numbers),
\+ SubList = [],
permutation(SubList, SubListPermutation),
number_codes(Number, SubListPermutation),
0 is Number mod 3), NumbersOfThree),
((NumbersOfThree = [], LargestOfThree = -1);
(max_list(NumbersOfThree, LargestOfThree))).
Sample Run
% gprolog --consult-file prolog/ch-2.p
| ?- largest_of_three("819", LargestOfThree).
LargestOfThree = 981
yes
| ?- largest_of_three("86710", LargestOfThree).
LargestOfThree = 8760
(1 ms) yes
| ?- largest_of_three("1", LargestOfThree).
LargestOfThree = -1 ?
yes
| ?-
Notes
This is perhaps the most naive solution to the problem: generate sublists and sort the matching permutations of those sublists.
References
posted at: 20:39 by: Adam Russell | path: /prolog | permanent link to this entry
Sleeping Threads Reveal the Largest of Three
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
Part 1
You are given two array of languages and its popularity. Write a script to sort the language based on popularity.
Solution
use Thread;
sub sort_language{
my @language = @{$_[0]};
my @popularity = @{$_[1]};
my @threads;
do{
push @threads, Thread->new(
sub{sleep($popularity[$_]); say $language[$_]}
);
} for 0 .. @popularity - 1;
do{$_ -> join()} for @threads;
}
MAIN:{
sort_language [qw/perl c python/], [2, 1, 3];
}
Sample Run
$ perl perl/ch-1.pl
c
perl
python
Notes
This is the most ridiculous solution I could imagine for this problem!
The sorting by popularity is done by way of a Sleep Sort. Sleep Sort is
a very silly thing where you sleep
for the values being sorted and
then as the sleeps finish the solution comes together.
For added fun I used Perl's threading mechanism. A convenient wrapper
for Perl's threads (which are properly called iThreads, and are
basically the same construct as, say, JavaScript's workers) is
use Thread
which used to be an entirely different sort of threading
model but is now just a handy set of functions around the current model.
Be sure to read the documentation before using, for simple thread tasks
it is perfectly fine! Just be aware of any issues with data sharing
between threads, which is of no concern to us here.
For each array element of @popularity
we create a new thread which is
then pushed into an array for tracking all the threads we create. Each
thread does nothing more than sleep and then print the corresponding
language. Note that we do need to administer our threads in the end by
looping over them and executing a join()
to ensure they complete
properly. We could just skip that, but doing so will cause Perl to warn
us that not all threads may have properly completed, although in this
case we wouldn't necessarily care since the program has completed
executing anyway. Still, it's better to maintain the good practice of
making sure everything is cleaned up!
Sleep Sort was the subject of a previous challenge
Part 2
You are given an array of integers >= 0. Write a script to return the largest number formed by concatenating some of the given integers in any order which is also multiple of 3. Return -1 if none found.
Solution
use v5.38;
use Algorithm::Permute;
sub largest_of_three{
my @digits = @_;
my $largest = -1;
do{
my $indices = $_;
my @sub_digits = @digits[grep{vec($indices, $_, 1) == 1} 0 .. @digits - 1];
my $permutor = Algorithm::Permute->new([@sub_digits]);
while(my @permutation = $permutor->next()){
my $d = join q//, @permutation;
$largest = $d if $d > $largest && $d % 3 == 0;
}
} for 1 .. 2**@digits - 1;
return $largest;
}
MAIN:{
say largest_of_three 8, 1, 9;
say largest_of_three 8, 6, 7, 1, 0;
say largest_of_three 1;
}
Sample Run
$ perl perl/ch-2.pl
981
8760
-1
Notes
I am not sure I have a whole lot to write about this one! My approach here is to take sublists and permute each one, checking at each step for divisibility by three. This works very well for small sets of digits but I cannot think of a more scaleable solution. Suppose we are given a million digits, is it possible to make some statement on the size of the number of digits we can use to compose a number as required? I suspect this problem is hitting on deeper complexities than I considered at first.
References
posted at: 13:34 by: Adam Russell | path: /perl | permanent link to this entry