Loading
Abi Travers

My Blog. Full Stack Software Engineer. Ex-Growth Hacker.

The Ruby Kata; Minimum Bonus, A Codewars Challenge

So it is week 4 of the pre-course for Makers Academy. I know what you are thinking .. where have you been on week3? I don’t see any posts? … Well the answer to your question is Barcelona, which meant having to do the whole of week 3 in two days .. which NO i do not recommend doing…

I thought I would delight my reader by creating a post on a codewars kuta I am bumbling through, since this week is all about achieving a level 5 kyu.

You can find my GitHub Repository to this challenge HERE so you can follow along with the commits and steps there if you prefer…  I would love it if you gave my little independent blog the chance to shine and stay on here though (..please mum …I know you don’t really read this, dad).

 

ruby kuta on codewars, minimum bonus

Obviously I was going to use a post on ‘kata’s to show off my pictures of Japan.

The Challenge:

Task which was given by codewars:

International hackers group organized a programming competition, in which n teams participated.

They were assigned to separate rooms for competitions, and the rooms were lined up in a straight line.

The game was over and each team scored points. It's time to pay bonuses. The rule is:

- The bonus unit is 1K($1000), and each team gets at least 1k.
- The bonus payment process is not public.
- A team can know the bonus amount of its adjacent team, if the
  score of the adjacent team is lower than itself.
- If a team finds that its bonus is no higher than the adjacent team whose
  score is lower than itself, the team will not be satisfied
Given an integer array scores represents the score of all teams. Your task is to calculate how much bonuses international hackers group need to pay to keep all teams satisfied.

Note, the unit of bonus is 1K. All teams are in a straight line, and their order is the same as that of the array elements.

Example

For scores = [10,20,30], the output should be 6.

team1's score = 10
team2's score = 20
team3's score = 30

team1 can get 1K, The team was satisfied
because it knew nothing about the other teams.

team2 can know team1's bonus amount,
So team2 at least get 2K to be satisfied

team3 can know team2's bonus amount,
So team3 at least get 3K to be satisfied

1 + 2 + 3 = 6
For scores = [10,20,20,30], the output should be 6.

The possible bonus amount of each team can be:[1,2,1,2]

For scores = [20,30,10,30,40,10,20,30,40,30], the output should be 20.

The possible bonus amount of each team can be:[1,2,1,2,3,1,2,3,4,1]

 

The Solution:

Step 1:

Understanding what is being asked and breaking it down into an english Explanation of what I want the code to do:

breaking the ruby kata down into english

def minimum_bonus(scores)
Making sense of the problem - writing it out in English 
  #scores are an array of numbers
  #the length of this array should be known/ calculated??)
  #1 (value) is asigned to the first number
  #if the second number is larger than the first it is given 2 (new_value =value +1)
  #if the second number is the same size or smaller than the first it is given 1
  #if the 3rd number is larger than the second it returns 3 (new_value +1)
  #if the 3rd number is smaller than the second it returns 1 (value)
  #all the values returned are added together and calculated.
end

The first thing I did was google; ‘how to select each element in an array with it’s index number’.

I found one extremely useful bit of information on how to best iterate through an array in ruby on stackoverflow:

  • each is sufficient for many usages, since I don’t often care about the indexes.
  • each_ with _index acts like Hash#each – you get the value and the index.
  • each_index – just the indexes. I don’t use this one often. Equivalent to “length.times”.
  • map is another way to iterate, useful when you want to transform one array into another.
  • select is the iterator to use when you want to choose a subset.
  • inject is useful for generating sums or products, or collecting a single result.

So I did this in irb:

2.4.0 :031 > minimum_bonus=[20,30,10,30,40,10,20,30,40,30]
 => [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]
2.4.0 :032 > minimum_bonus.each_with_index
 => #<Enumerator: [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]:each_with_index>
