Skip to content

Commit

Permalink
improve Python and Rust test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchuette committed Mar 2, 2019
1 parent 5618403 commit 0bbb2dc
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 42 deletions.
3 changes: 3 additions & 0 deletions input_files/test011.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12
34
56
25 changes: 10 additions & 15 deletions py_src/problem011.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import time


def parseMatrix(path):
def parse_matrix(path):
"""
Doc string.
"""
Expand All @@ -31,31 +31,28 @@ def parseMatrix(path):
return matrix


def greatestProduct(matrix):
def greatest_product(matrix):
"""
Doc string.
"""
nums = [] # temp stores data
max_nums = [] # temp stores max triplet
max_product = 0 # temp stores maximum product
max_adjacent = 4 # number of adjacent ints to multiply

# left/right
for arr in matrix:
for i in range(len(arr)-max_adjacent+1):
prod = multOverList(arr[i:(i+max_adjacent)])
prod = mult_over_list(arr[i:(i+max_adjacent)])
if prod > max_product:
max_nums = arr[i:(i+max_adjacent)]
max_product = prod

# up/down
for i in range(len(matrix)-max_adjacent+1): # row
for j in range(len(matrix[0])): # col
for k in range(i, (i+max_adjacent)):
nums.append(matrix[k][j])
prod = multOverList(nums)
prod = mult_over_list(nums)
if prod > max_product:
max_nums = nums
max_product = prod
nums = [] # reset for next iteration

Expand All @@ -64,9 +61,8 @@ def greatestProduct(matrix):
for j in range(len(matrix[0])-max_adjacent+1): # col
for idx, k in enumerate(range(i, (i+max_adjacent))):
nums.append(matrix[k][j+idx])
prod = multOverList(nums)
prod = mult_over_list(nums)
if prod > max_product:
max_nums = nums
max_product = prod
nums = [] # reset for next iteration

Expand All @@ -75,17 +71,16 @@ def greatestProduct(matrix):
for j in range(len(matrix[0])-1, -1, -1): # col right to left!
for idx, k in enumerate(range(i, (i+max_adjacent))):
nums.append(matrix[k][j-idx])
prod = multOverList(nums)
prod = mult_over_list(nums)
if prod > max_product:
max_nums = nums
max_product = prod
nums = [] # reset for next iteration

# return result
print(max_nums)
return max_product


def multOverList(l):
def mult_over_list(l):
"""
Doc string.
"""
Expand All @@ -98,8 +93,8 @@ def multOverList(l):
if __name__ == "__main__":
# calculate solution and time it
start = time.time()
data = parseMatrix("../input_files/problem011.txt")
solution = greatestProduct(data)
data = parse_matrix("../input_files/problem011.txt")
solution = greatest_product(data)
end = time.time()

# print out results
Expand Down
55 changes: 30 additions & 25 deletions py_src/problem019.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Project Euler Problem 19 Solution
#
# Problem statement:
# You are given the following information, but you may prefer to do some research for yourself.
# You are given the following information, but you may prefer to
# do some research for yourself.

# 1 Jan 1900 was a Monday.
# Thirty days has September,
Expand All @@ -10,47 +11,51 @@
# Saving February alone,
# Which has twenty-eight, rain or shine.
# And on leap years, twenty-nine.
# A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
# How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
# A leap year occurs on any year evenly divisible by 4, but not on
# a century unless it is divisible by 400. How many Sundays fell on
# the first of the month during the twentieth century (1 Jan 1901 to
# 31 Dec 2000)?
#
# Solution description:
# Bruteforce solution: Implements a simple calendar, iterates over
# all the days and counts the number of Sundays that fell on the
# first of a month
# Fast solution: Iterates only over the relevant dates and
# uses Zeller's congruence
# (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to figure
# out the weekday of each first day of a month
# Bruteforce solution: Implements a simple calendar, iterates over
# all the days and counts the number of Sundays that fell on the
# first of a month
#
# Fast solution: Iterates only over the relevant dates and
# uses Zeller's congruence
# (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to figure
# out the weekday of each first day of a month
#
# Author: Tom Praschan
# Date: 2019/02/17
# License: MIT (see ../LICENSE.md)

from math import floor
import time


