A Simple Binary Tree in Perl

This Binary Tree implementation uses Class::Struct and only defines find() and insert() operations, along with a simple print function for debugging purposes.

EDIT: The code was given some minor style updates based on Mark Gardner's feedback in the Perl Computer Science Discord Server. Please do join if you are interested in exploring Computer Science topics via a Perl lens!

package Tree129{
    use boolean;  
    use Class::Struct; 

    package Node{
        use boolean;  
        use Class::Struct; 
        struct(
            value => q/$/,
            left_child => q/Node/,
            right_child => q/Node/
        );  
        true; 
    }  
   
    struct(
        root => q/Node/
    );   

    sub print_tree{
        my($self, $node) = @_; 
        $node = $self->root() if !$node;
        if($node->left_child()){
            print $node->value() . "->" . $node->left_child()->value() . "\n";  
        } 
        if($node->right_child()){
            print $node->value() . "->" . $node->right_child()->value() . "\n";  
        } 
        else{
            print $node->value() . "\n";   
        } 
        $self->print_tree($node->left_child()) if $node->left_child;   
        $self->print_tree($node->right_child()) if $node->right_child;   
    }  

    sub find{
        my($self, $value, $node) = @_; 
        return undef if !$self->root(); 
        $node = $self->root() if !$node;
        return $node if $node->value() == $value; 
        if($value <= $node->value()){
            return $node if !$node->left_child();
            $self->find($value, $node->left_child()); 
        }  
        elsif($value >= $node->value()){
            return $node if !$node->right_child();
            $self->find($value, $node->right_child()); 
        }  
    }  

    sub insert{
        my($self, $value) = @_;  
        my $node = $self->find($value);  
        if(!$node){      # new root  
            $self->root(new Node(value => $value));  
        }   
        elsif($value < $node->value()){
            $node->left_child(new Node(value => $value));   
        } 
        elsif($value > $node->value()){
            $node->right_child(new Node(value => $value));   
        } 
        else{
            print "$value is already in the tree\n"; 
        }   
    }  
    true; 
}

package main{
    my $tree = new Tree129(); 
    $tree->insert(6); 
    $tree->insert(4); 
    $tree->insert(8); 
    $tree->insert(3); 
    $tree->insert(5); 
    $tree->insert(7); 
    $tree->insert(9);
    $tree->print_tree(); 
} 

The Weekly Challenge 127: Conflict Intervals (C++ Solutions)

Part 2 of The Weekly Challenge 127: You are given two sets with unique numbers. Write a script to figure out if they are disjoint.

#include <vector>
#include <iostream>
#include <algorithm>
/*
 * You are given a list of intervals. Write a script
 * to determine conflicts between the intervals.
*/
class ConflictIntervals{
    public:
        std::vector<std::vector<int>> conflicts(std::vector<std::vector<int>>);
};

std::vector<std::vector<int>> ConflictIntervals::conflicts(std::vector<std::vector<int>> v){
    std::vector<std::vector<int>> conflicts;
    std::sort(v.begin(), v.end(),
          [](const std::vector<int> &a, const std::vector<int> &b) {
              return a[1] < b[1];
          }
    );
    for(int i = v.size() - 1; i >= 0; i--){
        for (int j = 0; j < i; j++){
            if(v[i][0] >= v[j][0] && v[i][0] <= v[j][1]){
                conflicts.push_back(v[i]);
                break;
            }
        }
    }

    return conflicts;
}

int main(int argc, char** argv){
    std::vector<std::vector<int>> intervals = {{1, 4}, {3, 5}, {6, 8}, {12, 13}, {3, 20}};
    ConflictIntervals ci;
    std::vector<std::vector<int>> conflicts = ci.conflicts(intervals);
    for(int i=0; i < conflicts.size(); i++){
        std::cout << "[" << conflicts[i][0] << ", " << conflicts[i][1] <<  "]" << " ";
    }
    std::cout << std::endl;
    intervals = {{3, 4}, {5, 7}, {6, 9}, {10, 12}, {13, 15}};
    conflicts = ci.conflicts(intervals);
    for(int i=0; i < conflicts.size(); i++){
        std::cout << "[" << conflicts[i][0] << ", " << conflicts[i][1] <<  "]" << " ";
    }
    std::cout << std::endl;
}


