0
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?

3
  • 2
    I'm not able to see this happen, running your code "HERE2" is always just 1 character shorter than "HERE", is because "HERE2" actually gets output before the current guess is added and then "HERE" is output. Do you have any further information to help reproduce it? Commented Jun 6, 2018 at 1:22
  • imgur.com/a/jUkjHaz I'm running an RSPEC test and Im also using puts/prints to test what gets pushed into the @guessed_letters successfully. Im sorry if its hard to read Im still learning ruby. Commented Jun 6, 2018 at 1:32
  • -edit- This is the rspec that Im running repl.it/@dnangels/RSPECHangman Commented Jun 6, 2018 at 1:40

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I kind of understand...? But that doesnt seem to explain that in the second iteration of "HERE2" is it blank when you could see HERE in the first iteration to have an "e" in it already. imgur.com/a/jUkjHaz Why is HERE2 an empty array even though HERE has an "e" and their addressing the same instance variable?
The first "HERE2" is from the other test ("returns the most common letter in #candidate_words"), and then when that test finishes, you throw away that guesser and get a fresh one, that hasn't made any guesses. And you wouldn't want the state to carry over from one test to the other like that, tests should be runnable in random order...not reliant on any other test to have ran before it
Ah... okay I see. Thank you very much for helping me out. I guess I have to figure out another way to code the guessing method

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.