Perl Weekly Challenge 286: Self Spammer

These are some answers to the Week 286, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on September 15, 2024, at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Self Spammer

Write a program which outputs one word of its own script / source code at random. A word is anything between whitespace, including symbols.

Example 1

If the source code contains a line such as: 'open my $fh, "<", "ch-1.pl" or die;'
then the program would output each of the words { open, my, $fh,, "<",, "ch-1.pl", or, die; }
(along with other words in the source) with some positive probability.

Example 2

Technically 'print(" hello ");' is *not* an example program, because it does not
assign positive probability to the other two words in the script.
It will never display print(" or ");

Example 3

An empty script is one trivial solution, and here is another:
echo "42" > ch-1.pl && perl -p -e '' ch-1.pl

I do not understand the comment of Example 2. Given the definition provided for a word, the print(" hello "); program is made of three words which could equally be selected by a random process.

Self Spammer in Raku

First, we can use the $?FILE compile-time variable to access to the name of the file being run by the Raku compiler. Then we use the IO method to access the content of the file, and the words method to split the input file into words. Finally, we use the pick method to retrieve a single random item from the word list.

So the program might be a simple one-liner: say $?FILE.IO.words.pick;.

The only problem with this is that we have only two words, which makes the output not very interesting. So, I added one comment line to get a larger variety of words for the output.

# this is a comment line aimed at getting more words
say $?FILE.IO.words.pick;

This program ran five times and displayed the following output:

$ ./raku self-spammer.raku
is

$ raku ./self-spammer.raku
this

$ raku ./self-spammer.raku
say

$ raku ./self-spammer.raku
comment

$ raku ./self-spammer.raku
$?FILE.IO.words.pick;

Self Spammer in Perl

In Perl, we will read the program file (from the __FILE__ special variable) line by line, split each such line on white spaces et store the words into the @words array. Finally, we use the rand function to pick a single random item from the word list. Note that I had to strip leading spaces from each line to prevent "empty" words to be added to the word list.

use strict;
use warnings;
use feature 'say';

my @words;
open my $FH, '<', __FILE__ or die "Error opening file";
while (<$FH>) {
    s/^\s+//g;    # remove leading spaces from $_ if any
    push @words, split /\s+/, $_;
}
close $FH;
say $words[int(rand($#words + 1))];

This program ran six times and displayed the following output:

$ perl ./self-spammer.pl
=~

$ perl ./self-spammer.pl
use

$ perl ./self-spammer.pl
s/^\s+//g;

$ perl ./self-spammer.pl
"Error

$ perl ./self-spammer.pl
+

$ perl ./self-spammer.pl
opening

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on September 22, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.