Perl Weekly Challenge 124: Happy Women Day and Tug of War

These are some answers to the Week 124 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 August 8, 2021 at 24:00). This blog post offers some solutions to this challenge, please don’t read on if you intend to complete the challenge on your own.

Task 1: Happy Women Day

Write a script to print the Venus Symbol, international gender symbol for women. Please feel free to use any character.

Example:

    ^^^^^
   ^     ^
  ^       ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
  ^       ^
   ^     ^
    ^^^^^
      ^
      ^
      ^
    ^^^^^
      ^
      ^

Venus Symbol in Raku

The task specification provides little information, so we could just use a variable containing the ASCII art for the Venus symbol and print it out:

my $venus = q:to/END/;
    ^^^^^
   ^     ^
  ^       ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
  ^       ^
   ^     ^
    ^^^^^
      ^
      ^
      ^
    ^^^^^
      ^
      ^
END
say $venus;

Predictably, this script displays the Venus symbol:

$ raku ./venus.raku
    ^^^^^
   ^     ^
  ^       ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
 ^         ^
  ^       ^
   ^     ^
    ^^^^^
      ^
      ^
      ^
    ^^^^^
      ^
      ^

But, of course, that doesn’t really look like a programming challenge. So, we’ll try to do a little bit more coding, with loops, array slices and so on. There are basically five line types. We’ll store those lines in variables and print the variables as appropriate to obtain the right figure. This might look like this:

use v6;

my $bar = "   ^^^^^";
my @pairs = "  ^     ^", " ^       ^", "^         ^";
my $single = "     ^";

say $bar;
say join "\n", @pairs[0, 1, 2, 2, 2, 2, 2, 1, 0];
say $bar;
say $single for 1..3;
say $bar;
say $single for 1..2;

This program displays the following output:

$ raku ./venus2.raku
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

It would probably be simpler to put all five line types in an array, as we did in the Python implementation below, but it works as it is, and, as they say, if it ain’t broke, don’t fix it.

Venus Symbol in Perl

This is essentially the same as the second Raku solution above:

use strict;
use warnings;
use feature "say";

my $bar = "   ^^^^^";
my @pairs = ("  ^     ^", " ^       ^", "^         ^");
my $single = "     ^";

say $bar;
say join "\n", @pairs[0, 1, 2, 2, 2, 2, 2, 1, 0];
say $bar;
say $single for 1..3;
say $bar;
say $single for 1..2;

Output:

$ perl ./venus.pl
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

As for the Raku implementation, it would probably be simpler to put all five line types in an array, as we did in the Python implementation below.

Venus Symbol in Sed

Here we use a sed stream editor one-liner to reformat data passed to it by the shell:

$ echo '
llll11111llll
lll1lllll1lll
ll1lllllll1ll
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
ll1lllllll1ll
lll1lllll1lll
llll11111llll
llllll1llllll
llllll1llllll
llllll1llllll
llll11111llll
llllll1llllll
llllll1llllll
' | sed 's/l/ /g; s/1/x/g'

    xxxxx
   x     x
  x       x
 x         x
 x         x
 x         x
 x         x
 x         x
  x       x
   x     x
    xxxxx
      x
      x
      x
    xxxxx
      x
      x

Oh, yes, I know I probably shouldn’t be doing that, but I couldn’t resist the temptation of introducing a little bit of obfuscation. I guess the trick should be pretty obvious.

Venus Symbol in Awk

This essentially a port to awk of the sed script just above, with the same obfuscation trick:

$ echo '
llll11111llll
lll1lllll1lll
ll1lllllll1ll
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
l1lllllllll1l
ll1lllllll1ll
lll1lllll1lll
llll11111llll
llllll1llllll
llllll1llllll
llllll1llllll
llll11111llll
llllll1llllll
llllll1llllll
' | awk 'gsub("l", " ") gsub("1", "*")'

    *****
   *     *
  *       *
 *         *
 *         *
 *         *
 *         *
 *         *
  *       *
   *     *
    *****
      *
      *
      *
    *****
      *
      *

Venus Symbol in Python

Here we use a solution similar to the Raku and Perl solutions above, except that we store all the line types in a single array, making the code significantly shorter:

lines = ("   ^^^^^", "  ^     ^", " ^       ^", "^         ^", "     ^")
for x in 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4:
    print(lines[x])

