Skip to content

Instantly share code, notes, and snippets.

@heath
Last active December 17, 2015 09:18
Show Gist options
  • Save heath/5585863 to your computer and use it in GitHub Desktop.
Save heath/5585863 to your computer and use it in GitHub Desktop.
soon with iterative (instead of recursive) functions!
"""
License: MIT
Author: Heath Matlock
Problem: https://en.wikipedia.org/wiki/Weasel_program
"""
import string
import random
from time import time
from operator import itemgetter
class Typing_Monkey():
def __init__(self):
self.lowercase_letters = string.lowercase
self.space = ' '
self.possible_choices = self.lowercase_letters + self.space
self.desired_text = 'methinks it is a weasel'
self.attempts = []
self.attempts_count = 0
self.beginning_time = time()
self.solution = False
def generate_string(self):
random_text = ''.join(random.choice(self.possible_choices) for _ in range(27))
return random_text
def go_monkey_go(self):
while self.solution == False:
generated_text = self.generate_string()
self.attempts_count += 1
self.record_progress(generated_text)
self.check_accuraccy(generated_text)
ending_time = time()
time_ellapsed = ending_time - self.beginning_time
print str(self.attempts_count) + " attempts later"
print "beginning time: " + str(self.beginning_time)
print "ending time: " + str(ending_time)
print "time ellapsed " + str(time_ellapsed)
def check_accuraccy(self,text):
if text != self.desired_text:
# display progress
attempts_ranked = sorted(self.attempts, key = itemgetter('correct_letters'))
self.attempts = attempts_ranked[-5:]
print self.attempts
else:
self.solution = True
def record_progress(self, text):
number_correct = 0
for char in text:
if char in self.desired_text:
number_correct += 1
record_of_attempt = {"string": text, 'correct_letters': number_correct}
self.attempts.append(record_of_attempt)
#######################################################
# Start the monkey!
#######################################################
if __name__ == '__main__':
typing_monkey = Typing_Monkey()
typing_monkey.go_monkey_go()
"""
Python has a maximum depth for its call stack, so recursive functions should be translated to iterative functions. I'll be checking out this series of posts while correcting this:
http://blog.moertel.com/posts/2013-05-11-recursive-to-iterative.html
http://blog.moertel.com/posts/2013-05-14-recursive-to-iterative-2.html
"""
# License: MIT
# Author: Heath Matlock
# Problem: https://en.wikipedia.org/wiki/Weasel_program
class TypingMonkey
def initialize
@lowercase_letters = ('a'..'z').to_a
@space = ' '
@possible_choices = @lowercase_letters.push(@space)
@desired_text = 'methinks it is a weasel'
@attempts = []
@count_of_all_attempts = 0
@beginning_time = Time.new
end
def generate_string()
random_text = (0...26).map { |n| @possible_choices.sample }.join
return random_text
end
def go_monkey_go()
puts 1
@count_of_all_attempts += 1
@generated_text = generate_string()
if @generated_text != @desired_text
puts 2
# display progress
if @attempts.length > 100
puts 3
attempts_ranked = attempts.sort_by{ |key| key['correct_letters'] }
@attempts = attempts_ranked.last(5)
print @attempts
# continue generating random output
go_monkey_go()
end
else
puts 4
ending_time = Time.new
time_ellapsed = ending_time - @beginning_time
puts "#{@count_of_all_attempts} attempts later\n"
puts "beginning time: #{@beginning_time}\n"
puts "ending time: #{@ending_time}\n"
puts "time ellapsed #{@time_ellapsed}\n"
end
end
def record_progress()
number_correct = 0
for char in @generated_text
if @desired_text.count(char) > 0
number_correct += 1
end
end
record_of_attempt = {string: @generated_text, correct_letters: number_correct}
@attempts.push(record_of_attempt)
end
end
typing_monkey = TypingMonkey.new
typing_monkey.go_monkey_go()
# this will fail due to maximum recursion depth
@benolee
Copy link

benolee commented May 18, 2013

for the ruby one, you need to move the recursive call outside of the progress check:

diff --git a/classy_recursive_monkey.rb b/classy_recursive_monkey.rb
index a841bf8..b1811e1 100644
--- a/classy_recursive_monkey.rb
+++ b/classy_recursive_monkey.rb
@@ -32,11 +32,9 @@ class TypingMonkey
         attempts_ranked = attempts.sort_by{ |key| key['correct_letters'] }
         @attempts = attempts_ranked.last(5)
         print @attempts
-
-        # continue generating random output
-        go_monkey_go()
       end
-
+      # continue generating random output
+      go_monkey_go()
     else
       puts 4
       ending_time = Time.new

if you want tailcall optimization on MRI, you need to move it to the bottom of the method and turn on the compile option:

diff --git a/classy_recursive_monkey.rb b/classy_recursive_monkey.rb
index a841bf8..11187e5 100644
--- a/classy_recursive_monkey.rb
+++ b/classy_recursive_monkey.rb
@@ -1,3 +1,5 @@
+
+
 # License: MIT
 # Author: Heath Matlock
 # Problem: https://en.wikipedia.org/wiki/Weasel_program
@@ -19,25 +21,17 @@ class TypingMonkey
     return random_text
   end

+  RubyVM::InstructionSequence.compile_option = {
+    trace_instruction: false,
+    tailcall_optimization: true
+  }
+  eval <<-EORUBY
   def go_monkey_go()
     puts 1
     @count_of_all_attempts += 1
     @generated_text = generate_string()

-    if @generated_text != @desired_text
-      puts 2
-      # display progress
-      if @attempts.length > 100
-      puts 3
-        attempts_ranked = attempts.sort_by{ |key| key['correct_letters'] }
-        @attempts = attempts_ranked.last(5)
-        print @attempts
-
-        # continue generating random output
-        go_monkey_go()
-      end
-
-    else
+    if @generated_text == @desired_text
       puts 4
       ending_time = Time.new
       time_ellapsed = ending_time - @beginning_time
@@ -45,12 +39,28 @@ class TypingMonkey
       puts "beginning time: #{@beginning_time}\n"
       puts "ending time: #{@ending_time}\n"
       puts "time ellapsed #{@time_ellapsed}\n"
+      return
+    end
+
+    puts 2
+    # display progress
+    if @attempts.length > 100
+      puts 3
+      attempts_ranked = @attempts.sort_by{ |key| key['correct_letters'] }
+      @attempts = attempts_ranked.last(5)
+      print @attempts
+    else
+      record_progress
     end
+
+    # continue generating random output
+    go_monkey_go()
   end
+  EORUBY

   def record_progress()
     number_correct = 0
-    for char in @generated_text
+    @generated_text.each_char do |char|
       if @desired_text.count(char) > 0
         number_correct += 1
       end

@benolee
Copy link

benolee commented May 18, 2013

oh, I forgot to @heath you :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment