diff --git a/assignments/assignment01.rb b/assignments/assignment01.rb
deleted file mode 100644
index cf3a605..0000000
--- a/assignments/assignment01.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# ========================================================================================
-# Sample Problem - `number_to_string`
-def number_to_string(n, lang)
- lang_digit_strings = {
- en: %w(zero one two three four five six seven eight nine),
- de: %w(null eins zwei drei vier fünf sechs sieben acht neun),
- es: %w(cero uno dos tres cuatro cinco seis siete ocho nueve),
- fr: %w(zéro un deux trois quatre cinq six sept huit neuf)
- }
-
- digit_strings = lang_digit_strings[lang]
- return "no such language" if digit_strings.nil?
-
- s = n.to_s
- string_digits = s.split ""
-
-
- num_digits = []
- string_digits.each do |s|
- num_digits << s.to_i
- end
-
- result = ""
- num_digits.each do |digit|
- result << digit_strings[digit]
- result << " "
- end
-
- result.chop
-end
-
-
-# ========================================================================================
-# Problem 1 - `titleize`
-
-# implement a method `titleize`
-
-# it accepts a string
-# and returns the same string with each word capitalized.
-def titleize(s)
- words = s.split
- caps = []
- words.each do |word|
- caps << word.capitalize
- end
- caps.join " "
-end
-
-# Your method should generate the following results:
-titleize "hEllo WORLD" #=> "Hello World"
-
-titleize "gooDbye CRUel wORLD" #=> "Goodbye Cruel World"
-
-
-# ========================================================================================
-# Problem 2 - `my_reverse`
-
-# Write your own implementation of `reverse` called `my_reverse`
-# You may *not* use the built-in `reverse` method
-def my_reverse(s)
- output = ""
- letters = s.split ""
- n = letters.length
- while n > 0
- n -= 1
- output << letters[n]
- end
- output
-end
-
-# Your method should generate the following results:
-my_reverse "Hello World" #=> "dlroW olleH"
-
-my_reverse "Goodbye Cruel World" #=> "dlroW leurC eybdooG"
-
-
-# ========================================================================================
-# Problem 3 - `palindrome?`
-
-# Write a method `palindrome?`
-# that determines whether a string is a palindrome
-def palindrome?(s)
- stripped = s.delete(" ").delete(",").downcase
- stripped == stripped.reverse
-end
-
-# Your method should generate the following results:
-palindrome? "abba" #=> true
-palindrome? "aBbA" #=> true
-palindrome? "abb" #=> false
-
-palindrome? "Able was I ere I saw elba" #=> true
-palindrome? "A man, a plan, a canal, Panama" #=> true
diff --git a/assignments/assignment02-input.csv b/assignments/assignment02-input.csv
deleted file mode 100644
index a19c0fd..0000000
--- a/assignments/assignment02-input.csv
+++ /dev/null
@@ -1,53 +0,0 @@
-date,payee,amount,type
-12/1/2014,Walgreens,21.92,withdrawal
-12/18/2014,check #5129,125.00,withdrawal
-12/16/2014,check #5127,50.00,withdrawal
-12/7/2014,Safeway,23.89,withdrawal
-12/31/2014,Starbucks,8.45,withdrawal
-12/30/2014,ATM,100.00,withdrawal
-12/4/2014,Univ Washington,1500.00,deposit
-12/4/2014,Starbucks,5.30,withdrawal
-12/4/2014,Subway,7.80,withdrawal
-12/5/2014,Nike Town,85.00,withdrawal
-12/6/2014,Starbucks,5.30,withdrawal
-12/6/2014,ATM,50.00,deposit
-12/8/2014,Starbucks,5.30,withdrawal
-12/11/2014,Safeway,42.15,withdrawal
-12/9/2014,Bartell's,7.83,withdrawal
-12/9/2014,check #5128,575.00,withdrawal
-12/15/2014,Starbucks,5.30,withdrawal
-12/22/2014,check #5130,120.00,withdrawal
-12/15/2014,ATM,50.00,deposit
-12/11/2014,Home Depot,17.89,withdrawal
-12/18/2014,Starbucks,5.30,withdrawal
-12/27/2014,Walgreens,14.56,withdrawal
-12/30/2014,Safeway,35.17,withdrawal
-12/23/2014,Starbucks,5.30,withdrawal
-12/18/2014,Starbucks,5.30,withdrawal
-12/31/2014,check #5131,20.00,withdrawal
-12/7/2014,check #5132,75.00,withdrawal
-12/14/2014,check #5133,17.50,withdrawal
-12/13/2014,check #5134,45.68,withdrawal
-12/14/2014,Office Depot,24.85,withdrawal
-12/17/2014,Apple,110.62,withdrawal
-12/6/2014,ATM,500.00,deposit
-12/26/2014,check #5135,62.50,withdrawal
-12/28/2014,check #5136,62.50,withdrawal
-12/27/2014,Starbucks,5.30,withdrawal
-12/12/2014,ATM,60.00,withdrawal
-12/13/2014,QFC,13.25,withdrawal
-12/13/2014,check #5126,25.00,withdrawal
-12/19/2014,Chipotle,10.42,withdrawal
-12/18/2014,Bartell's,14.82,withdrawal
-12/22/2014,Safeway,28.45,withdrawal
-12/21/2014,ATM,20.00,deposit
-12/22/2014,QFC,48.13,withdrawal
-12/22/2014,Shell,52.00,withdrawal
-12/5/2014,ATM,60.00,withdrawal
-12/7/2014,Arco,42.00,withdrawal
-12/17/2014,Univ Washington,1500.00,deposit
-12/14/2014,Chipotle,10.42,withdrawal
-12/15/2014,ATM,60.00,withdrawal
-12/16/2014,7-Eleven,5.26,withdrawal
-12/16/2014,Arco,48.01,withdrawal
-12/29/2014,Starbucks,5.30,withdrawal
diff --git a/assignments/assignment02-output.html b/assignments/assignment02-output.html
deleted file mode 100644
index c327bd7..0000000
--- a/assignments/assignment02-output.html
+++ /dev/null
@@ -1,472 +0,0 @@
-
-
- Bank Statement
-
-
-
- Bank Statement
- Summary
-
- | Starting Balance | $ 0.00 |
- | Total Deposits | $ 3,620.00 |
- | Total Withdrawals | $ 2,178.76 |
- | Ending Balance | $ 1,441.24 |
-
-
- Withdrawals
-
-
- | 12/01/2014 |
- Walgreens |
- $ 21.92 |
-
-
-
- | 12/04/2014 |
- Subway |
- $ 7.80 |
-
-
-
- | 12/04/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/05/2014 |
- Nike Town |
- $ 85.00 |
-
-
-
- | 12/05/2014 |
- ATM |
- $ 60.00 |
-
-
-
- | 12/06/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/07/2014 |
- check #5132 |
- $ 75.00 |
-
-
-
- | 12/07/2014 |
- Arco |
- $ 42.00 |
-
-
-
- | 12/07/2014 |
- Safeway |
- $ 23.89 |
-
-
-
- | 12/08/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/09/2014 |
- Bartell's |
- $ 7.83 |
-
-
-
- | 12/09/2014 |
- check #5128 |
- $ 575.00 |
-
-
-
- | 12/11/2014 |
- Home Depot |
- $ 17.89 |
-
-
-
- | 12/11/2014 |
- Safeway |
- $ 42.15 |
-
-
-
- | 12/12/2014 |
- ATM |
- $ 60.00 |
-
-
-
- | 12/13/2014 |
- check #5134 |
- $ 45.68 |
-
-
-
- | 12/13/2014 |
- check #5126 |
- $ 25.00 |
-
-
-
- | 12/13/2014 |
- QFC |
- $ 13.25 |
-
-
-
- | 12/14/2014 |
- Office Depot |
- $ 24.85 |
-
-
-
- | 12/14/2014 |
- check #5133 |
- $ 17.50 |
-
-
-
- | 12/14/2014 |
- Chipotle |
- $ 10.42 |
-
-
-
- | 12/15/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/15/2014 |
- ATM |
- $ 60.00 |
-
-
-
- | 12/16/2014 |
- Arco |
- $ 48.01 |
-
-
-
- | 12/16/2014 |
- check #5127 |
- $ 50.00 |
-
-
-
- | 12/16/2014 |
- 7-Eleven |
- $ 5.26 |
-
-
-
- | 12/17/2014 |
- Apple |
- $ 110.62 |
-
-
-
- | 12/18/2014 |
- Bartell's |
- $ 14.82 |
-
-
-
- | 12/18/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/18/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/18/2014 |
- check #5129 |
- $ 125.00 |
-
-
-
- | 12/19/2014 |
- Chipotle |
- $ 10.42 |
-
-
-
- | 12/22/2014 |
- check #5130 |
- $ 120.00 |
-
-
-
- | 12/22/2014 |
- Shell |
- $ 52.00 |
-
-
-
- | 12/22/2014 |
- Safeway |
- $ 28.45 |
-
-
-
- | 12/22/2014 |
- QFC |
- $ 48.13 |
-
-
-
- | 12/23/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/26/2014 |
- check #5135 |
- $ 62.50 |
-
-
-
- | 12/27/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/27/2014 |
- Walgreens |
- $ 14.56 |
-
-
-
- | 12/28/2014 |
- check #5136 |
- $ 62.50 |
-
-
-
- | 12/29/2014 |
- Starbucks |
- $ 5.30 |
-
-
-
- | 12/30/2014 |
- ATM |
- $ 100.00 |
-
-
-
- | 12/30/2014 |
- Safeway |
- $ 35.17 |
-
-
-
- | 12/31/2014 |
- Starbucks |
- $ 8.44 |
-
-
-
- | 12/31/2014 |
- check #5131 |
- $ 20.00 |
-
-
-
-
- Deposits
-
-
- | 12/04/2014 |
- Univ Washington |
- $ 1,500.00 |
-
-
-
- | 12/06/2014 |
- ATM |
- $ 50.00 |
-
-
-
- | 12/06/2014 |
- ATM |
- $ 500.00 |
-
-
-
- | 12/15/2014 |
- ATM |
- $ 50.00 |
-
-
-
- | 12/17/2014 |
- Univ Washington |
- $ 1,500.00 |
-
-
-
- | 12/21/2014 |
- ATM |
- $ 20.00 |
-
-
-
-
- Daily Balances
-
-
- | 12/01/2014 |
- $ -21.92 |
-
-
-
- | 12/04/2014 |
- $ 1,464.98 |
-
-
-
- | 12/05/2014 |
- $ 1,319.98 |
-
-
-
- | 12/06/2014 |
- $ 1,864.68 |
-
-
-
- | 12/07/2014 |
- $ 1,723.79 |
-
-
-
- | 12/08/2014 |
- $ 1,718.49 |
-
-
-
- | 12/09/2014 |
- $ 1,135.66 |
-
-
-
- | 12/11/2014 |
- $ 1,075.62 |
-
-
-
- | 12/12/2014 |
- $ 1,015.62 |
-
-
-
- | 12/13/2014 |
- $ 931.69 |
-
-
-
- | 12/14/2014 |
- $ 878.92 |
-
-
-
- | 12/15/2014 |
- $ 863.62 |
-
-
-
- | 12/16/2014 |
- $ 760.35 |
-
-
-
- | 12/17/2014 |
- $ 2,149.73 |
-
-
-
- | 12/18/2014 |
- $ 1,999.31 |
-
-
-
- | 12/19/2014 |
- $ 1,988.89 |
-
-
-
- | 12/21/2014 |
- $ 2,008.89 |
-
-
-
- | 12/22/2014 |
- $ 1,760.31 |
-
-
-
- | 12/23/2014 |
- $ 1,755.01 |
-
-
-
- | 12/26/2014 |
- $ 1,692.51 |
-
-
-
- | 12/27/2014 |
- $ 1,672.65 |
-
-
-
- | 12/28/2014 |
- $ 1,610.15 |
-
-
-
- | 12/29/2014 |
- $ 1,604.85 |
-
-
-
- | 12/30/2014 |
- $ 1,469.68 |
-
-
-
- | 12/31/2014 |
- $ 1,441.24 |
-
-
-
-
-
-
-
diff --git a/assignments/assignment02.rb b/assignments/assignment02.rb
index 532f55c..95a94db 100644
--- a/assignments/assignment02.rb
+++ b/assignments/assignment02.rb
@@ -9,14 +9,12 @@
# creates an english string from array
-def to_sentence(ary)
- if ary.length == 0
- []
- elsif ary.length == 1
- ary[0]
+def to_sentence(ary)
+ unless (ary.length < 2)
+ last_word = ary.pop.to_s
+ sentence = (ary.join ", ") << " and " << last_word
else
- last = ary.pop
- "#{ary.join(", ")} and #{last}"
+ ary.pop.to_s
end
end
@@ -32,21 +30,13 @@ def to_sentence(ary)
# implement methods "mean", "median" on Array of numbers
def mean(ary)
- sum = ary.reduce(0) {|x, acc| acc + x}
- sum.to_f / ary.length
+ ary.reduce {|item, acc| acc + item} / ary.length.to_f
end
def median(ary)
- sorted_ary = ary.sort
- len = sorted_ary.length
- mid_index = len/2
- if len.odd?
- sorted_ary[mid_index]
- else
- mid_lo = sorted_ary[mid_index]
- mid_hi = sorted_ary[mid_index+1]
- (mid_lo + mid_hi)/2.0
- end
+ middle = ary.length / 2
+ sorted = ary.sort
+ ary.length.odd? ? sorted[middle] : 0.5 * (sorted[middle] + sorted[middle - 1])
end
# Your method should generate the following results:
@@ -62,7 +52,13 @@ def median(ary)
# implement method `pluck` on array of hashes
def pluck(ary, key)
- ary.map {|item| item[key]}
+ # create an empty array
+ values = []
+ # for each element in ary, fetch the value associated with key
+ # push the value into values
+ ary.each_index {|x| values.push ary[x].fetch(key, "")}
+ #return values
+ values
end
# Your method should generate the following results:
@@ -90,10 +86,9 @@ def pluck(ary, key)
# - daily balance
# - summary:
# - starting balance, total deposits, total withdrawals, ending balance
+
def bank_statement
-
- # ------------------------------------------------------------------------
- # formatting helpers:
+
def format_currency(amount)
prefix = if amount < 0
amount = -amount
@@ -117,15 +112,13 @@ def format_currency(amount)
end
"$ #{prefix}#{dollars}.#{cents}"
end
-
+
def format_date(date)
month_string = date[:month] < 10 ? "0#{date[:month]}" : date[:month].to_s
- day_string = date[:day] < 10 ? "0#{date[:day]}" : date[:day].to_s
+ day_string = date[:day] < 10 ? "0#{date[:day]}" : date[:day].to_s
"#{month_string}/#{day_string}/#{date[:year]}"
end
-
- # ------------------------------------------------------------------------
- # rendering:
+
def render_html(statement)
<<-HTML
@@ -133,7 +126,7 @@ def render_html(statement)
Bank Statement
@@ -142,105 +135,92 @@ def render_html(statement)
HTML
end
-
+
def render_body(statement)
- <<-BODY
-
- Bank Statement
- #{render_summary statement[:summary]}
- #{render_txs statement[:withdrawals], "Withdrawals"}
- #{render_txs statement[:deposits], "Deposits"}
- #{render_daily_balances statement[:dates], statement[:daily_balances]}
-
- BODY
+ <<-BODY
+
+ Bank Statement
+ #{render_summary statement[:summary]}
+ #{render_txs statement[:withdrawals], "Withdrawals"}
+ #{render_txs statement[:deposits], "Deposits"}
+ #{render_daily_balances statement[:dates], statement[:daily_balances]}
+
+ BODY
end
-
+
def render_summary(summary)
- <<-SUMMARY
- Summary
-
- | Starting Balance | #{format_currency summary[:starting_balance]} |
- | Total Deposits | #{format_currency summary[:sum_deposits]} |
- | Total Withdrawals | #{format_currency summary[:sum_withdrawals]} |
- | Ending Balance | #{format_currency summary[:ending_balance]} |
-
- SUMMARY
- end
-
- def render_tx(tx)
- <<-TX
-
- | #{tx[:formatted_date]} |
- #{tx[:payee]} |
- #{format_currency tx[:amount]} |
-
- TX
- end
-
- def render_txs(txs, label)
- <<-TXS
- #{label}
-
- #{txs.map {|tx| render_tx tx}.join "\n"}
-
- TXS
- end
+ <<-SUMMARY
+ Summary
+
+ | Starting Balance | #{format_currency summary[:starting_balance]} |
+ | Total Deposits | #{format_currency summary[:sum_deposits]} |
+ | Total Withdrawals | #{format_currency summary[:sum_withdrawals]} |
+ | Ending Balance | #{format_currency summary[:ending_balance]} |
+
+ SUMMARY
+ end
- def render_daily_balance(date, balance)
- <<-TXS
-
- | #{date} |
- #{format_currency balance[:summary][:ending_balance]} |
-
- TXS
- end
+ def render_tx(tx)
+ <<-TX
+
+ | #{tx[:formatted_date]} |
+ #{tx[:payee]} |
+ #{format_currency tx[:amount]} |
+
+ TX
+ end
- def render_daily_balances(dates, balances)
- <<-BALANCES
- Daily Balances
-
- #{dates.map {|date| render_daily_balance date, balances[date]}.join "\n"}
-
- BALANCES
- end
+ def render_txs(txs, label)
+ <<-TXS
+ #{label}
+
+ #{txs.map {|tx| render_tx tx}.join "\n"}
+
+ TXS
+ end
- # ------------------------------------------------------------------------
- # read csv file, generate txs:
- def read_txs
+ def render_daily_balance(date, balance)
+ <<-TXS
+
+ | #{date} |
+ #{format_currency balance[:summary][:ending_balance]} |
+
+ TXS
+ end
+
+ def read_transactions
File.open("assignment02-input.csv") do |file|
lines = file.readlines
keys = lines.shift.chomp.split(",").map {|key| key.to_sym}
lines.map do |line|
- tx = {}
+ transaction = {}
line.chomp.split(",").each_with_index do |field, index|
key = keys[index]
- tx[key] = field
+ transaction[key] = field
end
- tx
- end.map do |tx|
- tx[:amount] = (tx[:amount].to_f * 100).to_i
- month, day, year = tx[:date].split "/"
+ transaction
+ end.map do |transaction|
+ transaction[:amount] = (transaction[:amount].to_f * 100).to_i
+ month, day, year = transaction[:date].split "/"
date = {year: year.to_i, month: month.to_i, day: day.to_i}
- tx[:date] = date
- tx[:formatted_date] = format_date date
- tx
+ transaction[:date] = date
+ transaction[:formatted_date] = format_date date
+ transaction
end.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]}
end
end
-
- # ------------------------------------------------------------------------
- # calc totals for collection of txs:
- def txs_totals(txs, starting_balance)
- withdrawals = txs.select {|tx| tx[:type] == "withdrawal"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]}
- sum_withdrawals = withdrawals.reduce(0) {|acc, tx| acc += tx[:amount]}
- deposits = txs.select {|tx| tx[:type] == "deposit"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]}
- sum_deposits = deposits.reduce(0) {|acc, tx| acc += tx[:amount]}
+ def transaction_totals(transactions, starting_balance)
+ withdrawals = transactions.select {|transaction| transaction[:type] == "withdrawal"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]}
+ sum_withdrawals = withdrawals.reduce(0) {|acc, transaction| puts "transaction => #{transaction}, acc => #{acc}"; acc += transaction[:amount]}
+
+ deposits = transactions.select {|transaction| transaction[:type] == "deposit"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]}
+ sum_deposits = deposits.reduce(0) {|acc, transaction| puts "transaction => #{transaction}, acc => #{acc}"; acc += transaction[:amount]}
ending_balance = starting_balance + sum_deposits - sum_withdrawals
-
+
{
summary: {
starting_balance: starting_balance,
@@ -252,44 +232,37 @@ def txs_totals(txs, starting_balance)
deposits: deposits
}
end
-
- # ------------------------------------------------------------------------
- # calc statement from txs:
- def calc_statement(txs)
- statement = txs_totals txs, 0
- dates = txs.map {|tx| tx[:formatted_date]}.uniq.sort
+ def calc_statement(transactions)
+ statement = transactions_totals transactions, 0
+
+ dates = transactions.map {|transaction| transaction[:formatted_date]}.uniq.sort
daily_balances = {}
dates.each_with_index do |date, index|
- txs_for_date = txs.select {|tx| tx[:formatted_date] == date}
+ transactions_for_date transactions.select {|transaction| transaction[:formatted_date] == date}
starting_balance = if index == 0
- # first day, so use starting balance:
statement[:summary][:starting_balance]
else
- # use ending balance of previous date:
prev_date = dates[index-1]
daily_balances[prev_date][:summary][:ending_balance]
end
- daily_balances[date] = txs_totals txs_for_date, starting_balance
+ daily_balances[date] = transactions_totals transactions_for_date, starting_balance
end
statement[:dates] = dates
statement[:daily_balances] = daily_balances
statement
end
-
- # ------------------------------------------------------------------------
- # write html to file:
+
def write_html(html)
File.open("assignment02-output.html", "w") do |file|
file.write html
end
end
-
- # ------------------------------------------------------------------------
- txs = read_txs
- statement = calc_statement txs
+
+ transactions = read_transactions
+ statement = calc_statement transactions
html = render_html statement
write_html html
nil
-end
+end
\ No newline at end of file
diff --git a/assignments/assignment03.rb b/assignments/assignment03.rb
index ee5cd93..dfbe82f 100644
--- a/assignments/assignment03.rb
+++ b/assignments/assignment03.rb
@@ -4,37 +4,47 @@
# ========================================================================================
# Problem 1 - re-implement titleize, palindrome?
-
# re-implement titleize and palindrome? as methods on String
-"hEllo WORLD".titleize #=> "Hello World"
-"gooDbye CRUel wORLD".titleize #=> "Goodbye Cruel World"
-
-"abba".palindrome? #=> true
-"aBbA".palindrome? #=> true
-"abb".palindrome? #=> false
-
-"Able was I ere I saw elba".palindrome? #=> true
-"A man, a plan, a canal, Panama".palindrome? #=> true
-
+class String
+ def titleize
+ word = self.split
+ title=[]
+ word.each do |words|
+ title << words.capitalize
+ end
+ title.join " "
+ end
+
+ def palindrome?
+ inputstring = self.delete(" ").delete(",").downcase
+ inputstring == inputstring.reverse
+ end
+end
# ========================================================================================
# Problem 2 - re-implement mean, median, to_sentence
-
# re-implement mean, median, to_sentence as methods on Array
-
-# Your method should generate the following results:
-[1, 2, 3].mean #=> 2
-[1, 1, 4].mean #=> 2
-
-[1, 2, 3].median #=> 2
-[1, 1, 4].median #=> 1
-
-[].to_sentence #=> ""
-["john"].to_sentence #=> "john"
-["john", "paul"].to_sentence #=> "john and paul"
-[1, "paul", 3, "ringo"].to_sentence #=> "1, paul, 3 and ringo"
-
+class Array
+ def mean
+ self.reduce {|item, acc| acc + item} / self.length.to_f
+ end
+
+ def median
+ middle = self.length / 2
+ sorted = self.sort
+ self.length.odd? ? sorted[middle] : 0.5 * (sorted[middle] + sorted[middle - 1])
+ end
+
+ def to_sentence
+ unless (self.length < 2)
+ last_word = self.pop.to_s
+ sentence = (self.join ", ") << " and " << last_word
+ else
+ self.pop.to_s
+ end
+ end
+end
# ========================================================================================
# Problem 3 - re-implement bank statement
diff --git a/assignments/assignment04.rb b/assignments/assignment04.rb
deleted file mode 100644
index d2443a2..0000000
--- a/assignments/assignment04.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# ========================================================================================
-# Assignment 4
-# ========================================================================================
-
-# ========================================================================================
-# Problem 1 - Fibonacci
-
-# 1, 1, 2, 3, 5, 8, 13, 21, ...
-
-# F[0] -> 1
-# F[1] -> 1
-# F[n] -> F[n-2] + F[n-1]
-
-def fib(n)
- # your implementation here
-end
-
-# expected behavior:
-fib(0) #=> 1
-fib(1) #=> 1
-fib(5) #=> 8
-fib(4) #=> 5
-fib(12) #=> 233
-
-
-# ========================================================================================
-# Problem 2 - Queue
-
-# implement a Queue class that does not use Array.
-
-# expected behavior:
-q = Queue.new
-q.empty? #=> true
-q.enqueue "first"
-q.empty? #=> false
-q.enqueue "second"
-q.dequeue #=> "first"
-q.dequeue #=> "second"
-q.dequeue #=> nil
-
-class Queue
- def initialize
- # your implementation here
- end
- def enqueue(item)
- # your implementation here
- end
- def dequeue
- # your implementation here
- end
- def empty?
- # your implementation here
- end
- def peek
- # your implementation here
- end
- def length
- # your implementation here
- end
-end
-
-
-# ========================================================================================
-# Problem 3 - LinkedList
-
-# implement a LinkedList class that does not use Array.
-
-# expected behavior:
-ll = LinkedList.new
-ll.empty? #=> true
-
-ll << "first"
-ll.empty? #=> false
-ll.length #=> 1
-ll.first #=> "first"
-ll.last #=> "first"
-
-ll << "second"
-ll.length #=> 2
-ll.first #=> "first"
-ll.last #=> "second"
-
-ll << "third" #=> 3
-ll.each {|x| puts x} #=> prints out "first", "second", "third"
-
-ll.delete "second" #=> "second"
-ll.length #=> 2
-ll.each {|x| puts x} #=> prints out "first", "third"
-
-class LinkedList
- def initialize
- # your implementation here
- end
- def empty?
- # your implementation here
- end
- def length
- # your implementation here
- end
- def <<(item)
- # your implementation here
- end
- def first
- # your implementation here
- end
- def last
- # your implementation here
- end
- def each(&block)
- # your implementation here
- end
-end
diff --git a/assignments/assignment04_solution.rb b/assignments/assignment04_solution.rb
deleted file mode 100644
index 910866c..0000000
--- a/assignments/assignment04_solution.rb
+++ /dev/null
@@ -1,490 +0,0 @@
-# ========================================================================================
-# Assignment 4
-# ========================================================================================
-
-require 'minitest/autorun'
-
-
-module Assignment04
-
- # ========================================================================================
- # Problem 1 - Fibonacci
-
- # 1, 1, 2, 3, 5, 8, 13, 21, ...
-
- # F[0] -> 1
- # F[1] -> 1
- # F[n] -> F[n-2] + F[n-1]
-
- def self.fib(n)
- n < 2 ? 1 : fib(n-2)+fib(n-1)
- end
-
-
-
- # ========================================================================================
- # Problem 2 - Queue
-
- # implement a Queue class that does not use Array.
- class Queue
-
- class Node
- attr_accessor :item, :link
- def initialize(item, link)
- @item = item
- @link = link
- end
- def to_s
- "[item => #{item}, link => #{link}]"
- end
- end
-
- def initialize
- @nodes = nil
- end
-
- def enqueue(item)
- new_node = Node.new item, nil
-
- if empty?
- @nodes = new_node
- else
- node = @nodes
- while node.link
- node = node.link
- end
- node.link = new_node
- end
- self
- end
-
- def dequeue
- node = @nodes
- @nodes = node.nil? ? nil : node.link
- node.nil? ? nil : node.item
- end
-
- def empty?
- @nodes.nil?
- end
-
- def peek
- @nodes.nil? ? nil : @nodes.item
- end
-
- def length
- return 0 if empty?
-
- node = @nodes
- count = 1
- while node.link
- count += 1
- node = node.link
- end
- count
- end
- end
-
-
- # ========================================================================================
- # Problem 3 - LinkedList
-
- # implement a LinkedList class that does not use Array.
- class LinkedList
-
- class Node
- attr_accessor :item, :link
- def initialize(item, link)
- @item = item
- @link = link
- end
- def to_s
- "[item => #{item}, link => #{link}]"
- end
- end
-
- def initialize
- @nodes = nil
- end
-
- def empty?
- @nodes.nil?
- end
-
- def length
- return 0 if empty?
-
- node = @nodes
- count = 1
- while node.link
- count += 1
- node = node.link
- end
- count
- end
-
- def <<(item)
- new_node = Node.new item, nil
-
- if empty?
- @nodes = new_node
- else
- node = @nodes
- while node.link
- node = node.link
- end
- node.link = new_node
- end
- self
- end
-
- def first
- empty? ? nil : @nodes.item
- end
-
- def last
- return nil if empty?
-
- node = @nodes
- while node.link
- node = node.link
- end
-
- node.item
- end
-
- def delete(item)
- return nil if empty?
-
- node = @nodes
- if item == node.item
- @nodes = node.link
- return node.item
- end
-
- while node.link
- if item == node.link.item
- node.link = node.link.link
- return item
- end
- node = node.link
- end
-
- nil
- end
-
- def each(&block)
- return if empty?
-
- node = @nodes
- while node != nil
- yield node.item
- node = node.link
- end
- end
- end
-
-end
-
-
-# ========================================================================================
-require 'minitest/autorun'
-
-class TestAssignment04 < Minitest::Test
-
- def test_fib
- assert_equal 1, Assignment04.fib(0) #=> 1
- assert_equal 1, Assignment04.fib(1) #=> 1
- assert_equal 8, Assignment04.fib(5) #=> 8
- assert_equal 5, Assignment04.fib(4) #=> 5
- assert_equal 233, Assignment04.fib(12) #=> 233
- end
-
- def test_queue
- q = Assignment04::Queue.new
- refute_nil q
- assert_empty q #=> true
- assert_equal 0, q.length
-
- assert_equal q, q.enqueue("first")
- refute_empty q #=> true
- assert_equal 1, q.length
- assert_equal "first", q.peek
-
- assert_equal q, q.enqueue("second")
- refute_empty q #=> true
- assert_equal 2, q.length
- assert_equal "first", q.peek
-
- assert_equal q, q.enqueue("third")
- refute_empty q #=> true
- assert_equal 3, q.length
- assert_equal "first", q.peek
-
- assert_equal "first", q.dequeue #=> "first"
- refute_empty q #=> true
- assert_equal 2, q.length
- assert_equal "second", q.peek
-
- assert_equal "second", q.dequeue #=> "second"
- refute_empty q #=> true
- assert_equal 1, q.length
- assert_equal "third", q.peek
-
- assert_equal "third", q.dequeue #=> "second"
- assert_empty q #=> true
- assert_equal 0, q.length
-
- assert_nil q.dequeue #=> nil
- end
-
- def test_linked_list
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal ll, ll << "third"
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- items = []
- ll.each {|item| items << item}
- assert_equal ["first", "second", "third"], items
-
- assert_equal "second", ll.delete("second")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- items = []
- ll.each {|item| items << item}
- assert_equal ["first", "third"], items
- end
-
- def test_linked_list_delete_only
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal "first", ll.delete("first")
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
- end
-
- def test_linked_list_delete_first_of_two
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal "first", ll.delete("first")
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "second", ll.first
- assert_equal "second", ll.last
- end
-
- def test_linked_list_delete_last_of_two
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal "second", ll.delete("second")
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
- end
-
- def test_linked_list_delete_first_of_three
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal ll, ll << "third"
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_equal "first", ll.delete("first")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "second", ll.first
- assert_equal "third", ll.last
- end
-
- def test_linked_list_delete_middle_of_three
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal ll, ll << "third"
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_equal "second", ll.delete("second")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
- end
-
- def test_linked_list_delete_last_of_three
- ll = Assignment04::LinkedList.new
- refute_nil ll
- assert_empty ll
- assert_equal 0, ll.length
- assert_nil ll.first
- assert_nil ll.last
-
- assert_equal ll, ll << "first"
- refute_empty ll
- assert_equal 1, ll.length
- assert_equal "first", ll.first
- assert_equal "first", ll.last
-
- assert_equal ll, ll << "second"
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
-
- assert_equal ll, ll << "third"
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_nil ll.delete("other")
- refute_empty ll
- assert_equal 3, ll.length
- assert_equal "first", ll.first
- assert_equal "third", ll.last
-
- assert_equal "third", ll.delete("third")
- refute_empty ll
- assert_equal 2, ll.length
- assert_equal "first", ll.first
- assert_equal "second", ll.last
- end
-
-end
diff --git a/assignments/assignment05.rb b/assignments/assignment05.rb
deleted file mode 100644
index 9e96ea4..0000000
--- a/assignments/assignment05.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# ========================================================================================
-# Assignment 5
-# ========================================================================================
-
-# ========================================================================================
-# Problem 1 - implement prop_reader, write MiniTest unit tests
-
-# expected results:
-class PropReader
- prop_reader :flavor
- def initialize(flavor)
- @flavor = flavor
- end
-end
-
-obj = PropReader.new "spicy"
-obj.respond_to? :flavor #=> true
-obj.respond_to? :"flavor=" #=> false
-obj.flavor #=> "spicy"
diff --git a/assignments/assignment06.rb b/assignments/assignment06.rb
index 9017e02..d7289fd 100644
--- a/assignments/assignment06.rb
+++ b/assignments/assignment06.rb
@@ -7,101 +7,227 @@
# implement a PriorityQueue, validate using MiniTest unit tests
-class PriorityQueue
- def initialize
- # your implementation here
- end
- def enqueue(item, priority=:medium)
- # your implementation here
- end
- def dequeue
- # your implementation here
- end
- def empty?
- # your implementation here
- end
- def peek
- # your implementation here
- end
- def length
- # your implementation here
- end
-end
+module Assignment06
+ class PriorityQueue
+ def initialize
+ @items = []
+ end
-# expected results:
-pq = PriorityQueue.new
-pq.empty? #=> true
+ def enqueue(item,priority=:medium)
+ new_item = []
+ new_item << {item: item, priority: priority}
-pq.enqueue "first"
-pq.empty? #=> false
+ if @items.empty?
+ @items << {item: item, priority: priority}
+ @items.last[:item]
+
+ elsif new_item.last[:priority] == :medium and @items.last[:priority] == :low
+ if @items.first[:priority] == :low
+ @items.unshift({item: item, priority: priority})
+ @items.last[:item]
+ else
+ h = @items.rindex {|x| x[:priority] == :medium} + 1
+ @items.insert(h, {item: item, priority: priority})
+ @items.last[:item]
+ end
+ elsif new_item.last[:priority] == :high and @items.last[:priority] == :medium
+ if @items.first[:priority] == :medium
+ @items.unshift({item: item, priority: priority})
+ @items.last[:item]
+ else
+ h = @items.rindex {|x| x[:priority] == :high} + 1
+ @items.insert(h, {item: item, priority: priority})
+ @items.last[:item]
+ end
+ elsif new_item.last[:priority] == :high and @items.last[:priority] == :low
+ if @items.first[:priority] == :low or @items.first[:priority] == :medium
+ @items.unshift({item: item, priority: priority})
+ @items.last[:item]
+ else
+ h = @items.rindex {|x| x[:priority] == :high} + 1
+ @items.insert(h, {item: item, priority: priority})
+ @items.last[:item]
+ end
+ else
+ @items << {item: item, priority: priority}
+ @items.last[:item]
+ end
+ end
+
+ def dequeue
+ @items.empty? ? nil : @items.shift[:item]
+ end
-pq.enqueue "top", :high
-pq.enqueue "last", :low
-pq.enqueue "second"
-pq.enqueue "another top", :high
+ def empty?
+ @items.empty?
+ end
-pq.length #=> 5
+ def peek
+ @items.first[:item]
+ end
-pq.dequeue #=> "top"
-pq.dequeue #=> "another top"
-pq.dequeue #=> "first"
-pq.dequeue #=> "second"
-pq.dequeue #=> "last"
+ def length
+ @items.length
+ end
+ end
+ require 'minitest/autorun'
+
+ class TestPriorityQueue < MiniTest::Test
+ def test_priorityqueue
+ pq = PriorityQueue.new
+ a = pq.empty?
+ assert_equal a, true
+ b = pq.length
+ assert_equal b, 0
+ c = pq.enqueue "first"
+ assert_equal c, "first"
+ d = pq.length
+ assert_equal d, 1
+ e = pq.empty?
+ assert_equal e, false
+ f = pq.peek
+ assert_equal f, "first"
+ pq.enqueue "top", :high
+ g = pq.peek
+ assert_equal g, "top"
+ h = pq.length
+ assert_equal h, 2
+ pq.enqueue "last", :low
+ pq.enqueue "second"
+ pq.enqueue "another top", :high
+ j = pq.length
+ assert_equal j, 5
+ k = pq.dequeue
+ assert_equal k, "top"
+ l = pq.length
+ assert_equal l, 4
+ m = pq.dequeue
+ assert_equal m, "another top"
+ n = pq.dequeue
+ assert_equal n, "first"
+ o = pq.dequeue
+ assert_equal o, "second"
+ p = pq.dequeue
+ assert_equal p, "last"
+ q = pq.empty?
+ assert_equal q, true
+ r = pq.length
+ assert_equal r, 0
+ end
+ end
# ========================================================================================
# Problem 2 - Recipe to DSL
# render a Recipe object to Recipe DSL
-
-class Recipe
- attr_accessor :steps, :ingredients, :name, :category, :prep_time, :rating
- def initialize(name)
- @name = name
- end
+ class Recipe
+ attr_accessor :steps, :ingredients, :name, :category, :prep_time, :rating
+ def initialize(name)
+ @name = name
+ end
- def render_dsl
- # your code here
- end
-end
+ def render_ingredients
+ <<-INGREDIENTS
+ ingredients do
+ #{ingredients.map {|i| "x \"#{i}\""}}.join "\n"}
+ end
+ INGREDIENTS
+ end
-class RecipeBuilder
- def recipe(name, &block)
- @recipe = Recipe.new(name)
- self.instance_eval &block
- @recipe
+ def render_steps
+ <<-STEPS
+ steps do
+ #{steps.map {|s| "x \"#{s}\""}}.join "\n"}
+ end
+ STEPS
+ end
+
+ def render_dsl
+ <<-RECIPE
+ recipe "#{name}" do
+ category "#{category}"
+ prep_time "#{prep_time}"
+ rating "#{rating}"
+ #{render_ingredients}
+ #{render_steps}
+ end
+ RECIPE
+ end
end
+
+ class RecipeBuilder
+ def recipe(name, &block)
+ @recipe = Recipe.new(name)
+ self.instance_eval &block
+ @recipe
+ end
- def category(value)
- @recipe.category = value
- end
+ def category(value)
+ @recipe.category = value
+ end
- def prep_time(value)
- @recipe.prep_time = value
- end
+ def prep_time(value)
+ @recipe.prep_time = value
+ end
- def rating(value)
- @recipe.rating = value
- end
+ def rating(value)
+ @recipe.rating = value
+ end
- def ingredients(&block)
- @recipe.ingredients = []
- @items = @recipe.ingredients
- self.instance_eval &block
- end
+ def ingredients(&block)
+ @recipe.ingredients = []
+ @items = @recipe.ingredients
+ self.instance_eval &block
+ end
- def steps(&block)
- @recipe.steps = []
- @items = @recipe.steps
- self.instance_eval &block
- end
+ def steps(&block)
+ @recipe.steps = []
+ @items = @recipe.steps
+ self.instance_eval &block
+ end
- def x(item)
- @items << item
+ def x(item)
+ @items << item
+ end
+ end
+
+ def recipe(name, &block)
+ rb = RecipeBuilder.new
+ rb.recipe(name, &block)
end
-end
-def recipe(name, &block)
- rb = RecipeBuilder.new
- rb.recipe(name, &block)
-end
+ require 'minitest/autorun'
+
+ class TestRecipe < MiniTest::Test
+ def test_recipe
+ eggs = recipe "Scrambled Eggs" do
+ category "breakfast"
+ prep_time "10 minutes"
+ rating 4
+ ingredients do
+ x "2 eggs"
+ x "1/4 cup of milk"
+ x "1 tbsp of butter"
+ x "dash of salt"
+ x "dash of pepper"
+ end
+ steps do
+ x "crack eggs into medium mixing bowl"
+ x "whisk eggs"
+ x "add milk"
+ x "add salt & pepper to taste"
+ x "heat pan to medium high heat"
+ x "melt butter in pan"
+ x "once hot, add eggs to pan"
+ end
+ end
+ assert_equal eggs.name, "Scrambled Eggs"
+ assert_equal eggs.steps, ["crack eggs into medium mixing bowl", "whisk eggs", "add milk", "add salt & pepper to taste", "heat pan to medium high heat", "melt butter in pan", "once hot, add eggs to pan"]
+ assert_equal eggs.ingredients, ["2 eggs", "1/4 cup of milk", "1 tbsp of butter", "dash of salt", "dash of pepper"]
+ assert_equal eggs.category, "breakfast"
+ assert_equal eggs.prep_time, "10 minutes"
+ assert_equal eggs.rating, 4
+ end
+ end
+end
\ No newline at end of file
diff --git a/assignments/assignment07.rb b/assignments/assignment07.rb
index 5d86f95..64743ed 100644
--- a/assignments/assignment07.rb
+++ b/assignments/assignment07.rb
@@ -10,23 +10,42 @@
module Assignment07
module Observable
- def add_observer(obj)
- # your implementation here
+
+ attr_accessor :state
+
+ def add_observer(observer)
+ @observers ||= []
+ @observers << observer unless @observers.include? observer
end
- def delete_observer(obj)
- # your implementation here
+
+ def delete_observer(observer)
+ @observers.delete(observer) unless @observers == nil
end
+
def delete_observers
- # your implementation here
+ @observers.clear unless @obervers == nil
+ end
+
+ def count_observers
+ @observers.count
end
+
def changed(new_state=true)
- # your implementation here
+ @state = new_state
end
+
def changed?
- # your implementation here
+ @state unless @state == nil
end
+
def notify_observers(*args)
- # your implementation here
+ if @state == true
+ @observers.each do |observer|
+ observer.update(*args)
+ end
+ @state = false
+ end
end
+
end
-end
+end
\ No newline at end of file
diff --git a/assignments/assignment08.rb b/assignments/assignment08.rb
index 3d46269..8924aed 100644
--- a/assignments/assignment08.rb
+++ b/assignments/assignment08.rb
@@ -10,47 +10,442 @@
module Assignment08
class RomanNumeral
- def initialize(i)
- # your implementation here
+ def initialize(number)
+ @numeral = number
+ @rn = ""
end
def to_s
- # your implementation here
+ if @numeral > 3999
+ return "Number is too large to convert!"
+ elsif @numeral < 1
+ return "Number cannot be converted!"
+ else while @numeral > 999
+ @numeral = @numeral - 1000
+ @rn << "M"
+ end
+ while @numeral > 899
+ @numeral = @numeral - 900
+ @rn << "CM"
+ end
+ while @numeral > 499
+ @numeral = @numeral - 500
+ @rn << "D"
+ end
+ while @numeral > 399
+ @numeral = @numeral - 400
+ @rn << "CD"
+ end
+ while @numeral > 99
+ @numeral = @numeral - 100
+ @rn << "C"
+ end
+ while @numeral > 89
+ @numeral = @numeral - 90
+ @rn << "XC"
+ end
+ while @numeral > 49
+ @numeral = @numeral - 50
+ @rn << "L"
+ end
+ while @numeral > 39
+ @numeral = @numeral - 40
+ @rn << "XL"
+ end
+ while @numeral > 9
+ @numeral = @numeral - 10
+ @rn << "X"
+ end
+ while @numeral > 8
+ @numeral = @numeral - 9
+ @rn << "IX"
+ end
+ while @numeral > 4
+ @numeral = @numeral - 5
+ @rn << "V"
+ end
+ while @numeral > 3
+ @numeral = @numeral - 4
+ @rn << "IV"
+ end
+ while @numeral > 0
+ @numeral = @numeral - 1
+ @rn << "I"
+ end
+ end
+ @rn
end
-
+
def to_i
- # your implementation here
+ @rn = @numeral
+ if @rn == ""
+ return "No conversion is possible!"
+ elsif (@rn.delete "CDILMVX") != ""
+ return "That is not a valid roman numeral!"
+ else
+ rn = @rn.reverse
+ @numeral = 0
+ return "That is not a valid roman numeral!" if rn.end_with?("MMMM")
+ while rn.end_with?("M")
+ @numeral += 1000
+ rn.chop!
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("MC")
+ @numeral += 900
+ rn.chop!.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("D")
+ @numeral += 500
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("DC")
+ @numeral += 400
+ rn.chop!.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return @numeral if rn.empty?
+ end
+ return "That is not a valid roman numeral!" if rn.end_with?("CCCC")
+ while rn.end_with?("C")
+ @numeral += 100
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("CX")
+ @numeral += 90
+ rn.chop!.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return "That is not a valid roman numeral!" if rn.end_with?("X")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("L")
+ @numeral += 50
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("LX")
+ @numeral += 40
+ rn.chop!.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return "That is not a valid roman numeral!" if rn.end_with?("X")
+ return @numeral if rn.empty?
+ end
+ return "That is not a valid roman numeral!" if rn.end_with?("XXXX")
+ while rn.end_with?("X")
+ @numeral += 10
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("XI")
+ @numeral += 9
+ rn.chop!.chop!
+ return @numeral if rn.empty?
+ return "That is not a valid roman numeral!"
+ end
+ if rn.end_with?("V")
+ @numeral += 5
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return "That is not a valid roman numeral!" if rn.end_with?("X")
+ return "That is not a valid roman numeral!" if rn.end_with?("V")
+ return @numeral if rn.empty?
+ end
+ if rn.end_with?("VI")
+ @numeral += 4
+ rn.chop!.chop!
+ return @numeral if rn.empty?
+ return "That is not a valid roman numeral!"
+ end
+ return "That is not a valid roman numeral!" if rn.end_with?("IIII")
+ while rn.end_with?("I")
+ @numeral += 1
+ rn.chop!
+ return "That is not a valid roman numeral!" if rn.end_with?("M")
+ return "That is not a valid roman numeral!" if rn.end_with?("D")
+ return "That is not a valid roman numeral!" if rn.end_with?("C")
+ return "That is not a valid roman numeral!" if rn.end_with?("L")
+ return "That is not a valid roman numeral!" if rn.end_with?("X")
+ return "That is not a valid roman numeral!" if rn.end_with?("V")
+ return @numeral if rn.empty?
+ end
+ @numeral
+ end
end
# bonus: create from Roman Numeral
- def self.from_string
- # your implementation here
- # returns a new instance
+ def self.from_string(roman_numeral)
+ RomanNumeral.new(roman_numeral)
end
end
-end
-# expected results:
-RomanNumeral.new(1).to_s # => 'I'
-RomanNumeral.new(2).to_s # => 'II'
-RomanNumeral.new(3).to_s # => 'III'
-RomanNumeral.new(4).to_s # => 'IV'
-RomanNumeral.new(5).to_s # => 'V'
-RomanNumeral.new(6).to_s # => 'VI'
-RomanNumeral.new(9).to_s # => 'IX'
-RomanNumeral.new(10).to_s # => 'X'
-RomanNumeral.new(19).to_s # => 'XIX'
-RomanNumeral.new(32).to_s # => 'XXXII'
-RomanNumeral.new(51).to_s # => 'LI'
-# bonus:
-RomanNumeral.from_string('III').to_i # => 3
-RomanNumeral.from_string('IX').to_i # => 9
-RomanNumeral.from_string('IX').to_i # => 9
+require 'minitest/autorun'
+
+ class TestRomanNumeral < MiniTest::Test
+ def test_romannumeraltostring
+ a = RomanNumeral.new(1).to_s
+ assert_equal a, "I"
+ b = RomanNumeral.new(2).to_s
+ assert_equal b, "II"
+ c = RomanNumeral.new(3).to_s
+ assert_equal c, "III"
+ d = RomanNumeral.new(4).to_s
+ assert_equal d, "IV"
+ e = RomanNumeral.new(5).to_s
+ assert_equal e, "V"
+ f = RomanNumeral.new(6).to_s
+ assert_equal f, "VI"
+ g = RomanNumeral.new(9).to_s
+ assert_equal g, "IX"
+ h = RomanNumeral.new(10).to_s
+ assert_equal h, "X"
+ i = RomanNumeral.new(19).to_s
+ assert_equal i, "XIX"
+ j = RomanNumeral.new(32).to_s
+ assert_equal j, "XXXII"
+ k = RomanNumeral.new(40).to_s
+ assert_equal k, "XL"
+ l = RomanNumeral.new(49).to_s
+ assert_equal l, "XLIX"
+ m = RomanNumeral.new(50).to_s
+ assert_equal m, "L"
+ n = RomanNumeral.new(89).to_s
+ assert_equal n, "LXXXIX"
+ o = RomanNumeral.new(90).to_s
+ assert_equal o, "XC"
+ p = RomanNumeral.new(100).to_s
+ assert_equal p, "C"
+ q = RomanNumeral.new(399).to_s
+ assert_equal q, "CCCXCIX"
+ r = RomanNumeral.new(400).to_s
+ assert_equal r, "CD"
+ s = RomanNumeral.new(499).to_s
+ assert_equal s, "CDXCIX"
+ t = RomanNumeral.new(500).to_s
+ assert_equal t, "D"
+ u = RomanNumeral.new(899).to_s
+ assert_equal u, "DCCCXCIX"
+ v = RomanNumeral.new(900).to_s
+ assert_equal v, "CM"
+ w = RomanNumeral.new(999).to_s
+ assert_equal w, "CMXCIX"
+ x = RomanNumeral.new(1000).to_s
+ assert_equal x, "M"
+ y = RomanNumeral.new(1399).to_s
+ assert_equal y, "MCCCXCIX"
+ z = RomanNumeral.new(1400).to_s
+ assert_equal z, "MCD"
+ aa = RomanNumeral.new(1899).to_s
+ assert_equal aa, "MDCCCXCIX"
+ ab = RomanNumeral.new(1900).to_s
+ assert_equal ab, "MCM"
+ ac = RomanNumeral.new(1999).to_s
+ assert_equal ac, "MCMXCIX"
+ ad = RomanNumeral.new(2000).to_s
+ assert_equal ad, "MM"
+ ae = RomanNumeral.new(2999).to_s
+ assert_equal ae, "MMCMXCIX"
+ af = RomanNumeral.new(3999).to_s
+ assert_equal af, "MMMCMXCIX"
+ ag = RomanNumeral.new(4000).to_s
+ assert_equal ag, "Number is too large to convert!"
+ bo = RomanNumeral.new(0).to_s
+ assert_equal bo, "Number cannot be converted!"
+ end
-# given any arbitrary integer n:
-n == RomanNumeral.from_string(RomanNumeral.new(n).to_s).to_i
+ def test_romannumeraltointeger
+ ah = RomanNumeral.from_string("I").to_i
+ assert_equal ah, 1
+ ai = RomanNumeral.from_string("II").to_i
+ assert_equal ai, 2
+ aj = RomanNumeral.from_string("III").to_i
+ assert_equal aj, 3
+ ak = RomanNumeral.from_string("IV").to_i
+ assert_equal ak, 4
+ al = RomanNumeral.from_string("V").to_i
+ assert_equal al, 5
+ am = RomanNumeral.from_string("VI").to_i
+ assert_equal am, 6
+ an = RomanNumeral.from_string("IX").to_i
+ assert_equal an, 9
+ ao = RomanNumeral.from_string("X").to_i
+ assert_equal ao, 10
+ ap = RomanNumeral.from_string("XIX").to_i
+ assert_equal ap, 19
+ aq = RomanNumeral.from_string("XXXII").to_i
+ assert_equal aq, 32
+ ar = RomanNumeral.from_string("XL").to_i
+ assert_equal ar, 40
+ as = RomanNumeral.from_string("XLIX").to_i
+ assert_equal as, 49
+ at = RomanNumeral.from_string("L").to_i
+ assert_equal at, 50
+ au = RomanNumeral.from_string("LXXXIX").to_i
+ assert_equal au, 89
+ av = RomanNumeral.from_string("XC").to_i
+ assert_equal av, 90
+ aw = RomanNumeral.from_string("C").to_i
+ assert_equal aw, 100
+ ax = RomanNumeral.from_string("CCCXCIX").to_i
+ assert_equal ax, 399
+ ay = RomanNumeral.from_string("CD").to_i
+ assert_equal ay, 400
+ az = RomanNumeral.from_string("CDXCIX").to_i
+ assert_equal az, 499
+ ba = RomanNumeral.from_string("D").to_i
+ assert_equal ba, 500
+ bb = RomanNumeral.from_string("DCCCXCIX").to_i
+ assert_equal bb, 899
+ bc = RomanNumeral.from_string("CM").to_i
+ assert_equal bc, 900
+ bd = RomanNumeral.from_string("CMXCIX").to_i
+ assert_equal bd, 999
+ be = RomanNumeral.from_string("M").to_i
+ assert_equal be, 1000
+ bf = RomanNumeral.from_string("MCCCXCIX").to_i
+ assert_equal bf, 1399
+ bg = RomanNumeral.from_string("MCD").to_i
+ assert_equal bg, 1400
+ bh = RomanNumeral.from_string("MDCCCXCIX").to_i
+ assert_equal bh, 1899
+ bi = RomanNumeral.from_string("MCM").to_i
+ assert_equal bi, 1900
+ bj = RomanNumeral.from_string("MCMXCIX").to_i
+ assert_equal bj, 1999
+ bk = RomanNumeral.from_string("MM").to_i
+ assert_equal bk, 2000
+ bl = RomanNumeral.from_string("MMCMXCIX").to_i
+ assert_equal bl, 2999
+ bm = RomanNumeral.from_string("MMMCMXCIX").to_i
+ assert_equal bm, 3999
+ bn = RomanNumeral.from_string("MMMM").to_i
+ assert_equal bn, "That is not a valid roman numeral!"
+ bq = RomanNumeral.from_string("MCMM").to_i
+ assert_equal bq, "That is not a valid roman numeral!"
+ br = RomanNumeral.from_string("MCMD").to_i
+ assert_equal br, "That is not a valid roman numeral!"
+ bs = RomanNumeral.from_string("MCMC").to_i
+ assert_equal bs, "That is not a valid roman numeral!"
+ bt = RomanNumeral.from_string("DM").to_i
+ assert_equal bt, "That is not a valid roman numeral!"
+ bu = RomanNumeral.from_string("DD").to_i
+ assert_equal bu, "That is not a valid roman numeral!"
+ bv = RomanNumeral.from_string("CDM").to_i
+ assert_equal bv, "That is not a valid roman numeral!"
+ bw = RomanNumeral.from_string("CDD").to_i
+ assert_equal bw, "That is not a valid roman numeral!"
+ bx = RomanNumeral.from_string("CDC").to_i
+ assert_equal bx, "That is not a valid roman numeral!"
+ by = RomanNumeral.from_string("CCCC").to_i
+ assert_equal by, "That is not a valid roman numeral!"
+ bz = RomanNumeral.from_string("CMCM").to_i
+ assert_equal bz, "That is not a valid roman numeral!"
+ ca = RomanNumeral.from_string("CMCD").to_i
+ assert_equal ca, "That is not a valid roman numeral!"
+ cb = RomanNumeral.from_string("XCM").to_i
+ assert_equal cb, "That is not a valid roman numeral!"
+ cc = RomanNumeral.from_string("XCD").to_i
+ assert_equal cc, "That is not a valid roman numeral!"
+ cd = RomanNumeral.from_string("XCC").to_i
+ assert_equal cd, "That is not a valid roman numeral!"
+ ce = RomanNumeral.from_string("XCL").to_i
+ assert_equal ce, "That is not a valid roman numeral!"
+ cf = RomanNumeral.from_string("XCX").to_i
+ assert_equal cf, "That is not a valid roman numeral!"
+ cg = RomanNumeral.from_string("LM").to_i
+ assert_equal cg, "That is not a valid roman numeral!"
+ ch = RomanNumeral.from_string("LD").to_i
+ assert_equal ch, "That is not a valid roman numeral!"
+ ci = RomanNumeral.from_string("LC").to_i
+ assert_equal ci, "That is not a valid roman numeral!"
+ cj = RomanNumeral.from_string("LL").to_i
+ assert_equal cj, "That is not a valid roman numeral!"
+ ck = RomanNumeral.from_string("XLM").to_i
+ assert_equal ck, "That is not a valid roman numeral!"
+ cl = RomanNumeral.from_string("XLD").to_i
+ assert_equal cl, "That is not a valid roman numeral!"
+ cm = RomanNumeral.from_string("XLC").to_i
+ assert_equal cm, "That is not a valid roman numeral!"
+ cn = RomanNumeral.from_string("XLL").to_i
+ assert_equal cn, "That is not a valid roman numeral!"
+ co = RomanNumeral.from_string("XLX").to_i
+ assert_equal co, "That is not a valid roman numeral!"
+ cp = RomanNumeral.from_string("XXXX").to_i
+ assert_equal cp, "That is not a valid roman numeral!"
+ cq = RomanNumeral.from_string("XM").to_i
+ assert_equal cq, "That is not a valid roman numeral!"
+ cr = RomanNumeral.from_string("XD").to_i
+ assert_equal cr, "That is not a valid roman numeral!"
+ cs = RomanNumeral.from_string("XLXC").to_i
+ assert_equal cs, "That is not a valid roman numeral!"
+ ct = RomanNumeral.from_string("XLXL").to_i
+ assert_equal ct, "That is not a valid roman numeral!"
+ cu = RomanNumeral.from_string("IXM").to_i
+ assert_equal cu, "That is not a valid roman numeral!"
+ cv = RomanNumeral.from_string("IXD").to_i
+ assert_equal cv, "That is not a valid roman numeral!"
+ cw = RomanNumeral.from_string("IXC").to_i
+ assert_equal cw, "That is not a valid roman numeral!"
+ cx = RomanNumeral.from_string("IXL").to_i
+ assert_equal cx, "That is not a valid roman numeral!"
+ cy = RomanNumeral.from_string("IXX").to_i
+ assert_equal cy, "That is not a valid roman numeral!"
+ cz = RomanNumeral.from_string("IXV").to_i
+ assert_equal cz, "That is not a valid roman numeral!"
+ da = RomanNumeral.from_string("IVI").to_i
+ assert_equal da, "That is not a valid roman numeral!"
+ db = RomanNumeral.from_string("IIII").to_i
+ assert_equal db, "That is not a valid roman numeral!"
+ dc = RomanNumeral.from_string("IM").to_i
+ assert_equal dc, "That is not a valid roman numeral!"
+ dd = RomanNumeral.from_string("ID").to_i
+ assert_equal dd, "That is not a valid roman numeral!"
+ de = RomanNumeral.from_string("ID").to_i
+ assert_equal de, "That is not a valid roman numeral!"
+ df = RomanNumeral.from_string("IC").to_i
+ assert_equal df, "That is not a valid roman numeral!"
+ dg = RomanNumeral.from_string("IL").to_i
+ assert_equal dg, "That is not a valid roman numeral!"
+ dh = RomanNumeral.from_string("IXI").to_i
+ assert_equal dh, "That is not a valid roman numeral!"
+ di = RomanNumeral.from_string("IVIV").to_i
+ assert_equal di, "That is not a valid roman numeral!"
+ end
+ def test_romannumeralfromstring
+ bp = RomanNumeral.from_string("IX")
+ assert_instance_of RomanNumeral, bp
+ end
+ end
+#end
# ========================================================================================
@@ -60,13 +455,61 @@ def self.from_string
# calculate the golden ratio up to specified precision
# validate using MiniTest unit tests
-module Assignment08
+#module Assignment08
def golden_ratio(precision)
- # your implementation here
+ x = fib(99)/fib(98).to_f
+ x.round(precision)
end
-end
+ def fib(n)
+ def calc_fib(n, cache)
+ if cache.length > n
+ cache[n]
+ else
+ cache[n] = calc_fib(n-1, cache) + calc_fib(n-2, cache)
+ end
+ end
+ calc_fib(n, [1,1])
+ end
+
+require 'minitest/autorun'
-# expected results:
-golden_ratio(2) # => 1.62
-golden_ratio(5) # => 1.61803
-golden_ratio(8) # => 1.61803399
+ class TestGoldenRatio < MiniTest::Test
+ def test_goldenratio
+ a = golden_ratio(0)
+ assert_equal a, 2
+ b = golden_ratio(1)
+ assert_equal b, 1.6
+ c = golden_ratio(2)
+ assert_equal c, 1.62
+ d = golden_ratio(3)
+ assert_equal d, 1.618
+ e = golden_ratio(4)
+ assert_equal e, 1.618
+ f = golden_ratio(5)
+ assert_equal f, 1.61803
+ g = golden_ratio(6)
+ assert_equal g, 1.618034
+ h = golden_ratio(7)
+ assert_equal h, 1.618034
+ i = golden_ratio(8)
+ assert_equal i, 1.61803399
+ j = golden_ratio(9)
+ assert_equal j, 1.618033989
+ k = golden_ratio(10)
+ assert_equal k, 1.6180339887
+ l = golden_ratio(11)
+ assert_equal l, 1.61803398875
+ m = golden_ratio(12)
+ assert_equal m, 1.61803398875
+ n = golden_ratio(13)
+ assert_equal n, 1.6180339887499
+ o = golden_ratio(14)
+ assert_equal o, 1.6180339887499
+ p = golden_ratio(15)
+ assert_equal p, 1.618033988749895
+ q = golden_ratio(15)
+ assert_equal q, 1.618033988749895
+
+ end
+ end
+end
diff --git a/assignments/final_project.rb b/assignments/final_project.rb
deleted file mode 100644
index a621230..0000000
--- a/assignments/final_project.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# ========================================================================================
-# Final Project: Game of Life
-# ========================================================================================
-
-# The Game of Life is a simplified model of evolution and natural selection
-# invented by the mathematician James Conway.
-
-# http://en.wikipedia.org/wiki/Conway's_Game_of_Life
-
-
-# ---------------------------------------------------------------------------------------
-# Rules
-
-# You have a grid of cells in 2 dimensions.
-
-# Each cell has 8 neighbors:
-# - top, right, bottom, left
-# - top-left, top-right, bottom-right, bottom-left
-
-# Each cell has 2 possible states: alive or dead.
-
-# if a cell is alive and
-# - has fewer than 2 live neighbors, it dies
-# - has more than 3 live neighbors, it dies
-# - has 2 or 3 live neighbors, it lives to next generation
-
-# if cell is dead and
-# - has exactly 3 live neighbors, it becomes a live cell
-
-# edges of board:
-# - pretend the board is folded onto itself
-# - the edges touch each other
-
-
-# ---------------------------------------------------------------------------------------
-# Tests
-
-# You must have MiniTest unit tests for your class to validate your implementation.
-# You might need to add methods or change the method signatures to enable testing.
-
-
-# ---------------------------------------------------------------------------------------
-# Rendering
-
-# You choose how you want to render the current state of the board.
-# ASCII? HTML? Something else?
-
-
-# ---------------------------------------------------------------------------------------
-# Bonus: DSL
-
-# - Create a DSL that represents a state of the game.
-# - Your render method can then be formatted as the DSL, so that you can round-trip
-# between the textual DSL representation and the running instance.
-
-
-# ---------------------------------------------------------------------------------------
-# Suggested Implementation
-
-module FinalProject
- class GameOfLife
- def initialize(size)
- # randomly initialize the board
- end
- def evolve
- # apply rules to each cell and generate new state
- end
- def render
- # render the current state of the board
- end
- def run(num_generations)
- # evolve and render for num_generations
- end
- end
-end
diff --git a/assignments/final_project_with_tests.rb b/assignments/final_project_with_tests.rb
new file mode 100644
index 0000000..c62931f
--- /dev/null
+++ b/assignments/final_project_with_tests.rb
@@ -0,0 +1,414 @@
+# ========================================================================================
+# Final Project: Game of Life
+# ========================================================================================
+
+# The Game of Life is a simplified model of evolution and natural selection
+# invented by the mathematician James Conway.
+
+# http://en.wikipedia.org/wiki/Conway's_Game_of_Life
+
+
+# ---------------------------------------------------------------------------------------
+# Rules
+
+# You have a grid of cells in 2 dimensions.
+
+# Each cell has 8 neighbors:
+# - top, right, bottom, left
+# - top-left, top-right, bottom-right, bottom-left
+
+# Each cell has 2 possible states: alive or dead.
+
+# if a cell is alive and
+# - has fewer than 2 live neighbors, it dies
+# - has more than 3 live neighbors, it dies
+# - has 2 or 3 live neighbors, it lives to next generation
+
+# if cell is dead and
+# - has exactly 3 live neighbors, it becomes a live cell
+
+# edges of board:
+# - pretend the board is folded onto itself
+# - the edges touch each other
+
+
+# ---------------------------------------------------------------------------------------
+# Tests
+
+# You must have MiniTest unit tests for your class to validate your implementation.
+# You might need to add methods or change the method signatures to enable testing.
+
+
+# ---------------------------------------------------------------------------------------
+# Rendering
+
+# You choose how you want to render the current state of the board.
+# ASCII? HTML? Something else?
+
+
+# ---------------------------------------------------------------------------------------
+# Bonus: DSL
+
+# - Create a DSL that represents a state of the game.
+# - Your render method can then be formatted as the DSL, so that you can round-trip
+# between the textual DSL representation and the running instance.
+
+
+# ---------------------------------------------------------------------------------------
+# Suggested Implementation
+
+#module FinalProject
+ class GameOfLife
+ attr_accessor :gameboard, :seeds
+ def initialize(gameboard = GameBoard.new, seeds=[])
+ @gameboard = gameboard
+ @seeds = seeds
+
+ seeds.each do |seed|
+ gameboard.board[seed[0]][seed[1]].is_alive = true
+ end
+ end
+
+ def evolve!
+
+ cell_is_dead_in_next_state = []
+ cell_is_alive_in_next_state = []
+
+ gameboard.cells.each do |cell|
+ #Rule #1
+ if cell.is_alive? && gameboard.neighbors(cell).count < 2
+ cell_is_dead_in_next_state << cell
+ end
+ #Rule #2
+ if cell.is_alive? && gameboard.neighbors(cell).count > 3
+ cell_is_dead_in_next_state << cell
+ end
+ #Rule #3
+ if cell.is_alive? && gameboard.neighbors(cell).count == 2
+ cell_is_alive_in_next_state << cell
+ end
+
+ if cell.is_alive? && gameboard.neighbors(cell).count == 3
+ cell_is_alive_in_next_state << cell
+ end
+ #Rule #4
+ if !cell.is_alive? && gameboard.neighbors(cell).count == 3
+ cell_is_alive_in_next_state << cell
+ end
+ end
+
+ cell_is_dead_in_next_state.each do |cell|
+ cell.kill_cell!
+ end
+ cell_is_alive_in_next_state.each do |cell|
+ cell.resurrect!
+ end
+ end
+ end
+
+ class GameBoard
+ attr_accessor :rows, :columns, :board, :cells
+
+ def initialize(rows=3, columns=3)
+ @rows = rows
+ @columns = columns
+ @cells = []
+ @board = Array.new(rows) do |row|
+ Array.new(columns) do |column|
+ cell = Cell.new(column,row)
+ cells << cell
+ cell
+ end
+ end
+ end
+
+ def neighbors(cell)
+ neighbors = []
+
+ #northeast neighbor
+ if cell.x_pos < (columns - 1) && cell.y_pos > 0
+ neighbor = self.board[cell.y_pos - 1][cell.x_pos + 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos < (columns - 1) && cell.y_pos == 0
+ neighbor = self.board[cell.y_pos + (self.rows - 1)][cell.x_pos + 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos == (columns - 1) && cell.y_pos > 0
+ neighbor = self.board[cell.y_pos - 1][0]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[cell.y_pos + (self.rows - 1)][0]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #southeast neighbor
+ if cell.x_pos < (columns - 1) && cell.y_pos < (rows - 1)
+ neighbor = self.board[cell.y_pos + 1][cell.x_pos + 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos < (columns - 1) && cell.y_pos == (rows - 1)
+ neighbor = self.board[0][cell.x_pos + 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos == (columns - 1) && cell.y_pos < (rows - 1)
+ neighbor = self.board[cell.y_pos + 1][0]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[0][0]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #southwest neighbor
+ if cell.x_pos > 0 && cell.y_pos < (rows - 1)
+ neighbor = self.board[cell.y_pos + 1][cell.x_pos - 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos > 0 && cell.y_pos == (rows - 1)
+ neighbor = self.board[0][cell.x_pos - 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos == 0 && cell.y_pos < (rows - 1)
+ neighbor = self.board[cell.y_pos + 1][cell.x_pos + (self.columns - 1)]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[0][cell.x_pos + (self.columns - 1)]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #northwest neighbor
+ if cell.x_pos > 0 && cell.y_pos > 0
+ neighbor = self.board[cell.y_pos - 1][cell.x_pos - 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos > 0 && cell.y_pos == 0
+ neighbor = self.board[cell.y_pos + (self.rows - 1)][cell.x_pos - 1]
+ neighbors << neighbor if neighbor.is_alive?
+ elsif cell.x_pos == 0 && cell.y_pos > 0
+ neighbor = self.board[cell.y_pos - 1][cell.x_pos + (self.columns - 1)]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[cell.y_pos + (self.rows - 1)][cell.x_pos + (self.columns - 1)]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #north neighbor
+ if cell.y_pos > 0
+ neighbor = self.board[cell.y_pos - 1][cell.x_pos]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[cell.y_pos + (self.rows - 1)][cell.x_pos]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #east neighbor
+ if cell.x_pos < (columns - 1)
+ neighbor = self.board[cell.y_pos][cell.x_pos + 1]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[cell.y_pos][0]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #south neighbor
+ if cell.y_pos < (rows - 1)
+ neighbor = self.board[cell.y_pos + 1][cell.x_pos]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[0][cell.x_pos]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ #west_neighbor
+ if cell.x_pos > 0
+ neighbor = self.board[cell.y_pos][cell.x_pos - 1]
+ neighbors << neighbor if neighbor.is_alive?
+ else
+ neighbor = self.board[cell.y_pos][cell.x_pos + (self.columns - 1)]
+ neighbors << neighbor if neighbor.is_alive?
+ end
+
+ neighbors
+ end
+
+ def live_cells
+ cells.select{|cell| cell.is_alive?}
+ end
+
+ def randomly_populate
+ cells.each do |cell|
+ cell.is_alive = [true, false].sample
+ end
+ end
+
+ end
+
+ class Cell
+ attr_accessor :x_pos, :y_pos, :is_alive
+
+ def initialize(xpos=0, ypos=0)
+ @x_pos = xpos
+ @y_pos = ypos
+ @is_alive = false
+ end
+
+ def is_alive?
+ is_alive
+ end
+
+ def kill_cell!
+ @is_alive = false
+ end
+
+ def resurrect!
+ @is_alive = true
+ end
+ end
+
+ require 'gosu'
+
+ class GameOfLifeWindow < Gosu::Window
+
+ def initialize(height=800, width=600)
+ @height = height
+ @width = width
+ super height, width, false
+ self.caption = "Conway's Game Of Life"
+
+ @background_color = Gosu::Color.new(0xffdedede)
+ @cell_color = Gosu::Color.new(0xff121212)
+ @blank_color = Gosu::Color.new(0xffededed)
+
+ #game
+ @columns = width / 10
+ @rows = height / 10
+ @column_width = width / @columns
+ @row_height = height / @rows
+ @gameboard = GameBoard.new(@columns, @rows)
+ @game = GameOfLife.new(@gameboard)
+ @game.gameboard.randomly_populate
+ end
+
+ def update
+ @game.evolve!
+ end
+
+ def draw
+ draw_quad(0, 0, @background_color,
+ width, 0, @background_color,
+ width, height, @background_color,
+ 0, height, @background_color)
+
+ @game.gameboard.cells.each do |cell|
+
+ if cell.is_alive?
+ draw_quad(cell.x_pos * @column_width, cell.y_pos * @row_height, @cell_color,
+ cell.x_pos * @column_width + (@column_width - 1), cell.y_pos * @row_height, @cell_color,
+ cell.x_pos * @column_width + (@column_width - 1), cell.y_pos * @row_height + (@row_height - 1), @cell_color,
+ cell.x_pos * @column_width, cell.y_pos * @row_height + (@row_height - 1), @cell_color)
+
+ else
+ draw_quad(cell.x_pos * @column_width, cell.y_pos * @row_height, @blank_color,
+ cell.x_pos * @column_width + (@column_width - 1), cell.y_pos * @row_height, @blank_color,
+ cell.x_pos * @column_width + (@column_width - 1), cell.y_pos * @row_height + (@row_height - 1), @blank_color,
+ cell.x_pos * @column_width, cell.y_pos * @row_height + (@row_height - 1), @blank_color)
+ end
+ end
+ end
+
+ def needs_cursor?
+ true
+ end
+
+
+ end
+
+ GameOfLifeWindow.new.show
+
+ require 'minitest/autorun'
+
+ class TestGameOfLife < Minitest::Test
+
+ def test_GameBoard
+ a = GameBoard.new
+ assert_instance_of GameBoard, a
+ assert_respond_to a, :rows
+ assert_respond_to a, :columns
+ assert_respond_to a, :board
+ assert_respond_to a, :neighbors
+ assert_respond_to a, :cells
+ assert_respond_to a, :randomly_populate
+ assert_respond_to a, :live_cells
+ assert_instance_of Array, a.board
+ a.board.each do |row|
+ assert_instance_of Array, row
+ row.each do |column|
+ assert_instance_of Cell, column
+ end
+ end
+
+ assert_equal 9, a.cells.count
+
+ a.cells.each do |cell|
+ assert_equal false, cell.is_alive?
+ end
+
+ assert_equal 0, a.live_cells.count
+ a.randomly_populate
+ refute_equal 0, a.live_cells.count
+ end
+
+ def test_Cell
+ b = Cell.new
+ assert_instance_of Cell, b
+ assert_respond_to b, :is_alive
+ assert_equal false, b.is_alive
+ assert_respond_to b, :x_pos
+ assert_respond_to b, :y_pos
+ assert_respond_to b, :kill_cell!
+ assert_respond_to b, :resurrect!
+ assert_equal b.x_pos, 0
+ assert_equal b.y_pos, 0
+ end
+
+ def test_GameOfLife
+ c = GameOfLife.new
+ assert_instance_of GameOfLife, c
+ assert_respond_to c, :gameboard
+ assert_respond_to c, :seeds
+ assert_instance_of GameBoard, c.gameboard
+ assert_instance_of Array, c.seeds
+
+ d = GameOfLife.new(GameBoard.new, [[1,2], [0,2]])
+ assert_equal true, d.gameboard.board[1][2].is_alive?
+ assert_equal true, d.gameboard.board[0][2].is_alive?
+
+ e = GameOfLife.new(GameBoard.new, [[1,0], [2,0]])
+ e.evolve!
+ assert_equal false, e.gameboard.board[1][0].is_alive?
+ assert_equal false, e.gameboard.board[2][0].is_alive?
+
+ f = GameOfLife.new(GameBoard.new, [[0,1], [1,1], [2,1]])
+ assert_equal 2, f.gameboard.neighbors(f.gameboard.board[1][1]).count
+ assert_equal 2, f.gameboard.neighbors(f.gameboard.board[0][1]).count
+ assert_equal true, f.gameboard.board[1][1].is_alive?
+ f.evolve!
+ assert_equal true, f.gameboard.board[0][1].is_alive?
+ assert_equal true, f.gameboard.board[1][1].is_alive?
+ assert_equal true, f.gameboard.board[2][1].is_alive?
+
+ g = GameOfLife.new(GameBoard.new, [[0,1], [1,1], [2,1], [2,2]])
+ assert_equal 3, g.gameboard.neighbors(g.gameboard.board[1][1]).count
+ assert_equal true, g.gameboard.board[1][1].is_alive?
+ g.evolve!
+ assert_equal false, g.gameboard.board[0][1].is_alive?
+ assert_equal true, g.gameboard.board[1][1].is_alive?
+ assert_equal true, g.gameboard.board[2][1].is_alive?
+ assert_equal true, g.gameboard.board[2][2].is_alive?
+
+ h = GameOfLife.new(GameBoard.new, [[0,1], [1,1], [2,1], [2,2], [1,2]])
+ assert_equal 4, h.gameboard.neighbors(h.gameboard.board[1][1]).count
+ assert_equal true, h.gameboard.board[2][2].is_alive?
+ assert_equal 3, h.gameboard.neighbors(h.gameboard.board[2][2]).count
+ h.evolve!
+ assert_equal true, h.gameboard.board[0][1].is_alive?
+ assert_equal false, h.gameboard.board[1][1].is_alive?
+ assert_equal true, h.gameboard.board[2][1].is_alive?
+ assert_equal true, h.gameboard.board[2][2].is_alive?
+ assert_equal false, h.gameboard.board[1][2].is_alive?
+ end
+ end
+#end
\ No newline at end of file