# Perl Weekly Challenge 97.

My solutions (task 1 and task 2) to the The Weekly Challenge - 097.

You are given string \$S containing alphabets A..Z only and a number \$N.

Write a script to encrypt the given string \$S using Caesar Cipher with left shift of size \$N.

Example

``````Input: \$S = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", \$N = 3
Output: "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD"

Plain:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher:   XYZABCDEFGHIJKLMNOPQRSTUVW

Plaintext:  THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Ciphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
``````

I obtain the arguments from `@ARGV`; the first argument is the string to encode and the second is the displacement which must be numerical.

``````# Perl weekly challenge 097
#
use warnings;
use strict;
use v5.12;
use Scalar::Util qw(looks_like_number);

sub usage {
say <<END;
Usage:
./ch-1.pl S N
to encode string S using Casear's cipher with displacement N
END
exit 1;
}

usage() unless @ARGV==2;
my \$string = uc shift @ARGV; # Allow lower case but convert to uppercase
my \$displacement=shift @ARGV;
usage() unless looks_like_number(\$displacement);
``````

I build a translation table from the set of allowed characters. Note the sign of the `\$displacement`.

``````my @plain="A".."Z";
my %translation_of=map {(\$plain[\$_]=>\$plain[(\$_-\$displacement)%@plain])} 0..@plain-1;
``````

Finally, I apply the translation table to print the results. I keep untranslated characters unmodified, so that punctuation and spaces go through.

``````my \$translated=join '', map {\$translation_of{\$_}//\$_} split '', \$string;
say "Input:  \"\$string\" \$displacement\nOutput: \"\$translated\"\n";
say "Plain:\t", @plain, "\n",
"Cipher:\t", join '', @translation_of{sort keys %translation_of}, "\n",
"Displacement:\t\$displacement\n",
"Plaintext:\t\$string\n",
"Ciphertext:\t\$translated",
``````

Results:

``````./ch-1.pl "The quick brown fox jumps over the lazy dog" 3
``````

Results:

``````Input: "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" 3
Output: "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD"

Plain:	ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher:	XYZABCDEFGHIJKLMNOPQRSTUVW
Displacement:	3
Plaintext:	THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Ciphertext:	QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
``````

Check that the degenerate case works.

``````./ch-1.pl "" 3
``````

Results:

``````Input:  "" 3
Output: ""

Plain:	ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher:	XYZABCDEFGHIJKLMNOPQRSTUVW
Displacement:	3
Plaintext:
Ciphertext:
``````

Check that negative displacements work.

``````./ch-1.pl "The quick brown fox jumps over the lazy dog" -23
``````

Results:

``````Input:  "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" -23
Output: "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD"

Plain:	ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher:	XYZABCDEFGHIJKLMNOPQRSTUVW
Displacement:	-23
Plaintext:	THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Ciphertext:	QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
``````

You are given a binary string \$B and an integer \$S.

Write a script to split the binary string \$B of size \$S and then find the minimum number of flips required to make it all the same.

Example 1:

``````Input: \$B = “101100101”, \$S = 3
Output: 1

Binary Substrings:
"101": 0 flip
"100": 1 flip to make it "101"
"101": 0 flip
``````

Example 2:

``````Input \$B = “10110111”, \$S = 4
Output: 2

Binary Substrings:
"1011": 0 flip
"0111": 2 flips to make it "1011"
``````

Receive the two arguments in `@ARGV`.

``````# Perl weekly challenge 097
#
use warnings;
use strict;
use v5.12;

use List::Util qw(all reduce);
use Scalar::Util qw(looks_like_number);
use Memoize; # Just for fun
# Check arguments
usage() unless @ARGV==2;
my \$string = shift @ARGV;
my \$length=shift @ARGV;
usage() unless looks_like_number(\$length) && \$length>=1;
``````

Check that the string contains only 1’s and 0’s.

``````my %binary=("0"=>1,"1"=>1); # Binary characters
usage() unless all {\$binary{\$_}} split '', \$string;
``````

Split into substrings using split and keeping only substrings of the correct length, i.e., throwaway the last substring if incomplete.

``````my @substrings=grep {length \$_ == \$length} split /(\d{\$length})/, \$string;
``````

Choose the best target substring to minimize flips.

``````memoize('cost'); # Don't duplicate effort
my @total_costs=map {total_cost(\$substrings[\$_], @substrings)} 0..@substrings-1;
my \$best_index=reduce {\$total_costs[\$a]<=\$total_costs[\$b]?\$a:\$b} 0..@total_costs-1;
my \$target=\$substrings[\$best_index];
my @costs=map {cost(\$target, \$_)} @substrings;
``````

Finally, print results.

``````say "Input:\t\"\$string\"\t\$length\n",
"Output:\t\$total_costs[\$best_index]\n\n",
"Binary substrings\n",
map {"\"\$substrings[\$_]\": \$costs[\$_] flips to convert it to \"\$target\"\n"}
0..@substrings-1;
``````

Calculate the cost to flip a set of strings to the first one

``````sub total_cost {
my \$first=shift;
my \$cost=0;
\$cost+=cost(\$first,\$_) foreach @_;
return \$cost;
}
sub cost {
my @first=split '',shift;
my @second=split '',shift;
my \$cost=0;
\$cost += \$first[\$_]!=\$second[\$_]?1:0 foreach 0..@first-1;
return \$cost;
}
``````

Results: Finally, the usage message.

``````sub usage {
say <<END;
Usage:
./ch-1.pl B S
to split binary string B into substrings of size S>=1
and then enumerate changes to make them the same
END
exit 1;
}
``````

Example 1:

``````./ch-2.pl 101100101 3
``````

Results:

``````Input:	"101100101"	3
Output:	1

Binary substrings
"101": 0 flips to convert it to "101"
"100": 1 flips to convert it to "101"
"101": 0 flips to convert it to "101"
``````

Example 2:

``````./ch-2.pl 10110111 4
``````

Results:

``````Input:	"10110111"	4
Output:	2

Binary substrings
"1011": 0 flips to convert it to "1011"
"0111": 2 flips to convert it to "1011"
``````

Another couple of examples to check if it actually minimizes flips.

``````./ch-2.pl 0001101111 2
./ch-2.pl 0001101100 2
``````

Results:

``````Input:	"0001101111"	2
Output:	4

Binary substrings
"00": 2 flips to convert it to "11"
"01": 1 flips to convert it to "11"
"10": 1 flips to convert it to "11"
"11": 0 flips to convert it to "11"
"11": 0 flips to convert it to "11"

Input:	"0001101100"	2
Output:	4

Binary substrings
"00": 0 flips to convert it to "00"
"01": 1 flips to convert it to "00"
"10": 1 flips to convert it to "00"
"11": 2 flips to convert it to "00"
"00": 0 flips to convert it to "00"
``````
Written on January 25, 2021