diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..6200bfcb --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require "rake/testtask" + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + t.test_files = FileList["specs/*_spec.rb"] +end + +task default: :test diff --git a/art/distance.txt b/art/distance.txt new file mode 100644 index 00000000..e17e3b5f --- /dev/null +++ b/art/distance.txt @@ -0,0 +1,21 @@ + + + ________ + `---. `. + \ `. + )_______`. + .' //`---...___ + / || // || `-._ + )`-| =//= || || || / ).`. + _............_ ).-| || || `........'`-._ (o) + .-' `.----`. _...'.....__ || || _____ ||-\__.' + .' | Inter- | ).---.) /_______..--' || || ----- _ ||_/ +.'_ |Plantery| || || `-------' || || =\\= \_.' +| | | Travel | |'---'| )`-| || || _..-' +'--'_____________|_____| ).-| =\\= || \\ _.-' || +|[]--------------/ / __==\ \\ _.-' /o'\ + \ .--. / _...--'' '-.__......_.-' \__/ + `-._//'o\\___.'---'' \ .' + LGB \__/ -' / / + ___.' / + `-------' \ No newline at end of file diff --git a/art/goodbye.txt b/art/goodbye.txt new file mode 100644 index 00000000..b225f78c --- /dev/null +++ b/art/goodbye.txt @@ -0,0 +1,9 @@ + + + __ + \ \_____ +###[==_____> + /_/ __ + \ \_____ + ###[==_____> + /_/ diff --git a/art/planet.txt b/art/planet.txt new file mode 100644 index 00000000..a4bd805c --- /dev/null +++ b/art/planet.txt @@ -0,0 +1,12 @@ + + .::. + .:' .: + ,MMM8&&&.:' .:' + MMMMM88&&&& .:' + MMMMM88&&&&&&:' + MMMMM88&&&&&& + .:MMMMM88&&&&&& + .:' MMMMM88&&&& +.:' .:'MMM8&&&' +:' .:' +'::' jgs \ No newline at end of file diff --git a/art/solar.txt b/art/solar.txt new file mode 100644 index 00000000..51948f93 --- /dev/null +++ b/art/solar.txt @@ -0,0 +1,11 @@ + + + * + + ' | + () .-.,="``"=. - o - + '=/_ \ | + * | '=._ | + \ `=./`, ' + . '=.__.=' `=' * + + + + O * ' . jgs \ No newline at end of file diff --git a/art/unicorn.txt b/art/unicorn.txt new file mode 100644 index 00000000..8de66371 --- /dev/null +++ b/art/unicorn.txt @@ -0,0 +1,17 @@ + . + . . . . . . + . . . * + . * . . . . . . + . + "You Are Here" . . + . . . +. | . . . . . . + | . . . +. + . + \|/ . . . . + . . V . * . . . . + . + + . . . + + . . + .+. . + . . . + . . . . . + . . . . . . . . ! / + * . . . + . . - O - + . . . + . . * . . / | + . + . . . .. + . +. . . . * . * . +.. . * + . . . . . . . . + . . + \ No newline at end of file diff --git a/lib/main.rb b/lib/main.rb new file mode 100644 index 00000000..fc7e546b --- /dev/null +++ b/lib/main.rb @@ -0,0 +1,163 @@ +require "colorize" +require_relative "planet.rb" +require_relative "solar_system.rb" + +def main + display(load_solar_system_program) + continue = true + while continue + puts options + continue = do_option(get_option) + end + display(good_bye) +end + +def display(string, char = true, lag = 0.03) + if char + count = 0 + string.each_char do |ch| + print ch + sleep lag if count < 100 + count += 1 + end + else + puts string + end + return true +end + +def load_solar_system_program + @solar_system = SolarSystem.new("Err") + + create_system(solar_system) + return "Welcome to the".cyan + " Solar System Program.".light_magenta.bold \ + + read_file("./art/solar.txt").yellow + "\n\nYou are in the Solar System of #{solar_system.name}.\n".cyan +end + +def solar_system + return @solar_system +end + +def create_system(solar_system) + solar_system.add_planet(Planet.new("Willerr", "blue", 5.972e24, 1.496e28, + "raining rainbows")) + solar_system.add_planet(Planet.new("Saverr", "amber", 9.34e54, 2.345e23, + "saving time by reversing spin")) + solar_system.add_planet(Planet.new("Katerr", "green", 2.342e33, 4.234e43, + "being made of dolphins")) + solar_system.add_planet(Planet.new("Singherr", "onyx", 4.23e23, 46.2e23, + "emmitting song-like sounds")) +end + +def options + string_of_options = "\n\nEnter ".green + "LIST".cyan.on_blue.italic + " to display all the planets in system.".green \ + + "\nEnter ".green + "ADD ".cyan.on_blue.italic + " to add planets".green \ + + "\nEnter ".green + "CALC".cyan.on_blue.italic + " to calculate the distance between two planets".green \ + + "\nEnter ".green + "INFO".cyan.on_blue.italic + " to display information about a planet".green \ + + "\nEnter ".green + "Q ".cyan.on_blue.italic + " to quit program\n".green + return string_of_options +end + +def get_option + print "\nPlease Enter Selection: ".cyan + user_input = gets.chomp.upcase + return user_input if ["LIST", "ADD", "CALC", "INFO", "Q"].include?(user_input) + display("Hmm... ", true, 0.5) + puts "I don't understand \"#{user_input}\".".red.bold.underline + sleep 1 + get_option +end + +def do_option(option_key) + case option_key + when "LIST" + display(solar_system.list_planets.yellow) + when "ADD" + user_add_planet + when "CALC" + user_calc_distance + when "INFO" + display(user_info_planet.cyan) + sleep 1 + when "Q" + return false + end +end + +def user_add_planet + display("\nTo add a planet follow the prompts: \n".yellow) + print "Name? ".yellow + name = gets.chomp.capitalize + print "Color? ".yellow + color = gets.chomp.downcase + print "Mass in kg? ".yellow + mass = gets.chomp.to_i + print "Distance from sun in km? ".yellow + distance = gets.chomp.to_i + print "Fun fact? ".yellow + fun_fact = gets.chomp + begin + solar_system.add_planet(Planet.new(name, color, mass, distance, fun_fact)) + display("\nCongratulations #{solar_system.planets[-1].name} Succesfully Added!!".cyan.on_blue) + puts read_file("./art/planet.txt").light_magenta + rescue ArgumentError => error_message + display("\nError: #{error_message} \nReselect option from main menu to try again.".red.underline.bold) + end + return true +end + +def user_calc_distance + print "\nEnter first planet: ".yellow + planet1 = get_planet + return true if !planet1 + print "Enter second planet: ".yellow + planet2 = get_planet + return true if !planet2 + begin + distance = solar_system.distance_between(planet1, planet2) + puts read_file("./art/distance.txt").blue.bold + display("\nDirections from #{planet1.name.upcase} to #{planet2.name.upcase}:".light_magenta) + display("ONWARD -> ".cyan.on_blue) + display("%0.3e km ".cyan.on_blue % [distance]) + display("\nIt will take %0.2e light years, expected day of arrival: May 4th".magenta % [distance / 1.057e13]) + sleep 1 + rescue ArgumentError => error_message + display("\nError: #{error_message} \nReselect option from main menu to try again.".red.underline.bold) + end + return true +end + +def user_info_planet + print "\nWhich planet would you like more information on? ".yellow + planet = get_planet + return planet.summary if planet + return "Try using the numeric tags associated with planets from LIST command.".red +end + +def get_planet + planet_name = gets.chomp.capitalize + begin + planet = solar_system.find_planet_by_name(planet_name) + rescue ArgumentError + planet = planet_name.to_i.to_s == planet_name ? solar_system.planets[planet_name.to_i - 1] : nil + if !solar_system.is_a_Planet?(planet) + display("Hmm... ", true, 0.5) + puts "#{planet_name} is not in the system of #{solar_system.name}".cyan + end + end + return planet +end + +def read_file(file) + read = "" + File.open(file, "r") do |f| + read += f.read + end + return read +end + +def good_bye + return "\n\nGoodbye! Visit the #{solar_system.name} system again soon! Safe Travels!\n".magenta.bold.italic.underline + read_file("./art/unicorn.txt").light_magenta.bold + "\n" +end + +main diff --git a/lib/planet.rb b/lib/planet.rb new file mode 100644 index 00000000..2103668c --- /dev/null +++ b/lib/planet.rb @@ -0,0 +1,15 @@ +class Planet + attr_reader :name, :color, :mass_kg, :distance_from_sun_km, :fun_fact + + def initialize(name, color, mass_kg, distance_from_sun_km, fun_fact) + @name = name.capitalize + @color = color.downcase + @mass_kg = mass_kg > 0 ? mass_kg : (raise ArgumentError.new("Mass must be greater than 0.")) + @distance_from_sun_km = distance_from_sun_km > 0 ? distance_from_sun_km : (raise ArgumentError.new("Distance must be greater than 0.")) + @fun_fact = fun_fact.downcase + end + + def summary + return "\n#{name} is a #{color} planet that is %0.2e km from it's sun. \nIt has a mass of %0.2e kg and \nis known for #{fun_fact}." % [distance_from_sun_km, mass_kg] + end +end diff --git a/lib/solar_system.rb b/lib/solar_system.rb new file mode 100644 index 00000000..82a09204 --- /dev/null +++ b/lib/solar_system.rb @@ -0,0 +1,46 @@ +class SolarSystem + attr_reader :name, :planets + + def initialize(name) + @name = name.capitalize + @planets = Array.new + end + + def add_planet(planet) + raise ArgumentError.new("#{planet.capitalize} is not a Planet") if !is_a_Planet?(planet) + if planets.any? do |logged_planet| + planet.name == logged_planet.name + end + raise ArgumentError.new("#{planet.name}\'s name is in use.") + else + @planets << planet + end + return true + end + + def list_planets + string_planets = "\nPlanets orbiting #{self.name}\n" + @planets.each_with_index do |planet, i| + string_planets += "#{i + 1}. #{planet.name}\n" + end + return string_planets + end + + def find_planet_by_name(name) + @planets.each do |planet| + return planet if planet.name == name.capitalize + end + raise ArgumentError.new("No planet by #{name} found.") + end + + def distance_between(planet1, planet2) + if is_a_Planet?(planet1) && is_a_Planet?(planet2) + return (planet1.distance_from_sun_km - planet2.distance_from_sun_km).abs.to_i + end + raise ArgumentError.new("#{planet1} and/or #{planet2} not of type Planet") + end + + def is_a_Planet?(planet) + return planet.instance_of?(Planet) + end +end diff --git a/specs/planet_spec.rb b/specs/planet_spec.rb new file mode 100644 index 00000000..0e60f214 --- /dev/null +++ b/specs/planet_spec.rb @@ -0,0 +1,57 @@ +gem "minitest", ">= 5.0.0" +require "minitest/pride" +require "minitest/autorun" +require_relative "../lib/planet" + +describe "Planet" do + let (:earth) { + Planet.new("Earth", "blue-green", 5.972e24, 1.496e8, "Only planet known to support life") + } + + it "is an instance of Planet" do + expect(earth).must_be_instance_of Planet + end + + it "has a name" do + expect(earth.name).must_equal "Earth" + end + + it "has a color" do + expect(earth.color).must_equal "blue-green" + end + + it "has a mass" do + expect(earth.mass_kg).must_be_close_to 5.972e24, 0.01 + end + + it "has a distance from sun" do + expect(earth.distance_from_sun_km).must_be_close_to 1.496e8, 0.01 + end + + it "has a fun fact" do + expect(earth.fun_fact).must_equal "only planet known to support life" + end + + describe "summary" do + it "returns a string" do + expect(earth.summary).must_be_kind_of String + end + it "returns a summary of planet's attributes" do + expect(earth.summary).must_equal "\nEarth is a blue-green planet that is 1.50e+08 km from it's sun. \nIt has a mass of 5.97e+24 kg and \nis known for only planet known to support life." + end + end + + describe "test edge case for distance and mass" do + it "0 mass will raise argument error" do + expect { + Planet.new("Invisible", "clear", 0, 234230, " located everywhere, but nowhere") + }.must_raise ArgumentError + end + + it "0 distance will raise argument error" do + expect { + Planet.new("Rock", "jelly", 34535555, 0, " located everywhere, but nowhere") + }.must_raise ArgumentError + end + end +end diff --git a/specs/solar_system_spec.rb b/specs/solar_system_spec.rb new file mode 100644 index 00000000..9e9c386b --- /dev/null +++ b/specs/solar_system_spec.rb @@ -0,0 +1,98 @@ +gem "minitest", ">= 5.0.0" +require "minitest/pride" +require "minitest/autorun" +require_relative "../lib/solar_system" +require_relative "../lib/planet" + +describe "SolarSystem" do + let (:sol_system) { + SolarSystem.new("sol") + } + it "is an instance of SolarSystem" do + expect(sol_system).must_be_instance_of SolarSystem + end + + it "has a name" do + expect(sol_system.name).must_equal "Sol" + end + + let(:earth) { + Planet.new("Earth", "blue-green", 5.972e24, 1.496e8, "Only planet known to support life") + } + let(:mars) { + Planet.new("mars", "red", 5.9234, 1.2348, "Only planet thats red and dusty") + } + let(:mars2) { + Planet.new("mars", "red2", 25.9234, 12.2348, "Onlasdfy planet thats red and dusty") + } + before do + planets_test = [earth, mars] + planets_test.each do |planet| + sol_system.add_planet(planet) + end + end + describe "SolarSystem#add_planet" do + it "has a planet instance added to planets" do + expect(sol_system.planets).must_include earth + end + + it "raises ArgumentError if arg of type Planet" do + expect { + sol_system.add_planet("Earther") + }.must_raise ArgumentError + end + + it "raises ArgumentError if name is in use by another planet" do + expect { + sol_system.add_planet(mars2) + }.must_raise ArgumentError + end + end + + describe "SolarSystem#list_planets" do + it "returns a string" do + expect(sol_system.list_planets).must_be_instance_of String + end + + it "returns formatted list of sol_system" do + expect(sol_system.list_planets).must_equal "\nPlanets orbiting Sol\n1. Earth\n2. Mars\n" + end + end + + describe "SolarSystem#find_planet_by_name" do + it "returns instance of planet" do + expect(sol_system.find_planet_by_name("mArS")).must_be_instance_of Planet + end + + it "returns planet with same name, ignores mixed up/downcase" do + expect(sol_system.find_planet_by_name("mArS").name).must_equal "Mars" + end + + it "raises argument error if no planet by that name" do + expect { + sol_system.find_planet_by_name("whamo") + }.must_raise ArgumentError + end + end + + describe "SolarSystem#distance_between" do + it "returns an integer" do + expect(sol_system.distance_between(earth, mars)).must_be_instance_of Integer + end + + it "returns positive value" do + expect(sol_system.distance_between(mars, earth) >= 0).must_equal true + expect(sol_system.distance_between(earth, mars) >= 0).must_equal true + end + + it "raises ArgumentError if args not type Planet" do + expect { + sol_system.distance_between(mars, "earth") + }.must_raise ArgumentError + + expect { + sol_system.distance_between("earth", mars) + }.must_raise ArgumentError + end + end +end