# Wrapper for Controller, adding user commands to modify the score, etc. # This class can function both as a command-line program and # as an IRC bot when it is loaded by the RedTurnip IRC bot framework. begin require 'controller' # for when we start from the command line rescue LoadError require 'mod/bot/controller' # for when we start from RedTurnip end class ControlBot def initialize print "Hello\n" @agent = Controller.new @THRESHHOLD = 0 @MAX_RESPONSE = 10000 @MY_NAME = "(?i)#{$irc_nickname}" #if @MY_NAME == "(?i)" then @MY_NAME = "(?i)controlbot" end if @MY_NAME == "(?i)" then @MY_NAME = "(?i)trane" end @agent.MY_NAME = @MY_NAME @DEBUG = 0 @agent.DEBUG = @DEBUG @DELAY = 2.0 @agent.DELAY = @DELAY @SLEEP = 1.0 @agent.SLEEP = @SLEEP @rules = [] @rules.push("if response =~ /default response/i; response = '...'; score = 2; end") @SAFE_LEVEL = "low" @Low_safe_level_words = ["low", "default", "0", "off"] @High_safe_level_words = ["high", "on", "1"] end def getResponse(input) input = input.to_s print 'INPUT==' + input + "\n" unless @DEBUG == 0 # Add post-processing code. if input =~ /^#{@MY_NAME} add (.*) to PostProc/ return "That feature is disabled." # for safety =begin pp = PostProc.create begin pp.create_method(pp.getNewName, &eval("proc{#{$1}}")) return $1," added to PostProc.\n" rescue SyntaxError => boom return "Eep! Syntax error: " + boom end =end end # Set threshhold. if input =~ /^what is your name?/ name = @MY_NAME.gsub(/\(\?i\)/, '') return name end if input =~ /^#{@MY_NAME}[:,!]* (quiet|be quiet|stfu|shut.*up)/ @THRESHHOLD = @THRESHHOLD + 1 return "My threshhold is now " << @THRESHHOLD.to_s end if input =~ /^#{@MY_NAME}[:,!]* (speak.*up|loud|louder|i can't hear you)/ @THRESHHOLD = @THRESHHOLD - 1 return "My threshhold is now " << @THRESHHOLD.to_s end # Return threshhold if input =~ /^#{@MY_NAME}[:,!]* what is your (threshhold|threshold|volume)/ or input =~ /^#{@MY_NAME}[:,!]* (threshold|threshhold|volume)/ return "My threshhold is currently " << @THRESHHOLD.to_s end # Provide help message. if input =~ /^#{@MY_NAME}[:,!]* help/ return "I act as a traffic control among agents." end # trap restart case input when /^#{@MY_NAME}[:,!]* restart/, /^restart/ return "That command is disabled." # for safety end # Set DEBUG level case input when /^#{@MY_NAME}[:,!]*.*on ?(?:the )?debug(?: mode)?/i, /^#{@MY_NAME}[:,!]*.*debug(?: mode)? on/i @DEBUG = 1; @agent.DEBUG = 1; return "I have turned on debug output." when /^#{@MY_NAME}[:,!]*.*(?:off )?(?:the )?debug(?: mode)?(?: off)?/i @DEBUG = 0; @agent.DEBUG = 0; return "I have turned debug output off." end # Set DELAY case input when /^#{@MY_NAME}[:,!]*.*(?:the )?delay(?: to) (\d+.?\d+)/i @DELAY = $1; @agent.DELAY = $1; return "I have set the delay to #{$1}." when /^#{@MY_NAME}[:,!]*.*\bwhat.*(?:the |your )?delay/i return "The delay is #{@DELAY}." end # Set SLEEP case input when /^#{@MY_NAME}[:,!]*.*\bwhat.*(?:the |your )?sleep/i return "The sleep value is set to #{@SLEEP}." when /^#{@MY_NAME}[:,!]*.*(?:the )?sleep(?: to) (\d+.?\d+)/i begin @SLEEP = $1 rescue @SLEEP = 2 end @agent.SLEEP = @SLEEP; return "I have set the sleep value to #{@SLEEP}." end # add new if-then rules to post-process responses case input when /^#{@MY_NAME}[:,!]* (if .*? =~ .*?(?: then|;) .*)$/ return add_if_rule($1) end # show the rules case input when /^#{@MY_NAME}[:,!]*.* show.* rules/ return show_rules[0] end # delete a rule case input when /^#{@MY_NAME}[:,!]*.* delete.* rule.* (\d+)/ return delete_rule($1.to_i) end # set safe level case input when /^#{@MY_NAME}[:,! ]*.*turn (.*) (?:the )safe(?:ty)? level/, /^#{@MY_NAME}[:,! ]*(?:set )?.*safe(?:ty)? level (?:to )?(.*)/ return set_safe_level($1) end # get safe level case input when /^#{@MY_NAME}[:,! ]*what is.*?safe(?:ty)? level/ return get_safe_level end # Get the agent's response. begin r, s = @agent.getResponse(input) rescue Errno::EBADF, DRb::DRbConnError r, s = ['Default response', 0] end if s == nil then s = 1 end r, s = apply_if_rules(r, s, input) #begin; s = @agent.getScore; rescue NoMethodError; s = 1; end if r.to_s.size > @MAX_RESPONSE r = r[0..@MAX_RESPONSE] end if @DEBUG > 0 puts "\n[controlbot] score==" << s.to_s << "; threshhold==" << @THRESHHOLD.to_s end if s > @THRESHHOLD return postprocess(r) else puts "r==#{postprocess(r)}" unless @DEBUG == 0 end return "" end def postprocess input r = input return r end # add an if-then rule def add_if_rule(rule = '') if rule == '' then return "No rule found." end if @SAFE_LEVEL =~ /#{@Low_safe_level_words.join('|')}$/ @rules.push(rule) return "Okay I have added #{rule}." end return "I can't add any if rules because my safe level is #{@SAFE_LEVEL}." end # apply if-then rules def apply_if_rules(response, score, input) @rules.each { |rule| #puts "rule==#{rule}; response==#{response}; score==#{score}" begin eval(rule) rescue SyntaxError; puts "Can't apply rule: #{rule}"; next; end } #puts "returning: response==#{response}; score==#{score}" return [response, score] end # return the rules def show_rules return [@rules.join("\n"), 4] end # delete a rule by its index def delete_rule(i) if i < 1 or i > @rules.size return "The rules go from 1 to #{@rules.size}." end rule = @rules[i-1] @rules.delete_at(i-1) return "Okay, \"#{rule}\" deleted." end def set_safe_level(level) case level when /\b#{@Low_safe_level_words.join('|')}\b/ @SAFE_LEVEL = "off" return "Okay I have turned off the safe level." when /\b#{@High_safe_level_words.join('|')}\b/ @SAFE_LEVEL = "on" return "Okay I have turned the safe level on." end return "I don't understand #{level}." end def get_safe_level return "My safe level is set to #{@SAFE_LEVEL}." end # Respond to natural language method calls. def method_missing input return getResponse(input.to_s) end end class PostProc private_class_method :new @@postproc = nil @@count = 0 def PostProc.create @@postproc = new unless @@postproc @@postproc end def process(input) response = input.to_s self.methods.each { |method| if method =~ /^newMethod/ begin response = self.send(method, input) rescue NoMethodError => boom return "Eeep! Error!: " + boom end end } return response end def getNewName @@count = @@count + 1 return "newMethod" << @@count.to_s end def create_method(name, &block) self.class.send(:define_method, name, &block) end end if $0 == __FILE__ b = ControlBot.new pp = PostProc.create print("\n> "); $stdout.flush quitwords = [":q", "quit", "exit", "bye"] while (line = gets) !~ /^(#{quitwords.join('|')})+$/ #and line !~ /^$/ print "\n" + pp.process(b.send(line)) + "\n" print("\n> "); $stdout.flush end puts "Bye!" end