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
require 'set'

DIGRAMS = Set.new(<<EOF.scan(/[A-Z]{2}/))
TH  3.15%  TO  1.11%  SA  0.75%  MA  0.56%
HE  2.51   NT  1.10   HI  0.72   TA  0.56
AN  1.72   ED  1.07   LE  0.72   CE  0.55
IN  1.69   IS  1.06   SO  0.71   IC  0.55
ER  1.54   AR  1.01   AS  0.67   LL  0.55
RE  1.48   OU  0.96   NO  0.65   NA  0.54
ES  1.45   TE  0.94   NE  0.64   RO  0.54
ON  1.45   OF  0.94   EC  0.64   OT  0.53
EA  1.31   IT  0.88   IO  0.63   TT  0.53
TI  1.28   HA  0.84   RT  0.63   VE  0.53
AT  1.24   SE  0.84   CO  0.59   NS  0.51
ST  1.21   ET  0.80   BE  0.58   UR  0.49
EN  1.20   AL  0.77   DI  0.57   ME  0.48
ND  1.18   RI  0.77   LI  0.57   WH  0.48
OR  1.13   NG  0.75   RA  0.57   LY  0.47
EOF

FREQS = Hash[<<EOF.split(/\s+/).zip((1..26).to_a.reverse)]
e
t
a
o
i
n
s
h
r
d
l
c
u
m
w
f
g
y
p
b
v
k
j
x
q
z
EOF

def levenshtein_distance(s, t)
  m = s.length
  n = t.length
  return m if n == 0
  return n if m == 0
  d = Array.new(m+1) {Array.new(n+1)}

  (0..m).each {|i| d[i][0] = i}
  (0..n).each {|j| d[0][j] = j}
  (1..n).each do |j|
    (1..m).each do |i|
      d[i][j] = if s[i-1] == t[j-1]  # adjust index into string
                  d[i-1][j-1]       # no operation required
                else
                  [ d[i-1][j]+1,    # deletion
                    d[i][j-1]+1,    # insertion
                    d[i-1][j-1]+1,  # substitution
                  ].min
                end
    end
  end
  d[m][n]
end

p FREQS

max = Float::INFINITY
up = %w[ gol caspervan bosombud getme ]#.map(&:reverse)
down = %w[ hawn n s valonyourass ]#.map(&:reverse)
up.permutation.each do |up|
  up = %w[au] + up
  # up = up + %w[ua]
  down.permutation.each do |down|
    # down = down + %w[ ecn ]
    down = down + %w[nce]
    phrase = (up+down).join.split(//)
    # puts phrase.join
    phrase = phrase.values_at(40, 9, 43, 4, 22, 35, 20, 14, 47, 7, 24, 17, 31, 11, 1, 6)
    puts phrase.join
  end
end
# hash = phrase.permutation.each.with_object({}) do |phrase, hash|
#   phrase = phrase.join.each_char.to_a
#   # DIE is 27
#   phrase = phrase.values_at(40, 9, 43, 4, 22, 16, 20, 14, 47, 7, 25, 17, 31, 11, 2, 6)
#   freqs = phrase.each.with_object(Hash.new(0)) do |char, h|
#     h[char] += 1
#   end
#   freqs = freqs.sort_by {|_,v| -v }.join
#   count = levenshtein_distance(freqs, phrase.join)
#   max = count and p max, phrase.join if count <= max
# end