-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerator.rb
More file actions
167 lines (126 loc) · 4.12 KB
/
generator.rb
File metadata and controls
167 lines (126 loc) · 4.12 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
module LetterwiseMagicSquares
module Generator
class << self
def bits
@bits ||= 10
end
def bits=(bits)
@bits = bits
end
def max_value
2 ** (bits - 1) - 1
end
def generate(length:, dimension:)
<<-SNT
#{magic_square}
#{letter_square}
#{lookup_table}
array#{dimension}<array#{dimension}<int#{bits}>> square;
square.magicSquare!;
squares = [];
squares = squares.push(square);
#{length - 1}.times(function^ (i) {
square = letterSquare(square);
square.magicSquare!;
squares = squares.push(square);
});
sums = squares.map(function (square) {
return square.first.sum;
});
expose squares, sums;
SNT
end
def magic_square
<<-SNT
function^ magicSquare! (square) {
left_diagonal = square.map(function (row, i) {
return row[i];
}).sum;
right_diagonal = square.map(function (row, i) {
return row.reverse[i];
}).sum;
invariant left_diagonal == right_diagonal;
flat = [];
square.each(function^ (row) {
invariant row.sum == left_diagonal;
row.each(function^ (n) {
invariant n.positive?;
flat = flat.push(n);
});
});
square.transpose.each(function^ (column) {
invariant column.sum == left_diagonal;
});
invariant flat.uniq?;
};
SNT
end
def letter_square
<<-SNT
function^ letterSquare (square) {
return square.map(function^ (row) {
return row.map(*numberOfLettersIn);
});
};
SNT
end
def lookup_table
<<-SNT
# The number of letters in one..nine
# 0 is prepended for convenience
one_lookup = [0, 3, 3, 5, 4, 4, 3, 5, 5, 4];
# The number of letters in ten..ninety
ten_lookup = [0, 3, 6, 6, 5, 5, 5, 7, 6, 6];
# The delta of (eleven..nineteen) - ten - (one..nine)
teen_lookup = [0, 0, 0, 0, 1, 0, 1, 1, 0, 1];
function^ numberOfLettersUpto1000 (n) {
sum = 0;
hundreds, modulo_100 = n.divmod(100);
tens, remainder = modulo_100.divmod(10);
# Add the characters from the ones
sum += one_lookup[remainder];
# Add the characters from the tens
sum += ten_lookup[tens];
# Add the teen delta if 11 <= modulo_100 <= 19
sum += modulo_100.between?(11, 19) ? teen_lookup[remainder] : 0;
# Add the characters from the hundreds
sum += one_lookup[hundreds];
sum += hundreds.zero? ? 0 : 7;
# Add the word 'and'
and_required = hundreds != 0 && modulo_100 != 0;
sum += and_required ? 3 : 0;
return sum;
};
function^ numberOfLettersIn (n) {
total = 0;
remainder = n;
#{generate_exponentiated_terms(max_value)}
return total;
};
SNT
end
def generate_exponentiated_terms(max)
terms = ""
exponentials = calculate_exponentiated_terms(max)
exponentials.reverse.each do |(digits, word)|
terms += "\n#{word}s, remainder = remainder.divmod(1#{"0" * digits});"
end
terms += "\ntotal += numberOfLettersUpto1000(remainder);"
exponentials.each do |(digits, word)|
terms += "\ntotal += numberOfLettersUpto1000(#{word}s);"
terms += "\ntotal += #{word}s.zero? ? 0 : #{word.length};"
end
terms
end
def calculate_exponentiated_terms(max)
digits = max.to_s.length
exponentials = (digits - 1) / 3
1.upto(exponentials).map do |exp|
word = (1000 ** exp).to_words
word = word[4..-1].gsub(/[^a-z]/, "")
[exp * 3, word]
end
end
end
end
end