Skip to content

Instantly share code, notes, and snippets.

@smathy
Created November 6, 2009 21:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save smathy/228311 to your computer and use it in GitHub Desktop.
Save smathy/228311 to your computer and use it in GitHub Desktop.
Learn to Program

Chapter 2

Each one builds on the previous, ie. I re-use constants defined earlier.

Hours in a year

HOURS_IN_DAY = 24
DAYS_IN_YEAR = 365.242199
HOURS_IN_YEAR = HOURS_IN_DAY * DAYS_IN_YEAR
puts "Hours in an astronomical year: #{HOURS_IN_YEAR}"

Minutes in a decade

MINUTES_IN_HOUR = 60
MINUTES_IN_DECADE = 10 * MINUTES_IN_HOUR * HOURS_IN_YEAR
puts "Minutes in a decade: #{MINUTES_IN_DECADE}"

Your age in seconds

require 'date'
BIRTH_DATE = Date.new(1971,6,6)
SECONDS_IN_HOUR = 3600
SECONDS_IN_DAY = SECONDS_IN_HOUR * HOURS_IN_DAY
puts "My age in seconds: #{(Date.today - BIRTH_DATE).to_i * SECONDS_IN_DAY}"

Our dear author's age

AGE_IN_SECONDS = 1025 * 10**6
SECONDS_IN_YEAR = SECONDS_IN_DAY * DAYS_IN_YEAR
puts "Author's age: #{AGE_IN_SECONDS / SECONDS_IN_YEAR}"

Chapter 5

Full name greeting

names = []
%w/first second last/.each do |n|
  print "#{n.capitalize} name: "
  answer = gets.chomp
  names.push( answer ) if answer.length > 0
end

puts "Hello #{names.join(' ')}"

Bigger, better favorite number

print "What's your favorite number: "
answer = gets.chomp
puts "Don't you think #{ answer.to_i + 1 } is a bigger and better favorite number?"

Chapter 6

Angry boss

print "Whaddya want? "
answer = gets.chomp
puts %/WHADDYA MEAN "#{answer.upcase}"?!? YOU'RE FIRED!!/

Table of contents

WIDTH = 80
CONTENTS = [
  { :title => "Getting Started", :page => 1 },
  { :title => "Numbers", :page => 9 },
  { :title => "Letters", :page => 13 }
]

puts "Table of Contents".center(WIDTH)

CONTENTS.each_with_index do |h,i|
  lhs = "Chapter #{i+1}:  #{h[:title]} "
  rhs = " page" + h[:page].to_s.rjust(3)
  puts lhs + rhs.rjust(WIDTH-lhs.length, '.')
end

Chapter 7

99 Bottles of Beer on the Wall

i = START = 99
while i > 0
  b = i == 1 ? "" : "s"
  n = i-1
  c = "#{n} bottle#{n==1?'':'s'}"
  if i-1 == 0
    c = "no more bottles"
  end

  puts "#{i} bottle#{b} of beer on the wall, #{i} bottle#{b} of beer."
  puts "Take one down and pass it around, #{c} of beer on the wall."
  puts
  i -= 1
end

puts "No more bottles of beer on the wall, no more bottles of beer."
puts "Go to the store and buy some more, #{START} bottles of beer on the wall."

Deaf grandma

YEAR_B = 1930
YEAR_E = 1950

print "Hello dear.  "

answer = ''
while true
  print "What do you want? "
  answer = gets.chomp

  break if answer == 'BYE'

  if answer.match( /[a-z]/ )
    puts "HUH?!  SPEAK UP, SONNY!"
  else
    puts "NO, NOT SINCE #{YEAR_B + rand(YEAR_E-YEAR_B)}"
  end
  puts
end

puts "Bye dear."

Deaf grandma extended

YEAR_B = 1930
YEAR_E = 1950

print "Hello dear.  "

said_bye = 0

answer = ''
while said_bye < 3
  print "What do you want? "
  answer = gets.chomp

  if answer == 'BYE'
    said_bye += 1
  else
    said_bye = 0
  end
  if answer.match( /[a-z]/ )
    puts "HUH?!  SPEAK UP, SONNY!"
  else
    puts "NO, NOT SINCE #{YEAR_B + rand(1+YEAR_E-YEAR_B)}"
  end
  puts
end

puts "Oh, fine, bye dear."

Leap years

