Created
May 14, 2016 20:16
-
-
Save SleeplessByte/ec0d1aa3518db91897ffb84735f0b9fa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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