Skip to content

Instantly share code, notes, and snippets.

@erochest
Created November 28, 2012 21:41
Show Gist options
  • Save erochest/4164784 to your computer and use it in GitHub Desktop.
Save erochest/4164784 to your computer and use it in GitHub Desktop.
Jotto
# http://www.ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/Set.html
require 'set'
class Dictionary
attr_reader :words
def initialize
@words = Set.new []
end
def load_file(dict_file)
IO.foreach dict_file do |line|
@words.add line.strip.downcase
end
self
end
def filter_length(n)
@words.keep_if { |word| word.length == n }
self
end
def filter_duplicate_letters
@words.keep_if do |word|
word_set = Set.new word.chars
word_set.length == word.length
end
self
end
def random_word
word_array = @words.to_a
word_array[Random.rand(word_array.length)]
end
end
class Secret
attr_accessor :word
def initialize
@word = nil
end
def is_word?(guess)
@word == guess
end
def get_matches(guess)
word_set = Set.new @word.chars
guess_set = Set.new guess.chars
(word_set & guess_set).length
end
def to_s
@word.to_s
end
def length
@word.length
end
end
class Jotto
attr_reader :dict
attr_reader :secret
attr_reader :guess_count
attr_reader :max_guess_count
def initialize(max_guess_count, dict)
@dict = dict
@secret = Secret.new
@guess_count = 0
@max_guess_count = max_guess_count
end
def new_game
@secret.word = @dict.random_word
@guess_count = 0
end
def guess(word)
word = word.downcase
@guess_count += 1
{:guess => @guess_count,
:won => @secret.is_word?(word),
:over => (@secret.is_word?(word) || @guess_count >= @max_guess_count),
:matches => @secret.get_matches(word)}
end
end
class JottoConsole
def initialize(jotto)
@jotto = jotto
@wins = 0
@losses = 0
end
def loop
puts "Get ready to rumble!"
while true
game
break if ! again?
end
done
end
def again?
puts "Would you like to play again [Y/n]?"
gets[0].downcase != 'n'
end
def done
puts "You won #{@wins} games and lost #{@losses}."
if @wins > @losses
puts "Great job!"
elsif @wins == @losses
puts "We're evenly matched. Let's play again sometime."
else
puts "Better luck next time."
end
end
def game
@jotto.new_game
puts "I'm thinking of a #{@jotto.secret.length}-letter word. Guess what it is."
result = nil
while true
print "\nGuess #{@jotto.guess_count+1} of #{@jotto.max_guess_count}: "
word = gets.strip
if word == 'xyzzy'
puts @jotto.secret
puts result.inspect
else
result = @jotto.guess word
output_result result
break if result[:over]
end
end
output_game result[:won]
tally result[:won]
result[:won]
end
def output_result(result)
if result[:matches] == 1
jot = 'jot'
else
jot = 'jots'
end
puts "#{result[:matches]} #{jot}"
end
def output_game(won)
if won
puts "That's it! Great guessing."
else
puts "You're out of turns! Better luck next time."
end
end
def tally(won)
if won
@wins += 1
else
@losses += 1
end
end
end
## Prepare the dictionary.
dictionary = Dictionary.new
dictionary.load_file("/usr/share/dict/words")
.filter_length(5)
.filter_duplicate_letters()
## Prepare the game.
jotto = Jotto.new(20, dictionary)
## Run it on the console.
JottoConsole.new(jotto).loop
@erochest
Copy link
Author

I've simplified this for the specs here. For instance, JottoConsole#loop has been removed, so they no longer need to make it play multiple games, prompt to continue, or track wins and losses.

@erochest
Copy link
Author

I also refactored it to make it slightly more decoupled. The Secret class (SecretWord in the specs) should know nothing about the Dictionary class.

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