2 # Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
3 # New markov chain plugin
19 return nil if self.empty?
22 count = rand(self.size-i)
24 count = rand([n, self.size-i].min)
52 @hash.delete(el) if @hash[el] == 0
63 @picker << [total, el]
74 return @hash.keys.first
76 make_picker unless @valid_pick
78 @picker.each { |ch, el|
79 return el if pick < ch
89 # Word or nonword regexp:
90 # can be used to scan a string splitting it into
95 # mkv[i] holds the chains of order i
98 # Each chain is in the form
99 # [:array, :of, :symbols] => {
100 # :prev => ChanceHash,
101 # :next => ChanceHash
103 # except for order 0, which is a simple ChanceHash
105 @mkv[0] = ChanceHash.new
106 MAX_ORDER.times { |i|
107 @mkv[i+1] = Hash.new { |hash, key|
108 hash[key] = {:prev => ChanceHash.new, :next => ChanceHash.new}
115 s = sym.to_sym rescue nil
119 def add_before(array, prev)
120 raise "Not enough words in new data" if array.empty?
121 raise "Too many words in new data" if array.size > MAX_ORDER
123 h = @mkv[size][array.dup]
124 h[:prev].increase(prev)
127 def add_after(array, nxt)
128 raise "Not enough words in new data" if array.empty?
129 raise "Too many words in new data" if array.size > MAX_ORDER
131 h = @mkv[size][array.dup]
132 h[:next].increase(nxt)
136 raise "Too many words in new data" if array.size > MAX_ORDER + 1
137 add_before(array.butfirst, array.first)
138 add_after(array.butlast, array.last)
149 def simple_learn(text)
150 syms = text.scan(WNW).map { |w| w.intern }
154 syms.size.times { |i|
155 ([MAX_ORDER, syms.size-i].min+1).times { |ord|
157 # puts "Learning #{v.inspect}"
164 def learn(text, o={})
165 opts = {:lowercase => true}.merge o
167 lc = opts[:lowercase]
171 simple_learn(text.downcase)
174 pp @mkv if defined? pp
178 ar = syms.last([MAX_ORDER, syms.size].min)
183 if @mkv[ord].key?(ar)
184 @mkv[ord][ar][:next].random
186 raw_next(ar.last(ord-1))
192 syms = text.scan(WNW).map { |w| w.intern }
197 ar = syms.first([MAX_ORDER, syms.size].min)
202 if @mkv[ord].key?(ar)
203 @mkv[ord][ar][:prev].random
205 raw_prev(ar.first(ord-1))
211 syms = text.scan(WNW).map { |w| w.intern }
215 def complete_prev(text)
216 syms = text.scan(WNW).map { |w| w.intern }
217 prev = raw_prev(syms)
220 prev = raw_prev(syms)
225 def complete_next(text)
226 syms = text.scan(WNW).map { |w| w.intern }
238 txt = @mkv[0].random.to_s
240 syms = txt.scan(WNW).map { |w| w.intern }
241 prev = raw_prev(syms)
246 # Keep adding only on the side where we
247 # didn't come across a nil already
248 prev = raw_prev(syms) if prev
249 nxt = raw_next(syms) if nxt