, A short time ago in a galaxy not so far, , far away I came across a nice blog post: 15 Exercises for Learning a new Programming Language.
, One could argue if these are *really* the most appropriate 15(+) exercises to learn a new programming language - however, , the task of answering this rather complex question is left as an exercise for the reader. , Instead of this I will show you their implementation in Ruby - rubyrailways.com style.
, Why did I bother to solve these problems (including not really trivial ones, , like a scientific calculator with a GUI) ? Well, , actually to learn a new programming language! I still consider myself a beginner Ruby apprentice just playing it by ear in my somewhat scarce free time, , so I thought that systematically implementing a task list like this will mean great step forward for me compared to just coding random things at random times. , Fortunately I was perfectly right!
, Before we move onto the code, , one last disclaimer: the fact that I am still a Ruby n00b implies that the code can be somewhat hairy/not optimal/[insert any other language than Ruby here]-ish so don’t use these snippets as a textbook solution of the problems or anything like that. , I would be glad if someone could suggest a bit of refactoring of the bad parts but I also hope that that there are some nice parts which you can learn from (actually I am quite sure about this since I used some magick formulas from a few Ruby (grand)masters in some cases).
, OK, , enough talk for now. , Let’s see the stuff!
, 1. , Problem: “Display series of numbers (1, ,2, ,3, ,4, , 5….etc) in an infinite loop. , The program should quit if someone hits a specific key (Say ESCAPE key).”
, Solution: Hmm, , well, , errr…uh-oh… , I could not solve this problem fully (what a terrific start :-)). , If Henry Ford would sit beside me now, , he would say : You can hit any key to exit - so long as it’s ‘C’ - and one more advice: don’t forget to hold CTRL during this action :-). , More on this after the code snippet:
,
- i = 0
- loop { print "#{i+=1}, , " }
, Comments : If anyone knows how to add code which will cause this program to stop with a specific keyhit (say ‘ESC’) please, , please, , please drop me a note. , I have been researching this for at least 10% of the time of solving all the tasks, , nearly spitting blood when I gave up :-). , It seems (to me) that there is no simple (i.e. , no threads and similar) and clean platform-independent solution for this problem. , I guess (hope) the author’s idea here was different than to introduce threading or writing platform specific-code…
, 2. , Problem: “Fibonacci series, , swapping two variables, , finding maximum/minimum among a list of numbers.”
, Solution:
,
- #Fibonacci series
- Fib = Hash.new{ |h, , n| n < 2 ? h[n] = n : h[n] = h[n - 1] + h[n - 2] }
- puts Fib[50]
- #Swapping two variables
- x, ,y = y, ,x
- #Finding maximum/minimum among a list of numbers
- puts [1, ,2, ,3, ,4, ,5, ,6].max
- puts [7, ,8, ,9, ,10, ,11].min
, Comments: The Fibonacci code was written by Andrew Johnson (found via Ruby Quiz). , I like it so much that I think it would be a shame to present a trivial version here. , I guess the rest of the code is self-explanatory.
, 3. , Problem: “Accepting series of numbers, , strings from keyboard and sorting them ascending, , descending order.”
, Solution:
,
- a = []
- loop { break if (c = gets.chomp) == ‘q’; a << c }
- p a.sort
- p a.sort { |a, ,b| b<=>a }
, Comments: This version is accepting strings - I think anybody who got to this point can adapt it to work with numbers. ,
, 4. , Problem: “Reynolds number is calculated using formula (D*v*rho)/mu Where D = Diameter, , V= velocity, , rho = density mu = viscosity Write a program that will accept all values in appropriate units (Don’t worry about unit conversion) If number is < 2100, , display Laminar flow, , If it’s between 2100 and 4000 display 'Transient flow' and if more than '4000', , display 'Turbulent Flow' (If, , else, , then...)"
, Solution:
,
- vars = %w{D V Rho Mu}
- vars.each do |var|
- print "#{var} = "
- val = gets
- eval("#{var}=#{val.chomp}")
- end
- reynolds = (D*V*Rho)/Mu.to_f
- if (reynolds < 2100)
- puts "Laminar Flow"
- elsif (reynolds > 4000)
- puts "Turbulent Flow"
- else
- puts "Transient Flow"
- end
, Comments: Can you spot the trick in the part which is filling up the variables? They don’t go out of scope after the loop ends because they are constants. , Other possibility would be to use $global variables but I guess it is usually not a very good programming practice to do that.
, 5. , Problem: “Modify the above program such that it will ask for ‘Do you want to calculate again (y/n), , if you say ‘y’, , it’ll again ask the parameters. , If ‘n’, , it’ll exit. , (Do while loop) While running the program give value mu = 0. , See what happens. , Does it give ‘DIVIDE BY ZERO’ error? Does it give ‘Segmentation fault..core dump?’. , How to handle this situation. , Is there something built in the language itself? (Exception Handling)”
, Solution:
,
- vars = { "d" => nil, , "v" => nil, , "rho" => nil, , "mu" => nil }
- begin
- vars.keys.each do |var|
- print "#{var} = "
- val = gets
- vars[var] = val.chomp.to_i
- end
- reynolds = (vars["d"]*vars["v"]*vars["rho"]) / vars["mu"].to_f
- puts reynolds
- if (reynolds < 2100)
- puts "Laminar Flow"
- elsif (reynolds > 4000)
- puts "Turbulent Flow"
- else
- puts "Transient Flow"
- end
- print "Do you want to calculate again (y/n)? "
- end while gets.chomp != "n"
,
Comments: As you can see, , I could not use the same trick here when asking for the variables, , because when somebody wants to calculate again, , Ruby will complain (although by printing a warning only) that the constants have been already set up. , Therefore I went for the hash solution. , I think the do-you-want-to-calculate-again part is straightforward so I won’t analyze that here.
“While running the program give value mu = 0.”
Ruby gives a rather interesting result in this case: infinity :-).
“Is there something built in the language itself?”
Sure: exception handling. , Division by zero could be caught with a ZeroDivisionError rescue clause.
, 6. , Problem: “Scientific calculator supporting addition, , subtraction, , multiplication, , division, , square-root, , square, , cube, , sin, , cos, , tan, , Factorial, , inverse, , modulus”
,
Solution:
Since this code snippet is longer It would look ugly here - you can download it from here instead. ,
Screenshot:
, If you would like to try it, , you will need the Tk bindings for Ruby (maybe you have them already, , here on Ubuntu I did not). , Also note that only the regular 0-9 keys (and of course the mouse) work, , the numpad ones do not. , One more little detail: % stands for modulo, , not percent.
, Comments: Phew, , this was a real challenge, , mostly because I never did any GUI in Ruby before. , I was amazed that I could code up a relatively feature rich calculator in 100+ lines of code, , without any golfing or trying to optimize for shortness. , What I wanted to say with this is that the shortness does not praise my programming skills (since I did not eve try to golf) but the superb terseness of Ruby. , OK, , of course there are some problems (e.g. , cube, , cos, , tan, , inverse are not implemented) but the usability/amount of code ratio is unbelievably high.
, The GUI is also not the nicest since I have used Tk - wxRuby or qt-ruby would produce much nicer results, , but since I did not code any GUI in Ruby previously, , I have decided to try the good-old-skool Tk for the first time.
, 7. , Problem: “Printing output in different formats (say rounding up to 5 decimal places, , truncating after 4 decimal places, , padding zeros to the right and left, , right and left justification)(Input output operations)”
, Solution:
,
- #rounding up to 5 decimal pleaces
- puts sprintf("%.5f", , 124.567896)
- #truncating after 4 decimal places
- def truncate(number, , places)
- (number * (10 ** places)).floor / (10 ** places).to_f
- end
- puts truncate(124.56789, , 4)
- #padding zeroes to the left
- puts ‘hello’.rjust(10, ,’0‘)
- #padding zeroes to the right
- puts ‘hello’.ljust(10, ,’0‘)
- #right justification
- puts ">>#{’hello’.rjust(20)}<<"
- #left justification
- puts ">>#{’hello’.ljust(20)}<<"
, Comments: Amazingly lot of things can be done with sprintf() - I could solve nearly all the problems with it - but that would not really be rubyish, , so I have decided for built-in (and one homegrown) functions. , However, , mastering (s)printf() is a very handy thing, , since nearly all big players (C (of course :-)), , C++, , Java, , PHP, , … , ) have it so you get a powerful function in more languages for the price of learning one). , As you can see, , r/ljust is a nice one, , too.
, 8. , Problem: “Open a text file and convert it into HTML file. , (File operations/Strings)”
, Solution: Well, , this problem was not specified in a great detail, , to say the least - or to put it otherwise, , the solvers are given a great freedom to provide a solution spiced up with their fantasy. , This is what I came up with:
,