Example output:
$ g++ -o cxx/ch-2 cxx/ch-2.cxx
$ cxx/ch-2
[3, 20] [3, 5]
[6, 9]

The Weekly Challenge 127: Disjoint Lists (C++ Solutions)

Part 1 of The Weekly Challenge 127: You are given two sets with unique numbers. Write a script to figure out if they are disjoint.

#include <vector>
#include <iostream>
#include <algorithm>
/*
 * You are given two sets with unique numbers.
 * Write a script to figure out if they are disjoint.
*/
class DisjointSets{
    public:
        bool disjoint(std::vector<int>, std::vector<int>);
};

bool DisjointSets::disjoint(std::vector<int> v0, std::vector<int> v1){
    bool found = false;
    std::for_each(v0.begin(), v0.end(),
        [&v1, &found](int &n){
            if(std::find(v1.begin(), v1.end(), n) != v1.end())
                found = true;
        }
    );
    return !found;
}

int main(int argc, char** argv){
    std::vector<int> v0 {1, 2, 5, 3, 4};
    std::vector<int> v1 {4, 6, 7, 8, 9};
    DisjointSets ds;
    std::cout << ds.disjoint(v0, v1) << std::endl;
    std::vector<int> v2 {1, 3, 5, 7, 9};
    std::vector<int> v3 {0, 2, 4, 6, 8};
    std::cout << ds.disjoint(v2, v3) << std::endl;
}


Example output:
$ g++ -o cxx/ch-1 cxx/ch-1.cxx
$ cxx/ch-1
0
1

The Weekly Challenge 126: Minesweeper Game (C++ Solutions)

Part 2 of The Weekly Challenge 126: You are given a rectangle with points marked with either x or *. Please consider the x as a land mine. Write a script to print a rectangle with numbers and x as in the Minesweeper game.

#include <cstdlib>
#include <iostream>

/*
 * You are given a rectangle with points
 * marked with either x or *. Consider
 * the x as a land mine. Write a script
 * to print a rectangle with numbers
 * and x as in the Minesweeper game.
*/   

class MinesweeperGame{
    private:
        char** initialize_grid(int, int);   
    public:
        void make_print_grid(int, int);   
};     

char** MinesweeperGame::initialize_grid(int m, int n){
    char** grid = new char*[m];  
    for(int i = 0; i < m; i++){
        grid[i] = new char[n]; 
        for(int j = 0; j < n; j++){
            grid[i][j] = '*'; 
            if(rand() / double(RAND_MAX) < 1 / 3.0)
                grid[i][j] = 'x'; 
        } 
    } 
    return grid;
}

void MinesweeperGame::make_print_grid(int m, int n){
    char** grid = initialize_grid(m, n); 
    std::cout << "Input:" << std::endl; 
    for(int i = 0; i < m; i++){
        std::cout << "\t";
        for(int j = 0; j < n; j++){
            std::cout << grid[i][j] << " "; 
        } 
        std::cout << std::endl; 
    } 
    for(int i = 0; i < m; i++){
        for(int j = 0; j < n; j++){
            if(grid[i][j] == '*'){
                int mine_count = 0;
                if(i >= 1 && j >= 1 && grid[i - 1][j - 1] == 'x')
                    mine_count++; 
                if(i >= 1 && grid[i - 1][j] == 'x')
                    mine_count++; 
                if(i >= 1 && j < n - 1 && grid[i - 1][j + 1] == 'x')
                    mine_count++; 
                if(j >= 1 && grid[i][j - 1] == 'x')
                    mine_count++; 
                if(j < n - 1 && grid[i][j + 1] == 'x')
                    mine_count++; 
                if(i < m - 1 && j >= 1 && grid[i + 1][j - 1] == 'x')
                    mine_count++; 
                if(i < m - 1 && grid[i + 1][j] == 'x')
                    mine_count++; 
                if(i < m - 1 && j < n - 1 && grid[i + 1][j + 1] == 'x')
                    mine_count++; 
                char temp[1];
                sprintf(temp, "%d", mine_count); 
                grid[i][j] = *temp;
            } 
        } 
    } 
    std::cout << "Output:" << std::endl; 
    for(int i = 0; i < m; i++){
        std::cout << "\t";
        for(int j = 0; j < n; j++){
            std::cout << grid[i][j] << " "; 
        } 
        std::cout << std::endl; 
    } 
}