print "Start year: "
start_year = gets.chomp.to_i

print "End year: "
end_year = gets.chomp.to_i

start_year.upto(end_year) do |year|
  if year % 400 == 0 || ( year % 4 == 0 && year % 100 != 0 )
    puts year
  end
end

Chapter 8

Building and sorting an array

puts "Enter as many words as you like, one per line.  Blank line to end."
arr = []

while(true) do
  input = gets.chomp
  break if input == ''
  if input.include? ' '
    puts "Just one word per line please."
    next
  end
  arr.push input
end

puts "Your words, sorted alphabetically."
puts arr.sort

Table of contents, revisited

Already how I did it :)

Chapter 9

Improved ask method

def ask question
  while true
    puts question
    reply = gets.chomp.downcase
    if reply == 'yes' || reply == 'no'
      return reply == 'yes'
    else
      puts 'Please answer "yes" or "no".'
    end
  end
end

Old-school Roman numerals

@map = {
  1 => 'I',
  5 => 'V',
  10 => 'X',
  50 => 'L',
  100 => 'C',
  500 => 'D',
  1000 => 'M',
}

def roman_numeral num
  str = ''
  @map.sort.reverse.each do |decimal, roman|
    if( 0 < factor = num / decimal )
      str += roman * factor
      num %= decimal
    end
  end
  puts str
end

Modern Roman numerals

@map = {
  1 => 'I',
  4 => 'IV',
  5 => 'V',
  9 => 'IX',
  10 => 'X',
  40 => 'XL',
  50 => 'L',
  90 => 'XC',
  100 => 'C',
  400 => 'CD',
  500 => 'D',
  900 => 'CM',
  1000 => 'M',
}

def roman_numeral num
  str = ''
  @map.sort.reverse.each do |decimal, roman|
    if( 0 < factor = num / decimal )
      str += roman * factor
      num %= decimal
    end
  end
  puts str
end

Chapter 10

Sorts

This was my first free-form sort.

def __sort arr
  i = 0
  while i < arr.length - 1
    if arr[i] > arr[i+1]
      arr[i], arr[i+1] = arr[i+1], arr[i]
      i -= 1 unless i == 0
    else
      i += 1
    end
  end
end

This is the recursive version, but it just recurses on the index, not really the spirit of recursion.

def __recursive_sort arr, i = 0
  return unless i < arr.length - 1

  if arr[i] > arr[i+1]
    arr[i], arr[i+1] = arr[i+1], arr[i]
    i -= 1 unless i == 0
  else
    i += 1
  end
  __rsort arr, i
end

Here's a different version, which is my implementation of the algorithm Chris outlines in Learn to Program using a holder array.

Notice that I have extracted the core processing out into pop_smallest that pops the smallest element off an array. I also simplify the processing in that method by swapping the suspect rather than having the third array to hold the "still unsorted" elements.

class Array
  def pop_smallest
    suspect = self.shift

    self.each_with_index do |elem,i|
      if elem < suspect
        suspect, self[i] = self[i], suspect
      end
    end
    suspect
  end
end

Notice how simple these methods become once the core pop_smallest is factored out.

def sort to_sort
  sorted = []

  until to_sort.length == 0
    sorted << to_sort.pop_smallest
  end

  sorted
end

The recursive version is even simpler.

def rsort to_sort
  return [] if to_sort.length == 0

  return [ to_sort.pop_smallest ] + rsort( to_sort )
end

Shuffle

def shuffle arr
  arr.each_index do |i|
    r = rand(arr.length)
    arr[r], arr[i] = arr[i], arr[r]
  end
end

Dictionary sort

def __dsort arr
  i = 0
  while i < arr.length - 1
    if arr[i].downcase > arr[i+1].downcase
      arr[i], arr[i+1] = arr[i+1], arr[i]
      i -= 1 unless i == 0
    else
      i += 1
    end
  end
end

Expanded english_number

Wedding number

Ninety-nine Bottles of Beer on the Wall

Chapter 11

Safer picture downloading

Build your own playlist

Build a better playlist

Chapter 12

One billion seconds!

Happy birthday!

Party like it's roman_to_integer 'mcmxcix'!

Birthday helper!

Chapter 13

Extend the built-in classes

Orange tree

Interactive baby dragon

Chapter 14

Even better profiling

Grandfather clock

Program logger

Better program logger

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment