Tuesday, October 2, 2012

Ruby and the joy of programming

Years ago I used to solve many mathematical problems in Ruby. Looking backwards, I find difficult to explain my decision, because if I remember correctly Ruby was slow compared with C++ or Perl, and since most of the time I ended using a brute force approach to solve what my imagination could not solve efficiently I often ended awaiting longer times before obtaining my answers.

However, I can clearly remember that for the first time in my conscious programming life, I was happy and I was enjoying my time with some programming language. So I didn't worry too much about some additional time awaiting a stupid brute force solution. I was solving mathematical puzzles for fun and with Ruby I could quickly test some crazy ideas, leave the process running and go to do other things. Ruby was powerful, concise, elegant, and more importantly it didn't force over me its formatting policies or push me to do things in some way I didn't like to. I had finally found a language where everything fitted in place and seemed natural. I thought: this language must have been created by someone who really likes having fun while programming.

And indeed it was. Ruby was created by Yukihiro Matsumoto (aka Matz), who is one of my heroes actually. I found an interview he gave about Ruby and there he said something that really touched a fiber inside me, I have always used his words as an inspiration:

For me, the purpose of life is, at least partly, to have joy.
Programmers often feel joy when they can concentrate on the creative
side of programming, So Ruby is designed to make programmers happy.
Ruby inherited the Perl philosophy of having more than one way
to do the same thing. I inherited that philosophy from Larry Wall,
who is my hero actually. I want to make Ruby users free. I want to
give them the freedom to choose. People are different. People choose
different criteria. But if there is a better way among many
alternatives, I want to encourage that way by making it comfortable.
So that's what I've tried to do.
I want to solve problems I meet in the daily life by using computers,
so I need to write programs. By using Ruby, I want to concentrate the
things I do, not the magical rules of the language, like starting with
public void something something something to say, "print hello world."
I just want to say, "print this!" I don't want all the surrounding
magic keywords. I just want to concentrate on the task. That's the basic
idea. So I have tried to make Ruby code concise and succinct.
Yukihiro Matsumoto. (http://www.artima.com/intv/rubyP.html)
view raw gistfile1.txt hosted with ❤ by GitHub
Fun to use. Freedom to choose. This man taught me all.


Is it a sin to look for fun in our craft? I'm not going to say that programming is the the hardest work in the world, neither the most complex, I believe it has its fine share of angst and grieving but not too much. What I can say for sure is that sometimes as a programmer you'll find yourself cornered for some nasty bugs or trying desperately to find a way to make something work between layers and layers of abstraction and piles of ugly code behind a deadline. And at those dark times getting a helping hand from the language or framework that you are using is really priceless. It would save your head of some heavy banging against the wall. If we as programmers can not make things easy and fun to use for our fellow peers, who is going to do it? Even if we don't get it right the first time, we must not admit defeat and try to do things better the next time. This is important for every programmer but for language and API creators is crucially important. I call this the rule of the "joy of programming". If it is not easy and fun to use, don't bother.

From these years many things have changed, I no longer use Ruby frequently, I found new languages with different approaches to programming, learned some new things, but the spirit of Ruby is always with me even now, and I think it would follow me forever, in every thing I'll create I'll try to make things the way Matz tried. Nothing less.

So I was remembering that quote, and I recalled that I used it for years as a programming exercise for possible hires. I gave them this "encrypted" text

Fxr nb, ekb dmrdxjb xf upfb pj, ie ubije direuo, ex kizb txo.
Drxlrinnbrj xfeby fbbu txo akby ekbo qiy qxyqbyerieb xy ekb qrbiepzb
jpwb xf drxlrinnpyl, Jx Rmho pj wbjplybw ex nigb drxlrinnbrj kiddo.
Rmho pykbrpebw ekb Dbru dkpuxjxdko xf kizpyl nxrb ekiy xyb aio
ex wx ekb jinb ekpyl. P pykbrpebw ekie dkpuxjxdko frxn Uirro Aiuu,
akx pj no kbrx iqemiuuo. P aiye ex nigb Rmho mjbrj frbb. P aiye ex
lpzb ekbn ekb frbbwxn ex qkxxjb. Dbxdub irb wpffbrbye. Dbxdub qkxxjb
wpffbrbye qrpebrpi. Hme pf ekbrb pj i hbeebr aio inxyl niyo
iuebryiepzbj, P aiye ex byqxmrilb ekie aio ho nigpyl pe qxnfxreihub.
Jx ekie'j akie P'zb erpbw ex wx.
P aiye ex jxuzb drxhubnj P nbbe py ekb wipuo upfb ho mjpyl qxndmebrj,
jx P ybbw ex arpeb drxlrinj. Ho mjpyl Rmho, P aiye ex qxyqbyerieb ekb
ekpylj P wx, yxe ekb nilpqiu rmubj xf ekb uiylmilb, upgb jeirepyl apek
dmhupq zxpw jxnbekpyl jxnbekpyl jxnbekpyl ex jio, "drpye kbuux axruw."
P tmje aiye ex jio, "drpye ekpj!" P wxy'e aiye iuu ekb jmrrxmywpyl
nilpq gboaxrwj. P tmje aiye ex qxyqbyerieb xy ekb eijg. Ekie'j ekb hijpq
pwbi. Jx P kizb erpbw ex nigb Rmho qxwb qxyqpjb iyw jmqqpyqe.
Omgpkprx Niejmnxex. (lxllub keed://aaa.irepni.qxn/pyez/rmhoD.kenu)
view raw gistfile1.txt hosted with ❤ by GitHub
along with the frequency of characters used by the language of the original message sorted from more to less used:

freqLang = "TEOIARNSHMLYGCPUDWFBVKJXQZ"

and it was their task to find the table of frequency of the "encrypted" message, compare it with the one given and substitute the characters. It was not trivial as FizzBuzz at all but with the steps to follow already mentioned in the problem many candidates found the problem interesting and fun. The secret message of course was the nice part for me. So here is the solution to my question in Killa:

// The text to decipher. It was created using a substitution cipher
var text = """
Fxr nb, ekb dmrdxjb xf upfb pj, ie ubije direuo, ex kizb txo.
Drxlrinnbrj xfeby fbbu txo akby ekbo qiy qxyqbyerieb xy ekb qrbiepzb
jpwb xf drxlrinnpyl, Jx Rmho pj wbjplybw ex nigb drxlrinnbrj kiddo.
Rmho pykbrpebw ekb Dbru dkpuxjxdko xf kizpyl nxrb ekiy xyb aio
ex wx ekb jinb ekpyl. P pykbrpebw ekie dkpuxjxdko frxn Uirro Aiuu,
akx pj no kbrx iqemiuuo. P aiye ex nigb Rmho mjbrj frbb. P aiye ex
lpzb ekbn ekb frbbwxn ex qkxxjb. Dbxdub irb wpffbrbye. Dbxdub qkxxjb
wpffbrbye qrpebrpi. Hme pf ekbrb pj i hbeebr aio inxyl niyo
iuebryiepzbj, P aiye ex byqxmrilb ekie aio ho nigpyl pe qxnfxreihub.
Jx ekie'j akie P'zb erpbw ex wx.
P aiye ex jxuzb drxhubnj P nbbe py ekb wipuo upfb ho mjpyl qxndmebrj,
jx P ybbw ex arpeb drxlrinj. Ho mjpyl Rmho, P aiye ex qxyqbyerieb ekb
ekpylj P wx, yxe ekb nilpqiu rmubj xf ekb uiylmilb, upgb jeirepyl apek
dmhupq zxpw jxnbekpyl jxnbekpyl jxnbekpyl ex jio, "drpye kbuux axruw."
P tmje aiye ex jio, "drpye ekpj!" P wxy'e aiye iuu ekb jmrrxmywpyl
nilpq gboaxrwj. P tmje aiye ex qxyqbyerieb xy ekb eijg. Ekie'j ekb hijpq
pwbi. Jx P kizb erpbw ex nigb Rmho qxwb qxyqpjb iyw jmqqpyqe.
Omgpkprx Niejmnxex. (lxllub keed://aaa.irepni.qxn/pyez/rmhoD.kenu)
"""
// This is the frequency table of the language of the original text
// (from more frequent to less frequent).
var freqLang = "TEOIARNSHMLYGCPUDWFBVKJXQZ"
// Create frequency table for the encrypted text.
var len = string.len(text)
var frequency = []
for (var k = 0; k < len; k += 1) {
var c = string.upper(string.sub(text, k, k));
// Check if character is an uppercase letter.
if (string.find(c, "%u") != null) {
if (frequency[c] == null) {
frequency[c] = 1
}
else {
frequency[c] += 1
}
}
}
// Create table for sorting the text frequency.
var sortFreq = {}
for each (var k,v in pairs(frequency)) {
table.insert(sortFreq, {key: k, value: v})
}
// Sort in descending order.
table.sort(sortFreq, function(a, b) { return (a.value > b.value) })
// Create dictionary for deciphering.
var dic = {}
var freqText = ''
var index = 0
for each (var _,v in pairs(sortFreq)) {
freqText ..= v.key
dic[v.key] = string.sub(freqLang, index, index)
index += 1
}
// Deciphering text by replacing characters.
var decrypted = ''
for (var k = 0; k < len; k += 1) {
var uppercase = false;
var c = string.sub(text, k, k)
if (string.find(c, "%u")) {
uppercase = true
}
else {
c = string.upper(c);
}
if (dic[c] != null) {
if (uppercase) {
decrypted ..= dic[c]
}
else {
decrypted ..= string.lower(dic[c])
}
}
else {
decrypted ..= c
}
}
print(decrypted)
view raw gistfile1.js hosted with ❤ by GitHub
After all I created Killa because I wanted to have more fun programming in Lua.

3 comments:

  1. Hi Laurens. An interesting looking language, though not intutively obvious how it works.

    I answered your challenge in PHP. If I knew Ruby better I would have used that. Not accounting for comment lines, I solved it in just 1 more line than you. PHP is odd. Not particularly elegant, it's 'swiss army knife' is an incredibly flexible array structure. Happy to share my code if you're interested.

    ReplyDelete
    Replies
    1. hi! it would be fun to see the PHP solution

      Delete
  2. minecraft java Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info.

    ReplyDelete