Skip to content

Instantly share code, notes, and snippets.

@SleeplessByte
Created May 14, 2016 20:16
Show Gist options
  • Save SleeplessByte/ec0d1aa3518db91897ffb84735f0b9fa to your computer and use it in GitHub Desktop.
Save SleeplessByte/ec0d1aa3518db91897ffb84735f0b9fa to your computer and use it in GitHub Desktop.
source 'https://rubygems.org'
gem 'rambling-trie'
### end gemfile
require 'rubygems'
require 'bundler/setup'
require 'rambling-trie'
require 'optparse'
class WordSolver
include Rambling
def initialize
@trie = Trie.create
end
# Reads a file and adds each line to the solvable results
def read_file( filename )
unless File.exists? filename
$stdout.puts "#{filename} does not exist"
return self
end
$stdout.puts "adding #{filename}"
File.foreach( filename ).each do |line|
@trie.add line.strip
end
$stdout.puts "added #{filename}"
self
end
def solve( *letters )
solve_with_options( Array( letters ).flatten, Options.new( self ) )
end
class Options
def initialize( word_solver )
@word_solver = word_solver
@min_len = 3
@favourable_letters = []
end
def minimum_length=( len )
len = len.to_i
if len < 1
raise ArgumentError.new "len should be 1 or larger"
end
@min_len = len
end
def favourable_letters=( *letters )
@favourable_letters = Array( letters ).flatten.compact
end
def solve( *letters )
@word_solver.solve_with_options( Array( letters ).flatten, self )
end
def minimum_length
@min_len
end
def favourable_letters
@favourable_letters
end
end
def options
Options.new self
end
def solve_with_options( letters, options )
$stdout.puts "solving for #{ letters }"
_solve_with_prefix( nil, letters, options )
end
protected
def _solve_with_prefix( prefix, letters, options )
#$stdout.puts "solving for #{ letters } /w #{ prefix }"
if !prefix.nil? && [email protected]_word?( prefix )
#$stdout.puts "#{prefix} not in trie"
return {}
end
prefix = prefix.to_s
results = {}
if @trie.word?( prefix ) &&
options.minimum_length <= prefix.length &&
options.favourable_letters.all? { |f| prefix.include? f }
#$stdout.puts "#{prefix} is in trie"
results[prefix.length] ||= []
results[prefix.length].push prefix
end
#$stdout.puts "letters: #{letters.dup.uniq}"
done = []
new_input = letters.dup
letters.each_with_index do |letter, i|
if done.include? letter
next
end
done.push letter
new_input.delete_at( i )
#$stdout.puts "#{prefix}:#{letter}"
it_res = _solve_with_prefix( prefix + letter, new_input, options )
new_input.insert( i, letter )
it_res.each_key do |len|
results[len] ||= []
results[len] += it_res[len]
end
end
results
end
end
def ordered_print( hash, output = 5 )
max = hash.keys.max
if max.nil?
$stdout.puts 'No results'
return
end
count = 0
i = 0
while count < output && i < max
if hash.has_key?( max - i )
$stdout.print hash[ max - i ]
$stdout.print "\n"
count += 1
end
i += 1
end
end
options = { :filename => "en.txt", :size => 3, :output => 5 }
OptionParser.new do |opts|
opts.banner = "Usage: word_solver.rb [options]"
opts.on("-d D", "--dictionary D", "Dictionary file with line separated words") do |d|
options[:filename] = d
$stdout.puts "dictionary is #{d}"
end
opts.on( "-l N", "--length N", "Minimum length of output is N" ) do |n|
options[:size] = n
$stdout.puts "size is #{n}"
end
opts.on( "-o O", "--output O", "Number O of result groups below max length" ) do |o|
options[:output] = o
$stdout.puts "output is #{o}"
end
opts.on("-h", "--help", "Prints this help") do
$stdout.puts opts
exit
end
end.parse!
@word_solver = WordSolver.new.read_file( options[:filename] )
@options = @word_solver.options
@options.minimum_length = options[ :size ]
while true do
input = $stdin.gets.chomp
if input === "exit"
exit(0)
return
end
cmd, *args = input.split ' '
if cmd === "run"
ordered_print( @options.solve( args[0].tr('^A-Za-z', '').downcase.chars ), options[ :output ] )
next
end
if cmd === "set"
if args[0] === "length"
@options.minimum_length = args[1]
next
elsif args[0] === "fav"
@options.favourable_letters = args[1].strip.chars
next
elsif args[0] === "output"
options[:output] = args[1].to_i
end
$stdout.puts "`#{args[0]}` is not a valid command. Use set length [l], set fav [abc] or set output [o]"
next
end
if cmd === "reset"
@options.minimum_length = options[ :size ]
@options.favourable_letters = []
next
end
$stdout.puts "`#{cmd}` is not a valid command. Use run [letters], set [option] or exit"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment