#!/usr/bin/env ruby

# Trap
# Steve Ullman, 1972-08-01
# Ruby version Glenn Vanderburg, 2022-03-04

# Change these values to make the game easier or harder.
GUESSES_PER_GAME = 6
NUMBER_UPPER_BOUND = 100

# Put everything in methods for order of presentation; we
# want to be able to refer to methods before declaring them,
# so the code reads nicely from top to bottom.
def main
  print_banner_and_instructions

  loop do
    play_a_game
    break unless yes?("Try again?")
  end
end

def yes?(prompt)
  print "\n#{prompt} "
  answer = gets
  return answer.downcase.start_with?("y")
end

def print_banner_and_instructions
  banner = "Creative Computing -- Morristown, New Jersey"

  puts "Trap!".center(banner.size)
  puts banner
  2.times { puts }

  return unless yes?("Instructions?")

  puts <<~"END"
    I am thinking of a number between 1 and #{NUMBER_UPPER_BOUND}.
    Try to guess my number. On each guess,
    you are to enter 2 numbers, trying to trap
    my number between the two numbers. I will
    tell you if you have trapped my number, if my
    number is larger than your two numbers, or if
    my number is smaller than your two numbers.
    If you want to guess one single number, type
    your guess for both your trap numbers.
    You get #{GUESSES_PER_GAME} guesses to get my number.
  END
end

def play_a_game
  n = choose_number

  GUESSES_PER_GAME.times do |i|
    lower, upper = get_guesses("Guess ##{i+1}?")

    case
    when n < lower
      puts "My number is smaller than your trap numbers."
    when n > upper
      puts "My number is larger than your trap numbers."
    when lower != upper
      puts "You have trapped my number."
    else
      puts "You got it!!!"
      return
    end
  end

  puts "Sorry, that's #{GUESSES_PER_GAME} guesses. Number was #{n}"
end

def choose_number
  rand(NUMBER_UPPER_BOUND) + 1
end

def get_guesses(prompt)
  loop do
    print "\n#{prompt} "

    # This is forgiving of input format; it ignores spaces and
    # punctuation, returning only the strings of consecutive
    # digits in the input line.
    guesses = gets.scan(/\d+/)

    if guesses.size != 2
      puts "Please enter two numbers for each guess."
    else
      # convert the strings of digits to integers:
      numbers = guesses.map(&:to_i)
      # and return them, lowest number first:
      return numbers.sort
    end
  end
end

main
