]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - data/rbot/plugins/games/shiritori.rb
azgame plugin: whitespace cleanup
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / games / shiritori.rb
index f13afeb83ca93caa123ebbb6787d496c1a54a62e..71016e5434ecbde960aa44197641f04c31853fe8 100644 (file)
 # playing several games, each per channel. A game can be turn-based, where only new
 # players can interrupt a turn to join, or a free mode where anyone can speak at any
 # time.
+#
+# In Japanese mode, if present, the plugin can use normalize-japanese 
+# <http://neruchan.mine.nu:60880/normalize-japanese.rb> to allow
+# katakana words be used like hiragana.
 # 
 # TODO
 # * a system to describe settings, so they can be displayed, changed and saved
@@ -45,7 +49,7 @@ class WordlistDictionary < Dictionary
   def initialize(words)
     super()
     @words = words
-    debug "Created dictionary with #{@words.length} words"
+    debug "Created dictionary with #{@words.length} words"
   end
   
     # whether string s is a word
@@ -120,7 +124,7 @@ class Shiritori
     # TODO optionally allow used words
     # TODO ruby2 unicode
     if len(s) < @overlap_lengths.min || !@dictionary.has_word?(s)
-      debug "#{s} is too short or not in dictionary"
+      debug "#{s} is too short or not in dictionary"
       :ignore
     elsif @used_words.empty?
       if !@check_continuable || continuable_from?(s)
@@ -171,6 +175,10 @@ class ShiritoriGame
                                       @ruleset[:allow_reuse])
   end
   
+  def say(s)
+     @say.call(s)
+  end
+
   # Whether the players must take turns
   # * when there is only one player, turns are not enforced
   # * when time_limit > 0, new players can join at any time, but existing players must
@@ -195,13 +203,17 @@ class ShiritoriGame
   
   # announce the current word, and player if take_turns?
   def announce
-    if take_turns?
-      @say.call "#{current_player}, it's your turn. #{previous_word} -> #{current_word}"
+    say(if take_turns?
+      _("%{current_player}, it's your turn. %{previous_word} -> %{current_word}") %
+       { :current_player => current_player, :previous_word => previous_word,
+         :current_word => current_word }
     elsif @players.empty?
-      @say.call "No one has given the first word yet. Say the first word to start."
+      _("No one has given the first word yet. Say the first word to start.")
     else
-      @say.call "Poor #{current_player} is playing alone! Anyone care to join? #{previous_word} -> #{current_word}"
-    end
+      _("Poor %{current_player} is playing alone! Anyone care to join? %{previous_word} -> %{current_word}") %
+      { :current_player => current_player, :previous_word => previous_word,
+        :current_word => current_word }
+    end)
   end
   # create/reschedule timer
   def restart_timer
@@ -229,18 +241,21 @@ class ShiritoriGame
   # handle when turn time limit goes out
   def time_out
     if @ruleset[:lose_when_timeout]
-      @say.call "#{current_player} took too long and is out of the game. Try again next game!"
+      say _("%{player} took too long and is out of the game. Try again next game!") %
+      { :player => current_player }
       if @players.length == 2 
         # 2 players before, and one should remain now
         # since the game is ending, save the trouble of removing and booting the player
-        @say.call "#{@players[1]} is the last remaining player and the winner! Congratulations!"
+        say _("%{player} is the last remaining player and the winner! Congratulations!") %
+          {:player => @players.last}
         die
       else
         @booted_players << @players.shift
         announce
       end
     else
-      @say.call "#{current_player} took too long and skipped the turn."
+      say _("%{player} took too long and skipped the turn.") %
+          {:player => current_player}
       next_player
     end
   end
@@ -267,28 +282,32 @@ class ShiritoriGame
     case @game.process @ruleset[:normalize].call(message)
     when :start
       @players << speaker
-      m.reply "#{speaker} has given the first word: #{current_word}"
+      m.reply _("%{player} has given the first word: %{word}") %
+              {:player => speaker, :word => current_word}
     when :next
       if !@players.include?(speaker)
         # A new player
         @players.unshift speaker
-        m.reply "Welcome to shiritori, #{speaker}."
+        m.reply _("Welcome to shiritori, %{player}.") %
+                {:player => speaker}
       end
       next_player
     when :used
-      m.reply "The word #{message} has been used. Retry from #{current_word}"
+      m.reply _("The word %{used_word} has been used. Retry from %{word}") %
+              {:used_word => message, :word => current_word}
     when :end
       # TODO respect shiritori.end_when_uncontinuable setting
       if @ruleset[:end_when_uncontinuable]
-        m.reply "It's impossible to continue the chain from #{message}. The game has ended. Thanks a lot, #{speaker}! :("
+        m.reply _("It's impossible to continue the chain from %{word}. The game has ended. Thanks a lot, %{player}! :(") %
+                {:word => message, :player => speaker}
         die
       else
