markov_chain_chat_bot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +44 -0
- data/lib/auto_marshalling_map.rb +29 -0
- data/lib/chat_bot.rb +6 -0
- data/lib/markov_chain.rb +93 -0
- data/lib/markov_chain_chat_bot.rb +560 -0
- metadata +51 -0
data/README
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
== Markov chain chat bot
|
2
|
+
|
3
|
+
|
4
|
+
A chat bot utilizing Markov chains. It speaks Russian and English.
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
=== Examples
|
11
|
+
|
12
|
+
|
13
|
+
Basic usage:
|
14
|
+
|
15
|
+
require 'chat_bot'
|
16
|
+
|
17
|
+
bot = ChatBot.from(Hash.new)
|
18
|
+
bot.learn("one two three two one")
|
19
|
+
bot.answer("count up and down please")
|
20
|
+
#=> "one two three two three two one two one two three two one two one"
|
21
|
+
bot.learn("three four six")
|
22
|
+
bot.answer("count from three please")
|
23
|
+
#=> "three two one two one two three four six"
|
24
|
+
|
25
|
+
One may save the bot's knowledge into key-value storage:
|
26
|
+
|
27
|
+
require 'chat_bot'
|
28
|
+
require 'auto_marshalling_map'
|
29
|
+
require 'gdbm'
|
30
|
+
|
31
|
+
# 1.
|
32
|
+
kvs = GDBM.open("chat_bot.dat")
|
33
|
+
bot = ChatBot.from(AutoMarhsallingMap.new(kvs))
|
34
|
+
bot.learn("one two three two one")
|
35
|
+
kvs.close()
|
36
|
+
|
37
|
+
# 2.
|
38
|
+
kvs = GDBM.open("chat_bot.dat")
|
39
|
+
bot = ChatBot.from(AutoMarhsallingMap.new(kvs))
|
40
|
+
bot.answer("count up and down please")
|
41
|
+
#=> "one two three two three two three two one two one"
|
42
|
+
|
43
|
+
|
44
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# A map which automatically marshals all keys and values passed to it.
|
4
|
+
#
|
5
|
+
class AutoMarshallingMap
|
6
|
+
|
7
|
+
#
|
8
|
+
# +backend+ is a Map from String to (String or nil). It will be used as
|
9
|
+
# a backend storage for the new AutoMarshallingMap.
|
10
|
+
#
|
11
|
+
def initialize(backend)
|
12
|
+
@backend = backend
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
value_string = @backend[Marshal.dump(key)]
|
17
|
+
return nil if value_string.nil?
|
18
|
+
return Marshal.load value_string
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, value)
|
22
|
+
@backend[Marshal.dump(key)] = Marshal.dump(value)
|
23
|
+
return value
|
24
|
+
end
|
25
|
+
|
26
|
+
# +backend+ argument passed to #new().
|
27
|
+
attr_reader :backend
|
28
|
+
|
29
|
+
end
|
data/lib/chat_bot.rb
ADDED
data/lib/markov_chain.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
class MarkovChain
|
3
|
+
|
4
|
+
#
|
5
|
+
# +data+ is #data() of the other MarkovChain. It becomes owned by the
|
6
|
+
# returned MarkovChain.
|
7
|
+
#
|
8
|
+
def self.from(data)
|
9
|
+
new(data)
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# creates an empty MarkovChain.
|
14
|
+
#
|
15
|
+
# +data+ is a map which becomes owned by this MarkovChain.
|
16
|
+
#
|
17
|
+
def initialize(data = {})
|
18
|
+
@data = data
|
19
|
+
@last_state = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# appends +states+ to the end of this MarkovChain.
|
24
|
+
#
|
25
|
+
# +states+ are arbitrary objects.
|
26
|
+
#
|
27
|
+
# It returns this (modified) MarkovChain.
|
28
|
+
#
|
29
|
+
def append!(states)
|
30
|
+
for next_state in states
|
31
|
+
state_occurences_map = (@data[@last_state] or Hash.new)
|
32
|
+
state_occurences_map[next_state] ||= 0
|
33
|
+
state_occurences_map[next_state] += 1
|
34
|
+
@data[@last_state] = state_occurences_map
|
35
|
+
@last_state = next_state
|
36
|
+
end
|
37
|
+
return self
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# returns Enumerable of predicted states. The result may contain nils if
|
42
|
+
# the MarkovChain can not predict a state.
|
43
|
+
#
|
44
|
+
def predict()
|
45
|
+
self.extend(Prediction)
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# +data+ passed to #initialize().
|
50
|
+
#
|
51
|
+
def data
|
52
|
+
@data
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# :enddoc:
|
58
|
+
|
59
|
+
#
|
60
|
+
# This module is only intended for inclusion into MarkovChain.
|
61
|
+
#
|
62
|
+
module Prediction
|
63
|
+
|
64
|
+
include Enumerable
|
65
|
+
|
66
|
+
def each
|
67
|
+
#
|
68
|
+
last_state = @last_state
|
69
|
+
loop do
|
70
|
+
#
|
71
|
+
next_state = begin
|
72
|
+
state_occurences_map = (@data[last_state] or Hash.new)
|
73
|
+
occurences_sum = state_occurences_map.reduce(0) do |sum, entry|
|
74
|
+
sum + entry[1]
|
75
|
+
end
|
76
|
+
choice = rand(occurences_sum + 1)
|
77
|
+
chosen_state_and_occurences = state_occurences_map.find do |state, occurences|
|
78
|
+
choice -= occurences
|
79
|
+
choice <= 0
|
80
|
+
end
|
81
|
+
chosen_state_and_occurences ||= [nil, nil]
|
82
|
+
chosen_state_and_occurences[0]
|
83
|
+
end
|
84
|
+
#
|
85
|
+
yield next_state
|
86
|
+
#
|
87
|
+
last_state = next_state
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,560 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'markov_chain'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
#
|
6
|
+
# A chat bot utilizing MarkovChain.
|
7
|
+
#
|
8
|
+
class MarkovChainChatBot
|
9
|
+
|
10
|
+
private_class_method :new
|
11
|
+
|
12
|
+
#
|
13
|
+
# +data+ is a map. It may be empty, in this case a brand new ChatBot is
|
14
|
+
# created. +data+ becomes owned by the returned ChatBot.
|
15
|
+
#
|
16
|
+
# +answer_limit+ is maximum size of the result of #answer().
|
17
|
+
#
|
18
|
+
def self.from(data, answer_limit = 1000)
|
19
|
+
new(data, answer_limit)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(data, answer_limit) # :nodoc:
|
23
|
+
@markov_chain =
|
24
|
+
if data.empty? then MarkovChain.new(data)
|
25
|
+
else MarkovChain.from(data)
|
26
|
+
end
|
27
|
+
@answer_limit = answer_limit
|
28
|
+
end
|
29
|
+
|
30
|
+
# +data+ passed to #from().
|
31
|
+
def data
|
32
|
+
@markov_chain.data
|
33
|
+
end
|
34
|
+
|
35
|
+
def learn(text)
|
36
|
+
@markov_chain.append!(tokenize(text)).append!([EndOfMessage.new])
|
37
|
+
end
|
38
|
+
|
39
|
+
def answer(question)
|
40
|
+
answer = ""
|
41
|
+
previous_token = nil
|
42
|
+
catch :out_of_limit do
|
43
|
+
for token in @markov_chain.predict()
|
44
|
+
break if token.tkn_is_a? EndOfMessage or token.nil?
|
45
|
+
delimiter =
|
46
|
+
if (previous_token.tkn_is_a? Word and token.tkn_is_a? Word) then " "
|
47
|
+
else ""
|
48
|
+
end
|
49
|
+
answer.append_limited(delimiter + token.tkn_value, @answer_limit)
|
50
|
+
previous_token = token
|
51
|
+
end
|
52
|
+
end
|
53
|
+
return answer
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# :enddoc:
|
59
|
+
|
60
|
+
class ::String
|
61
|
+
|
62
|
+
# appends +appendment+ to this String or throws +:out_of_limit+ if
|
63
|
+
# this String will exceed +limit+ after the appending.
|
64
|
+
#
|
65
|
+
# It returns this (modified) String.
|
66
|
+
#
|
67
|
+
def append_limited(appendment, limit)
|
68
|
+
throw :out_of_limit if self.length + appendment.length > limit
|
69
|
+
self << appendment
|
70
|
+
return self
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
Token = Object
|
76
|
+
|
77
|
+
class Token
|
78
|
+
|
79
|
+
def tkn_value
|
80
|
+
self[1..-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
def tkn_is_a?(clazz)
|
84
|
+
clazz === self
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
class Word < Token
|
90
|
+
|
91
|
+
def self.new(value)
|
92
|
+
"w" + value
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.===(x)
|
96
|
+
x.is_a? String and x[0] == "w"
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
class PunctuationMark < Token
|
102
|
+
|
103
|
+
def self.new(value)
|
104
|
+
"p" + value
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.===(x)
|
108
|
+
x.is_a? String and x[0] == "p"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
class EndOfMessage < Token
|
114
|
+
|
115
|
+
def self.new()
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.===(x)
|
120
|
+
x.nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# returns Array of Token-s.
|
127
|
+
#
|
128
|
+
def tokenize(text)
|
129
|
+
yy_parse(StringIO.new(text))
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
#
|
135
|
+
# +input+ is IO. It must have working IO#pos, IO#pos= and
|
136
|
+
# IO#set_encoding() methods.
|
137
|
+
#
|
138
|
+
# It may raise YY_SyntaxError.
|
139
|
+
#
|
140
|
+
def yy_parse(input)
|
141
|
+
input.set_encoding("UTF-8", "UTF-8")
|
142
|
+
context = YY_ParsingContext.new(input)
|
143
|
+
yy_from_pcv(
|
144
|
+
yy_nonterm1(context) ||
|
145
|
+
# TODO: context.worst_error can not be nil here. Prove it.
|
146
|
+
raise(context.worst_error)
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
# TODO: Allow to pass String to the entry point.
|
151
|
+
|
152
|
+
|
153
|
+
# :nodoc:
|
154
|
+
### converts value to parser-compatible value (which is always non-false and
|
155
|
+
### non-nil).
|
156
|
+
def yy_to_pcv(value)
|
157
|
+
if value.nil? then :yy_nil
|
158
|
+
elsif value == false then :yy_false
|
159
|
+
else value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# :nodoc:
|
164
|
+
### converts value got by #yy_to_pcv() to actual value.
|
165
|
+
def yy_from_pcv(value)
|
166
|
+
if value == :yy_nil then nil
|
167
|
+
elsif value == :yy_false then false
|
168
|
+
else value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# :nodoc:
|
173
|
+
class YY_ParsingContext
|
174
|
+
|
175
|
+
# +input+ is IO.
|
176
|
+
def initialize(input)
|
177
|
+
@input = input
|
178
|
+
@worst_error = nil
|
179
|
+
end
|
180
|
+
|
181
|
+
attr_reader :input
|
182
|
+
|
183
|
+
# It is YY_SyntaxExpectationError or nil.
|
184
|
+
attr_accessor :worst_error
|
185
|
+
|
186
|
+
# adds possible error to this YY_ParsingContext.
|
187
|
+
#
|
188
|
+
# +error+ is YY_SyntaxExpectationError.
|
189
|
+
#
|
190
|
+
def << error
|
191
|
+
# Update worst_error.
|
192
|
+
if worst_error.nil? or worst_error.pos < error.pos then
|
193
|
+
@worst_error = error
|
194
|
+
elsif worst_error.pos == error.pos then
|
195
|
+
@worst_error = @worst_error.or error
|
196
|
+
end
|
197
|
+
#
|
198
|
+
return self
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
# :nodoc:
|
204
|
+
def yy_string(context, string)
|
205
|
+
#
|
206
|
+
string_start_pos = context.input.pos
|
207
|
+
# Read string.
|
208
|
+
read_string = context.input.read(string.bytesize)
|
209
|
+
# Set the string's encoding; check if it fits the argument.
|
210
|
+
unless read_string and (read_string.force_encoding(Encoding::UTF_8)) == string then
|
211
|
+
#
|
212
|
+
context << YY_SyntaxExpectationError.new(yy_displayed(string), string_start_pos)
|
213
|
+
#
|
214
|
+
return nil
|
215
|
+
end
|
216
|
+
#
|
217
|
+
return read_string
|
218
|
+
end
|
219
|
+
|
220
|
+
# :nodoc:
|
221
|
+
def yy_end?(context)
|
222
|
+
#
|
223
|
+
if not context.input.eof?
|
224
|
+
context << YY_SyntaxExpectationError.new("the end", context.input.pos)
|
225
|
+
return nil
|
226
|
+
end
|
227
|
+
#
|
228
|
+
return true
|
229
|
+
end
|
230
|
+
|
231
|
+
# :nodoc:
|
232
|
+
def yy_begin?(context)
|
233
|
+
#
|
234
|
+
if not (context.input.pos == 0)
|
235
|
+
context << YY_SyntaxExpectationError.new("the beginning", context.input.pos)
|
236
|
+
return nil
|
237
|
+
end
|
238
|
+
#
|
239
|
+
return true
|
240
|
+
end
|
241
|
+
|
242
|
+
# :nodoc:
|
243
|
+
def yy_char(context)
|
244
|
+
#
|
245
|
+
char_start_pos = context.input.pos
|
246
|
+
# Read a char.
|
247
|
+
c = context.input.getc
|
248
|
+
#
|
249
|
+
unless c then
|
250
|
+
#
|
251
|
+
context << YY_SyntaxExpectationError.new("a character", char_start_pos)
|
252
|
+
#
|
253
|
+
return nil
|
254
|
+
end
|
255
|
+
#
|
256
|
+
return c
|
257
|
+
end
|
258
|
+
|
259
|
+
# :nodoc:
|
260
|
+
def yy_char_range(context, from, to)
|
261
|
+
#
|
262
|
+
char_start_pos = context.input.pos
|
263
|
+
# Read the char.
|
264
|
+
c = context.input.getc
|
265
|
+
# Check if it fits the range.
|
266
|
+
# NOTE: c has UTF-8 encoding.
|
267
|
+
unless c and (from <= c and c <= to) then
|
268
|
+
#
|
269
|
+
context << YY_SyntaxExpectationError.new(%(#{yy_displayed from}...#{yy_displayed to}), char_start_pos)
|
270
|
+
#
|
271
|
+
return nil
|
272
|
+
end
|
273
|
+
#
|
274
|
+
return c
|
275
|
+
end
|
276
|
+
|
277
|
+
# :nodoc:
|
278
|
+
### The form of +string+ suitable for displaying in messages.
|
279
|
+
def yy_displayed(string)
|
280
|
+
if string.length == 1 then
|
281
|
+
char = string[0]
|
282
|
+
char_code = char.ord
|
283
|
+
case char_code
|
284
|
+
when 0x00...0x20, 0x2028, 0x2029 then %(#{yy_unicode_s char_code})
|
285
|
+
when 0x20...0x80 then %("#{char}")
|
286
|
+
when 0x80...Float::INFINITY then %("#{char} (#{yy_unicode_s char_code})")
|
287
|
+
end
|
288
|
+
else
|
289
|
+
%("#{string}")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# :nodoc:
|
294
|
+
### "U+XXXX" string corresponding to +char_code+.
|
295
|
+
def yy_unicode_s(char_code)
|
296
|
+
"U+#{"%04X" % char_code}"
|
297
|
+
end
|
298
|
+
|
299
|
+
class YY_SyntaxError < Exception
|
300
|
+
|
301
|
+
def initialize(message, pos)
|
302
|
+
super(message)
|
303
|
+
@pos = pos
|
304
|
+
end
|
305
|
+
|
306
|
+
attr_reader :pos
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
# :nodoc:
|
311
|
+
class YY_SyntaxExpectationError < YY_SyntaxError
|
312
|
+
|
313
|
+
#
|
314
|
+
# +expectations+ are String-s.
|
315
|
+
#
|
316
|
+
def initialize(*expectations, pos)
|
317
|
+
super(nil, pos)
|
318
|
+
@expectations = expectations
|
319
|
+
end
|
320
|
+
|
321
|
+
#
|
322
|
+
# returns other YY_SyntaxExpectationError with #expectations combined.
|
323
|
+
#
|
324
|
+
# +other+ is another YY_SyntaxExpectationError.
|
325
|
+
#
|
326
|
+
# #pos of this YY_SyntaxExpectationError and +other+ must be equal.
|
327
|
+
#
|
328
|
+
def or other
|
329
|
+
raise %(can not "or" #{YY_SyntaxExpectationError}s with different pos) unless self.pos == other.pos
|
330
|
+
YY_SyntaxExpectationError.new(*(self.expectations + other.expectations), pos)
|
331
|
+
end
|
332
|
+
|
333
|
+
def message
|
334
|
+
expectations = self.expectations.uniq
|
335
|
+
[expectations[0...-1].join(", "), expectations[-1]].join(" or ") + " is expected"
|
336
|
+
end
|
337
|
+
|
338
|
+
protected
|
339
|
+
|
340
|
+
# Private
|
341
|
+
attr_reader :expectations
|
342
|
+
|
343
|
+
end
|
344
|
+
|
345
|
+
# :nodoc:
|
346
|
+
def yy_nonterm1(yy_context)
|
347
|
+
val = :yy_nil
|
348
|
+
(begin
|
349
|
+
val = []
|
350
|
+
true
|
351
|
+
end and while true
|
352
|
+
yy_vare = yy_context.input.pos
|
353
|
+
if not begin; yy_var9 = yy_context.input.pos; (begin
|
354
|
+
yy_vara = yy_nontermf(yy_context)
|
355
|
+
if yy_vara then
|
356
|
+
w = yy_from_pcv(yy_vara)
|
357
|
+
end
|
358
|
+
yy_vara
|
359
|
+
end and begin
|
360
|
+
val << Word.new(w)
|
361
|
+
true
|
362
|
+
end) or (yy_context.input.pos = yy_var9; (begin
|
363
|
+
yy_varb = yy_nonterm14(yy_context)
|
364
|
+
if yy_varb then
|
365
|
+
p = yy_from_pcv(yy_varb)
|
366
|
+
end
|
367
|
+
yy_varb
|
368
|
+
end and begin
|
369
|
+
val << PunctuationMark.new(p)
|
370
|
+
true
|
371
|
+
end)) or (yy_context.input.pos = yy_var9; yy_nonterm20(yy_context) and while true
|
372
|
+
yy_vard = yy_context.input.pos
|
373
|
+
if not yy_nonterm20(yy_context) then
|
374
|
+
yy_context.input.pos = yy_vard
|
375
|
+
break true
|
376
|
+
end
|
377
|
+
end); end then
|
378
|
+
yy_context.input.pos = yy_vare
|
379
|
+
break true
|
380
|
+
end
|
381
|
+
end) and yy_to_pcv(val)
|
382
|
+
end
|
383
|
+
|
384
|
+
# :nodoc:
|
385
|
+
def yy_nontermf(yy_context)
|
386
|
+
val = :yy_nil
|
387
|
+
(begin
|
388
|
+
val = ""
|
389
|
+
true
|
390
|
+
end and begin; yy_varp = yy_context.input.pos; begin
|
391
|
+
yy_varq = yy_nontermx(yy_context)
|
392
|
+
if yy_varq then
|
393
|
+
val << yy_from_pcv(yy_varq)
|
394
|
+
end
|
395
|
+
yy_varq
|
396
|
+
end or (yy_context.input.pos = yy_varp; (begin
|
397
|
+
yy_varr = yy_string(yy_context, "-")
|
398
|
+
if yy_varr then
|
399
|
+
h = yy_from_pcv(yy_varr)
|
400
|
+
end
|
401
|
+
yy_varr
|
402
|
+
end and begin
|
403
|
+
yy_varu = yy_context.input.pos
|
404
|
+
yy_varv = yy_nontermx(yy_context)
|
405
|
+
yy_context.input.pos = yy_varu
|
406
|
+
yy_varv
|
407
|
+
end and begin
|
408
|
+
val << h
|
409
|
+
true
|
410
|
+
end)); end and while true
|
411
|
+
yy_varw = yy_context.input.pos
|
412
|
+
if not begin; yy_varp = yy_context.input.pos; begin
|
413
|
+
yy_varq = yy_nontermx(yy_context)
|
414
|
+
if yy_varq then
|
415
|
+
val << yy_from_pcv(yy_varq)
|
416
|
+
end
|
417
|
+
yy_varq
|
418
|
+
end or (yy_context.input.pos = yy_varp; (begin
|
419
|
+
yy_varr = yy_string(yy_context, "-")
|
420
|
+
if yy_varr then
|
421
|
+
h = yy_from_pcv(yy_varr)
|
422
|
+
end
|
423
|
+
yy_varr
|
424
|
+
end and begin
|
425
|
+
yy_varu = yy_context.input.pos
|
426
|
+
yy_varv = yy_nontermx(yy_context)
|
427
|
+
yy_context.input.pos = yy_varu
|
428
|
+
yy_varv
|
429
|
+
end and begin
|
430
|
+
val << h
|
431
|
+
true
|
432
|
+
end)); end then
|
433
|
+
yy_context.input.pos = yy_varw
|
434
|
+
break true
|
435
|
+
end
|
436
|
+
end) and yy_to_pcv(val)
|
437
|
+
end
|
438
|
+
|
439
|
+
# :nodoc:
|
440
|
+
def yy_nontermx(yy_context)
|
441
|
+
val = :yy_nil
|
442
|
+
begin; yy_vary = yy_context.input.pos; begin
|
443
|
+
yy_varz = yy_char_range(yy_context, "a", "z")
|
444
|
+
if yy_varz then
|
445
|
+
val = yy_from_pcv(yy_varz)
|
446
|
+
end
|
447
|
+
yy_varz
|
448
|
+
end or (yy_context.input.pos = yy_vary; begin
|
449
|
+
yy_var10 = yy_char_range(yy_context, "A", "Z")
|
450
|
+
if yy_var10 then
|
451
|
+
val = yy_from_pcv(yy_var10)
|
452
|
+
end
|
453
|
+
yy_var10
|
454
|
+
end) or (yy_context.input.pos = yy_vary; begin
|
455
|
+
yy_var11 = yy_char_range(yy_context, "\u{430}", "\u{44f}")
|
456
|
+
if yy_var11 then
|
457
|
+
val = yy_from_pcv(yy_var11)
|
458
|
+
end
|
459
|
+
yy_var11
|
460
|
+
end) or (yy_context.input.pos = yy_vary; begin
|
461
|
+
yy_var12 = yy_char_range(yy_context, "\u{410}", "\u{42f}")
|
462
|
+
if yy_var12 then
|
463
|
+
val = yy_from_pcv(yy_var12)
|
464
|
+
end
|
465
|
+
yy_var12
|
466
|
+
end) or (yy_context.input.pos = yy_vary; begin
|
467
|
+
yy_var13 = yy_char_range(yy_context, "0", "9")
|
468
|
+
if yy_var13 then
|
469
|
+
val = yy_from_pcv(yy_var13)
|
470
|
+
end
|
471
|
+
yy_var13
|
472
|
+
end); end and yy_to_pcv(val)
|
473
|
+
end
|
474
|
+
|
475
|
+
# :nodoc:
|
476
|
+
def yy_nonterm14(yy_context)
|
477
|
+
val = :yy_nil
|
478
|
+
(begin
|
479
|
+
val = ""
|
480
|
+
true
|
481
|
+
end and while true
|
482
|
+
yy_var1b = yy_context.input.pos
|
483
|
+
if not begin
|
484
|
+
yy_var1a = yy_nonterm20(yy_context)
|
485
|
+
if yy_var1a then
|
486
|
+
val << yy_from_pcv(yy_var1a)
|
487
|
+
end
|
488
|
+
yy_var1a
|
489
|
+
end then
|
490
|
+
yy_context.input.pos = yy_var1b
|
491
|
+
break true
|
492
|
+
end
|
493
|
+
end and (begin
|
494
|
+
yy_var1p = yy_context.worst_error
|
495
|
+
begin
|
496
|
+
not begin
|
497
|
+
yy_var1q = yy_context.input.pos
|
498
|
+
yy_var1r = yy_nontermx(yy_context)
|
499
|
+
yy_context.input.pos = yy_var1q
|
500
|
+
yy_var1r
|
501
|
+
end
|
502
|
+
ensure
|
503
|
+
yy_context.worst_error = yy_var1p
|
504
|
+
end
|
505
|
+
end and begin
|
506
|
+
yy_var1s = yy_char(yy_context)
|
507
|
+
if yy_var1s then
|
508
|
+
val << yy_from_pcv(yy_var1s)
|
509
|
+
end
|
510
|
+
yy_var1s
|
511
|
+
end) and while true
|
512
|
+
yy_var1t = yy_context.input.pos
|
513
|
+
if not (begin
|
514
|
+
yy_var1p = yy_context.worst_error
|
515
|
+
begin
|
516
|
+
not begin
|
517
|
+
yy_var1q = yy_context.input.pos
|
518
|
+
yy_var1r = yy_nontermx(yy_context)
|
519
|
+
yy_context.input.pos = yy_var1q
|
520
|
+
yy_var1r
|
521
|
+
end
|
522
|
+
ensure
|
523
|
+
yy_context.worst_error = yy_var1p
|
524
|
+
end
|
525
|
+
end and begin
|
526
|
+
yy_var1s = yy_char(yy_context)
|
527
|
+
if yy_var1s then
|
528
|
+
val << yy_from_pcv(yy_var1s)
|
529
|
+
end
|
530
|
+
yy_var1s
|
531
|
+
end) then
|
532
|
+
yy_context.input.pos = yy_var1t
|
533
|
+
break true
|
534
|
+
end
|
535
|
+
end and while true
|
536
|
+
yy_var1z = yy_context.input.pos
|
537
|
+
if not begin
|
538
|
+
yy_var1y = yy_nonterm20(yy_context)
|
539
|
+
if yy_var1y then
|
540
|
+
val << yy_from_pcv(yy_var1y)
|
541
|
+
end
|
542
|
+
yy_var1y
|
543
|
+
end then
|
544
|
+
yy_context.input.pos = yy_var1z
|
545
|
+
break true
|
546
|
+
end
|
547
|
+
end) and yy_to_pcv(val)
|
548
|
+
end
|
549
|
+
|
550
|
+
# :nodoc:
|
551
|
+
def yy_nonterm20(yy_context)
|
552
|
+
val = :yy_nil
|
553
|
+
(begin; yy_var23 = yy_context.input.pos; yy_char_range(yy_context, "\t", "\r") or (yy_context.input.pos = yy_var23; yy_string(yy_context, " ")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{85}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{a0}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{1680}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{180e}")) or (yy_context.input.pos = yy_var23; yy_char_range(yy_context, "\u{2000}", "\u{200a}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{2028}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{2029}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{202f}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{205f}")) or (yy_context.input.pos = yy_var23; yy_string(yy_context, "\u{3000}")); end and begin
|
554
|
+
val = " "
|
555
|
+
true
|
556
|
+
end) and yy_to_pcv(val)
|
557
|
+
end
|
558
|
+
|
559
|
+
end
|
560
|
+
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: markov_chain_chat_bot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lavir the Whiolet
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-07-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A chat bot utilizing Markov chains. It speaks Russian and English.
|
15
|
+
email: Lavir.th.Whiolet@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README
|
20
|
+
files:
|
21
|
+
- lib/auto_marshalling_map.rb
|
22
|
+
- lib/chat_bot.rb
|
23
|
+
- lib/markov_chain.rb
|
24
|
+
- lib/markov_chain_chat_bot.rb
|
25
|
+
- README
|
26
|
+
homepage: https://github.com/LavirtheWhiolet/markov-chain-bot-module
|
27
|
+
licenses:
|
28
|
+
- Public Domain
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 1.8.23
|
48
|
+
signing_key:
|
49
|
+
specification_version: 3
|
50
|
+
summary: Markov chain chat bot
|
51
|
+
test_files: []
|