# Implementation of the Loebner Prize Protocol # http://www.loebner.net/Prizef/2009_Contest/LP_2009.html puts "Loebner Prize Contest 2010" puts "When Directory Chooser appears, choose the dir to write program output and read judge's input." puts "(If the file other_dir.txt exists in this directory, that directory will be automatically selected. Delete that file and run the program again to select a directory other than the one in the other_dir.txt file.)" # Don't display Directory Chooser dialog if there's an other_dir.txt if not File.exists?("other_dir.txt") # Have the user choose a directory to write responses to and read input from. system("python DirChooser.py") end # Store the chosen directories. File.open("other_dir.txt", "r") { |f| $other_dir = f.gets } # Judge's directory is the same directory that the bot will write responses to. $judge_dir = $other_dir # Uncomment the following line if $judge_dir is not the same as $other_dir #File.open("judge_dir.txt", "r") { |f| $judge_dir = f.gets } puts "judge's input #{$judge_dir}" puts "bot's output #{$other_dir}" # Start the bot. Dir.chdir("Z:\\controlbot\\controller") require 'controlbot' $DELAY = 0.7 # added between typing strokes class Lpp def initialize @the_count = 0 # Variables to deal with assuming a Judge's Return if they don't enter it. @last_size = 0 @WAIT = 4 # seconds to wait before assuming a Return end def read begin input_hash = Hash.new dir = Dir.new($judge_dir) if dir.entries.size == 2 then return false end # contains only "." and ".." # is there a Return? return_found = false dir.each { |d| if d =~ /(.*)\.Return\.judge$/ then return_found = true end } dir.each { |d| if d =~ /(.*)\.Return\.judge$/ and dir.entries.size == 3 then delete_judge_directories; @last_size = 0; @last_time = nil; return false end } # If no Return, if there's been a delay longer than @WAIT, assume a return. size = dir.entries.size if @last_time == nil then @last_time = Time.now end puts "*****\n" puts "dir.entries.size==#{dir.entries.size}." puts "@last_size==#{@last_size}." puts "@last_time==#{@last_time}." puts "Time.now==#{Time.now}." puts "return_found==#{return_found}." if size == @last_size and size == 3 then @last_time = Time.now end if (size > 2) and (size == @last_size) and (return_found == false) if (Time.now - @last_time) > @WAIT return_found = true @last_size = 0 end end if size > @last_size then @last_time = Time.now end @last_size = size if not return_found then return false end dir.sort.each { |d| if d =~ /(.*)\.(.*)\.judge$/ time = $1 char = $2 if char =~ /backspace/i to_delete = input_hash.sort.delete_at(input_hash.length - 1) #puts "[Lpp.read] to_delete==#{to_delete.inspect}" begin input_hash.delete(to_delete[0]); rescue; end next end if char =~ /return/i then return_found = true end char = rev_substitute char input_hash["#{time}"] = "#{char}" end } #puts "input_hash.sort==#{input_hash.sort.inspect}" input = '' input_hash.sort.each do |time,char| input << char end #puts "[Lpp.read] input==#{input}" delete_judge_directories @last_time = nil; @last_size = 0 return input rescue Exception; retry; end end def delete_judge_directories save_dir = Dir.pwd Dir.chdir($judge_dir) require 'fileutils' file_path = File.dirname(".") file_name = File.basename(file_path) dir = File.dirname(file_path) Dir.foreach(dir) do |f| if f == file_name or f == '.' or f == '..' or f =~ /\.other$/ then next end if File.directory?(f) and f =~ /\.judge$/ FileUtils.rm_rf(f) end end Dir.chdir(save_dir) end def write response response = insert_backspaces response size = response.size size.downto(1) { |n| char = response.slice!(0,1) char = substitute(char) time = "%.4f" % Time.new.to_f time = time.sub(/\./, '') # Play with the time. #time = time.to_i + 10 #too slow time = time.to_i + 1 time = time.to_s time = time.rjust(18, "0") dirname = "#{$other_dir}/#{time}.#{char}.other" #puts "[Lpp.write] dirname==#{dirname}" begin; Dir.mkdir(dirname); rescue Exception => e; puts e; retry; end if $DELAY > 1 then r = rand + $DELAY end if $DELAY <= 1 then r = rand - $DELAY end if r < 0 then r = 0.2 end if $DELAY <= 0.0 then r = 0.0 end sleep(r) } # Print a line return at the end of the message time = "%.4f" % Time.new.to_f time = time.sub(/\./, '') time = time.to_i + 100 time = time.to_s time = time.rjust(18, "0") dirname = "#{$other_dir}/#{time}.Return.other" begin; Dir.mkdir(dirname); rescue Exception => e; puts "e==#{e}"; retry; end end def insert_backspaces response if response =~ / the / if @the_count % 3 == 0 response.sub!(/ the /, " teh\b\bhe ") end @the_count += 1 end if response =~ /you/ if rand(3) == 1 response.sub!(/you/, "yuo\b\bou") sleep(1) end end if response =~ /what/ if rand(3) == 1 response.sub!(/what/, "waht\b\b\bhat") sleep(0.5) end end if response =~ /\.\.\./ if rand(3) == 1 response.sub!(/\.\.\./, ",,,\b\b\b...") end end if response =~ /y/ if rand(3) == 1 response.sub!(/y/, "u\by") sleep(0.5) end end if rand(9) == 1 response = "I don't kno\b\b\b\b\b\b\b\b\b\b\b" + response end if rand(10) == 1 response = response + "\\" end if rand(10) == 5 if response =~ /T/ then response.sub!(/T/, "/t\b\bT") end end if rand(10) == 7 if response =~ /r/ then response.sub!(/r/, "r4\b") end end if response =~ /p/ if rand(5) == 2 then response.sub!(/p/, "[\bp") end end return response end def rev_substitute char #puts "[Lpp.substitute] char==#{char}" if char == "braceleft" then char = "{" end if char == "braceright" then char = "}" end if char == "bracketleft" then char = "[" end if char == "bracketright" then char = "]" end if char == "parenleft" then char = "(" end if char == "parenright" then char = ")" end if char == "space" then char = " " end if char == "comma" then char = "," end if char == "period" then char = "." end if char == "greater" then char = ">" end if char == "less" then char = "<" end if char == "slash" then char = "/" end if char == "backslash" then char = "\\" end if char == "bar" then char = "|" end if char == 'quotedbl' then char = '"' end if char == "quoteright" then char = "'" end if char == "Tab" then char = "\t" end if char == "equal" then char = "=" end if char == "underscore" then char = "_" end if char == "plus" then char = "+" end if char == "minus" then char = "-" end if char == "exclam" then char = "!" end if char == "at" then char = "@" end if char == "numbersign" then char = "#" end if char == "dollar" then char = "$" end if char == "percent" then char = "%" end if char == "asterisk" then char = "*" end if char == "asciicircum" then char = "^" end if char == "asciitilde" then char = "~" end if char == "quoteleft" then char = "`" end if char == "ampersand" then char = "&" end if char == "Return" then char = "\n" end if char == "colon" then char = ":" end if char == "semicolon" then char = ";" end if char == "question" then char = "?" end if char == "BackSpace" then char = "BackSpace" end return char end def substitute char if char == "{" then char = "braceleft" end if char == "}" then char = "braceright" end if char == "[" then char = "bracketleft" end if char == "]" then char = "bracketright" end if char == "(" then char = "parenleft" end if char == ")" then char = "parenright" end if char == " " then char = "space" end if char == "," then char = "comma" end if char == "." then char = "period" end if char == ">" then char = "greater" end if char == "<" then char = "less" end if char == "/" then char = "slash" end if char == "\\" then char = "backslash" end if char == "|" then char = "bar" end if char == '"' then char = "quotedbl" end if char == "'" then char = "quoteright" end if char == "\t" then char = "Tab" end if char == "=" then char = "equal" end if char == "_" then char = "underscore" end if char == "+" then char = "plus" end if char == "-" then char = "minus" end if char == "!" then char = "exclam" end if char == "@" then char = "at" end if char == "#" then char = "numbersign" end if char == "$" then char = "dollar" end if char == "%" then char = "percent" end if char == "*" then char = "asterisk" end if char == "^" then char = "asciicircum" end if char == "~" then char = "asciitilde" end if char == "`" then char = "quoteleft" end if char == "&" then char = "ampersand" end if char == "\n" then char = "Return" end if char == ":" then char = "colon" end if char == ";" then char = "semicolon" end if char == "?" then char = "question" end #if char == "BackSpace" then char = "BackSpace" end if char == "\b" then char = "BackSpace" end return char end end # get/set $DELAY def process_lpp_commands_in line case line when /type faster/ $DELAY -= 0.5; return "The $DELAY is #{$DELAY}" when /type slower/, /slow down/ $DELAY += 0.5; return "The $DELAY is #{$DELAY}" when /what is.*typing speed/, /show.*delay/i, /^what is.*delay/i return "The $DELAY is #{$DELAY}" when /^set.*delay.*?(\d+\.*\d*)/i $DELAY = $1.to_f; return "$DELAY set to #{$DELAY}" end return false return false end # Entry point quitwords = ["buh-byenow", "trane: quit"] b = ControlBot.new lpp = Lpp.new puts "Hello" # read each entry with a .judge extension under $judge_dir to get input while (line = lpp.read) !~ /^(#{quitwords.join('|')})$/ #while (line = lpp.read) #if not line then puts "skipping read..."; next end if not line then next end puts "line==#{line}" response = "" response = b.getResponse(line) unless response = process_lpp_commands_in(line) print "\nresp==" + response + "\n" # write each character of response to a directory name under $other_dir lpp.write(response) #sleep($DELAY) unless $DELAY < 0 end # kill the bot system("Z:\\controlbot\\controller\\exit\\rubykill.exe")