int main(int argc, char** argv){
    srand(time(NULL)); 
    int m = atoi(argv[1]); 
    int n = atoi(argv[2]); 
    MinesweeperGame mn;
    mn.make_print_grid(m, n);
}


Example output:
$ g++ -o cxx/ch-2 cxx/ch-2.cxx 
$ ./cxx/ch-2 5 10
Input:
        * * * * * * x * * * 
        * x * x * * * x x x 
        x * x x * * x * * x 
        x * x * * * x * * x 
        x * x * * * x * * * 
Output:
        1 1 2 1 1 1 x 3 3 2 
        2 x 4 x 2 2 3 x x x 
        x 5 x x 2 2 x 4 5 x 
        x 6 x 4 1 3 x 3 2 x 
        x 4 x 2 0 2 x 2 1 1 

The Weekly Challenge 126: Count Numbers (C++ Solutions)

Part 1 of The Weekly Challenge 126: You are given a positive integer $N. Write a script to print count of numbers from 1 to $N that don’t contain digit 1.

#include <iostream>

/* 
 * You are given a positive integer n.
 * Write a script to print the count of 
 * numbers from 1 to n that don't contain digit the 1. 
*/

class CountNumbers{
    private:
        int has_1(int);   
        int count_with_1(int);
    public:
        int count_without_1(int);
};     

int CountNumbers::has_1(int n){
    std::string s = std::to_string(n);  
    const char* c = s.c_str();
    while(*c != '\0'){
        if(*c == '1')
            return 1;
        c++;
    } 
    return 0;
}

int CountNumbers::count_with_1(int n){
    int count = 0;
    for(int i = 1; i <= n; i++)
        count += has_1(i);  
    return count; 
}

int CountNumbers::count_without_1(int n){
    return n - count_with_1(n);  
}

int main(int argc, char** argv){
    CountNumbers cn;
    int n;
    n = 15; 
    std::cout << cn.count_without_1(n) << std::endl;
    n = 25; 
    std::cout << cn.count_without_1(n) << std::endl;
}


Example output:
$ g++ -o cxx/ch-1 cxx/ch-1.cxx 
$ ./cxx/ch-1              
8
13

A Very BareBones Discord Chat Bot in Perl

This is a minimal working Discord Chat Bot written in Perl.

use strict;
use warnings;
##
# Mr. Plow
##
use AnyEvent::Discord::Client;

use constant TOKEN   => "DISCORD_SERVER_TOKEN";
        
my %commands_hidden; 
my $bot = new AnyEvent::Discord::Client(
    token => TOKEN,
    commands => {
        "commands" => sub{
            my ($bot, $args, $msg, $channel, $guild) = @_;
            $bot->say($channel->{id}, join("   ", map {"`$_`"} sort grep {!$commands_hidden{$_}} keys %{$bot->commands}));
        },
    },
    process_all => sub{
        my ($bot, $args, $msg, $channel, $guild) = @_;
        if($guild){
            print "$bot, $args, $msg, $channel, $guild\n";
        }
        else{
            #$bot->say($channel->{id}, $msg->{content});
        }
    }
);
 
$bot->add_commands(
    "who_are_you" => sub{
        my ($bot, $args, $msg, $channel, $guild) = @_;
        $bot->say($channel->{id}, "Hello, $msg->{author}{username}!\nMr. Plow, that's my name. That name again is Mr. Plow.https://www.youtube.com/watch?v=QacpBRPonzM&feature=youtu.be&t=68");
    },
    "ping" => sub{
        my ($bot, $args, $msg, $channel, $guild) = @_;
        $bot->say($channel->{id}, "pong");
    },
);
$bot->connect();
AnyEvent->condvar->recv;

Dockerfile for SWI-Prolog + JPL

I ordinarily use Alpine Linux based containers but in this case could not since there do not appear to be any .apk files available for SWI-Prolog. Here is the Dockerfile used to build a Debian based container for deploying a Spring Boot application which uses JPL.

##
# Set up Debian Linux based container with necessary requirements.
##
FROM debian
RUN apt-get -y update
RUN apt-get -y install swi-prolog
RUN apt-get -y install openjdk-11-jdk
RUN apt-get -y install swi-prolog-java

