]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - data/rbot/plugins/games/azgame.rb
refactor: wordlist shouldn't use bot singleton #35
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / games / azgame.rb
index b1bb09e5f934e92aa202e7770d8644211516ac66..b4dbabc1b73a03573c8883112b89c3e8246119df 100644 (file)
@@ -35,6 +35,34 @@ class AzGame
     def @range.to_s
       return "%s -- %s" % self
     end
+    if @rules[:list]
+      @check_method = "is_#{@rules[:addlang]}?"
+      # trick: if addlang was not in rules, this will be is_? which is
+      # not a method of the plugin
+      if @check_method and not @plugin.respond_to? @check_method
+        @check_method = nil
+      end
+      @check = Proc.new do |w|
+        wl = @rules[:list].include?(w)
+        if !wl and @check_method
+          if wl = @plugin.send(@check_method, w)
+            debug "adding #{w} to #{@rules[:addfile]}"
+            begin
+              File.open(@rules[:addfile], "a") do |f|
+                f.puts w
+              end
+            rescue Exception => e
+              error "failed to add #{w} to #{@rules[:addfile]}"
+              error e
+            end
+          end
+        end
+        wl
+      end
+    else
+      @check_method = "is_#{@lang}?"
+      @check = Proc.new { |w| @plugin.send(@check_method, w) }
+    end
   end
 
   def check(word)
@@ -47,7 +75,7 @@ class AzGame
     return [:out, @range] if w < @range.first or w > @range.last
     return [:ignore, @range] if w == @range.first or w == @range.last
     # This is potentially slow (for languages that check online)
-    return [:noexist, @range] unless @plugin.send("is_#{@lang}?", w)
+    return [:noexist, @range] unless @check.call(w)
     debug "we like it"
     # Check again if there was a winner in the mean time,
     # and bail out if there was
@@ -117,26 +145,41 @@ class AzGamePlugin < Plugin
       :good => /(?:singular )?noun|verb|adj/,
       :first => 'abacus',
       :last => 'zuni',
-      :url => "http://www.chambersharrap.co.uk/chambers/features/chref/chref.py/main?query=%s&title=21st",
+      :url => "http://www.chambers.co.uk/search.php?query=%s&title=21st",
       :listener => /^[a-z]+$/
     },
     }
 
-    japanese_wordlist = "#{@bot.botclass}/azgame/wordlist-japanese"
-    if File.exist?(japanese_wordlist)
-      words = File.readlines(japanese_wordlist) \
-                             .map {|line| line.strip} .uniq
+    @autoadd_base = datafile "autoadd-"
+  end
+
+  def initialize_wordlist(params)
+    lang = params[:lang]
+    addlang = params[:addlang]
+    autoadd = @autoadd_base + addlang.to_s
+    if Wordlist.exist?(@bot, lang)
+      # wordlists are assumed to be UTF-8, but we need to strip the BOM, if present
+      words = Wordlist.get(@bot, lang)
+      if addlang and File.exist?(autoadd)
+        word += File.readlines(autoadd).map {|line| line.sub("\xef\xbb\xbf",'').strip}
+      end
+      words.uniq!
+      words.sort!
       if(words.length >= 4) # something to guess
