From: Dale Martenson Date: 2007-01-08T14:20:07+09:00 Subject: Re: Word Blender (#108) Here is my solution. I didn't post the whole thing. This is the main engine minus the Tk UI class. You can get the full solution (dictionary, graphics and ruby source at http://www.dalemartenson.com/files/rubytexttwist.tar.gz --Dale Martenson class TextTwist # Algorithm derived from online book by Robert Sedgewick and Kevin Wayne. # It was origomally written in Java. # # References: # http://www.cs.princeton.edu/introcs/31datatype/ # http://www.cs.princeton.edu/introcs/31datatype/TextTwist.java.html class Profile < Hash def initialize( word ) super word.downcase.each_byte do |b| self[b.chr] = 0 unless self.has_key?(b.chr) self[b.chr] += 1 end end def contains( p ) p.each_pair do |k,v| return false unless self.has_key?(k) return false if self[k] < v end true end end attr_reader :word, :words def initialize( dictionary, word=nil ) @dictionary = dictionary @dictionary.collect! {|x| x.downcase} @dictionary.sort! word.nil? ? restart : start( word ) end def start( word ) @word = word.downcase @profile = Profile.new( @word ) @words = process end def process result = [] @dictionary.each do |dw| next if dw.length < 3 || dw.length > @word.length result << dw if @profile.contains( Profile.new( dw ) ) end result end def mix a = @word.split(//) 1.upto(a.length) do i1 = rand(a.length) i2 = rand(a.length) t = a[i1] a[i1] = a[i2] a[i2] = t end a end def check( word ) @words.include?( word.downcase ) end def contains( word ) @profile.contains( Profile.new( word ) ) end def restart six_letter_words = [] @dictionary.each do |w| six_letter_words << w if w.length == 6 end start( six_letter_words[ rand(six_letter_words.size) ] ) end end class TextTwistUI # ... SNIP ... end # MAIN PROGRAM -- where the magic begins # Using the crossword dictionary from "Moby Word Lists" by Grady Ward (part of # Project Gutenberg). I reduced the dictionary to only words that are 3 to 6 # characters in length. # # Note: This may not be the best dictionary for this game, but it works. It # does contain numerous obscure words which is both good and bad. # # irb(main):001:0> f = File.open("crosswd.txt") # => # # irb(main):002:0> of = File.open("3-6.txt","w+") # => # # irb(main):003:0> f.each_line do |line| # irb(main):004:1* l = line.strip # irb(main):005:1> if l.length >= 3 && l.length <= 6 then # irb(main):006:2* of.puts( l ) # irb(main):007:2> end # irb(main):008:1> end # => # # irb(main):009:0> of.close # => nil # # References: # http://www.gutenberg.org/etext/3201 dictionary = [] f = File.open("3-6.txt") dictionary = f.read.split tt = TextTwist.new( dictionary ) TextTwistUI.new( tt ) Tk.mainloop