##
# Configure our application.
#
WORKDIR /app
ADD ./target/application-0.0.1-SNAPSHOT.jar .
COPY . .

ENV LD_LIBRARY_PATH=/usr/lib/swi-prolog/lib/x86_64-linux/
ENV CLASSPATH=/usr/lib/swi-prolog/lib/jpl.jar
ENV LD_PRELOAD=/usr/lib/libswipl.so

##
# Execute
##
USER 1001
EXPOSE 8080
CMD ["java", "-jar", "application-0.0.1-SNAPSHOT.jar"]

The Weekly Challenge 123: Square Points (C++ Solutions)

Part 2 of The Weekly Challenge 123 is to determine if a given set of four points determine a square.

#include <vector>
#include <utility>
#include <iostream>
#include <algorithm>

class SquarePoints{
    private:
        std::vector<std::pair<int, int>> sort_points_x(std::vector<std::pair<int, int>>);  
        std::vector<std::pair<int, int>> sort_points_y(std::vector<std::pair<int, int>>);   
    public:
        std::vector<std::pair<int, int>> sort_points(std::vector<std::pair<int, int>>); 
        bool is_square(std::vector<std::pair<int, int>>); 
};

int dot_product(std::pair<int, int> a, std::pair<int, int> b){
    int product = 0;
    product = product + a.first * b.first;
    product = product + a.second * b.second;
    return product;
}

bool point_x_compare(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.first < b.first;   
} 

bool point_y_compare(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.second < b.second;   
} 

std::vector<std::pair<int, int>> SquarePoints::sort_points_x(std::vector<std::pair<int, int>> points){
    sort(points.begin(), points.end(), point_x_compare); 
    return points; 
} 

std::vector<std::pair<int, int>> SquarePoints::sort_points_y(std::vector<std::pair<int, int>> points){
    sort(points.begin(), points.end(), point_y_compare); 
    return points; 
} 
        
bool SquarePoints::is_square(std::vector<std::pair<int, int>> points){
    std::vector<int> x_s;
    std::vector<int> y_s;
    for(int i = 0; i < points.size() ; i++){
        if(!(std::find(x_s.begin(), x_s.end(), points[i].first) != x_s.end())) {
            x_s.push_back(points[i].first);  
        }
        if(!(std::find(y_s.begin(), y_s.end(), points[i].first) != y_s.end())) {
            y_s.push_back(points[i].first);  
        }
    }
    /* if only 2 each of x and y then we have a level square */
    if(x_s.size() == 2 && y_s.size() == 2)
        return true;
    /* sort points and compute side lengths */
    std::vector<std::pair<int, int>> points_by_x = this->sort_points_x(points);  
    std::vector<std::pair<int, int>> points_by_y = this->sort_points_y(points);  
    std::pair<int, int> s = points_by_y[points_by_y.size() - 1];  
    std::pair<int, int> t = points_by_x[points_by_x.size() - 1];  
    std::pair<int, int> u = points_by_y[0];  
    std::pair<int, int> v = points_by_x[0];  
    if(s.first + u.first != t.first + v.first)
        return false; 
    if(s.second + u.second != t.second + v.second)
        return false; 
    if(s.second - u.second != t.first - v.first)
        return false; 
    /* compute angles */
    std::pair<int, int> dv_st = std::make_pair(s.first - t.first, s.second - t.second);  
    std::pair<int, int> dv_tu = std::make_pair(t.first - u.first, t.second - u.second);  
    std::pair<int, int> dv_uv = std::make_pair(u.first - v.first, u.second - v.second);  
    std::pair<int, int> dv_vs = std::make_pair(v.first - s.first, v.second - s.second);  
    if(dot_product(dv_st, dv_tu) != 0)
        return false;   
    if(dot_product(dv_tu, dv_uv) != 0)
        return false;   
    if(dot_product(dv_uv, dv_vs) != 0)
        return false;   
    return true;  
}  

int main(int argc, char** argv){
    SquarePoints sp; 
    std::vector<std::pair<int, int>> points;
    points.push_back(std::make_pair(10, 20));
    points.push_back(std::make_pair(20, 20));
    points.push_back(std::make_pair(20, 10));
    points.push_back(std::make_pair(10, 10));
    std::cout << sp.is_square(points) << std::endl;    
    points.clear(); 
    points.push_back(std::make_pair(12, 24));
    points.push_back(std::make_pair(16, 10));
    points.push_back(std::make_pair(20, 12));
    points.push_back(std::make_pair(18, 16));
    std::cout << sp.is_square(points) << std::endl;    
    points.clear(); 
    points.push_back(std::make_pair(-3, 1));
    points.push_back(std::make_pair(4, 2));
    points.push_back(std::make_pair(9, -3));
    points.push_back(std::make_pair(2, -4));
    std::cout << sp.is_square(points) << std::endl;    
    points.clear(); 
    points.push_back(std::make_pair(0, 0));
    points.push_back(std::make_pair(2, 1));
    points.push_back(std::make_pair(3, -1));
    points.push_back(std::make_pair(1, -2));
    std::cout << sp.is_square(points) << std::endl;    
}  


Example Output:

$ g++ cxx/ch-2.cxx 
$ ./a.out 
1
0
0
1

The Weekly Challenge 123: Ugly Numbers (C++ Solutions)

Part 1 of The Weekly Challenge 123 is to identify Ugly Numbers.

You are given an integer n. Write a script to find the nth Ugly Number.


#include <vector>
#include <iostream>

/* 
 * You are given an integer n >= 1.
 * Write a script to find the nth Ugly Number.
*/

class Ugly{
    private:
        std::vector<int> factor(int);   
        bool is_ugly(int);
    public:
        int nth_ugly(int); 
};     

std::vector<int> Ugly::factor(int n){
    std::vector<int> factors;  
    for (int i=2; i*i<=n; i++){
        if (n%i==0){
            if(i*i!=n){  
                factors.push_back(i);
                factors.push_back(n/i);
            }
            else
                factors.push_back(i);
        }
    }
    return factors;  
}

bool Ugly::is_ugly(int n){
    std::vector<int> factors = this->factor(n);
    for(int i = 0; i < factors.size(); i++){
        if(factors[i] != 2 && factors[i] != 3 && factors[i] != 5)
            return false; 
    }    
    return true;   
} 

int Ugly::nth_ugly(int n){
    int ugly_count = 1; 
    int i = 2; 
    if(n == 1)
        return 1; 
    do{
        if(is_ugly(i))
            ugly_count++;  
        i++;  
    }while(ugly_count != n); 
    return i; 
} 

int main(int argc, char** argv){
    Ugly ugly;
    int u = ugly.nth_ugly(10);   
    std::cout << u << std::endl;
}


Example output:

$ g++ cxx/ch-1.cxx 
$ ./a.out 
12

/r/prolog Coding Challenge #27

Developed and tested with SWI-Prolog 8.2.3.

/*
* Prints the Lyrics to The Twelve Days of Christmas.
* Lyrics from https://www.lyricsmode.com/lyrics/c/christmas_carols/the_twelve_days_of_christmas.html
*/

day(1, first).
day(2, second).
day(3, third).
day(4, fourth).
day(5, fifth).
day(6, sixth).
day(7, seventh).
day(8, eighth).
day(9, ninth).
day(10, tenth).
day(11, eleventh).
day(12, twelfth).

truelove('My true love gave to me:').

items(1, 'A partridge in a pear tree.').
items(2, 'Two turtle doves and').
items(3, 'Three french hens').
items(4, 'Four calling birds').
items(5, 'Five golden rings').
items(6, 'Six geese a-laying').
items(7, 'Seven swans a-swimming').
items(8, 'Eight maids a-milking').
items(9, 'Nine ladies dancing').
items(10, 'Ten lords a-leaping').
items(11, 'Eleven pipers piping').
items(12, 'Twelve drummers drumming').

write_accum([]):-
    nl.
write_accum([H|T]):-
    write(H), nl,
    write_accum(T).

the_twelve_days_of_christmas:-
    the_twelve_days_of_christmas(1, []).
the_twelve_days_of_christmas(13, _).    
the_twelve_days_of_christmas(Day, ItemsAccum):-
    day(Day, D),
    truelove(TL),
    items(Day, Items),
    format("On the ~s day of Christmas~n~s~n~s~n", [D, TL, Items]),
    NextDay is Day + 1,
    write_accum(ItemsAccum),
    the_twelve_days_of_christmas(NextDay, [Items|ItemsAccum]).