################################################################################ # gagent.rb implements a natural language interface to graph.rb. # (see subbot.org/gagent/graph.rb). # # To run: put subbot.org/gagent/graph.rb and subbot.org/gagent/gagent-api.yaml # in the same directory as this file. Then: # # C:\trane\gagent>ruby gagent.rb # I have loaded C:/trane/gagent/gagent-api.yaml. # # > All metals are solid. # Okay, All metals are solid. # # > Mercury is a metal. # Okay, Mercury is a metal. # # > a metal is all metals # Okay, a metal is all metals. # # > is Mercury solid? # Yes, Mercury is solid. # # > Mercury is not solid. # That contradicts the information I have that Mercury is solid because: # mercury is a metal, and a metal is all metals, and all metals are solid. # # > forget "all metals are solid." # Okay I have forgotten all metals are solid. # # > is Mercury solid? # I have no knowledge that Mercury is solid. # # > ################################################################################ require 'yaml' require 'graph' require 'drb' $Quitwords = [':q', 'quit', 'exit', 'bye'] class MyAgent attr_accessor :plurals, :singulars, :verbs, :verb_forms, :names def initialize(args=Array.new) @workingDir = File.expand_path(File.dirname(__FILE__)) @filename = @workingDir + "/gagent-api.yaml" @gagent_state = @workingDir + "/memory/gagent_state.txt" unless load_message = load_synonyms @patterns = [ [/^(.*?) is a synonym for (.*)/, :add_synonym], [/^save syn/, :save_synonyms], [/^load syn/, :load_synonyms], [/^add pattern (.*), (.*)/, :add_pattern], [/^>(.*)/, :defining_method], [/^restart/, :restart], [/^(#{$Quitwords.join('|')})$/, :quit] ] save_synonyms # creates patterns.yaml on first use. else puts load_message end @method_def = '' @graph = Graph.new @plurals = Array.new @plurals << "you"; @plurals << "I" @singulars = Array.new @verbs = [ "is", "=", "are", "has", "have", "eat", "eats", "is had by", "are had by", "student teach", "student teaches", "contains" ] @verb_forms = { "is" => "are", "has" => "have", "eats" => "eat", "is had by" => "are had by", "student teaches" => "student teach", "contains" => "contain" } @names = Array.new @save = false @already_asked = false @quit_question_state = '' @logging = false # not being used; $logger is called from client DRb.start_service() @monty = DRbObject.new(nil, 'druby://localhost:9070') @those = nil # @last_file_read must be the last line in initialize @last_file_read = "highest.txt" end def def_method method_def file = IO.read(__FILE__) return "Doesn't have 'end # class'" unless file =~ /(.*)end # class(.*)if \$0 == __FILE__(.*)/m grp1 = $1.to_s grp2 = $2.to_s grp3 = $3.to_s new_filename = get_new_filename File.open(new_filename, "w+") { |f| f.puts grp1 + method_def + "\n\nend # class\n\nif $0 == __FILE__" + grp3 } @patterns.push( [@new_regexp, @new_symbol] ) save_synonyms puts "#{method_def} added." MyAgent.class_eval(method_def) end # If this file has a '.' + a number before the '.rb' extension # (i.e. foo.0.rb), increment the number (i.e. return foo.1.rb). # Otherwise return the name of this file unchanged. def get_new_filename old_filename = __FILE__ if old_filename =~ /(.*)\.(\d+)\.rb$/ incr = $2.to_i + 1 return new_filename = $1.to_s + "." + incr.to_s + ".rb" end return old_filename # Dangerous! end # Match input against each regexp pattern in @patterns; # if there's a match, call the method associated with the pattern. def getResponse input r = "Default response." # Strip names from input (don't strip if input is "NAME is not a name") @names.each { |name| escaped_name = Regexp.escape(name) if input =~ /^#{escaped_name}[:, ]*(.*)/ new_input = $1.strip break if new_input =~ /^is not a name/ input = new_input break end } #puts "input==#{input}" @patterns.each { |pattern| if input =~ pattern[0] return [self.send(pattern[1], pattern[0], input), 2] rescue return r end } return r end def load_synonyms(pattern=nil, input=nil) if File.exist?(@filename) @patterns = YAML.load_file(@filename) return "I have loaded #{@filename}." end return false end def save_synonyms(pattern=nil, input=nil) r = "Eep! error saving synonyms! " begin File.open(@filename, 'w') do |out| YAML.dump(@patterns, out) end return "Okay I have saved the synonyms to disk." rescue => error return r << error end end def add_synonym(pattern, input) return "Problem matching pattern." unless input =~ pattern #grp1 = %r{^#{$1}} grp1 = %r{(?i-mx:^#{$1})} #grp2 = %r{^#{$2}} grp2 = %r{(?i-mx:^#{$2})} method ='' @patterns.each { |p| #puts "p[0]==#{p[0]}; p[0].class==#{p[0].class}; grp2==#{grp2}; grp2.class==#{grp2.class}" if p[0].to_s == grp2.to_s method = p[1] break end } return unless method.to_s != nil @patterns.push( [grp1, method] ) save_synonyms return "Okay, #{grp1} has been added, and will now call #{method}." end def add_pattern(pattern=nil, input=nil) if input =~ pattern @new_regexp = $1 @new_symbol = $2 @new_regexp.gsub!(/\//, '') new_re = %r{#{@new_regexp}} # Make the regexp case insensitive. new_re_s = new_re.to_s if new_re_s =~ /(-mix)/ new_re_s = $~.pre_match << "i-mx" << $~.post_match end @new_regexp = %r{#{new_re_s}} #puts "@new_regexp==#{@new_regexp}" method_def = " def #{@new_symbol}(pattern=nil, input=nil)\n return \"#\{input} doesn't match #\{pattern}\" unless input =~ pattern\n return 'Default response from " + @new_symbol + "'\n end # method_def" return def_method(method_def) else return "#{input} doesn't match #{pattern}." end end def defining_method(pattern=nil, input=nil) if input =~ pattern @method_def << "\n " << $1.to_s if @method_def =~ /end # method_def/ return def_method(@method_def) end return '' else return "#{input} doesn't match #{pattern}." end end def quit(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern if @save then return 'quit' end if @already_asked then return 'quit' end #if @already_asked then return end @already_asked = true @quit_question_state = "waiting for yes/no" return "Do you wish to save the graph to graph.yaml?" end def no(pattern=nil, input=nil) #puts "@quit_question_state==#{@quit_question_state}" return "#{input} doesn't match #{pattern}" unless input =~ pattern if @quit_question_state == "waiting for yes/no" @quit_question_state = 'answered' return 'quit' end return '' end def yes(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern if @quit_question_state == "waiting for yes/no" @quit_question_state = 'answered' self.send("save graph") return 'quit' end return '' end def method_missing input, *rest return getResponse(input.to_s) end # Strips delimiters. def process str str.strip! str.sub!(/\?$/, '') str.sub!(/^\[/, '') str.sub!(/\]$/, '') str.sub!(/^(?:"|')/, '') str.sub!(/(?:"|')$/, '') str.sub!(/\.$/, '') str.sub!(/;$/, '') str.sub!(/,$/, '') str.sub!(/!$/, '') str.sub!(/\?$/, '') str.sub!(/\"/, '') # strips double quotes from inside the string return str end def a_r_b!(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 b = process $2 @graph.a_r_b!(a.downcase, "is", b.downcase) if @save then @graph.save end be = "is"; if isPlural?(a) then be = "are" end return "Okay, #{a} #{be} #{b}." end # method_def def what_is(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 be = "is"; if isPlural?(a) then be = "are" end arr = @graph.a_r_?(a.downcase, "is") if arr.empty? or arr == nil return "I don't know what #{a} #{be}." end return "#{a} #{be} #{arr.join(', ')}" end # method_def def is_a_b?(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 grp2 = process $2 if grp1 == "" or grp1 == nil then return "No" end puts "[gagent] is_a_b?: grp1==#{grp1}; grp2==#{grp2}" be = "is"; if isPlural?(grp1) then be = "are" end if grp1 == grp2 then return "Yes, #{grp1} #{be} #{grp2}." end # reflexivity if @graph.a_r_b?(grp1.downcase, "is_not", grp2.downcase) return "No, #{grp1} #{be} not #{grp2}." end if @graph.a_r_b?(grp1.downcase, "is", grp2.downcase) return "Yes, #{grp1} #{be} #{grp2}." end return "I have no knowledge that #{grp1} #{be} #{grp2}." end # method_def def restart(pattern=nil,input=nil) exec "ruby #{__FILE__}" end # method_def # why is ___ ____ def why(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 arr = @graph.shortest_path(grp1.downcase, "is", grp2.downcase) #puts arr.inspect arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } be = "is"; if isPlural?(grp1) then be = "are" end if grp1 == grp2 return "#{grp1} #{be} #{grp2} because 'is' is reflexive." end if arr2.empty?; return "I have no knowledge that #{grp1} #{be} #{grp2}" end return "#{grp1} #{be} #{grp2} because: #{arr2.join(', and ')}" end # method_def def make_verb_agree(s) begin if s =~ /(.*) (#{@verbs.join('|')}) (.*)/ a = process $1; r = process $2; b = process $3 verb = getForm(a, r) return "#{a} #{verb} #{b}" end rescue return s end return s end def getForm(a, verb = "is") if isPlural?(a) return getPlural(verb) end return verb end def getPlural(verb) @verb_forms.fetch(verb, verb) end def isPlural?(word = '') @plurals.each { |plural| if word =~ /^#{plural}$/i then return true end } if word =~ /socrates$/i; return false; end if word =~ /men$/i; return true; end @singulars.each { |singular| if word =~ /^#{singular}$/i then return false end } if word =~ /s$/i; return true; end end # "___ is not ___" def a_is_not_b(input=nil, pattern=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 s = self.send("is #{grp1} #{grp2}?")[0] if s =~ /^Yes/ s2 = self.send("why is #{grp1} #{grp2}?")[0] return "That contradicts the information I have that #{s2}." end # Here we need to store the "is not" relation in the graph, but for now: @graph.a_r_b!(grp1.downcase, "is_not", grp2.downcase) if @save then @graph.save end return "Okay, #{grp1} is not #{grp2}." end # method_def # "___ does not have ___" def a_does_not_have_b(input=nil, pattern=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 s = self.send("does #{grp1} have #{grp2}?")[0] if s =~ /^Yes/ s2 = self.send("why does #{grp1} have #{grp2}?")[0] return "That contradicts the information I have that #{s2}." end # We need to store the "does not have" relation in the graph, but for now: return "Okay" end # method_def # "remove edge ____ is ____" def remove_is_edge(input=nil, pattern=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 be = "is"; if isPlural?(grp1.downcase) then be = "are" end begin b = @graph.remove_edge(grp1.downcase, "is", grp2.downcase) if @save then @graph.save end if b return "Okay I have forgotten #{grp1} #{be} #{grp2}." end rescue => error return "Error: #{error}" end return "I can't remove #{grp1} #{be} #{grp2}." end # method_def # "remove edge ___ = ___" def remove_equals_edge(input = nil, pattern = nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 begin #b = @graph.remove_edge(grp1.downcase, "=", grp2.downcase) b = @graph.remove_edge(grp1, "=", grp2) if @save then @graph.save end if b return "Okay I have deleted #{grp1} = #{grp2}." end rescue => error return "I can't remove #{grp1} = #{grp2}. Error: #{error}" end end # method_def def remove_has_edge(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1; r = "has"; b = process $2 has = "has"; if isPlural?(a) then has = "have" end if @graph.remove_edge!(a, r, b) if @save then @graph.save end return "Okay I have forgotten #{a} #{has} #{b}." end return "I can't find #{a} #{has} #{b}..." end # method_def def print_graph(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern s = @graph.to_s arr2 = Array.new arr = s.split("\n") #puts "arr==#{arr}" arr.each { |phrase| phrase = make_verb_agree(phrase) arr2 << phrase } #return s unless s == nil or s.size == 0 return arr2.join("\n") unless arr2.empty? return "The graph is empty." end # method_def def add_to_plurals(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 @plurals.push(grp1) return "Okay I have recorded #{grp1} as a plural form." end # method_def def add_to_singulars(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 @singulars.push(grp1) return "Okay I have recorded #{grp1} as a singular form." end # method_def def save_graph(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern file = nil begin file = process $1 rescue; end puts "\n... Saving graph (this may take minutes) ..." r = @graph.save(file) #puts "HELLOOOO: r==#{r}" return "#{r}" end # method_def def load_graph(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern begin file = process $1 rescue; end return @graph.load(file) end def reset_graph(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern @graph = Graph.new(false) @save = false return "Okay, I have reset the graph." end # method_def def a_equals_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 puts "[gagent.a_equals_b] grp1==#{grp1}; grp2==#{grp2}" #@graph.a_r_b!(grp1.downcase, "=", grp2.downcase) #@graph.a_r_b!(grp2.downcase, "=", grp1.downcase) # symmetric #@graph.a_r_b!(grp1.downcase, "=", grp1.downcase) # reflexive #@graph.a_r_b!(grp2.downcase, "=", grp2.downcase) @graph.a_r_b!(grp1, "=", grp2) @graph.a_r_b!(grp2, "=", grp1) # symmetric @graph.a_r_b!(grp1, "=", grp1) # reflexive @graph.a_r_b!(grp2, "=", grp2) if @save then @graph.save end return "Okay, #{grp1} = #{grp2}." end # method_def def does_a_equal_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 puts "[gagent.does_a_equal_b] grp1==#{grp1}; grp2==#{grp2}" #if @graph.a_r_b?(grp1.downcase, "=", grp2.downcase) if @graph.a_r_b?(grp1, "=", grp2) return "Yes, #{grp1} = #{grp2}." end return "I am not certain whether #{grp1} = #{grp2}." end # method_def def why_does_a_equal_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 #arr = @graph.shortest_path(grp1.downcase, "=", grp2.downcase) arr = @graph.shortest_path(grp1, "=", grp2) if arr.empty?; return "I have no knowledge that #{grp1} = #{grp2}." end return "#{grp1} = #{grp2} because: #{arr.join(', and ')}" end # method_def def what_does_a_equal(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 puts "[gagent.what_does_a_equal] grp1==#{grp1}" #arr = @graph.a_r_?(grp1.downcase, "=") arr = @graph.a_r_?(grp1, "=") puts "arr==#{arr}" return "#{grp1} = #{arr.join(', and ')}" end # method_def # "all birds have wings" def a_has_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1; r = process $2; b = process $3 r2 = r if r == "have" then r2 = "has" end @graph.a_r_b!(a.downcase, r2.downcase, b.downcase) if @save then @graph.save end return "Okay, #{a} #{r} #{b}." end # method_def def what_does_a_have(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; a = process $2 is_array = @graph.a_r_?(a.downcase, "is") has_array = Array.new is_array.each { |e| has_array.concat(@graph.a_r_?(e, "has")) } ar = @graph.a_r_?(a.downcase, "has") ar.concat(has_array) has = "has"; if isPlural?(a); has = "have"; end if a =~ /^i$/i then a = "you"; has = "have" end return "#{a} #{has}: #{ar.join(', and ')}" end # method_def def does_a_have_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; a = process $2; b = process $3 r = ["has","is"] bool = @graph.a_r_b?(a.downcase, r, b.downcase) has = "has"; if isPlural?(a) then has = "have" end if a =~ /^i$/i then a = "you"; has = "have" end if bool then return "Yes, #{a} #{has} #{b}" end return "I have nothing to indicate that #{a} #{has} #{b}." end # method_def def why_does_a_have_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 arr = @graph.shortest_path(grp1.downcase, ["has", "is"], grp2.downcase) arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } has = "has"; if isPlural?(grp1) then has = "have" end if grp1 =~ /^i$/i then grp1 = "You"; has = "have"; end if arr2.empty? return "I have no knowledge that #{grp1} #{has} #{grp2}." end return "#{grp1} #{has} #{grp2} because: #{arr2.join(', and ')}" end # method_def def a_may_make_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1; b = process $2 r = "may make" @graph.a_r_b!(a.downcase, r, b.downcase) if @save then @graph.save end return "Okay, #{a} #{r} #{b}." end # method_def def can_a_make_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1; b = process $2 bool = @graph.a_r_b?(a.downcase, ["may make", "is"], b.downcase) if bool then return "Yes, #{a} may make #{b}." end return "I have no knowledge that #{a} may make #{b}." end # method_def def a_is_part_of_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern b = process $1; a = process $2 has = "has"; if isPlural?(a) then has = "have" end @graph.a_r_b!(a.downcase, "has", b.downcase) if @save then @graph.save end return "Okay, #{a} #{has} #{b.downcase}." end # method_def def a_flies(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 fly = "flies"; if isPlural?(a) then fly = "fly" end @graph.a_r_b!(a.downcase, "flies", ' ') if @save then @graph.save end return "Okay, #{a} #{fly}." end # method_def def can_a_fly(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 if @graph.a_r_b?(a.downcase, ["flies", "is"] , ' ') then return "Yes, #{a} can fly." end return "No, #{a} can't fly." end # method_def def why_does_a_fly(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 arr = @graph.shortest_path(grp1.downcase, ["flies", "is"], ' ') arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } fly = "flies"; if isPlural?(grp1) then fly = "fly" end if grp1 =~ /^i$/i then grp1 = "You"; fly = "fly"; end if arr2.empty? return "I have no knowledge that #{grp1} #{fly}." end return "#{grp1} #{fly} because: #{arr2.join(', and ')}" end # method_def def begin_log(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern file = process $1 file = @workingDir + "/log.txt" unless file != nil and file != '' @logging = true $logger = File.open(file, "w") t = Time.now; y = t.year; m = t.month; d = t.day; h= t.hour; min = t.min; s = t.sec mins = sprintf("%02d", min) secs = sprintf("%02d", s) time = "#{y}/#{m}/#{d} #{h}:#{mins}:#{secs}" return "Okay I have started logging to #{file} at #{time}" end # method_def def end_log(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern t = Time.now; y = t.year; m = t.month; d = t.day; h= t.hour; min = t.min; s = t.sec mins = sprintf("%02d", min) secs = sprintf("%02d", s) time = "#{y}/#{m}/#{d} #{h}:#{mins}:#{secs}" r = "Okay I have stopped logging at #{time}." $logger.puts(r); $logger.close; $logger == nil @logging = false return r end # method_def def how_many_facts(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern begin; a = @graph.vertex_hash.keys; rescue => boom; puts boom; end puts 'hello' n = a.size vertices = "vertices"; if n == 1 then vertices = "vertex" end return "I have #{n} #{vertices} stored in my database." end # method_def def add_name(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern #grp1 = process $1 grp1 = $1.strip grp1.sub!(/^(?:"|')/, '') grp1.sub!(/(?:"|')$/, '') grp1.sub!(/(?:,)$/, '') @names.push(grp1) return "Okay, #{grp1} is a name." end # method_def def what_are_names(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern return @names.join(", ") end # method_def def set_save_mode_off(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern @save = false return "Okay I have turned off save mode." end # method_def def set_save_mode_on(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern @save = true return "Okay I have turned on save mode." end # method_def def x_is_not_a_name(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern name_to_del = $1 result = @names.delete(name_to_del) if result == nil return "I can't find #{name_to_del} among the names I have stored." end return "Okay, I have deleted #{result}." end # method_def def is_x_a_name(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern name = $1 if @names.include?(name) return "Yes, #{name} is a name." end return "No, #{name} is not a name." end # method_def alias is_x_a_name? is_x_a_name def what_is_save_mode(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern save_mode = "on"; save_mode = "off" unless @save return "The save mode is #{save_mode}." end # method_def def read_file(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern file = process $1 if file !~ /^highest.txt/ if file !~ /^openmind(\\|\/)/ then file = "openmind/" + file end end turn_save_back_on = false if @save; @save = false; turn_save_back_on = true; end count = 0 IO.foreach(file) { |assertion| if assertion =~ /^#/ then next end if assertion.strip == '' then next end count += 1 puts "#{count}: " + assertion self.send(assertion) } if turn_save_back_on; self.send("save graph"); @save = true; end @last_file_read = file write_last_file(file) #unless @save == false plural = 's'; if count == 1 then plural = ''; end return "Okay, #{file} read; #{count} assertion#{plural}." end # method_def def write_last_file(file) orig = IO.read(__FILE__) orig =~ /(.*?)\@last_file_read \= (.*?)( end.*)/m grp1 = $1; grp2 = $2; grp3 = $3 new_filename = get_new_filename File.open(new_filename, "w+") { |f| f.puts grp1 + "@last_file_read = \"" + file + "\"\n" + grp3 } end def what_was_last_file_read(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern return "The last file I read was: #{@last_file_read}." end # method_def def you_are_likely_to_find(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern two_phrases = process $1 # now use link or montylingua to separate the two phrases return "Not yet implemented." end # method_def def how_many_factoids(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern hash = @graph.vertex_hash count = 0 keys = hash.keys keys.each { |key| values = @graph.vertex_hash.fetch(key) values.each { |value| count += 1 #puts "#{count}: #{value}" } } return "I know #{count} factoids." end # method_def def is_blank_true(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 subject = @monty.send("subject: #{grp1}") verb = @monty.send("verb: #{grp1}") object = @monty.send("object: #{grp1}") puts "subject==#{subject}; verb==#{verb}; object==#{object}" if @graph.a_r_b?(subject.downcase, "recommends", object.downcase) return "Yes, #{grp1}." else return "I have no knowledge that #{grp1}." end end # method_def def does_a_recommend_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 s = 's'; if isPlural?(grp1) then s = ''; end puts "a==#{grp1}; b==#{grp2}" if @graph.a_r_b?(grp1.downcase, "recommends", grp2.downcase) return "Yes, #{grp1} recommend#{s} #{grp2}." else return "I have no knowledge that #{grp1} recommend#{s} #{grp2}." end end def a_recommends_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 @graph.a_r_b!(grp1.downcase, "recommends", grp2.downcase) if @save then @graph.save end return "Okay, #{grp1} recommends #{grp2}" end # method_def def x_eat_y(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 @graph.a_r_b!(grp1.downcase, "eat", grp2.downcase) if @save then @graph.save end return "Okay, #{grp1} eat #{grp2}" end # method_def def does_x_eat_y(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 s = 's'; if isPlural?(grp1) then s = ''; end puts "x==#{grp1}; y==#{grp2}" if @graph.a_r_b?(grp1.downcase, "eat", grp2.downcase) return "Yes, #{grp1} eat#{s} #{grp2}." else return "I have no knowledge that #{grp1} eat#{s} #{grp2}." end end # method_def def why_does_a_eat_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 arr = @graph.shortest_path(grp1.downcase, ["eat"], grp2.downcase) arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } eats = "eats"; if isPlural?(grp1) then eats = "eat" end if grp1 =~ /^i$/i then grp1 = "You"; eats = "eat"; end if arr2.empty? return "I have no knowledge that #{grp1} #{eats} #{grp2}." end return "#{grp1} #{eats} #{grp2} because: #{arr2.join(', and ')}" end # method_def def what_do_x_eat(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 eat = "eats"; if isPlural?(grp1) then eat = "eat" end #arr = @graph.a_r_?(grp1.downcase, ["eat","is"]) arr = @graph.a_r_?(grp1.downcase, ["eat"]) if arr.empty? or arr == nil return "I don't know what #{grp1} #{eat}." end return "#{grp1} #{eat} #{arr.join(', ')}" end # method_def def what_eat_x(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 arr = @graph.what_r_b?("eat", grp1.downcase) #puts "arr==#{arr.inspect}" if arr.empty? or arr == nil return "I don't know what eats #{grp1}" end return "#{arr.join(', ')} eat #{grp1}." end # method_def def x_student_teach(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 es = "es"; if isPlural?(grp1) then es = "" end @graph.a_r_b!(grp1.downcase, "student teach", "") return "Okay, #{grp1} student teach#{es}." end # method_def def do_x_student_teach(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 es = "es"; if isPlural?(grp1) then es = "" end if @graph.a_r_b?(grp1.downcase, ["student teach", "is had by", "is"], "") return "Yes, #{grp1} student teach#{es}." end return "I have no knowledge that #{grp1} student teach#{es}." end # method_def def why_do_x_student_teach(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 es = "es"; if isPlural?(grp1) then es = "" end arr = @graph.shortest_path(grp1.downcase, ["student teach", "is had by", "is"], "") arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } if arr2.size > 0 return "#{grp1} student teach#{es} because: #{arr2.join(', and ')}." end return "I have no knowledge that #{grp1} student teach#{es}." end # method_def def a_is_had_by_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 is = "is"; if isPlural?(grp1) then is = "are" end @graph.a_r_b!(grp1.downcase, "is had by", grp2.downcase) return "Okay, #{grp1} #{is} had by #{grp2}." end # method_def def a_contains_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 puts "[gagent.a_contains_b] grp1==#{grp1}; grp2==#{grp2}" @graph.a_r_b!(grp1.downcase, "contains", grp2.downcase) contains = "contains"; if isPlural?(grp1) then contains = "contain"; end return "Okay, #{grp1} #{contains} #{grp2}." end # method_def def does_a_contain_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 contains = "contains"; if isPlural?(grp1) then contains = "contain"; end puts "[gagent.does_a_contain_b] grp1==#{grp1}; grp2==#{grp2}" if @graph.a_r_b?(grp1.downcase, "contains", grp2.downcase) return "Yes, #{grp1} #{contains} #{grp2}." end return "I have no knowledge that #{grp1} #{contains} #{grp2}." end # method_def def why_does_a_contain_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 s = 's'; if isPlural?(grp1) then s = ''; end arr = @graph.shortest_path(grp1.downcase, ["contains"], grp2.downcase) arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } if arr2.size > 0 return "#{grp1} contain#{s} #{grp2} because: #{arr2.join(', and ')}." end return "I have no knowledge that #{grp1} contain#{s} #{grp2}." end # method_def def what_contains_x(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 arr = @graph.what_r_b?("contains", grp1.downcase) if arr.size > 0 return "#{arr.join(', ')} contain #{grp1}." end return "I have no knowledge that anything contains #{grp1}." end # method_def def how_many_contain_x(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 arr = @graph.what_r_b?("contains", grp1.downcase) @those = arr return "#{arr.size}" end # method_def def what_are_those(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern if @those != nil arr = @those @those = nil return "#{arr.join(', ')}" end if @those != nil and @those.size == 0 @those = nil return "Nothing" end return "I don't know what 'those' refers to." end # method_def def what_does_a_contain(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 arr = @graph.a_r_?(grp1.downcase, "contains") s = "s"; if isPlural?(grp1) then s = ''; end if arr.size == 0 return "I have no knowledge that #{grp1} contain#{s} anything." end return "#{grp1} contain#{s}: #{arr.join(', ')}" end # method_def def what_color_is_x(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 if @graph.a_r_b?(grp1.downcase, "is", "a color") == false return "I don't know what color #{grp1} is." end arr = @graph.shortest_path(grp1.downcase, "is", "a color") prop = arr[-2] if prop =~ / are (.*)/ or prop =~ / is (.*)/ color = process $1 else color = prop end return "I think #{grp1} is #{color}." end # method_def def a_is_related_to_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 b = process $2 @graph.a_r_b!(a.downcase, "is related to", b.downcase) if @save then @graph.save end be = "is"; if isPlural?(a) then be = "are" end return "Okay, #{a} #{be} related to #{b}." end # method_def def what_is_a_related_to?(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 be = "is"; if isPlural?(a) then be = "are" end arr = @graph.a_r_?(a.downcase, "is related to") if arr.empty? or arr == nil return "I don't know what #{a} #{be} related to." end return "#{a} #{be} related to #{arr.join(', ')}" end # method_def alias what_is_a_related_to what_is_a_related_to? def is_a_related_to_b?(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 grp2 = process $2 if grp1 == "" or grp1 == nil then return "No" end puts "[gagent] is_a_related_to_b?: grp1==#{grp1}; grp2==#{grp2}" be = "is"; if isPlural?(grp1) then be = "are" end if grp1 == grp2 then return "Yes, #{grp1} #{be} related to #{grp2}." end # reflexivity if @graph.a_r_b?(grp1.downcase, ["is related to", "is", "="], grp2.downcase) return "Yes, #{grp1} #{be} related to #{grp2}." end return "I have no knowledge that #{grp1} #{be} related to #{grp2}." end # method_def def why_is_a_related_to_b?(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 arr = @graph.shortest_path(grp1.downcase, ["is related to", "is", "="], grp2.downcase) #puts arr.inspect arr2 = Array.new arr.each_with_index { |phrase, i| phrase = make_verb_agree(phrase) arr2 << phrase } be = "is"; if isPlural?(grp1) then be = "are" end if grp1 == grp2 return "#{grp1} #{be} related to #{grp2} because 'is' is reflexive." end if arr2.empty?; return "I have no knowledge that #{grp1} #{be} related to #{grp2}" end return "#{grp1} #{be} related to #{grp2} because: #{arr2.join(', and ')}" end # method_def def a_sat_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 b = process $2 @graph.a_r_b!(a.downcase, "sat", b.downcase) if @save then @graph.save end return "Okay, #{a} sat #{b}." end # method_def def what_did_a_sit(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern a = process $1 arr = @graph.a_r_?(a.downcase, "sat") if arr.empty? or arr == nil return "I don't know what #{a} sat." end return "#{a} sat #{arr.join(', ')}" end # method_def def did_a_sit_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 grp2 = process $2 if grp1 == "" or grp1 == nil then return "No" end puts "[gagent] did_a_sit_b: grp1==#{grp1}; grp2==#{grp2}" if grp1 == grp2 then return "Yes, #{grp1} sat #{grp2}." end # reflexivity if @graph.a_r_b?(grp1.downcase, ["sat", "is", "="], grp2.downcase) return "Yes, #{grp1} sat #{grp2}." end return "I have no knowledge that #{grp1} sat #{grp2}." end # method_def def why_did_a_sit_b(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1; grp2 = process $2 arr = @graph.shortest_path(grp1.downcase, ["sat", "is", "="], grp2.downcase) if arr2.empty?; return "I have no knowledge that #{grp1} sat #{grp2}" end return "#{grp1} sat #{grp2} because: #{arr.join(', and ')}" end # method_def end # class if $0 == __FILE__ bot = MyAgent.new print "\n> "; $stdout.flush while (line = gets)# !~ /^#{$Quitwords.join('|')}$/i and line !~ /^$/ begin; $logger.puts("> #{line}"); rescue; end response = bot.send(line.to_s).to_s if response.class == "Array" then response = response[0] end response = response.chop # remove the score if response.strip == 'quit' then break end puts response + "\n\n" begin; $logger.puts(response); rescue; end print "> "; $stdout.flush end puts "Bye" end # of file