Bri Expost
Bri Expost

Reputation: 111

Somehow Accessing Different Instance Variables

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

Answers (1)

Simple Lime
Simple Lime

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

Related Questions