Output:

   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Scala

object root extends App {
  var venus = """
OOOO00000OOOO
OOO0OOOOO0OOO
OO0OOOOOOO0OO
O0OOOOOOOOO0O
O0OOOOOOOOO0O
O0OOOOOOOOO0O
O0OOOOOOOOO0O
O0OOOOOOOOO0O
OO0OOOOOOO0OO
OOO0OOOOO0OOO
OOOO00000OOOO
OOOOOO0OOOOOO
OOOOOO0OOOOOO
OOOOOO0OOOOOO
OOOO00000OOOO
OOOOOO0OOOOOO
OOOOOO0OOOOOO"""
  val pattern = "O".r
  venus = pattern replaceAllIn (venus, " ")
  val pattern2 = "0".r
  println(pattern2 replaceAllIn (venus, "+"))
}

Output:

   +++++    
  +     +   
 +       +  
+         + 
+         + 
+         + 
+         + 
+         + 
 +       +  
  +     +   
   +++++    
     +      
     +      
     +      
   +++++    
     +      
     +

Venus Symbol in Bash

We use a heredoc and pipe the input through a sed command to get a more interesting output:

#!/usr/bin/bash

  if true; then
    cat <<- END |  sed 's/v/♀/g'

       vvvvv
      v     v
     v       v
    v         v
    v         v
    v         v
    v         v
    v         v
     v       v
      v     v
       vvvvv
         v
         v
         v
       vvvvv
         v
         v

END
fi

Output:

$ bash venus.bash

       ♀♀♀♀♀
      ♀     ♀
     ♀       ♀
    ♀         ♀
    ♀         ♀
    ♀         ♀
    ♀         ♀
    ♀         ♀
     ♀       ♀
      ♀     ♀
       ♀♀♀♀♀
         ♀
         ♀
         ♀
       ♀♀♀♀♀
         ♀
         ♀

Venus Symbol in Plain Bourne shell

Cheating a little bit, we can display the Venus symbol with a very simple shell one-liner:

$ echo "♀"
♀

Venus Symbol in TCL

A very simple TCL script:

/usr/bin/tclsh

puts "♀"

Output:

$tclsh venus.tcl
♀

Venus Symbol in Java