def is_leapyear(year):
"""
"""
Returns True if year is a leap year and false otherwise
"""
return year % 4 == 0 and not (year % 100 == 0 and year % 400 != 0)


def days_per_month(month, year):
"""
Given a month (1=january, 2=february, etc.) this function
returns the number of days in that month (leap years are)
returns the number of days in that month (leap years are)
taken into account
"""
if month in [1, 3, 5, 7, 8, 10, 12]:
return 31
return 31
elif month in [4, 6, 9, 11]:
return 30
return 30
elif month == 2:
return 29 if is_leapyear(year) else 28
raise ValueError("The provided month m must fullfill 1 <= m <= 12!")


def bruteforce_solution():
weekday = 1 # 1 = Monday, 2 = Tueday, ..., 7 = Sunday
weekday = 1 # 1 = Monday, 2 = Tueday, ..., 7 = Sunday
day = 1
month = 1
year = 1900
Expand All @@ -69,36 +74,38 @@ def bruteforce_solution():
weekday = weekday % 7 + 1

# Increment month
if day == 1:
if day == 1:
month = month % 12 + 1

# Increment year
if day == 1 and month == 1:
year += 1
return num_sundays


def zellers_congruence(day, month, year):
"""
For a given date year/month/day this algorithm returns
For a given date year/month/day this algorithm returns
the weekday of that date (1 = Monday, 2 = Tuesday, etc.)
For details see https://en.wikipedia.org/wiki/Zeller%27s_congruence
"""

# Consistent variable names with the formula on on Wikipedia
q = day
if month >= 3:
m = month
m = month # pragma: no cover
else:
m = month + 12
year -= 1
K = year % 100
J = year // 100

h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 + 5*J) % 7

# Convert to ISO
h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 + 5*J) % 7

# Convert to ISO
return ((h + 5) % 7) + 1


def fast_solution():
num_sundays = 0
for year in range(1901, 2001):
Expand All @@ -122,5 +129,3 @@ def fast_solution():

print(f"Fast Solution (Zeller's congruence): {solution}")
print(f"Elapsed time: {end - start:.6}s")


39 changes: 39 additions & 0 deletions py_src/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,21 @@ def test_sum_primes(self):
self.assertEqual(problem010.sum_primes(10), 17)


class TestProblem011Solution(unittest.TestCase):
def test_parse_matrix(self):
self.assertListEqual(
problem011.parse_matrix("../input_files/test011.txt"),
[["12"], ["34"], ["56"]]
)

def test_greatest_product(self):
self.data = problem011.parse_matrix("../input_files/problem011.txt")
self.assertEqual(problem011.greatest_product(self.data), 70600674)

def test_mult_over_list(self):
self.assertEqual(problem011.mult_over_list([1, 2, 3]), 6)


class TestProblem013Solution(unittest.TestCase):
def test_sum_numbers(self):
self.assertEqual(problem013.sum_numbers([123, 100, 400]), 623)
Expand All @@ -123,25 +138,49 @@ def test_digit_sum(self):
self.assertEqual(problem016.digit_sum(123), 6)
self.assertEqual(problem016.digit_sum('7356'), 21)


class TestProblem019Solution(unittest.TestCase):
def test_is_leapyear(self):
self.assertEqual(problem019.is_leapyear(1904), True)
self.assertEqual(problem019.is_leapyear(1800), False)
self.assertEqual(problem019.is_leapyear(2400), True)

def test_days_per_month(self):
self.assertEqual(problem019.days_per_month(1, 2019), 31)
self.assertEqual(problem019.days_per_month(2, 2019), 28)
self.assertEqual(problem019.days_per_month(2, 2012), 29)
self.assertEqual(problem019.days_per_month(4, 2019), 30)
self.assertRaises(
ValueError,
problem019.days_per_month,
-1,
2019
)

def test_zeller(self):
self.assertEqual(problem019.zellers_congruence(1, 1, 1900), 1)
self.assertEqual(problem019.zellers_congruence(17, 2, 2019), 7)

def test_brute_force_solution(self):
# TODO
pass

def test_fast_solution(self):
# TODO
pass


class TestProblem022Solution(unittest.TestCase):
def test_alphabetical_value(self):
self.assertEqual(problem022.alphabetical_value('COLIN'), 53)
self.assertEqual(problem022.alphabetical_value('ABC'), 6)


class TestProblem025Solution(unittest.TestCase):
def test_num_digits(self):
self.assertEqual(problem025.num_digits(123), 3)
self.assertEqual(problem025.num_digits('25431'), 5)


if __name__ == "__main__":
unittest.main()
3 changes: 2 additions & 1 deletion rust_src/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ fn main() {
opts_expanded.push(s);
}
}
} else { // #no_code
} else {
// #no_code
opts_expanded.push(option.to_string());
}

Expand Down
9 changes: 8 additions & 1 deletion rust_src/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ mod tests {
assert_eq!(lib::problem004::is_palindrome(9009), true);
assert_eq!(lib::problem004::is_palindrome(9809), false);

assert_eq!( // #no_code
assert_eq!(
// #no_code
lib::problem004::reverse_str(&"ab".to_string()),
"ba".to_string()
);
Expand Down Expand Up @@ -74,6 +75,12 @@ mod tests {
assert_eq!(lib::problem007::nth_prime(6), 13);
}

#[test]
#[should_panic]
fn test_invalid_path() {
lib::problem008::parse_data("invalid-path".to_string());
}

#[test]
fn test_problem008() {
assert_eq!(
Expand Down

0 comments on commit 0bbb2dc

Please sign in to comment.