]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/markov.rb
Plugin header boilerplating.
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / markov.rb
1 class MarkovPlugin < Plugin
2   def initialize
3     super
4     @registry.set_default([])
5     @registry['enabled'] = false unless @registry.has_key?('enabled')
6     @lastline = false
7   end
8
9   def generate_string(word1, word2)
10     # limit to max of 50 words
11     output = word1 + " " + word2
12
13     # try to avoid :nonword in the first iteration
14     wordlist = @registry["#{word1} #{word2}"]
15     wordlist.delete(:nonword)
16     if not wordlist.empty?
17       word3 = wordlist[rand(wordlist.length)]
18       output = output + " " + word3
19       word1, word2 = word2, word3
20     end
21
22     49.times do
23       wordlist = @registry["#{word1} #{word2}"]
24       break if wordlist.empty?
25       word3 = wordlist[rand(wordlist.length)]
26       break if word3 == :nonword
27       output = output + " " + word3
28       word1, word2 = word2, word3
29     end
30     return output
31   end
32
33   def help(plugin, topic="")
34     "markov plugin: listens to chat to build a markov chain, with which it can (perhaps) attempt to (inanely) contribute to 'discussion'. Sort of.. Will get a *lot* better after listening to a lot of chat. usage: 'markov' to attempt to say something relevant to the last line of chat, if it can.  other options to markov: 'ignore' => ignore a hostmask (accept no input), 'status' => show current status, 'probability' => set the % chance of rbot responding to input, 'chat' => try and say something intelligent, 'chat about <foo> <bar>' => riff on a word pair (if possible)"
35   end
36
37   def clean_str(s)
38     str = s.dup
39     str.gsub!(/^\S+[:,;]/, "")
40     str.gsub!(/\s{2,}/, ' ') # fix for two or more spaces
41     return str.strip
42   end
43
44   def probability?
45     prob = @registry['probability']
46     prob = 25 if prob.kind_of? Array;
47     prob = 0 if prob < 0
48     prob = 100 if prob > 100
49     return prob
50   end
51
52   def status(m,params)
53     enabled = @registry['enabled']
54     if (enabled)
55       m.reply "markov is currently enabled, #{probability?}% chance of chipping in"
56     else
57       m.reply "markov is currently disabled"
58     end
59   end
60
61   def ignore?(user=nil)
62     return false unless user
63     @registry['ignore_users'].each do |mask|
64       return true if user.matches?(mask)
65     end
66     return false
67   end
68
69   def ignore(m, params)
70     if @registry['ignore_users'].nil?
71       @registry['ignore_users'] = []
72     end
73     action = params[:action]
74     user = params[:option]
75     case action
76     when 'remove':
77       if @registry['ignore_users'].include? user
78         s = @registry['ignore_users']
79         s.delete user
80         @registry['ignore_users'] = s
81         m.reply "#{user} removed"
82       else
83         m.reply "not found in list"
84       end
85     when 'add':
86       if user
87         if @registry['ignore_users'].include?(user)
88           m.reply "#{user} already in list"
89         else
90           @registry['ignore_users'] = @registry['ignore_users'].push user 
91           m.reply "#{user} added to markov ignore list"
92         end
93       else
94         m.reply "give the name of a person to ignore"
95       end
96     when 'list':
97       m.reply "I'm ignoring #{@registry['ignore_users'].join(", ")}"
98     else
99       m.reply "have markov ignore the input from a hostmask.  usage: markov ignore add <mask>; markov ignore remove <mask>; markov ignore list"
100     end
101   end
102
103   def enable(m, params)
104     @registry['enabled'] = true
105     m.okay
106   end
107
108   def probability(m, params)
109     @registry['probability'] = params[:probability].to_i
110     m.okay
111   end
112
113   def disable(m, params)
114     @registry['enabled'] = false
115     m.okay
116   end
117
118   def should_talk
119     return false unless @registry['enabled']
120     prob = probability?
121     return true if prob > rand(100)
122     return false
123   end
124
125   def delay
126     1 + rand(5)
127   end
128
129   def random_markov(m, message)
130     return unless should_talk
131
132     word1, word2 = message.split(/\s+/)
133     line = generate_string(word1, word2)
134     return unless line
135     return if line == message
136     @bot.timer.add_once(delay, m) {|m|
137       m.reply line
138     }
139   end
140
141   def chat(m, params)
142     line = generate_string(params[:seed1], params[:seed2])
143     if line != "#{params[:seed1]} #{params[:seed2]}"
144       m.reply line 
145     else
146       m.reply "I can't :("
147     end
148   end
149
150   def rand_chat(m, params)
151     # pick a random pair from the db and go from there
152     word1, word2 = :nonword, :nonword
153     output = Array.new
154     50.times do
155       wordlist = @registry["#{word1} #{word2}"]
156       break if wordlist.empty?
157       word3 = wordlist[rand(wordlist.length)]
158       break if word3 == :nonword
159       output << word3
160       word1, word2 = word2, word3
161     end
162     if output.length > 1
163       m.reply output.join(" ")
164     else
165       m.reply "I can't :("
166     end
167   end
168   
169   def listen(m)
170     return unless m.kind_of?(PrivMessage) && m.public?
171     return if m.address?
172     return if ignore? m.source
173
174     # in channel message, the kind we are interested in
175     message = clean_str m.message
176
177     if m.action?
178       message = "#{m.sourcenick} #{message}"
179     end
180     
181     wordlist = message.split(/\s+/)
182     return unless wordlist.length >= 2
183     @lastline = message
184     word1, word2 = :nonword, :nonword
185     wordlist.each do |word3|
186       @registry["#{word1} #{word2}"] = @registry["#{word1} #{word2}"].push(word3)
187       word1, word2 = word2, word3
188     end
189     @registry["#{word1} #{word2}"] = @registry["#{word1} #{word2}"].push(:nonword)
190
191     return if m.replied?
192     random_markov(m, message)
193   end
194 end
195
196 plugin = MarkovPlugin.new
197 plugin.map 'markov ignore :action :option', :action => "ignore"
198 plugin.map 'markov ignore :action', :action => "ignore"
199 plugin.map 'markov ignore', :action => "ignore"
200 plugin.map 'markov enable', :action => "enable"
201 plugin.map 'markov disable', :action => "disable"
202 plugin.map 'markov status', :action => "status"
203 plugin.map 'chat about :seed1 :seed2', :action => "chat"
204 plugin.map 'chat', :action => "rand_chat"
205 plugin.map 'markov probability :probability', :action => "probability",
206            :requirements => {:probability => /^\d+%?$/}