aboutsummaryrefslogtreecommitdiff
path: root/challenge-097/perlboy1967/perl/ch-2.pl
blob: a3a35ac4c5a4281d45a887ad7b6fdfa940fbfb4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/perl

# Perl Weekly Challenge - 097
# - https://perlweeklychallenge.org/blog/perl-weekly-challenge-097/
#
# Task 2 - Binary Substrings
#
# Author: Niels 'PerlBoy' van Dijke

use v5.16;
use strict;
use warnings;

use List::Util qw(sum);
use Data::Printer;

# Unbuffered STDOUT
$|++;

my $S = shift(@ARGV) // 3;
my $B = shift(@ARGV) // '101100101';

die "S must be bigger than 1"
  unless ($S > 1);
die "B must be string with only '0' and '1'"
  unless ($B =~ m#^[0-1]+$#);
die "length(B) must be N times S"
  unless (length($B) % $S == 0);

my ($C, $F, @F) = binarySubstrings($B, $S);

printf "Input: \$B = '%s', \$S = %d\n", $B, $S;
printf "Output: %d\n\n", $F;
printf "Binary Substrings and flips needed for common '%s':\n\t%s\n", 
       $C, join("\t", map { "$_\n" } @F);

sub binarySubstrings {
  my ($b, $s) = @_;

  my ($common, $f, @f);

  # Create list of 'b' length substrings / chunks
  my @bitStringChunks = unpack("(A$s)*", $b);

  # Create integer values of 'b' length substrings
  my @intValues = map { oct("0b$_") } @bitStringChunks;

  # Count 0 and 1 bits to find the most frequent bit value
  my $bitPosFreq;
  foreach my $bitString (@bitStringChunks) {
    my $j = 0;
    map { $bitPosFreq->[$j++][$_]++ } reverse split(//, $bitString);
  }
  my @mostBitFreq;
  foreach my $j (0 .. $s - 1) {
    # The challenge didn't provide if we should be in favor of
    # having preference for '0' or '1'. I choose '1'.
    push(@mostBitFreq, ($bitPosFreq->[$j][0] // 0) > ($bitPosFreq->[$j][1] // 0) ?
                       0 : 1);
  }

  my $bestValue = oct(sprintf('0b%s', join('', reverse @mostBitFreq)));
 
  for (my $i = 0; $i < scalar(@bitStringChunks); $i++) {
    my $bitFlips = sum(split(//, sprintf('%b', $intValues[$i] ^ $bestValue)));

    push(@f, sprintf(qq("%s": %d flip(s)), $bitStringChunks[$i], $bitFlips));

    $f += $bitFlips;
  }

  return (sprintf("%0${s}b", $bestValue), $f, @f);
}