-        m.reply "It's impossible to continue the chain from #{message}. Retry from #{current_word}"
+        m.reply _("It's impossible to continue the chain from %{bad_word}. Retry from %{word}") % {:bad_word => message, :word => current_word}
       end
     when :start_end
       # when the first word is uncontinuable, the game doesn't stop, as presumably
       # someone wanted to play
-      m.reply "It's impossible to continue the chain from #{message}. Start with another word."
+      m.reply _("It's impossible to continue the chain from %{word}. Start with another word.") % {:word => message}
     end
   end
   
@@ -309,7 +328,8 @@ end
 # shiritori plugin for rbot
 class ShiritoriPlugin < Plugin
   def help(plugin, topic="")
-    "A game in which each player must continue the previous player's word, by using its last one or few characters/letters of the word to start a new word. 'shiritori <ruleset>' => Play shiritori with a set of rules. Available rulesets: #{@rulesets.keys.join ', '}. 'shiritori stop' => Stop the current shiritori game."
+    _("A game in which each player must continue the previous player's word, by using its last one or few characters/letters of the word to start a new word. 'shiritori <ruleset>' => Play shiritori with a set of rules. Available rulesets: %{rulesets}. 'shiritori stop' => Stop the current shiritori game.") %
+      {:rulesets => @rulesets.keys.join(', ')}
   end
   
   def initialize()
@@ -351,41 +371,58 @@ class ShiritoriPlugin < Plugin
         :listen => /\A\S+\Z/u,
         :overlap_lengths => 1..4,
         :desc => 'Use Japanese words in hiragana; 1-4 kana at the beginning of the next word must overlap with those at the end of the previous word.',
-        # Optionally use a module to normalize Japanese words, enabling input in multiple writing systems
+        :normalize =>
+          begin
+            require 'normalize-japanese'
+            lambda {|w| w.to_hiragana}
+          rescue LoadError
+            lambda {|w| w}
+          end
       }
     }
-    @rulesets.each_value do |ruleset|
-      # set default values for each rule to default_ruleset's values
-      ruleset.replace @default_ruleset.merge(ruleset)
-      unless ruleset.has_key?(:words)
-        if ruleset.has_key?(:wordlist_file)
-          # TODO read words only when rule is used
-          # read words separated by newlines from file
+  end
+
+  def load_ruleset(ruleset_name)
+    # set default values for each rule to default_ruleset's values
+    ruleset = @rulesets[ruleset_name].dup
+    ruleset.replace @default_ruleset.merge(ruleset)
+    unless ruleset.has_key?(:words)
+      if ruleset.has_key?(:wordlist_file)
+        begin
           ruleset[:words] =
             File.new("#{@bot.botclass}/shiritori/#{ruleset[:wordlist_file]}").grep(
               ruleset[:listen]) {|l| ruleset[:normalize].call l.chomp}
-        else
-          raise NotImplementedError
+        rescue
+          raise "unable to load word list"
         end
+      else
+        raise NotImplementedError, "ruleset not implemented (properly)"
       end
     end
+    return ruleset
   end
   
   # start shiritori in a channel
   def cmd_shiritori(m, params)
     if @games.has_key?( m.channel )
-      m.reply "Already playing shiritori here"
+      m.reply _("Already playing shiritori here")
       @games[m.channel].announce
     else
-      if @rulesets.has_key? params[:ruleset]
-        @games[m.channel] = ShiritoriGame.new(
-          m.channel, @rulesets[params[:ruleset]],
-          @bot.timer,
-          lambda {|msg| m.reply msg},
-          lambda {remove_game m.channel} )
-        m.reply "Shiritori has started. Please say the first word"
+      ruleset = params[:ruleset].downcase
+      if @rulesets.has_key? ruleset
+        begin
+          @games[m.channel] = ShiritoriGame.new(
+            m.channel, load_ruleset(ruleset),
+            @bot.timer,
+            lambda {|msg| m.reply msg},
+            lambda {remove_game m.channel} )
+          m.reply _("Shiritori has started. Please say the first word")
+        rescue => e
+          m.reply _("couldn't start %{ruleset} shiritori: %{error}") %
+                  {:ruleset => ruleset, :error => e}
+        end
       else
-        m.reply "There is no defined ruleset named #{params[:ruleset]}"
+        m.reply _("There is no ruleset named %{ruleset}") % {:ruleset => ruleset}
       end
     end
   end
@@ -403,10 +440,10 @@ class ShiritoriPlugin < Plugin
     if @games.has_key? m.channel
       # TODO display statistics
       @games[m.channel].die
-      m.reply "Shiritori has stopped. Hope you had fun!"
+      m.reply _("Shiritori has stopped. Hope you had fun!")
     else
       # TODO display statistics
-      m.reply "No game to stop here, because no game is being played."
+      m.reply _("No game to stop here, because no game is being played.")
     end
   end
   
@@ -427,6 +464,7 @@ class ShiritoriPlugin < Plugin
   def cleanup
     @games.each_key {|g| g.die}
     @games.clear
+    super
   end
 end