Starting with Java 15, you can use so-called test blocks (i.e. multiline strings) by declaring the string with """ (three double-quote marks).

public class Main {
    private static String venus = """ 
       ^^^^^
      ^     ^
     ^       ^
    ^         ^
    ^         ^
    ^         ^
    ^         ^
    ^         ^
     ^       ^
      ^     ^
       ^^^^^
         ^
         ^
         ^
       ^^^^^
         ^
         ^
    """;

    public static void main(String args[]) {
        System.out.printf(venus);
    }
}

Output:

   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Lua

In Lua, you can use double square brackets [[ and ]] to define multiline strings.

venus =   [[
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^
]]
print(venus)

Output:

$ lua venus.lua
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in C

Essentially a port to C of the Python program above:

#include <stdio.h>

const char * lines[] = { "   ^^^^^", "  ^     ^", 
                         " ^       ^", "^         ^", 
                         "     ^"};
const int indexes[] = { 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 };

int main() {
    int size = sizeof (indexes) / sizeof (int);
    for (int i = 0; i < size; i++) {
        printf("%s\n", lines[indexes[i]]);
    }
}

Output:

$ ./a.out
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in D

The D programming language syntax is quite similar to C, so this is a port to D of the C program just above:

import std.stdio;

string lines[] = [ "   ^^^^^", "  ^     ^", 
                         " ^       ^", "^         ^", 
                         "     ^"];
int indexes[] = [ 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 ];

int main() {
    for (int i = 0; i < 18; i++) {
        writeln(lines[indexes[i]]);
    }
    return 0;
}

Output:

$ ./venus.amx
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Ruby

Same algorithm as in Python (and some other languages):

lines = ["   ooooo", "  o     o", " o       o", "o         o", "     o"]

for i in [0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4] do
    puts lines[i]
end

Output:

$ ruby venus.rb
   ooooo
  o     o
 o       o
o         o
o         o
o         o
o         o
o         o
 o       o
  o     o
   ooooo
     o
     o
     o
   ooooo
     o
     o

Venus Symbol in Dart

var lines = [ "   ^^^^^", "  ^     ^", 
                         " ^       ^", "^         ^", 
                         "     ^"];
var indexes = [ 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 ];

void main() {
    for (int i = 0; i < 18; i++ ) { 
        print(lines[indexes[i]]); 
    } 
}

Output:

$ dart venus.dart
   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Kotlin

fun main() {
    val lines = arrayOf("   ^^^^^", "  ^     ^", 
        " ^       ^", "^         ^",  "     ^");

    for (i in arrayOf(0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4)) {
        println(lines[i]);
    }
}

Output (Kotlin program compiled to a Java Jar):

$ java -jar venus.jar

   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Go

package main
import "fmt"

func main() {
    lines := [5]string{"   ^^^^^", "  ^     ^", 
        " ^       ^", "^         ^",  "     ^"} 
    indexes := [18]int{0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4}

    for i := 0; i < 18; i++ {
        fmt.Printf("%s\n", lines[indexes[i]])
    }
}

Same output as usual:

   ^^^^^
  ^     ^
 ^       ^
^         ^
^         ^
^         ^
^         ^
^         ^
^         ^
 ^       ^
  ^     ^
   ^^^^^
     ^
     ^
     ^
   ^^^^^
     ^
     ^

Venus Symbol in Nim

Nim uses Python-like code indentation.

let lines = ["   #####", "  #     #", " #       #", "#         #", "     #"]

for i in [ 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 ]: 
  echo lines[i]

Output:

   #####
  #     #
 #       #
#         #
#         #
#         #
#         #
#         #
#         #
 #       #
  #     #
   #####
     #
     #
     #
   #####
     #
     #

Venus Symbol in Julia

Julia arrays are 1-based, i.e. they start at 1, not 0.

lines = ["   ♀♀♀♀♀", "  ♀     ♀", " ♀       ♀", "♀         ♀", "     ♀"]
for i = [1, 2, 3, 4, 4, 4, 4, 4, 3, 2, 1, 5, 5, 5, 1, 5, 5]
    println( lines[i] )
end

Output:

$ julia ./venus.jl
   ♀♀♀♀♀
  ♀     ♀
 ♀       ♀
♀         ♀
♀         ♀
♀         ♀
♀         ♀
♀         ♀
 ♀       ♀
  ♀     ♀
   ♀♀♀♀♀
     ♀
     ♀
     ♀
   ♀♀♀♀♀
     ♀
     ♀

Venus Symbol in Rust

fn main() {
    let line = ["   #####", "  #     #", " #       #", "#         #", "     #"];
    for i in [ 0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 ] {
        println!("{}", line[i]);
    }
}

Output:

   #####
  #     #
 #       #
#         #
#         #
#         #
#         #
#         #
 #       #
  #     #
   #####
     #
     #
     #
   #####
     #
     #

Venus Symbol in Pascal

program venus;
var
    lines: array[0..4] of string = ('   OOOOO', '  O     O', ' O       O', 'O         O', '     O');
    indexes: array[0..16] of integer = (0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4);
    i: integer;
begin
    for i:= 0 to 16 do
    writeln(lines[indexes[i]]);
end.

Output:

   OOOOO
  O     O
 O       O
O         O
O         O
O         O
O         O
O         O
 O       O
  O     O
   OOOOO
     O
     O
     O
   OOOOO
     O
     O

Venus Symbol in Zig

const std = @import("std");
const lines: [5][]const u8 = [_][]const u8{"   QQQQQ", "  Q     Q", " Q       Q", "Q         Q", "     Q"};
const indexes = [_]usize{ 0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4 };
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    for (indexes) | idx | {
        try stdout.print("{s}\n", .{lines[idx]});
    }
}

Output:

./venus
   QQQQQ
  Q     Q
 Q       Q
Q         Q
Q         Q
Q         Q
Q         Q
Q         Q
Q         Q
 Q       Q
  Q     Q
   QQQQQ
     Q
     Q
     Q
   QQQQQ
     Q
     Q

Venus Symbol in Io

Io is a class-less object-oriented language. The object system is based on prototypes. To build an object, you basically clone another object. Io also has strong support to cocurrent programming. To give a gist of its syntax, let me just give an “Hello world” example:

"Hello world" print

What’s going on here is that the code sends the print message to the string "Hello world". Receivers go on the left, and messages go on the right. You just send messages to objects. Another thing to know is that that to read an item of an array, the Io syntax is array at(ind), where ind is the item subscript or index. With this in mind, it is quite easy to understand the venus.io script below:

lines := list("   *****", "  *     *", " *       *", "*         *", "     *", "")
indexes := list(0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 4, 4, 4, 0, 4, 4, 5)
for (i, 0, 17, lines at(indexes at(i)) println)

Output:

$ io venus.io
   *****
  *     *
 *       *
*         *
*         *
*         *
*         *
*         *
 *       *
  *     *
   *****
     *
     *
     *
   *****
     *
     *

Task 2: Tug of War

You are given a set of $n integers (n1, n2, n3, ….).

Write a script to divide the set in two subsets of n/2 sizes each so that the difference of the sum of two subsets is the least. If $n is even then each subset must be of size $n/2 each. In case $n is odd then one subset must be ($n-1)/2 and other must be ($n+1)/2.

Example:

Input:        Set = (10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
Output:  Subset 1 = (30, 40, 60, 70, 80)
         Subset 2 = (10, 20, 50, 90, 100)

Input:        Set = (10, -15, 20, 30, -25, 0, 5, 40, -5)
         Subset 1 = (30, 0, 5, -5)
         Subset 2 = (10, -15, 20, -25, 40)

Tug of War in Raku

We implement a find_smallest_diff subroutine that uses the combinations built-in method to generate all combinations of int $n/2 elements; for each such combination, it uses the (-) set difference operator to find the complementary combination and proceeds to compute the difference between the item sums; finally, it returns the partition having the smallest difference and the value of this difference.

use v6;

sub find_smallest_diff(@in) {
    my $inbag = @in.Bag;
    my $min_val = Inf;
    my $min_seq;
    my $count = @in.elems div 2;
    for @in.combinations: $count -> @c1 {
        my @c2 = ($inbag (-) @c1.Bag).keys;
        if abs(@c2.sum - @c1.sum) < $min_val {
            $min_val = abs(@c2.sum - @c1.sum);
            $min_seq = (@c1, " -- ", @c2);
        }
    }
    return "$min_seq => $min_val";
}

my @tests = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
            [10, -15, 20, 30, -25, 0, 5, 40, -5];
say find_smallest_diff($_) for @tests;

This programs displays the following output:

$ raku ./tug.raku
10 20 50 90 100  --  40 30 80 70 60 => 10
10 -15 30 5  --  20 40 0 -25 -5 => 0

Tug of War in Perl

In Perl, we implement a combine recursive subroutine to find all combinations of a given size, and a sum subroutine to find the sum of all items of an array or list. Except for that, the algorithm to find the smallest difference (in the find_smallest_diff subroutine) is essentially the same as in Raku.

use strict;
use warnings;
use feature "say";

my @comb;

sub combine {
    my $count = shift;
    my @out = @{$_[0]};
    my @in  = @{$_[1]};
    if ($count == 0) {
        push @comb, [@out];
        return;
    }
    for my $i (0..$#in) {
        combine ($count - 1, [@out, $in[$i]], [@in[0..$i -1], @in[$i+1..$#in]]);
    }
}

sub sum {
    my $sum = 0;
    $sum += $_ for @_;
    return $sum;
}

sub find_smallest_diff {
    my @in = @{$_[0]};
    my $min_val;
    my $min_seq;
    for my $c (@comb) {
        my @c1 = @$c;
        my %seen = map { $_ => 1 } @c1;
        my @c2 = grep  { not exists $seen{$_}} @in;
        my $diff = abs(sum(@c2) - sum(@c1));
        $min_val = $diff unless defined $min_val;
        if ($diff < $min_val) {
            $min_val = $diff;
            $min_seq = ("@c1 -- @c2 ");
        }
    }
    return "$min_seq => $min_val";
}

for my $test ( [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
               [10, -15, 20, 30, -25, 0, 5, 40, -5] ) {
    my $count = int (@$test / 2);
    combine $count, [], $test;
    say find_smallest_diff $test;
}

This program displays the following output:

$ perl tug_of_war.pl
10 20 50 90 100 -- 30 40 60 70 80  => 10
10 -15 30 5 -- 20 -25 0 40 -5  => 0

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 August 15, 2021. 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.