Sha256: d8319444f69f6528408ec9ae908c986d4d2c15a0c150bc1221b33f0acae986ba

Contents?: true

Size: 1.58 KB

Versions: 1

Compression:

Stored size: 1.58 KB

Contents

# frozen_string_literal: true

module Codebreaker
  # Matching mechanism to determine the number
  # of bulls and cows in the guess.
  class Matcher
    attr_reader :marker, :secret_code_hash
    def initialize(marker = Markers::PlusMinusMarker.new)
      @marker = marker
    end

    def secret_code=(secret_code)
      @secret_code_hash = array_to_hash_of_positions(unify_code(secret_code))
    end

    def match?(guess)
      match(array_to_hash_of_positions(unify_code(guess)))

      @bulls == 4
    end

    def marks
      marker.mark(@bulls, @cows)
    end

    private

    def unify_code(code)
      code.is_a?(String) ? code.split('') : code
    end

    def array_to_hash_of_positions(array)
      array
        .each_with_object({})
        .with_index do |(digit, hash), position|
          hash[digit] ||= []
          hash[digit].push(position)
          hash
        end
    end

    def match(guess_hash)
      @exact_matches = 0
      @all_matches = 0

      guess_hash.each do |digit, positions|
        next if digit_is_not_present_in_the_secret_code(digit)

        add_exact_matches(digit, positions)
        add_all_matches(digit, positions)
      end

      @bulls = @exact_matches
      @cows = @all_matches - @exact_matches
    end

    def digit_is_not_present_in_the_secret_code(digit)
      secret_code_hash[digit].empty?
    end

    def add_exact_matches(digit, positions)
      @exact_matches += (secret_code_hash[digit] & positions).size
    end

    def add_all_matches(digit, positions)
      @all_matches += [secret_code_hash[digit], positions].min_by(&:size).size
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
codebreaker_mats-0.1.7 lib/codebreaker_mats/matcher.rb