Warden
Warden

Reputation: 109

Ruby small refactoring

I am making console app and user have to choose difficulty

def set_difficulty
  puts 'Choose difficulty between easy/normal/hard'
  difficulty = user_input

  if (difficulty) == 'easy'
    @hints = 2
    @attempts = 15
  elsif (difficulty) == 'normal'
    @hints = 1
    @attempts = 10
  elsif (difficulty) == 'hard'
    @hints = 1
    @attempts = 5
  else
    puts 'Wrong input'
    set_difficulty
  end
end

Is there any way to make this method smaller but easy to read and understand

Upvotes: 0

Views: 62

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110755

I would be inclined to write that as follows.

def set_difficulty
  loop do
    print 'Choose difficulty between easy/normal/hard: '
    case user_input
    when 'easy'
      break { hints: 2, attempts: 15 }
    when 'normal'
      break { hints: 1, attempts: 10 }
    when 'hard'
      break { hints: 1, attempts: 5 }
    else
      puts 'Wrong input'
    end
  end
end
def user_input
  gets.chomp.downcase
end

When set_difficulty is executed the following actions might take place.

Method displays 'Choose difficulty between easy/normal/hard: '
User enters     'Impossible!'      
Method displays 'Wrong input'
Method displays 'Choose difficulty between easy/normal/hard: '
User enters     'normal' (or 'Normal' or 'nOrMal' or similar)       
Method returns  { hints: 1, attempts: 10 }
  • I do not know what the method user_input does so I have assumed it merely accepts the user's entry, removes the return character and downcases what remains. If that's all it does there is no need for that method; simply replace user_input in set_difficulty with gets.chomp.downcase.
  • It is common practice to use a loop in these situations, breaking out of the loop after the user has given a valid answer. Making the method recursive (as in the question) is inefficient and makes the method harder to understand.
  • I have chosen to have the method return a hash (e.g., { hints: 1, attempts: 10 }) rather than an array (e.g., [1, 10]), to make its meaning more understandable in the part of the program where it is used.
  • by using print rather than puts in print 'Choose ... : ' the user's input is displayed immediately after the space that follows the colon (rather than at the beginning of the next line).

Upvotes: 0

dawg
dawg

Reputation: 104102

You can use a hash to hold different levels and unpacking to assign multiple variables:

levels={
    'easy'=>[2,15],
    'normal'=>[1,10],
    'hard'=>[1,5]
}

hints,attempts=levels['easy'] #hints=2, attempts=15

Upvotes: 2

spickermann
spickermann

Reputation: 107142

You could use a case block instead of elif:

def set_difficulty
  puts 'Choose difficulty between easy/normal/hard'
  
  case user_input 
  when  'easy'
    @hints = 2
    @attempts = 15
  when 'normal'
    @hints = 1
    @attempts = 10
  when 'hard'
    @hints = 1
    @attempts = 5
  else
    puts 'Wrong input'
    set_difficulty
  end
end

Or a hash with all options:

LEVELS = ={
  easy: [2, 15], normal: [1, 10], hard: [1, 5]
}

def set_difficulty
  puts 'Choose difficulty between easy/normal/hard'
  
  @hints, @attemps = LEVELS.fetch(user_input.to_sym) do
    puts 'Wrong input'
    set_difficulty      
  end
end

Note that the block of Hash#fetch is only called when the key is not found in the hash.

Upvotes: 3

Related Questions