aboutsummaryrefslogtreecommitdiff
path: root/challenge-138/duncan-c-white/perl/tabulate-split-sums
blob: 529934c589044e985ca3de368a3a372ce097a584 (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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/perl
# 
# TASK #2 - Split Number
# 
# Variation that Tabulates the first N perfect squares and whether or
# not they have a split whose sum is sqrt(that square).
# 
# Example 1
# 
# 	Input: $n = 81
# 	Output: 1
# 
# 	Since, sqrt(81) = 8 + 1
# 
# Example 2
# 
# 	Input: $n = 9801
# 	Output: 1
# 
# 	Since, sqrt(9801) = 98 + 0 + 1
# 
# Example 3
# 
# 	Input: $n = 36
# 	Output: 0
# 
# 	Since, sqrt(36) != 3 + 6
# 
# MY NOTES: Sounds pretty easy.  The only tricky part is identifying all
# distinct "splits" of the number.  Is there a "binary counting" method,
# where bit i being true means: split the number between digit i and i+1?
# 

use strict;
use warnings;
use feature 'say';
use Function::Parameters;
use Getopt::Long;
use Data::Dumper;
use List::Util qw(sum);

my $debug = 0;

die "Usage: split-numbers [-d|--debug] MAXN\n"
	unless GetOptions( "debug"=>\$debug ) && @ARGV==1;
my $maxsq = shift @ARGV;
#
# my @pieces = BinarySplit( $str, $count );
#	Split $str using the binary count $count
#	and return the list of split pieces.  Each bit of
#	the count $count determines whether to split the
#	string at the corresponding letter - or
#	equivalently, whether to insert a ',' before the letter.
#
fun BinarySplit( $str, $count )
{
	$str =~ s/^(.)//;		# always add the first letter
	my $result = $1;

	while( $str =~ s/^(.)// )
	{
		my $letter = $1;
		$result .= ',' if $count&1;
		$result .= $letter;
		$count >>= 1;
	}
	return split(/,/,$result);
}


#die Dumper BinarySplit( "hello", 0b100 );


#
# my $issplit = SplitSum( $n, $sum );
#	Return 1 iff the digits of $n can be split at
#	any position set of positions st the sum of those
#	split values is $sum.  Return 0 otherwise.
#	For example SplitSum(81,9) is true as 9 = 8 + 1
#
fun SplitSum( $n, $sum )
{
	my $bits = length($n)-1;
	my $twopower = 2**$bits;
	say "debug: twopower=$twopower" if $debug;
	# ignore i=0, that doesn't split $n at all, and sum($n)==$n
	# which is always > $sqrt($n) so can't be an answer
	for( my $i=1; $i<$twopower; $i++ )
	{
		my @pieces = BinarySplit( $n, $i );
		my $actualsum = sum(@pieces);
		say "debug: i=$i, want sum=$sum, ".join(',',@pieces).
		    ", got sum=$actualsum, want $sum" if $debug;
		return 1 if $actualsum == $sum;
	}
	return 0;
}


foreach my $sq (1..$maxsq)
{
	my $n = $sq*$sq;
	my $issplit = SplitSum( $n, $sq );
	say "$n - $sq" if $issplit;
}