Reputation: 111
class Hangman
attr_reader :guesser, :referee, :board
def initialize(options = {})
@guesser = options[:guesser]
@referee = options[:referee] #class objects
end
def play
setup
take_turn until over?
conclude
end
def setup
secret_length = @referee.pick_secret_word
@guesser.register_secret_length(secret_length)
@board = Array.new(secret_length)
end
def take_turn
letter = @guesser.guess(@board)
correct_indicies = @referee.check_guess(letter)
self.update_board(letter,correct_indicies)
@guesser.handle_response(letter,correct_indicies)
end
def update_board(letter,correct_indicies)
correct_indicies.each{|index| @board[index] = letter}
end
private
def over?
@board.count(nil) == 0
end
def conclude
puts "Congrats the game is over."
puts "The hidden word was #{board.join}"
end
end
class HumanPlayer
def initialize
@guessed_letters = []
end
def pick_secret_word
puts "Enter the length of your word."
gets.chomp.to_i
end
def register_secret_length(length)
puts "The length of the word is #{length}"
end
def guess(board)
print_board(board)
print "> "
guess = gets.chomp
processed_guess(guess)
end
def check_guess(letter)
puts "The letter, #{letter}, guessed was at these indicies."
puts "Input formart ex. (2 4 6)"
indicies = gets.chomp.split(" ").map(&:to_i)
end
def handle_response(letter, indicies)
puts "Found #{letter} at positions #{indicies}"
end
private
def print_board(board)
board_string = board.map do |el|
el.nil? ? "_" : el
end.join("")
puts "Secret word: #{board_string}"
end
def processed_guess(guess)
unless @guessed_letters.include?(guess) || guess.length > 1
@guessed_letters << guess
return guess
else
puts "You have already guessed #{guess}"
puts "Please try again."
puts "You have guessed #{@guessed_letters}"
print "> "
guess = gets.chomp
processed_guess(guess)
end
end
end
class ComputerPlayer
attr_reader :secret_word, :secret_word_length, :candidate_words,
:guessed_letters
def initialize(dictionary = ComputerPlayer.default_dictionary)
@dictionary = dictionary
@alphabet = ("a".."z").to_a
@guessed_letters = []
end
def self.default_dictionary
contents = File.readlines("dictionary.txt").map{|word| word.chomp}
end
def pick_secret_word
@secret_word = @dictionary.sample
print @secret_word
secret_word_length = @secret_word.length
end
def check_guess(letter)
secret_word_arr = @secret_word.chars
secret_word_arr.each_index.select{|index| @secret_word[index] == letter}
end
def register_secret_length(secret_length)
@candidate_words = @dictionary.select{|word| word.length == secret_length}
end
def guess(board)
print_board(board)
letter = guess_most_common
processed_most_common(letter)
puts "HERE #{@guessed_letters}"
letter
end
def handle_response(letter, indicies)
@candidate_words.select! do |word|
indicies == word.chars.each_index.select {|index| word[index] == letter} #so the problem here is if you guess "r" give correct index of [0] and it checks "rear" it would assume its correct even tho theres an extra "r"
end
puts "Found #{letter} at positions #{indicies}"
end
def guess_most_common
puts "HERE2 #{@guessed_letters}"
most_common_hash = Hash.new(0)
uniq_candidate_arr = @candidate_words.map{|word| word.chars.uniq.join}
uniq_candidate_arr.join.each_char{|char| most_common_hash[char] += 1 unless @guessed_letters.include?(char)
p char}
print "#{most_common_hash}"
most_common_letter = most_common_hash.sort_by{|key,value| value}.reverse.to_h.keys.first
end
private
def print_board(board)
board_string = board.map do |el|
el.nil? ? "_" : el
end.join("")
puts "Secret word: #{board_string}"
end
def processed_most_common(letter)
@guessed_letters << letter unless @guessed_letters.include?(letter)
end
end
if __FILE__ == $PROGRAM_NAME
my_computer = ComputerPlayer.new
my_human = HumanPlayer.new
game = Hangman.new({guesser:my_human, referee:my_computer})
game.play
end
Sorry if this is crappy format but I am working on a Hangman Project but got stuck. I am trying to make the ComputerPlayer guess the most common letter. After it guesses the most common letter, it will guess the next most common letter and so fourth.
I've made a @guessed_letters = [] to keep track of the letters I've already guessed so I wont count it the next time the computer guesses a letter.
Problem is that @guessed_letter does not keep track of my guessed letters correctly. I printed them in 2 areas. One in class ComputerPlayer#guess and one in ComputerPlayer#guess_most_common. The guess method prints @guessed_letters array correctly with the letters already guessed. guess_most_common method always prints a empty @guessed_letters array. How is that possible that they're both printing different things?
Upvotes: 0
Views: 53
Reputation: 11035
So you're problem is that in the following RSpec test case, the "HERE2" is an empty array and doesn't contain the guess "e", yet:
describe "Phase III" do
describe "#guess" do
let(:guesser) { ComputerPlayer.new(["reel","keel","meet"]) }
before(:each) { guesser.register_secret_length(4) }
context "when a guess has been made" do
it "returns the most common letter in the remaining #candidate_words" do
board = [nil, "e", "e", nil]
expect(guesser.guess(board)).to eq("l")
end
end
end
The reason for this is you haven't told any code that you have guessed "e", yet (i.e., you haven't called processed_most_common
with "e"). You only tell the guesser
that the board is in a state such that the 2 middle letters are "e".
If we were to, for example, change the test to:
context "when a guess has been made" do
it "returns the most common letter in the remaining #candidate_words" do
board = [nil, "e", "e", nil]
guesser.guess(board) # guesses 'e' and marks it as guessed.
expect(guesser.guess(board)).to eq("l")
end
end
Now, we've got the board in a state such that it knows that "e" is in the middle 2 positions, and then we tell it to guess the most common letter, which is still "e" because guesser
doesn't know that it guessed it yet (because it hasn't). After that, we tell it to guess the next letter, which this time is "l", and the "HERE2" code correctly outputs that "e" has already been guessed (because it has).
There are other ways to fix this, you just need to make sure processed_most_common
gets called with "e", to fix the issue you're seeing. But if you have the code go through the entire guess process, you don't end up missing out on any other steps that might be expected that you had gone through.
Upvotes: 1