Eojo
Eojo

Reputation: 35

Trying to cull a set but the set keeps disappearing

I'm trying to program the AI for a Mastermind game in ruby using Donal Knuth's 5 guess algorithm. The game consists of a codemaker, who uses 8 different colored pegs to create a set of 4, and a codebreaker, who guesses at the code and receives feedback (a red square for a peg which is both the right color and in the right spot, and a white square for a peg which is the right color but in the wrong spot).

I've created a set for all possible codes. My goal is to compare feedback from the guess to feedback from all codes in the set, then delete the ones that don't match. It seems to delete the entire set though.

class ComputerPlayer < Player
  def initialize(game)
    super(game)
    @all_possible_codes = create_codes
    @turn = 1
  end

  def get_code
    Array.new(4){rand(1..6)}
  end

  def get_guess
    puts @all_possible_codes.length
    if @turn == 0
      @turn += 1
      cull_set([1, 1, 2, 2])
      @all_possible_codes.delete("1122")
      return [1, 1, 2, 2]
    else 
      random_sample = @all_possible_codes.to_a.sample.split('').map{|str| str.to_i}
      @all_possible_codes.delete(random_sample.join(''))
      cull_set(random_sample)
      random_sample
    end
  end

  def cull_set(guess)
    feedback = @game.feedback_on_guess(guess)
    puts feedback
    @all_possible_codes.delete_if { |str| @game.feedback_on_guess(str.split.map{|num| num.to_i}) != feedback }
  end

  def create_codes
    set = Set.new
    (1..8).each do |i|
      (1..8).each do |j|
        (1..8).each do |k|
          (1..8).each do |l|
            set << [i, j, k, l].join('')
          end
        end
      end
    end
    set
  end
end

#this is the feedback_on_guess method used by the above class

def feedback_on_guess(code_guess)
    code_duplicate = @code
    feedback = []
    code_duplicate.map.with_index do |entry, i|
      if entry == code_guess[i]
        feedback.push('r')
        code_guess[i] = -1
        -2
      else
      entry
      end
    end.each do |entry|
      found_index = code_guess.find_index(entry)
      if found_index
        feedback.push('g')
        code_guess[found_index] = -1
      end
    end
    puts feedback
    feedback
  end

Upvotes: 0

Views: 53

Answers (1)

Pascal
Pascal

Reputation: 8646

Try

copy = something.dup

because after just

copy = something

copy and something are pointing to the same object. You can confirm this by checking the object_id of the object referenced by the variable. If it is the same, then it is the same object.

When you dup an object, you will cretae a copy. Depending on what you want to dup you might need to implement/override the logic to create a copy. For built in Classes like String, Hash and so on it will work out of the box.

Be aware that nested constructs (eq. Hash containing other Hashes) are not duplicated.

h1 = {"a" => {"b" => 2}}
h2 = h1.dup
puts h1.object_id      # 70199597610060
puts h2.object_id      # 70199597627020
puts h1["a"].object_id # 70199597610080 
puts h2["a"].object_id # 70199597610080

Upvotes: 1

Related Questions