3
\$\begingroup\$

This is the "Codebreaker" game in Ruby. Tell me what I can make better!

#!/usr/bin/env ruby
class Sequence
  attr_accessor :guess, :code
  def initialize
    puts "Type the difficulty level you would like: 1, 2, 3, 4, or 5"
    begin
      @level = gets; @level = @level.to_i
      if @level > 6
        raise "Error"
      end
    rescue
      puts "Invalid Difficulty"
      exit
    end
  end
  def create_code
    @code = "#{rand(@level*2)}#{rand(@level*2)}#{rand(@level*2)}#{rand(@level*2)}"
    if @level == 5
      @code += "#{rand(@level*2)}"
    end
    if @code.length > 5
      puts "Invalid Difficulty!"
      exit
    end
    puts @code
  end
  def prompt
    @retstring = ""
    @guess = ""
    guesses = 0
    while guesses < 4
      print "Enter a guess: "
      @guess = gets
      x = 0
      4.times do
        if @code[x] == @guess[x]
          @retstring += "+"
        else
          @retstring += "-"
        end
        puts @retstring
        sleep(1)
        x += 1
      end
      puts "Would you like a hint? Type 'hint' to get a hint"
      hint = gets
      match = hint =~ /(h|H)(i|I)(n|N)\w/
      unless match == nil
        j = rand(@level*2)
        puts "#{j}: #{@code[j]}"
      end
      guesses += 1
      if @retstring == "++++"
        puts "Correct!"
        break
      end
      @retstring = ""
    end
  end
  def print_code
    print @code
    print " was the code\n"
  end
end
j = Sequence.new
j.create_code
j.prompt
j.print_code
\$\endgroup\$
5
\$\begingroup\$

Interesting game :), and reasonable code. I only have a few suggestions.

for

      if @level > 6
        raise "Error"
      end

and

    if @code.length > 5
      puts "Invalid Difficulty!"
      exit
    end

Any particular reason you handled the first one using exception and the second one using an if condition?

Also consider returning an error code, If program can be used in non-interactive way, printing any errors to stderr also helps. I would also modify it as

 def sexit(code, str)
     puts str
     exit code
 end

 def initialize
    puts "Type the difficulty level you would like: 1, 2, 3, 4, or 5"
    @level = gets.to_i
    sexit 1 "Invalid Difficulty"  if @level > 6
  end
  def create_code
    code_rows = 4
    code_rows += 1 if @level > 4
    @code = ''
    code_rows.times do
      @code += "#{rand(@level*2)}
    end

Should you check this here? It is more of an assert than a problem with user input, and the user input is validated elsewhere.

    # sexit 2 "Invalid Difficulty" if @code.length > 5

    puts @code
  end

Avoid magic numbers, replace 4 with a constant.

  def askuser(var)
      print var
      return gets
  end

Why is retstring and guess a member variable? You dont seem to be using them any where else.

  def prompt
    guess = ""

Whi is this a while loop? while you used a times loop inside?

    max_guess.times |guesses|
      retstring = ""
      guess = askuser "Enter a guess: "

you dont need to maintain x. Also, why do you have only 4 here? from the above, if the level is 5 you add a new cell.

      4.times do |x|

and better put as ternary

        retstring += (@code[x] == guess[x] ? "+" : "-")
        puts retstring
        sleep(1)
      end
      hint = askuser "Would you like a hint? Type 'hint' to get a hint"

Why do you use a separate match? Also name j some thing descriptive. And why \w ? Do you want to catch spellos in hint?

      if hint =~ /hint/i
        j = rand(@level*2)
        puts "#{j}: #{@code[j]}"
      end

Personally I prefer a case statement to check this. Also note you can get a case insensitive match.

      case askuser "Would you like a hint? Type 'hint' to get a hint"
      when /hint/i
        j = rand(@level*2)
        puts "#{j}: #{@code[j]}"
      end

      if retstring == "++++"
        puts "Correct!"
        break
      end

retstring is better reset at the beginning of the loop.

    end
  end

Regarding the whole organization, it might be better organized as a small command interpreter with specific commands for hint, level etc

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.