-        @rules[:japanese] = {
+        rules = {
             :good => /^\S+$/,
             :list => words,
             :first => words[0],
             :last => words[-1],
+            :addlang => addlang,
+            :addfile => autoadd,
             :listener => /^\S+$/
         }
-        debug "Japanese wordlist loaded, #{@rules[:japanese][:list].length} lines; first word: #{@rules[:japanese][:first]}, last word: #{@rules[:japanese][:last]}"
+        debug "#{lang} wordlist loaded, #{rules[:list].length} lines; first word: #{rules[:first]}, last word: #{rules[:last]}"
+        return rules
       end
     end
+    return false
   end
 
   def save
@@ -144,8 +187,7 @@ class AzGamePlugin < Plugin
     @registry[:wordcache] = @wordcache
   end
 
-  def listen(m)
-    return unless m.kind_of?(PrivMessage)
+  def message(m)
     return if m.channel.nil? or m.address?
     k = m.channel.downcase.to_s # to_sym?
     return unless @games.key?(k)
@@ -234,12 +276,20 @@ class AzGamePlugin < Plugin
           m.reply _("couldn't think of anything ...")
           return
         end
+        m.reply _("got it!")
+        @games[k] = AzGame.new(self, lang, @rules[lang], word)
+      elsif !@rules.has_key?(lang) and rules = initialize_wordlist(params)
+        word = random_pick_wordlist(rules)
+        if word.empty?
+          m.reply _("couldn't think of anything ...")
+          return
+        end
+        m.reply _("got it!")
+        @games[k] = AzGame.new(self, lang, rules, word)
       else
         m.reply _("I can't play A-Z in %{lang}, sorry") % {:lang => lang}
         return
       end
-      m.reply _("got it!")
-      @games[k] = AzGame.new(self, lang, @rules[lang], word)
     end
     tr = @games[k].total_tries
     # this message building code is rewritten to make translation easier
@@ -305,10 +355,10 @@ class AzGamePlugin < Plugin
       if wc[word].key?(:when)
         tr = _("%{word} learned from %{user} on %{date}") % {:word => word, :user => wc[word][:who], :date => wc[word][:when]}
       else
-        tr = _("%{word} learned from %{user}") % {:word => word, :user => wc[word][:who]} 
+        tr = _("%{word} learned from %{user}") % {:word => word, :user => wc[word][:who]}
       end
       m.reply tr
-    when :delete 
+    when :delete
       if pars.empty?
         m.reply _("provide a word")
         return
@@ -336,17 +386,12 @@ class AzGamePlugin < Plugin
     end
   end
 
-  def is_japanese?(word)
-    @rules[:japanese][:list].include?(word)
-  end
-
   # return integer between min and max, inclusive
   def rand_between(min, max)
     rand(max - min + 1) + min
   end
 
-  def random_pick_japanese(min=nil, max=nil)
-    rules = @rules[:japanese]
+  def random_pick_wordlist(rules, min=nil, max=nil)
     min = rules[:first] if min.nil_or_empty?
     max = rules[:last]  if max.nil_or_empty?
     debug "Randomly picking word between #{min} and #{max}"
@@ -515,6 +560,7 @@ class AzGamePlugin < Plugin
         debug "getting random word from dictionary, matching #{random}"
         p = @bot.httputil.get(rules[:url] % CGI.escape(random))
         debug p
+        raise 'unable to get search results' if not p.match /id="fullsearchresults"/i
         lemmi = Array.new
         good = rules[:good]
         # We look for a lemma composed by a single word and of length at least two
@@ -553,7 +599,14 @@ class AzGamePlugin < Plugin
     when 'play'
       return _("az => start a game if none is running, show the current word range otherwise; you can say 'az <language>' if you want to play in a language different from the current bot default")
     end
-    return _("az topics: play, rules, cancel, manage, check")
+    langs = @rules.keys
+    wls = Wordlist.list(@bot)
+    return [
+      _("az topics: play, rules, cancel, manage, check"),
+      _("available languages: %{langs}") % { :langs => langs.join(", ") },
+      wls.empty? ? nil : _("available wordlists: %{wls}") % { :wls => wls.join(", ") },
+    ].compact.join(". ")
+
   end
 
 end
@@ -562,5 +615,5 @@ plugin = AzGamePlugin.new
 plugin.map 'az [:lang] word :cmd *params', :action=>'wordlist', :defaults => { :lang => nil, :cmd => 'count', :params => [] }, :auth_path => '!az::edit!'
 plugin.map 'az cancel', :action=>'stop_game', :private => false
 plugin.map 'az check :word', :action => 'manual_word_check', :private => false
-plugin.map 'az [play] [:lang]', :action=>'start_game', :private => false, :defaults => { :lang => nil }
+plugin.map 'az [play] [:lang] [autoadd :addlang]', :action=>'start_game', :private => false, :defaults => { :lang => nil, :addlang => nil }