2.4.0 :033 > minimum_bonus.each_with_index do |x, index|
2.4.0 :034 >     if x[index

…..and before completing it I though .. oh I don’t think I need the index ..What I need is to change the input scores into the bonus number .. so I need map?

  • map is another way to iterate, useful when you want to transform one array into another.

The next thing I tested in irb was this:

def minimum_bonus(scores)
  scores=[20,30,10,30,40,10,20,30,40,30]
    scores.map do |x|
        x(1) = 1
        end
end

Then I googled:

“how to access an element in an array by its index number ruby”

And I came across each_with_index again, so decided to give it another chance.

def minimum_bonus(scores)
  scores=[20,30,10,30,40,10,20,30,40,30]
    scores.map.each_with_index do |item, index|
        if index == 0 then 
          item = 1
        end
    end

 

I still needed the map because I needed to alter the values in the original array.

When I tried this in irb it seemed to work:

2.4.0 :054 > scores=[20,30,10,30,40,10,20,30,40,30]
 => [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]
2.4.0 :055 >     scores.map.each_with_index do |item, index|
2.4.0 :056 >             if index == 0 then
2.4.0 :057 >                 item = 1
2.4.0 :058?>             end
2.4.0 :059?>       end
 => [1, nil, nil, nil, nil, nil, nil, nil, nil, nil]

When I extended the logic from this method it did not seem to work:

2.4.0 :088 > scores.map.each_with_index do |item, index|
2.4.0 :089 >             if index == 0 then
2.4.0 :090 >                 item = 1
2.4.0 :091?>             end
2.4.0 :092?>           if index[1] > index [0] then
2.4.0 :093 >                 item = 2
2.4.0 :094?>             end
2.4.0 :095?>         end
 => [nil, nil, 2, nil, nil, nil, 2, nil, nil, nil]
2.4.0 :096 >

So it looks like separating out the if statements over-rides the first one and the item in the array is only set for the second statement when it is returned.

It also looks like there is an issue with the numbering I am assigning to the index.

2.4.0 :096 >   scores.map.each_with_index do |item, index|
2.4.0 :097 >             if index == 0 then
2.4.0 :098 >                 item = 1
2.4.0 :099?>             elsif index[1] > index [0] then
2.4.0 :100 >                 item = 2
2.4.0 :101?>             end
2.4.0 :102?>     end
 => [1, nil, 2, nil, nil, nil, 2, nil, nil, nil]

I noticed I was still messing up on the index number while comparing values in the array. It then dawned on me that this is a ‘comparator’ question. We are to compare values in an array with each other and then assign them a new value based on that. So map may still be correct but I needed to set about googling:

“Comparing numerical values in an array with each other, Ruby”

I started to realised I had been spending too long on this kata and it is currently above my ability. I thought the best thing for me to do was to look at the answer and try to understand it and walk through it.

The Answer:

def minimum_bonus(scores)
  not_satisfy = true
  bonus = [1]
  (1...scores.size).each { |i| bonus << (scores[i] > scores[i-1] ? bonus[i-1]+1 : 1) }
  while not_satisfy
    (1...bonus.size).each do |i|  
      bonus[i-1]+=1 if bonus[i] == bonus[i-1] && scores[i] < scores[i-1]
    end
    
    (1...bonus.size).each do |i|
      if bonus[i] == bonus[i-1] && scores[i] != scores[i-1]
        not_satisfy = true
        break
      else
        not_satisfy = FALSE
      end
    end  
  end
  bonus.reduce(:+)
end

 

The Walk Through:

 

So there you have it, my complete thought process and logical reasoning while working through a codewar’s kuta on comparing elements within an array. I am very new to Ruby so I am assuming I will look back on this in the future and cringe at how long winded my approach was and how I went so wrong.

 

Learning Ruby The Hard Way | How I Beat the Un-stoppable Error Messages

Trouble shooting exercise 25 of learning ruby the hard way by zed

I have enrolled at the intense computer programming bootcamp, the Maker Academy, next month. To get a head start I thought I would work through Zed Shaw’s Learn Ruby the Hard Way book.

Exercise 25 seems to be testing my problem solving skills so I thought I would write a post documenting how I worked out then fixed my error messages. This post is aimed at newbies to the programming world as I imagine it is very basic things which I am getting wrong.

First Script – The Start of the Problem 

This was my first attempt at writing exercise 25’s script in my editor:

exercise 25 of Learn ruby the hard way by zed shaw error messages

 

 

 

 

 

 

 

 

 

 

 

 

When I ran this in the terminal I got the following error message:

ex25.rb:2:in `<main>’: undefined local variable or method `ex25′ for main:Object (NameError)

The first thing I did was google the error message.

Solving the Error Message with Google 

I found an answer on Stackoverflow. It told me I was accidentally typing Alt + Space on my Mac, therefore creating non-breaking space. That this is considered by Ruby as part of the variable name as opposed to the whitespace it was intended to be.

It gave two solutions to this problem:

1.  Remapping Alt + Space to space to stop this typo occurring again.

2. Highlighting invisible characters in text editor to immediately realise the typos.

 

The preference seemed to be for solution 2  so I thought I would try this way first. It seemed the most simple and quick to fix. I wanted to rule out the off-the-shelf issue to my broken code.

Highlight invisible characters in my text editor – Part 1

Next I googled how to highlight invisible characters with my text editor, Sublime Text editor 2.

Turns out this is supposed to be a default feature of my text editor. Every time I highlight text I am supposed to be able to see little white dots like the image below (look close they are there in the empty spaces):

how to highlight invisible characters with Sublime Text editor 2

 

 

 

 

 

 

 

 

So I highlighted the text and nothing happened:

textselected in sublime text editor 2 learn ruby the hard way ex25

 

I decided to park the problem of ‘non-breaking’ spaces here for now and try and solve my error message an easier way. I am relatively new to coding so the next solution for finding ‘non-breaking’ spaces, fixing the preferences or default key assignments in Sublime Text editor, did not seem like the easiest way to solve my problem.

Googling the exercise itself

The next thing I did was google ‘Ex25 learn Ruby the hard way’ to see if anyone else was having the same issues as I was. I found a blog with the exercise typed out. I compared our files word for word on my screen.

I could not SEE any difference between our files (indicating the hidden non-breaking spaces may be what is causing my error).

However I needed to rule out the idea there was a typo I couldn’t spot somewhere, so I typed out the whole file again. Figuring this was a quicker way to get to the solution.

My second file worked when I ran it in the terminal. No error message.

Here is the second file:

Script for exercise 25 learn ruby the hard way. no errors

I was intrigued where I went wrong with the first file still, so I compared them line for line.

Comparing the working script to the one with an error message

Compared them on my screen and noticed two differences which I fixed one at a time.

exercise 25 of learn ruby hard way. Errors

1.  When the earlier functions were called in later ones eg.

def ex25.print_first_and_last(sentence)

words = ex25.break_word ..

The ex25.break_word function looked like it had not been recognised in the error script (one on the right) whereas the Ex25. appeared blue in the other script (left).

The most obvious reason I could come up with  was that the ‘e’ wasn’t capitalised. So I changed all Ex25’s in the broken script to a capitalised e.

exercise 25 of learning ruby the hard way, broken script

 

I ran the script but still got the same error message:

ex25.rb:2:in `<main>’: undefined local variable or method `ex25' for main:Object (NameError)
2. The next easy fix I noticed was the file name and the function name in the broken script were the same but in my new script I had named the file EX25b.rb.

Maybe it was this difference in naming which was responsible for the error?

Nope ..

ex25.rb:2:in `<main>’: undefined local variable or method `ex25' for main:Object (NameError)

Had I read the whole of the exercise in Learning Ruby the Hard Way I would have seen this wasn’t the answer:

“The Ex25 module doesn’t have to be in a file named ex25.rb. Try putting it in a new file with a random name then import that file and see how you still have Ex25 available.”

So I decided to go back to the first solution, non-breaking space as I had now exhausted the easy options and couldn’t for the life of me  see any difference between the error or the correct script.

Highlight invisible characters in my text editor- Part 2 

I read how to do this here.

1.  Open the ‘preferences’ within Sublime text editor & select ‘key bindings’.

Preferences, key bindings within Sublime text editor 2

 

 

 

 

 

 

2.   Insert into the left side, the ‘user’ tab the following code:

{

"keys": ["alt+space"],
"command": "insert_snippet",
"args": {"contents": " "}

}


User tab of key binding sublime text editor

code inserted sublime text editor changing key bindings to show up alt + space bar on macs

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3.   Saved then re-opened the original (broken 🙁 ) file.

Sure enough there was the accidental Alt and space bar non-breaking space:

Alt and Space bar error on a mac and sublime editor 2

 

 

HALLELUJAH .. I thought.. I have finally fixed my old script…….

I ran it again and I STILL had the same error message!

Here is where I probably should have thought:

“I got it correct once and managed to work through the exercise and complete it. I will just call it a day and not worry about the file which is returning an error message”.

But I am too curious / stubborn to settle for just allowing the error to hang over my first script.

I ran irb in the terminal.

I ran the file I had got correct again & the file with the error message:

Error message in terminal. Incorrect Ex25 of learning Ruby the hard way

I tried to work out what was the difference between the two files.

Maybe it was the directories they were saved in?

I check and sure enough they were saved in different directories.

So I saved the error file in the same directory as the file that worked…. STILL the error message!!

I could see no other difference so I ….

Copied and pasted the text from the working file to the error file.

Then something terrible happened!

BOTH the files stopped working!!!!

The same error message appeared for the first file and now the working file was returning ‘false’ when I ‘required’ it with irb:

Ex25 script from learn ruby the hard way returning false in the terminal

Possible cause of this problem:

Too many files with the same or similar name in the same directory?

I deleted all but one… And like magic ..

IT WORKED !!!

I ran the working script for Ex25 in the terminal and followed the instructions on how to use irb to call it’s functions.

Here are my results and my explanation of what is happening:

The correct script for Ex25

Script for exercise 25 learn ruby the hard way. no errors

Running the script in command line ‘irb’

Ex25 in the terminal correct

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I have labeled the points where I had to think a bit about how it was working. Here is my explanation:

1.   Prints ‘wait’  because the function is acting on the ‘words’ array which is not sorted. The sorted array is called ‘sorted_words’.

2.   ‘Words’ array has had the first and last (“all’ and ‘wait’ ) values shifted off  in the print function.

3.  Calling on the ‘sorted_words’ array, not the ‘words’ array which has the missing values. Therefore ‘all’ is still in the array.

4….Seems to be missing from the picture … So I clearly deemed it irrelevant then therefore i will do the same again now..

5.  Using the original ‘sentence’ variable and passing this through the function. It is breaking this sentence variable into an array every time it encounters a space. Then using Ex25.sort_words function to sort this array of words.

6.  It is taking the original variable ‘sentence’, breaking it into an array of words then printing the first and last value of that array.

 

So we have now come to the end of my struggling with exercise 25 of Learn Ruby the Hard way. I hope you have enjoyed and found useful  my higgledy piggldy problem solving which eventually resulted in me beating the error messages given by running my script.  Please do contact me if you are by a slim chance reading this & need any help understanding it.

Enjoy, 🙂