# frozen_string_literal: true module Codebreaker class Game include Validations attr_reader :difficulty, :errors, :secret_code CODE_DIGITS = (1..6).freeze CODE_LENGTH = 4 MATCH = '+' PRESENCE = '-' LEVELS = { silly: { attempts: 15, hints: 2, command: 'silly' }, moderate: { attempts: 10, hints: 1, command: 'moderate' }, clever: { attempts: 5, hints: 1, command: 'clever' } }.freeze def initialize @secret_code = Array.new(CODE_LENGTH) { rand(CODE_DIGITS) } @errors = [] end def guess(input) user_number = input.chars.map(&:to_i) validate(user_number) @user_number = user_number end def start @code = @secret_code.dup @attempts -= 1 matches_result = check_matches presence_result = check_presence @result = (matches_result + presence_result).join end def win? @result == MATCH * CODE_LENGTH end def lost? @attempts.zero? end def hint @hints.pop end def hints_left? @hints.any? end def set(input) return unless LEVELS.key?(input.to_sym) @difficulty = LEVELS.dig(input.to_sym, :command) @hints = @secret_code.sample(LEVELS.dig(@difficulty.to_sym, :hints)) @attempts = LEVELS.dig(@difficulty.to_sym, :attempts) end def to_h(name) { name: name, difficulty: @difficulty, attempts_total: LEVELS.dig(@difficulty.to_sym, :attempts), attempts_used: (LEVELS.dig(@difficulty.to_sym, :attempts) - @attempts), hints_total: LEVELS.dig(@difficulty.to_sym, :hints), hints_used: (LEVELS.dig(@difficulty.to_sym, :hints) - @hints.size) } end private def check_matches output = [] @code.each_with_index do |num, index| next unless num == @user_number[index] output << MATCH @user_number[index] = nil @code[index] = nil end output end def check_presence output = [] @code.compact! @user_number.compact.each do |num| next unless @code.include? num output << PRESENCE @code[@code.index(num)] = nil end output end # rubocop:disable Metrics/LineLength def validate(number) @errors = [] @errors << I18n.t(:GUESS_ERROR, quan: CODE_LENGTH, min: CODE_DIGITS.min, max: CODE_DIGITS.max) unless match_checker(number.size, CODE_LENGTH) number.each { |digit| @errors << I18n.t(:GUESS_ERROR, quan: CODE_LENGTH, min: CODE_DIGITS.min, max: CODE_DIGITS.max) unless range_checker(digit, CODE_DIGITS) } end # rubocop:enable Metrics/LineLength end end