From b702c214d87608b709e1b68815910433f742f1cb Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Tue, 18 Mar 2014 18:12:21 +0100 Subject: [PATCH 01/29] New exercise: python series --- EXERCISES.txt | 1 + series/example.py | 11 +++++++++++ series/series_test.py | 44 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 series/example.py create mode 100644 series/series_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 2347f307651..8aa88af667a 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -5,6 +5,7 @@ word-count anagram beer-song nucleotide-count +series point-mutations phone-number grade-school diff --git a/series/example.py b/series/example.py new file mode 100644 index 00000000000..44ebaaabc61 --- /dev/null +++ b/series/example.py @@ -0,0 +1,11 @@ +class Series(object): + def __init__(self, digits): + self.digits = digits + self.numbers = [int(d) for d in digits] + + def slices(self, length): + if not 1 <= length <= len(self.numbers): + raise ValueError("Invalid slice length for this series: " + + str(length)) + return [self.numbers[i:i + length] + for i in range(len(self.numbers) - length + 1)] diff --git a/series/series_test.py b/series/series_test.py new file mode 100644 index 00000000000..e32696a0ba6 --- /dev/null +++ b/series/series_test.py @@ -0,0 +1,44 @@ +try: + from series import Series +except ImportError: + raise SystemExit('Could not find series.py. Does it exist?') + +import unittest + + +class SeriesTest(unittest.TestCase): + def test_slices_of_one(self): + self.assertEqual([[0], [1], [2], [3], [4]], + Series("01234").slices(1)) + + def test_slices_of_two(self): + self.assertEqual([[9, 7], [7, 8], [8, 6], [6, 7], + [7, 5], [5, 6], [6, 4]], + Series("97867564").slices(2)) + + def test_slices_of_three(self): + self.assertEqual([[9, 7, 8], [7, 8, 6], [8, 6, 7], + [6, 7, 5], [7, 5, 6], [5, 6, 4]], + Series("97867564").slices(3)) + + def test_slices_of_four(self): + self.assertEqual([[0, 1, 2, 3], [1, 2, 3, 4]], + Series("01234").slices(4)) + + def test_slices_of_five(self): + self.assertEqual([[0, 1, 2, 3, 4]], + Series("01234").slices(5)) + + def test_overly_long_slice(self): + self.assertRaisesRegexp(ValueError, + "^Invalid slice length for this series: 4$", + Series("012").slices, 4) + + def test_overly_short_slice(self): + self.assertRaisesRegexp(ValueError, + "^Invalid slice length for this series: 0$", + Series("01234").slices, 0) + + +if __name__ == '__main__': + unittest.main() From 36d2dd996bb35fcfe2ed8af6b5f3e181febee5fe Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Tue, 18 Mar 2014 09:00:03 +0100 Subject: [PATCH 02/29] New exercise: python octal --- EXERCISES.txt | 1 + octal/example.py | 13 +++++++++++++ octal/octal_test.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 octal/example.py create mode 100644 octal/octal_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 8aa88af667a..7a9f8096191 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -6,6 +6,7 @@ anagram beer-song nucleotide-count series +octal point-mutations phone-number grade-school diff --git a/octal/example.py b/octal/example.py new file mode 100644 index 00000000000..b30b46b5c34 --- /dev/null +++ b/octal/example.py @@ -0,0 +1,13 @@ +class Octal(object): + def __init__(self, octal_string): + self.digits = self.__validate(octal_string) + + def __validate(self, s): + for char in s: + if not '0' <= char < '8': + raise ValueError("Invalid octal digit: " + char) + return s + + def to_decimal(self): + return sum(int(digit) * 8 ** i + for (i, digit) in enumerate(reversed(self.digits))) diff --git a/octal/octal_test.py b/octal/octal_test.py new file mode 100644 index 00000000000..1273a318f25 --- /dev/null +++ b/octal/octal_test.py @@ -0,0 +1,45 @@ +try: + from octal import Octal +except ImportError: + raise SystemExit('Could not find octal.py. Does it exist?') + +import unittest + + +class OctalTest(unittest.TestCase): + def test_octal_1_is_decimal_1(self): + self.assertEqual(1, Octal("1").to_decimal()) + + def test_octal_10_is_decimal_8(self): + self.assertEqual(8, Octal("10").to_decimal()) + + def test_octal_17_is_decimal_15(self): + self.assertEqual(15, Octal("17").to_decimal()) + + def test_octal_130_is_decimal_88(self): + self.assertEqual(88, Octal("130").to_decimal()) + + def test_octal_2047_is_decimal_1063(self): + self.assertEqual(1063, Octal("2047").to_decimal()) + + def test_octal_1234567_is_decimal_342391(self): + self.assertEqual(342391, Octal("1234567").to_decimal()) + + def test_8_is_seen_as_invalid(self): + self.assertRaisesRegexp(ValueError, "^Invalid octal digit: 8$", + Octal, "8") + + def test_invalid_octal_is_recognized(self): + self.assertRaisesRegexp(ValueError, "^Invalid octal digit: c$", + Octal, "carrot") + + def test_6789_is_seen_as_invalid(self): + self.assertRaisesRegexp(ValueError, "^Invalid octal digit: 8$", + Octal, "6789") + + def test_valid_octal_formatted_string_011_is_decimal_9(self): + self.assertEqual(9, Octal("011").to_decimal()) + + +if __name__ == '__main__': + unittest.main() From 4ad8c8a32a444e817bbe85eeb0fadc15257551a0 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Tue, 18 Mar 2014 20:46:15 +0100 Subject: [PATCH 03/29] New exercise: python difference-of-squares --- EXERCISES.txt | 1 + .../difference_of_squares.py | 11 +++++++ .../difference_of_squares_test.py | 31 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 difference-of-squares/difference_of_squares.py create mode 100644 difference-of-squares/difference_of_squares_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 7a9f8096191..cecbe4169f3 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -7,6 +7,7 @@ beer-song nucleotide-count series octal +difference-of-squares point-mutations phone-number grade-school diff --git a/difference-of-squares/difference_of_squares.py b/difference-of-squares/difference_of_squares.py new file mode 100644 index 00000000000..b2944ecf111 --- /dev/null +++ b/difference-of-squares/difference_of_squares.py @@ -0,0 +1,11 @@ +def square_of_sum(n): + sum_ = n * (n + 1) / 2 + return sum_ * sum_ + + +def sum_of_squares(n): + return sum(m * m for m in range(n + 1)) + + +def difference(n): + return square_of_sum(n) - sum_of_squares(n) diff --git a/difference-of-squares/difference_of_squares_test.py b/difference-of-squares/difference_of_squares_test.py new file mode 100644 index 00000000000..728ff4c6f69 --- /dev/null +++ b/difference-of-squares/difference_of_squares_test.py @@ -0,0 +1,31 @@ +try: + from difference_of_squares import difference, square_of_sum, sum_of_squares +except ImportError: + raise SystemExit('Could not find difference_of_squares.py. Does it exist?') + +import unittest + + +class DifferenceOfSquaresTest(unittest.TestCase): + + def test_square_of_sum_5(self): + self.assertEqual(225, square_of_sum(5)) + + def test_sum_of_squares_5(self): + self.assertEqual(55, sum_of_squares(5)) + + def test_difference_5(self): + self.assertEqual(170, difference(5)) + + def test_square_of_sum_100(self): + self.assertEqual(25502500, square_of_sum(100)) + + def test_sum_of_squares_100(self): + self.assertEqual(338350, sum_of_squares(100)) + + def test_difference_100(self): + self.assertEqual(25164150, difference(100)) + + +if __name__ == '__main__': + unittest.main() From 319fb2a637748c4327b5430427850b37805fa2e9 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Tue, 18 Mar 2014 18:44:48 -0400 Subject: [PATCH 04/29] Rename difference-of-squares example implementation --- difference-of-squares/{difference_of_squares.py => example.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename difference-of-squares/{difference_of_squares.py => example.py} (100%) diff --git a/difference-of-squares/difference_of_squares.py b/difference-of-squares/example.py similarity index 100% rename from difference-of-squares/difference_of_squares.py rename to difference-of-squares/example.py From 9617279674d40e2e57f85e2ab65f09511f5d7314 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Fri, 21 Mar 2014 21:08:28 +0100 Subject: [PATCH 05/29] New exercise: python luhn --- EXERCISES.txt | 1 + luhn/example.py | 20 ++++++++++++++++++++ luhn/luhn_test.py | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 luhn/example.py create mode 100644 luhn/luhn_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 2347f307651..4a41d460bf7 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -18,6 +18,7 @@ gigasecond triangle scrabble-score sieve +luhn roman-numerals binary prime-factors diff --git a/luhn/example.py b/luhn/example.py new file mode 100644 index 00000000000..5d061b568d9 --- /dev/null +++ b/luhn/example.py @@ -0,0 +1,20 @@ +class Luhn(object): + def __init__(self, number): + self.number = number + + def addends(self): + old_digits = [int(d) for d in str(self.number)] + luhn_transform = lambda n: (2 * n - 9) if (n > 4) else (2 * n) + return [(luhn_transform(n) if (i % 2 == 0) else n) + for i, n in enumerate(old_digits, start=len(old_digits) % 2)] + + def checksum(self): + return sum(self.addends()) % 10 + + def is_valid(self): + return self.checksum() == 0 + + @staticmethod + def create(n): + diff = (10 - Luhn(n * 10).checksum()) % 10 + return 10 * n + diff diff --git a/luhn/luhn_test.py b/luhn/luhn_test.py new file mode 100644 index 00000000000..994ff1014b7 --- /dev/null +++ b/luhn/luhn_test.py @@ -0,0 +1,39 @@ +try: + from luhn import Luhn +except ImportError: + raise SystemExit('Could not find luhn.py. Does it exist?') + +import unittest + + +class LuhnTests(unittest.TestCase): + def test_addends(self): + self.assertEqual([1, 4, 1, 4, 1], Luhn(12121).addends()) + + def test_addends_large(self): + self.assertEqual([7, 6, 6, 1], Luhn(8631).addends()) + + def test_checksum1(self): + self.assertEqual(2, Luhn(4913).checksum()) + + def test_ckecksum2(self): + self.assertEqual(1, Luhn(201773).checksum()) + + def test_invalid_number(self): + self.assertFalse(Luhn(738).is_valid()) + + def test_valid_number(self): + self.assertTrue(Luhn(8739567).is_valid()) + + def test_create_valid_number1(self): + self.assertEqual(1230, Luhn.create(123)) + + def test_create_valid_number2(self): + self.assertEqual(8739567, Luhn.create(873956)) + + def test_create_valid_number3(self): + self.assertEqual(8372637564, Luhn.create(837263756)) + + +if __name__ == '__main__': + unittest.main() From 0f8b13dcf6188d77f78542a557308644a7cbe5ad Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Sat, 22 Mar 2014 05:42:45 +0100 Subject: [PATCH 06/29] New exercise: python palindrome-products --- EXERCISES.txt | 1 + palindrome-products/example.py | 18 +++++++ .../palindrome_products_test.py | 50 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 palindrome-products/example.py create mode 100644 palindrome-products/palindrome_products_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index b00b09fc8dd..3c5f5923ea1 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -18,6 +18,7 @@ sum-of-multiples space-age grains gigasecond +palindrome-products triangle scrabble-score sieve diff --git a/palindrome-products/example.py b/palindrome-products/example.py new file mode 100644 index 00000000000..6d209b7f0fb --- /dev/null +++ b/palindrome-products/example.py @@ -0,0 +1,18 @@ +def largest_palindrome(max_factor, min_factor=0): + return max(palindromes(max_factor, min_factor), key=lambda tup: tup[0]) + + +def smallest_palindrome(max_factor, min_factor): + return min(palindromes(max_factor, min_factor), key=lambda tup: tup[0]) + + +def palindromes(max_factor, min_factor): + return ((a * b, (a, b)) + for a in range(min_factor, max_factor + 1) + for b in range(min_factor, a + 1) + if is_palindrome(a * b)) + + +def is_palindrome(n): + s = str(n) + return s == s[::-1] diff --git a/palindrome-products/palindrome_products_test.py b/palindrome-products/palindrome_products_test.py new file mode 100644 index 00000000000..9927e5323ee --- /dev/null +++ b/palindrome-products/palindrome_products_test.py @@ -0,0 +1,50 @@ +""" +Notes regarding the implementation of smallest_palindrome and +largest_palindrome: + +Both functions must take two keyword arguments: + max_factor -- int + min_factor -- int, default 0 + +Their return value must be a tuple (value, factors) where value is the +palindrome itself, and factors is an iterable containing both factors of the +palindrome in arbitrary order. +""" + +try: + from palindrome import smallest_palindrome, largest_palindrome +except ImportError: + raise SystemExit('Could not find palindrome.py. Does it exist?') + +import unittest + + +class PalindromesTests(unittest.TestCase): + def test_largest_palindrome_from_single_digit_factors(self): + value, factors = largest_palindrome(max_factor=9) + self.assertEqual(9, value) + self.assertIn(set(factors), [{1, 9}, {3, 3}]) + + def test_largest_palindrome_from_double_digit_factors(self): + value, factors = largest_palindrome(max_factor=99, min_factor=10) + self.assertEqual(9009, value) + self.assertEqual({91, 99}, set(factors)) + + def test_smallest_palindrome_from_double_digit_factors(self): + value, factors = smallest_palindrome(max_factor=99, min_factor=10) + self.assertEqual(121, value) + self.assertEqual({11}, set(factors)) + + def test_largest_palindrome_from_triple_digit_factors(self): + value, factors = largest_palindrome(max_factor=999, min_factor=100) + self.assertEqual(906609, value) + self.assertEqual({913, 993}, set(factors)) + + def test_smallest_palindrome_from_triple_digit_factors(self): + value, factors = smallest_palindrome(max_factor=999, min_factor=100) + self.assertEqual(10201, value) + self.assertEqual({101, 101}, set(factors)) + + +if __name__ == '__main__': + unittest.main() From b3a141753f9331306704818c1b7b806ae8836834 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Sat, 22 Mar 2014 06:58:39 +0100 Subject: [PATCH 07/29] New exercise: python nth-prime --- EXERCISES.txt | 1 + nth-prime/example.py | 31 +++++++++++++++++++++++++++++++ nth-prime/nth_prime_test.py | 25 +++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 nth-prime/example.py create mode 100644 nth-prime/nth_prime_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index b00b09fc8dd..d7b2f3f76a6 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -21,6 +21,7 @@ gigasecond triangle scrabble-score sieve +nth-prime luhn roman-numerals binary diff --git a/nth-prime/example.py b/nth-prime/example.py new file mode 100644 index 00000000000..d997d8a29b1 --- /dev/null +++ b/nth-prime/example.py @@ -0,0 +1,31 @@ +from itertools import count +from math import sqrt + + +def nth_prime(n): + known = [] + candidates = prime_candidates() + + def is_prime(m): + sqrt_m = sqrt(m) + for k in known: + if k > sqrt_m: + return True + elif m % k == 0: + return False + return True + + while len(known) < n: + x = next(candidates) + if is_prime(x): + known.append(x) + + return known[n - 1] + + +def prime_candidates(): + yield 2 + yield 3 + for n in count(6, 6): + yield n - 1 + yield n + 1 diff --git a/nth-prime/nth_prime_test.py b/nth-prime/nth_prime_test.py new file mode 100644 index 00000000000..761e07ce105 --- /dev/null +++ b/nth-prime/nth_prime_test.py @@ -0,0 +1,25 @@ +try: + from prime import nth_prime +except ImportError: + raise SystemExit('Could not find prime.py. Does it exist?') + +import unittest + + +class NthPrimeTests(unittest.TestCase): + def test_first_prime(self): + self.assertEqual(2, nth_prime(1)) + + def test_sixth_prime(self): + self.assertEqual(13, nth_prime(6)) + + def test_first_twenty_primes(self): + self.assertEqual([2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71], + [nth_prime(n) for n in range(1, 21)]) + + def test_prime_no_10000(self): + self.assertEqual(104729, nth_prime(10000)) + + +if __name__ == '__main__': + unittest.main() From c51ea3f8ec1522fc8aab66345f2c114267658d2e Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Sat, 22 Mar 2014 08:26:43 +0100 Subject: [PATCH 08/29] New exercise: python largest-series-product --- EXERCISES.txt | 1 + largest-series-product/example.py | 19 ++++++++ .../largest_series_product_test.py | 44 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 largest-series-product/example.py create mode 100644 largest-series-product/largest_series_product_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 3cfb0fb25f5..8f78cf1ea2e 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -6,6 +6,7 @@ anagram beer-song nucleotide-count series +largest-series-product octal difference-of-squares point-mutations diff --git a/largest-series-product/example.py b/largest-series-product/example.py new file mode 100644 index 00000000000..daa4cde478f --- /dev/null +++ b/largest-series-product/example.py @@ -0,0 +1,19 @@ +from functools import reduce +from operator import mul + + +class Series(object): + def __init__(self, number_string): + self.digits = [int(d) for d in number_string] + + def slices(self, length): + if not 1 <= length <= len(self.digits): + raise ValueError("Invalid slice length for this series: " + + str(length)) + return [self.digits[i:i + length] + for i in range(len(self.digits) - length + 1)] + + def largest_product(self, length): + if length == 0: + return 1 + return max(reduce(mul, slc) for slc in self.slices(length)) diff --git a/largest-series-product/largest_series_product_test.py b/largest-series-product/largest_series_product_test.py new file mode 100644 index 00000000000..474dfea6d86 --- /dev/null +++ b/largest-series-product/largest_series_product_test.py @@ -0,0 +1,44 @@ +try: + from series import Series +except ImportError: + raise SystemExit('Could not find series.py. Does it exist?') + +import unittest + + +class SeriesTest(unittest.TestCase): + def test_slices_of_two(self): + self.assertEqual([[9, 7], [7, 8], [8, 6], [6, 7], + [7, 5], [5, 6], [6, 4]], + Series("97867564").slices(2)) + + def test_overly_long_slice(self): + self.assertRaisesRegexp(ValueError, + "^Invalid slice length for this series: 4$", + Series("012").slices, 4) + + def test_largest_product_of_2(self): + self.assertEqual(72, Series("0123456789").largest_product(2)) + + def test_tiny_number(self): + self.assertEqual(9, Series("19").largest_product(2)) + + def test_largest_product_of_3(self): + self.assertEqual(270, Series("1027839564").largest_product(3)) + + def test_big_number(self): + self.assertEqual(28350, + Series("52677741234314237566414902593461595376319419" + "139427").largest_product(6)) + + def test_identity(self): + self.assertEqual(1, Series("").largest_product(0)) + + def test_slices_bigger_than_number(self): + self.assertRaisesRegexp(ValueError, + "^Invalid slice length for this series: 4$", + Series("012").largest_product, 4) + + +if __name__ == '__main__': + unittest.main() From b3da077bd688d1846d683a91a252645e63d5dedb Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Sun, 23 Mar 2014 09:17:40 +0100 Subject: [PATCH 09/29] New exercise: python twelve-days. --- EXERCISES.txt | 1 + twelve-days/example.py | 33 +++++++++++++++ twelve-days/twelve_days_test.py | 71 +++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 twelve-days/example.py create mode 100644 twelve-days/twelve_days_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 3c5f5923ea1..c27e911ee2b 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -2,6 +2,7 @@ bob rna-transcription matrix word-count +twelve-days anagram beer-song nucleotide-count diff --git a/twelve-days/example.py b/twelve-days/example.py new file mode 100644 index 00000000000..029a142750c --- /dev/null +++ b/twelve-days/example.py @@ -0,0 +1,33 @@ +GIFTS = ['twelve Drummers Drumming', + 'eleven Pipers Piping', + 'ten Lords-a-Leaping', + 'nine Ladies Dancing', + 'eight Maids-a-Milking', + 'seven Swans-a-Swimming', + 'six Geese-a-Laying', + 'five Gold Rings', + 'four Calling Birds', + 'three French Hens', + 'two Turtle Doves', + 'a Partridge in a Pear Tree'] + +ORDINAL = [None, 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', + 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth'] + + +def verse(n): + gifts = GIFTS[-n:] + if len(gifts) > 1: + gifts[:-1] = [', '.join(gifts[:-1])] + gifts = ', and '.join(gifts) + return 'On the {} day of Christmas my true love gave to me, {}.\n'.format( + ORDINAL[n], gifts) + + +def verses(start, end): + return ''.join([verse(n) + '\n' + for n in range(start, end + 1)]) + + +def sing(): + return verses(1, 12) diff --git a/twelve-days/twelve_days_test.py b/twelve-days/twelve_days_test.py new file mode 100644 index 00000000000..d60ce28e936 --- /dev/null +++ b/twelve-days/twelve_days_test.py @@ -0,0 +1,71 @@ +try: + from twelve_days import sing, verse, verses +except ImportError: + raise SystemExit('Could not find twelve_days.py. Does it exist?') + +import unittest + + +class TwelveDaysTests(unittest.TestCase): + + def test_verse1(self): + expected = "On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(1)) + + def test_verse2(self): + expected = "On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(2)) + + def test_verse3(self): + expected = "On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(3)) + + def test_verse4(self): + expected = "On the fourth day of Christmas my true love gave to me, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(4)) + + def test_verse5(self): + expected = "On the fifth day of Christmas my true love gave to me, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(5)) + + def test_verse6(self): + expected = "On the sixth day of Christmas my true love gave to me, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(6)) + + def test_verse7(self): + expected = "On the seventh day of Christmas my true love gave to me, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(7)) + + def test_verse8(self): + expected = "On the eighth day of Christmas my true love gave to me, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(8)) + + def test_verse9(self): + expected = "On the ninth day of Christmas my true love gave to me, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(9)) + + def test_verse10(self): + expected = "On the tenth day of Christmas my true love gave to me, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(10)) + + def test_verse11(self): + expected = "On the eleventh day of Christmas my true love gave to me, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(11)) + + def test_verse12(self): + expected = "On the twelfth day of Christmas my true love gave to me, twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n" + self.assertEqual(expected, verse(12)) + + def test_multiple_verses(self): + expected = ( + "On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.\n\n" + + "On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.\n\n" + + "On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n") + self.assertEqual(expected, verses(1, 3)) + + def test_the_whole_song(self): + self.assertEqual(verses(1, 12), sing()) + + +if __name__ == '__main__': + unittest.main() From a1e5258523d730f045266385e41d2dedfdeacd4c Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Wed, 26 Mar 2014 14:12:41 +0100 Subject: [PATCH 10/29] New exercise: python allergies --- EXERCISES.txt | 1 + allergies/allergies_test.py | 43 +++++++++++++++++++++++++++++++++++++ allergies/example.py | 22 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 allergies/allergies_test.py create mode 100644 allergies/example.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 2af8253f41a..82394ea421d 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -12,6 +12,7 @@ octal difference-of-squares point-mutations phone-number +allergies grade-school robot-name etl diff --git a/allergies/allergies_test.py b/allergies/allergies_test.py new file mode 100644 index 00000000000..c349e71d4ea --- /dev/null +++ b/allergies/allergies_test.py @@ -0,0 +1,43 @@ +try: + from allergies import Allergies +except ImportError: + raise SystemExit('Could not find allergies.py. Does it exist?') + +import unittest + + +class AllergiesTests(unittest.TestCase): + + def test_no_allergies_means_not_allergic(self): + allergies = Allergies(0) + self.assertFalse(allergies.is_allergic_to('peanuts')) + self.assertFalse(allergies.is_allergic_to('cats')) + self.assertFalse(allergies.is_allergic_to('strawberries')) + + def test_is_allergic_to_eggs(self): + self.assertTrue(Allergies(1).is_allergic_to('eggs')) + + def test_has_the_right_allergies(self): + allergies = Allergies(5) + self.assertTrue(allergies.is_allergic_to('eggs')) + self.assertTrue(allergies.is_allergic_to('shellfish')) + self.assertFalse(allergies.is_allergic_to('strawberries')) + + def test_no_allergies_at_all(self): + self.assertEqual([], Allergies(0).list) + + def test_allergic_to_just_peanuts(self): + self.assertEqual(['peanuts'], Allergies(2).list) + + def test_allergic_to_everything(self): + self.assertEqual( + ('eggs peanuts shellfish strawberries tomatoes ' + 'chocolate pollen cats').split(), + Allergies(255).list) + + def test_ignore_non_allergen_score_parts(self): + self.assertEqual(['eggs'], Allergies(257).list) + + +if __name__ == '__main__': + unittest.main() diff --git a/allergies/example.py b/allergies/example.py new file mode 100644 index 00000000000..37d779330e4 --- /dev/null +++ b/allergies/example.py @@ -0,0 +1,22 @@ +def powers_of_2(n): + """Return a list of the powers of 2 whose sum is the input number.""" + return [2 ** exponent + for exponent, bit in enumerate(bin(n)[:1:-1]) + if bit == '1'] + + +class Allergies(object): + + __allergens = {2 ** exponent: allergen + for exponent, allergen in enumerate( + ("eggs peanuts shellfish strawberries tomatoes " + "chocolate pollen cats").split())} + + def __init__(self, score): + self.score = score + self.list = [self.__allergens[p] + for p in powers_of_2(score) + if p in self.__allergens] + + def is_allergic_to(self, allergen): + return allergen in self.list From 78995b0a4509699659486dc4291f0277fbcf4770 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Thu, 27 Mar 2014 10:42:07 -0300 Subject: [PATCH 11/29] Add atbash-cipher exercise --- EXERCISES.txt | 1 + atbash-cipher/atbash_cipher_test.py | 45 +++++++++++++++++++++++++++++ atbash-cipher/example.py | 14 +++++++++ 3 files changed, 60 insertions(+) create mode 100644 atbash-cipher/atbash_cipher_test.py create mode 100644 atbash-cipher/example.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 82394ea421d..e8df4e346b8 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -31,3 +31,4 @@ roman-numerals binary prime-factors raindrops +atbash-cipher diff --git a/atbash-cipher/atbash_cipher_test.py b/atbash-cipher/atbash_cipher_test.py new file mode 100644 index 00000000000..e42b3c90ac5 --- /dev/null +++ b/atbash-cipher/atbash_cipher_test.py @@ -0,0 +1,45 @@ +try: + from atbash_cipher import encode, decode +except ImportError: + raise SystemExit('Could not find atbash_cipher.py. Does it exist?') + +import unittest + + +class AtbashCipherTest(unittest.TestCase): + def test_encode_no(self): + self.assertEqual("ml", encode("no")) + + def test_encode_yes(self): + self.assertEqual("bvh", encode("yes")) + + def test_encode_OMG(self): + self.assertEqual("lnt", encode("OMG")) + + def test_encode_O_M_G(self): + self.assertEqual("lnt", encode("O M G")) + + def test_encode_long_word(self): + self.assertEqual("nrmwy oldrm tob", encode("mindblowingly")) + + def test_encode_numbers(self): + self.assertEqual("gvhgr mt123 gvhgr mt", + encode("Testing, 1 2 3, testing.")) + + def test_encode_sentence(self): + self.assertEqual("gifgs rhurx grlm", + encode("Truth is fiction.")) + + def test_encode_all_things(self): + plaintext = "The quick brown fox jumps over the lazy dog." + ciphertext = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt" + self.assertEqual(ciphertext, encode(plaintext)) + + def test_decode_word(self): + self.assertEqual("exercism", decode("vcvix rhn")) + + def test_decode_sentence(self): + self.assertEqual("anobstacleisoftenasteppingstone", decode("zmlyh gzxov rhlug vmzhg vkkrm thglm v")) + +if __name__ == '__main__': + unittest.main() diff --git a/atbash-cipher/example.py b/atbash-cipher/example.py new file mode 100644 index 00000000000..021cd07d2bc --- /dev/null +++ b/atbash-cipher/example.py @@ -0,0 +1,14 @@ +from string import maketrans, lowercase, digits, punctuation, whitespace + +BLKSZ = 5 +trtbl = maketrans(lowercase+digits, "".join(reversed(lowercase))+digits) + +def base_trans(text): + return text.lower().translate(trtbl, punctuation+whitespace) + +def encode(plain): + cipher = base_trans(plain) + return " ".join([cipher[i:i+BLKSZ] for i in range(0,len(cipher),BLKSZ)]) + +def decode(ciphered): + return base_trans(ciphered) \ No newline at end of file From 6b37aff9b8ee4ba18cf4bcf5e182b9ebccefa9ea Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Thu, 27 Mar 2014 16:31:41 -0300 Subject: [PATCH 12/29] Add wordy exercise --- EXERCISES.txt | 1 + wordy/example.py | 33 +++++++++++++++++ wordy/wordy_test.py | 90 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 wordy/example.py create mode 100644 wordy/wordy_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index e8df4e346b8..1cadfb94899 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -32,3 +32,4 @@ binary prime-factors raindrops atbash-cipher +wordy diff --git a/wordy/example.py b/wordy/example.py new file mode 100644 index 00000000000..7e0fda310fb --- /dev/null +++ b/wordy/example.py @@ -0,0 +1,33 @@ +from operator import add, div, mul, sub + +VALID_OPERATIONS = {"plus": add, "minus": sub, "times": mul, + "multiplied by": mul, "divided by": div} + +def calculate(stmt): + if not (stmt.startswith("What is ") and stmt.endswith("?")): + raise ValueError("Ill-formed question") + l = stmt[8:-1].strip().lower().split() + if not l: + raise ValueError("Ill-formed question") + l.reverse() + try: + op1 = int(l.pop()) + except ValueError: + raise ValueError("Ill-formed question") + while l: + oprt = [l.pop()] + while l: + try: + next_tk = l.pop() + op2 = int(next_tk) + break + except ValueError: + oprt.append(next_tk) + else: + raise ValueError("Ill-formed question") + oprt = " ".join(oprt) + try: + op1 = VALID_OPERATIONS[oprt](op1, op2) + except KeyError: + raise ValueError("Ill-formed question") + return op1 \ No newline at end of file diff --git a/wordy/wordy_test.py b/wordy/wordy_test.py new file mode 100644 index 00000000000..0ddd0218d4e --- /dev/null +++ b/wordy/wordy_test.py @@ -0,0 +1,90 @@ +try: + from wordy import calculate +except ImportError: + raise SystemExit('Could not find wordy.py. Does it exist?') + +import unittest + +class WordyTest(unittest.TestCase): + def test_simple_add_1(self): + self.assertEqual(18, calculate("What is 5 plus 13?")) + + @unittest.skip("Not implemented yet") + def test_simple_add_2(self): + self.assertEqual(-8, calculate("What is 5 plus -13?")) + + @unittest.skip("Not implemented yet") + def test_simple_sub_1(self): + self.assertEqual(6, calculate("What is 103 minus 97?")) + + @unittest.skip("Not implemented yet") + def test_simple_sub_2(self): + self.assertEqual(-6, calculate("What is 97 minus 103?")) + + @unittest.skip("Not implemented yet") + def test_simple_mult(self): + self.assertEqual(21, calculate("What is 7 times 3?")) + + @unittest.skip("Not implemented yet") + def test_simple_div(self): + self.assertEqual(9, calculate("What is 45 divided by 5?")) + + @unittest.skip("Not implemented yet") + def test_add_negative_numbers(self): + self.assertEqual(-11, calculate("What is -1 plus -10?")) + + @unittest.skip("Not implemented yet") + def test_add_more_digits(self): + self.assertEqual(45801, calculate("What is 123 plus 45678?")) + + @unittest.skip("Not implemented yet") + def test_add_twice(self): + self.assertEqual(4, calculate("What is 1 plus 2 plus 1?")) + + @unittest.skip("Not implemented yet") + def test_add_then_subtract(self): + self.assertEqual(14, calculate("What is 1 plus 5 minus -8?")) + + @unittest.skip("Not implemented yet") + def test_subtract_twice(self): + self.assertEqual(-7, calculate("What is 20 minus 14 minus 13?")) + + @unittest.skip("Not implemented yet") + def test_multiply_twice(self): + self.assertEqual(-12, calculate("What is 2 multiplied by -2 multiplied by 3?")) + + @unittest.skip("Not implemented yet") + def test_add_then_multiply(self): + self.assertEqual(-8, calculate("What is -3 plus 7 multiplied by -2?")) + + @unittest.skip("Not implemented yet") + def test_divide_twice(self): + self.assertEqual(16, calculate("What is -12000 divided by 25 divided by -30?")) + + @unittest.skip("Not implemented yet") + def test_invalid_operation(self): + with self.assertRaises(ValueError) as context: + calculate("What is 4 xor 7?") + self.assertEqual(context.exception.message, 'Ill-formed question') + + @unittest.skip("Not implemented yet") + def test_missing_operation(self): + with self.assertRaises(ValueError) as context: + calculate("What is 2 2 minus 3?") + self.assertEqual(context.exception.message, 'Ill-formed question') + + @unittest.skip("Not implemented yet") + def test_missing_number(self): + with self.assertRaises(ValueError) as context: + calculate("What is 7 plus times -2?") + self.assertEqual(context.exception.message, 'Ill-formed question') + + @unittest.skip("Not implemented yet") + def test_irrelevant_question(self): + with self.assertRaises(ValueError) as context: + calculate("Which is greater, 3 or 2?") + self.assertEqual(context.exception.message, 'Ill-formed question') + + +if __name__ == '__main__': + unittest.main() From 55126db9e0d434873b766a63e0a01a1845a2776c Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Fri, 28 Mar 2014 22:19:26 -0300 Subject: [PATCH 13/29] New exercise: minesweeper --- EXERCISES.txt | 1 + minesweeper/example.py | 36 +++++++++++++ minesweeper/minesweeper_test.py | 91 +++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 minesweeper/example.py create mode 100644 minesweeper/minesweeper_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 1cadfb94899..9c4d086c4c7 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -15,6 +15,7 @@ phone-number allergies grade-school robot-name +minesweeper etl leap sum-of-multiples diff --git a/minesweeper/example.py b/minesweeper/example.py new file mode 100644 index 00000000000..27f1559e2cb --- /dev/null +++ b/minesweeper/example.py @@ -0,0 +1,36 @@ +def board(inp): + verify_board(inp) + rowlen = len(inp[0]) + collen = len(inp) + b = [list(r) for r in inp] + for i1 in range(collen): + for i2 in range(rowlen): + if b[i1][i2] != ' ': + continue + cnt = inp[i1-1][i2-1:i2+2].count('*') + \ + inp[i1][i2-1:i2+2].count('*') + \ + inp[i1+1][i2-1:i2+2].count('*') + if cnt == 0: + continue + b[i1][i2] = str(cnt) + return ["".join(r) for r in b] + +def verify_board(inp): + # Null board or a null row + if not inp or not all(r for r in inp): + raise ValueError("Invalid board") + # Rows with different lengths + rowlen = len(inp[0]) + collen = len(inp) + if not all(len(r)==rowlen for r in inp): + raise ValueError("Invalid board") + # Unknown character in board + cset = set() + for r in inp: + cset.update(r) + if cset - set('+- *|'): + raise ValueError("Invalid board") + # Borders not as expected + if any(inp[i1] != '+'+'-'*(rowlen-2)+'+' for i1 in [0,-1]) or \ + any(inp[i1][i2] != '|' for i1 in range(1,collen-1) for i2 in [0,-1]): + raise ValueError("Invalid board") \ No newline at end of file diff --git a/minesweeper/minesweeper_test.py b/minesweeper/minesweeper_test.py new file mode 100644 index 00000000000..241ecffbde4 --- /dev/null +++ b/minesweeper/minesweeper_test.py @@ -0,0 +1,91 @@ +try: + from minesweeper import board +except ImportError: + raise SystemExit('Could not find minesweeper.py. Does it exist?') + +import unittest + +class MinesweeperTest(unittest.TestCase): + def test_board1(self): + inp = ["+------+", "| * * |", "| * |", "| * |", "| * *|", + "| * * |", "| |", "+------+"] + out = ["+------+", "|1*22*1|", "|12*322|", "| 123*2|", "|112*4*|", + "|1*22*2|", "|111111|", "+------+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board2(self): + inp = ["+-----+", "| * * |", "| |", "| * |", "| * *|", + "| * * |", "+-----+"] + out = ["+-----+", "|1*2*1|", "|11322|", "| 12*2|", "|12*4*|", + "|1*3*2|", "+-----+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board3(self): + inp = ["+-----+", "| * * |", "+-----+"] + out = ["+-----+", "|1*2*1|", "+-----+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board4(self): + inp = ["+-+", "|*|", "| |", "|*|", "| |", "| |", "+-+"] + out = ["+-+", "|*|", "|2|", "|*|", "|1|", "| |", "+-+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board5(self): + inp = ["+-+", "|*|", "+-+"] + out = ["+-+", "|*|", "+-+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board6(self): + inp = ["+--+", "|**|", "|**|", "+--+"] + out = ["+--+", "|**|", "|**|", "+--+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board7(self): + inp = ["+--+", "|**|", "|**|", "+--+"] + out = ["+--+", "|**|", "|**|", "+--+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board8(self): + inp = ["+---+", "|***|", "|* *|", "|***|", "+---+"] + out = ["+---+", "|***|", "|*8*|", "|***|", "+---+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_board9(self): + inp = ["+-----+", "| |", "| * |", "| |", "| |", + "| * |", "+-----+"] + out = ["+-----+", "| 111|", "| 1*1|", "| 111|", "|111 |", + "|1*1 |", "+-----+"] + self.assertEqual(out, board(inp)) + + @unittest.skip("Not implemented yet") + def test_different_len(self): + inp = ["+-+", "| |", "|* |", "| |", "+-+"] + with self.assertRaises(ValueError) as context: + board(inp) + self.assertEqual(context.exception.message, 'Invalid board') + + @unittest.skip("Not implemented yet") + def test_faulty_border(self): + inp = ["+-----+", "* * |", "+-- --+"] + with self.assertRaises(ValueError) as context: + board(inp) + self.assertEqual(context.exception.message, 'Invalid board') + + @unittest.skip("Not implemented yet") + def test_invalid_char(self): + inp = ["+-----+", "|X * |", "+-----+"] + with self.assertRaises(ValueError) as context: + board(inp) + self.assertEqual(context.exception.message, 'Invalid board') + + +if __name__ == '__main__': + unittest.main() From 9e7b0980d9c55320d4a642d77a3c7d5e7ca21ea8 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Sat, 29 Mar 2014 12:59:34 -0300 Subject: [PATCH 14/29] New exercise: ocr-numbers --- EXERCISES.txt | 1 + ocr-numbers/example.py | 16 ++++++++++++ ocr-numbers/ocr_test.py | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 ocr-numbers/example.py create mode 100644 ocr-numbers/ocr_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 9c4d086c4c7..24275add07b 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -9,6 +9,7 @@ nucleotide-count series largest-series-product octal +ocr-numbers difference-of-squares point-mutations phone-number diff --git a/ocr-numbers/example.py b/ocr-numbers/example.py new file mode 100644 index 00000000000..009f3030f88 --- /dev/null +++ b/ocr-numbers/example.py @@ -0,0 +1,16 @@ +def number(g): + if not g or len(g) < 4 or any(len(r)!=len(g[0]) for r in g): + raise ValueError('Ill-formed grid') + if g == [" _ ","| |","|_|"," "]: + return '0' + elif g == [" "," |"," |"," "]: + return '1' + else: + return '?' + +def grid(n): + if n == '0': + return [" _ ","| |","|_|"," "] + elif n == '1': + return [" "," |"," |"," "] + raise ValueError('Unknown digit') \ No newline at end of file diff --git a/ocr-numbers/ocr_test.py b/ocr-numbers/ocr_test.py new file mode 100644 index 00000000000..6134d3358e1 --- /dev/null +++ b/ocr-numbers/ocr_test.py @@ -0,0 +1,56 @@ +try: + from ocr import number, grid +except ImportError: + raise SystemExit('Could not find ocr.py. Does it exist?') + +import unittest + +class OcrTest(unittest.TestCase): + def test_0(self): + self.assertEqual('0', number([" _ ","| |","|_|"," "])) + + @unittest.skip("Not implemented yet") + def test_1(self): + self.assertEqual('1', number([" "," |"," |"," "])) + + @unittest.skip("Not implemented yet") + def test_garbage(self): + self.assertEqual('?', number([" _ "," _|"," |"," "])) + + @unittest.skip("Not implemented yet") + def test_last_line_nonblank(self): + self.assertEqual('?', number([" "," |"," |","| |"])) + + @unittest.skip("Not implemented yet") + def test_unknown_char(self): + self.assertEqual('?', number([" - "," _|"," X|"," "])) + + @unittest.skip("Not implemented yet") + def test_too_short_row(self): + with self.assertRaises(ValueError) as context: + number([" "," _|"," |"," "]) + self.assertEqual(context.exception.message, 'Ill-formed grid') + + @unittest.skip("Not implemented yet") + def test_insufficient_rows(self): + with self.assertRaises(ValueError) as context: + number([" "," _|"," X|"]) + self.assertEqual(context.exception.message, 'Ill-formed grid') + + @unittest.skip("Not implemented yet") + def test_grid0(self): + self.assertEqual([" _ ","| |","|_|"," "], grid('0')) + + @unittest.skip("Not implemented yet") + def test_grid1(self): + self.assertEqual([" "," |"," |"," "], grid('1')) + + @unittest.skip("Not implemented yet") + def test_invalid_digit(self): + with self.assertRaises(ValueError) as context: + grid('2') + self.assertEqual(context.exception.message, 'Unknown digit') + + +if __name__ == '__main__': + unittest.main() From c182801211c0ddbb780ec84a270069e6223f6a8f Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Sun, 30 Mar 2014 11:38:57 -0300 Subject: [PATCH 15/29] New exercise: secret-handshake --- EXERCISES.txt | 1 + secret-handshake/example.py | 46 +++++++++++++++++++++++ secret-handshake/handshake_test.py | 60 ++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 secret-handshake/example.py create mode 100644 secret-handshake/handshake_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 24275add07b..2b581575d2c 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -26,6 +26,7 @@ gigasecond palindrome-products triangle scrabble-score +secret-handshake sieve nth-prime luhn diff --git a/secret-handshake/example.py b/secret-handshake/example.py new file mode 100644 index 00000000000..efb165c57d8 --- /dev/null +++ b/secret-handshake/example.py @@ -0,0 +1,46 @@ +gestures = ['wink','double blink','close your eyes','jump'] + +def handshake(s): + s = list(sanitize(s)) + s.reverse() + seq = [] + lim = len(s) if len(s) <= len(gestures) else len(gestures) + for i1 in range(lim): + if s[i1] == '1': + seq.append(gestures[i1]) + if len(s) == 5: + seq.reverse() + return seq + +def code(seq): + if not seq or set(seq)-set(gestures): + return '0' + s = find_subseq(seq) + if not s: + s = ['1'] + find_subseq(reversed(seq)) + return "".join(s) + +def sanitize(s): + if not(isinstance(s, int) or isinstance(s,str)): + raise TypeError('Unknown type') + if isinstance(s,int): + if s < 0: + return "" + s = bin(s)[2:] + elif set(s)-set(['0','1']): + return "" + if len(s) > 5: + raise ValueError('Binary string too long') + return "0"*(len(gestures)-len(s)) + s + +def find_subseq(seq): + idx = 0 + s = [] + for g in seq: + if g not in gestures[idx:]: + return [] + newidx = gestures.index(g,idx) + 1 + s.extend(['0']*(newidx-idx-1)+['1']) + idx = newidx + s.reverse() + return s \ No newline at end of file diff --git a/secret-handshake/handshake_test.py b/secret-handshake/handshake_test.py new file mode 100644 index 00000000000..48d35a01794 --- /dev/null +++ b/secret-handshake/handshake_test.py @@ -0,0 +1,60 @@ +from handshake import handshake, code + +import unittest + +class HandshakeTest(unittest.TestCase): + def test_shake_int(self): + self.assertEqual(['wink','jump'], handshake(9)) + + @unittest.skip("Not implemented yet") + def test_shake_bin1(self): + self.assertEqual(['close your eyes','double blink'], handshake('10110')) + + @unittest.skip("Not implemented yet") + def test_shake_bin2(self): + self.assertEqual(['wink','close your eyes'], handshake('101')) + + @unittest.skip("Not implemented yet") + def test_shake_negative_int(self): + self.assertEqual([], handshake(-9)) + + @unittest.skip("Not implemented yet") + def test_shake_bin_invalid(self): + self.assertEqual([], handshake('121')) + + @unittest.skip("Not implemented yet") + def test_unknown_action(self): + self.assertEqual('0', code(['wink','sneeze'])) + + @unittest.skip("Not implemented yet") + def test_code1(self): + self.assertEqual('1100', code(['close your eyes','jump'])) + + @unittest.skip("Not implemented yet") + def test_code2(self): + self.assertEqual('11', code(['wink','double blink'])) + + @unittest.skip("Not implemented yet") + def test_code3(self): + self.assertEqual('11010', code(['jump','double blink'])) + + @unittest.skip("Not implemented yet") + def test_composition1(self): + self.assertEqual('11011', code(handshake(27))) + + @unittest.skip("Not implemented yet") + def test_composition2(self): + self.assertEqual('1', code(handshake(1))) + + @unittest.skip("Not implemented yet") + def test_composition3(self): + self.assertEqual('111', code(handshake('111'))) + + @unittest.skip("Not implemented yet") + def test_composition4(self): + inp = ['wink','double blink','jump'] + self.assertEqual(inp, handshake(code(inp))) + + +if __name__ == '__main__': + unittest.main() From a6dcaa41bb439472549f3e028ceaebf4bca4a919 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Tue, 1 Apr 2014 17:57:32 -0300 Subject: [PATCH 16/29] New exercise: pascals-triangle --- EXERCISES.txt | 1 + pascals-triangle/example.py | 12 +++++++ pascals-triangle/pascals_triangle_test.py | 43 +++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 pascals-triangle/example.py create mode 100644 pascals-triangle/pascals_triangle_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 2b581575d2c..be7b5c7fe8e 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -13,6 +13,7 @@ ocr-numbers difference-of-squares point-mutations phone-number +pascals-triangle allergies grade-school robot-name diff --git a/pascals-triangle/example.py b/pascals-triangle/example.py new file mode 100644 index 00000000000..47c74842e2a --- /dev/null +++ b/pascals-triangle/example.py @@ -0,0 +1,12 @@ +def triangle(nth): + return [row(i) for i in xrange(nth+1)] + +def is_triangle(t): + new_t = triangle(len(t)-1) + return t == new_t + +def row(nth): + r = [1] + for i in xrange(1,nth+1): + r.append(r[-1]*(nth-i+1)/i) + return " ".join([str(i) for i in r]) \ No newline at end of file diff --git a/pascals-triangle/pascals_triangle_test.py b/pascals-triangle/pascals_triangle_test.py new file mode 100644 index 00000000000..035014b0545 --- /dev/null +++ b/pascals-triangle/pascals_triangle_test.py @@ -0,0 +1,43 @@ +from pascals_triangle import triangle, row, is_triangle + +import unittest + +class PascalsTriangleTest(unittest.TestCase): + def test_triangle1(self): + ans = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1'] + self.assertEqual(ans, triangle(4)) + + @unittest.skip("Not implemented yet") + def test_triangle2(self): + ans = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1', '1 5 10 10 5 1', + '1 6 15 20 15 6 1'] + self.assertEqual(ans, triangle(6)) + + @unittest.skip("Not implemented yet") + def test_is_triangle_true(self): + inp = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1', '1 5 10 10 5 1'] + self.assertEqual(True, is_triangle(inp)) + + @unittest.skip("Not implemented yet") + def test_is_triangle_false(self): + inp = ['1', '1 1', '1 2 1', '1 4 4 1'] + self.assertEqual(False, is_triangle(inp)) + + @unittest.skip("Not implemented yet") + def test_row1(self): + ans = '1' + self.assertEqual(ans, row(0)) + + @unittest.skip("Not implemented yet") + def test_row2(self): + ans = '1 2 1' + self.assertEqual(ans, row(2)) + + @unittest.skip("Not implemented yet") + def test_row3(self): + ans = '1 7 21 35 35 21 7 1' + self.assertEqual(ans, row(7)) + + +if __name__ == '__main__': + unittest.main() From 4547a835eeecf24f3bc2423993f5246c113b67bc Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Tue, 1 Apr 2014 23:49:52 -0300 Subject: [PATCH 17/29] New exercise: pythagorean triplet --- EXERCISES.txt | 1 + pythagorean-triplet/example.py | 72 ++++++++++++++ .../pythagorean_triplet_test.py | 93 +++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 pythagorean-triplet/example.py create mode 100644 pythagorean-triplet/pythagorean_triplet_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index be7b5c7fe8e..064cb5ac038 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -37,3 +37,4 @@ prime-factors raindrops atbash-cipher wordy +pythagorean-triplet diff --git a/pythagorean-triplet/example.py b/pythagorean-triplet/example.py new file mode 100644 index 00000000000..3910a4089c5 --- /dev/null +++ b/pythagorean-triplet/example.py @@ -0,0 +1,72 @@ +from itertools import product +from operator import mul +from math import sqrt + +def primitive_triplets(nbr): + if nbr % 4 != 0: + raise ValueError('Argument must be divisible by 4') + prime_factors,powers = factor(nbr/2) + args = [(1,prime_factors[i1]**powers[i1]) for i1 in range(len(powers))] + a = [reduce(mul, p) for p in product(*args)] + a.sort() + factors = [(m,n) for m,n in zip(reversed(a),a) if m>n] + ts = set() + for m,n in factors: + l = [nbr, m*m-n*n,m*m+n*n] + l.sort() + ts.update([tuple(l)]) + return ts + +def is_triplet(t): + t = list(t) + t.sort() + a,b,c = t + return c*c == a*a + b*b + +def triplets_in_range(m, n): + t = set() + for a in xrange(m,n+1): + for b in xrange(a+1,n+1): + c = int(sqrt(a*a + b*b)+0.5) + if c*c == a*a + b*b and c >= m and c <= n: + t.update([(a,b,c)]) + return t + +primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, + 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, + 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, + 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, + 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, + 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, + 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, + 941, 947, 953, 967, 971, 977, 983, 991, 997] + +def factor(n): + global primes + if n == 1: + return (1,),(0,) + factors = [] + powers = [] + idx = 0 + while n > 1: + prime = primes[idx] + idx += 1 + if n % prime != 0: + continue + factors.append(prime) + p = 0 + while n % prime == 0: + p += 1 + n /= prime + powers.append(p) + return factors,powers + +if __name__ == '__main__': + print primitive_triplets(4) + print primitive_triplets(84) + print primitive_triplets(288) + print triplets_in_range(50,100) \ No newline at end of file diff --git a/pythagorean-triplet/pythagorean_triplet_test.py b/pythagorean-triplet/pythagorean_triplet_test.py new file mode 100644 index 00000000000..5e09b9d0dc6 --- /dev/null +++ b/pythagorean-triplet/pythagorean_triplet_test.py @@ -0,0 +1,93 @@ +# +#============================================================================== +# The test cases below assume two functions are defined: +# +# - triplets_in_range(min, max) +# Compute all pythagorean triplets (a,b,c) with min <= a,b,c <= max +# +# - primitive_triplets(b) +# Find all primitive pythagorean triplets having b as one of their +# components +# +# Args: +# b - an integer divisible by 4 (see explanantion below) +# +# Note that in the latter function the components other than the argument can +# be quite large. +# +# A primitive pythagorean triplet has its 3 componentes coprime. So, (3,4,5) is +# a primitive pythagorean triplet since 3,4 and 5 don't have a common factor. +# On the other hand, (6,8,10), although a pythagorean triplet, is not primitive +# aince 2 divides all three components. +# +# A method for finding all primitive pythagorean triplet is given in wikipedia +# (http://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple). The +# triplet a=(m^2-n^2), b=2*m*n and c=(m^2+n^2), where m and n are coprime and +# m-n>0 is odd, generate a primitive triplet. Note that this implies that b has +# to be divisible by 4 and a and c are odd. Also note that we may have either +# a>b or b>a. +# +# The function primitive_triplets should then use the formula above with b set +# to its argument and find all possible pairs (m,n) such that m>n, m-n is odd, +# b=2*m*n and m and n are coprime. +# +#============================================================================== + +from pythagorean_triplet import primitive_triplets, triplets_in_range, is_triplet + +import unittest + +class PythagoreanTripletTest(unittest.TestCase): + def test_triplet1(self): + ans = set([(3,4,5)]) + self.assertEqual(ans, primitive_triplets(4)) + +# @unittest.skip("Not implemented yet") + def test_triplet2(self): + ans = set([(13, 84, 85), (84, 187, 205), (84, 437, 445), + (84, 1763, 1765)]) + self.assertEqual(ans, primitive_triplets(84)) + +# @unittest.skip("Not implemented yet") + def test_triplet3(self): + ans = set([(29, 420, 421), (341, 420, 541), (420, 851, 949), + (420, 1189, 1261), (420, 1739, 1789), (420, 4891, 4909), + (420, 11021, 11029), (420, 44099, 44101)]) + self.assertEqual(ans, primitive_triplets(420)) + +# @unittest.skip("Not implemented yet") + def test_triplet4(self): + ans = set([(175, 288, 337), (288, 20735, 20737)]) + self.assertEqual(ans, primitive_triplets(288)) + +# @unittest.skip("Not implemented yet") + def test_range1(self): + ans = set([(3,4,5),(6,8,10)]) + self.assertEqual(ans, triplets_in_range(1, 10)) + +# @unittest.skip("Not implemented yet") + def test_range2(self): + ans = set([(57,76,95),(60,63,87)]) + self.assertEqual(ans, triplets_in_range(56, 95)) + +# @unittest.skip("Not implemented yet") + def test_is_triplet1(self): + self.assertEqual(True, is_triplet((29,20,21))) + +# @unittest.skip("Not implemented yet") + def test_is_triplet2(self): + self.assertEqual(False, is_triplet((25,25,1225))) + +# @unittest.skip("Not implemented yet") + def test_is_triplet3(self): + self.assertEqual(True, is_triplet((924,43,925))) + +# @unittest.skip("Not implemented yet") + def test_odd_number(self): + with self.assertRaises(ValueError) as context: + primitive_triplets(5) + self.assertEqual(context.exception.message, 'Argument must be divisible by 4') + + +if __name__ == '__main__': + unittest.main() From b827705aa160623cdf4276b95dea0b82295b9f17 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Wed, 2 Apr 2014 18:11:17 +0200 Subject: [PATCH 18/29] Add meetup exercise --- EXERCISES.txt | 1 + meetup/example.py | 17 +++++++++++++++++ meetup/meetup_test.py | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 meetup/example.py create mode 100644 meetup/meetup_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 82394ea421d..9233de30922 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -22,6 +22,7 @@ space-age grains gigasecond palindrome-products +meetup triangle scrabble-score sieve diff --git a/meetup/example.py b/meetup/example.py new file mode 100644 index 00000000000..2abeb1d1308 --- /dev/null +++ b/meetup/example.py @@ -0,0 +1,17 @@ +from calendar import Calendar + + +def meetup_day(year, month, day_of_the_week, which): + candidates = [date + for date in Calendar().itermonthdates(year, month) + if date.month == month + if date.strftime('%A') == day_of_the_week] + return _choice(which)(candidates) + + +def _choice(which): + if which == 'teenth': + return lambda dates: next(d for d in dates if 13 <= d.day <= 19) + + ix = -1 if (which == 'last') else (int(which[0]) - 1) + return lambda dates: dates[ix] diff --git a/meetup/meetup_test.py b/meetup/meetup_test.py new file mode 100644 index 00000000000..54304b1a6eb --- /dev/null +++ b/meetup/meetup_test.py @@ -0,0 +1,41 @@ +from datetime import date +import unittest + +from meetup import meetup_day + + +class MeetupTest(unittest.TestCase): + def test_monteenth_of_may_2013(self): + self.assertEqual(date(2013, 5, 13), + meetup_day(2013, 5, 'Monday', 'teenth')) + + def test_saturteenth_of_february_2013(self): + self.assertEqual(date(2013, 2, 16), + meetup_day(2013, 2, 'Saturday', 'teenth')) + + def test_first_tuesday_of_may_2013(self): + self.assertEqual(date(2013, 5, 7), + meetup_day(2013, 5, 'Tuesday', '1st')) + + def test_second_monday_of_april_2013(self): + self.assertEqual(date(2013, 4, 8), + meetup_day(2013, 4, 'Monday', '2nd')) + + def test_third_thursday_of_september_2013(self): + self.assertEqual(date(2013, 9, 19), + meetup_day(2013, 9, 'Thursday', '3rd')) + + def test_fourth_sunday_of_march_2013(self): + self.assertEqual(date(2013, 3, 24), + meetup_day(2013, 3, 'Sunday', '4th')) + + def test_last_thursday_of_october_2013(self): + self.assertEqual(date(2013, 10, 31), + meetup_day(2013, 10, 'Thursday', 'last')) + + def test_last_wednesday_of_february_2012(self): + self.assertEqual(date(2012, 2, 29), + meetup_day(2012, 2, 'Wednesday', 'last')) + +if __name__ == '__main__': + unittest.main() From 3d1d0f19134553f5407b4e2f87b642320b1be081 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Wed, 2 Apr 2014 07:29:54 -0300 Subject: [PATCH 19/29] New exercise: saddle-points --- EXERCISES.txt | 1 + saddle-points/example.py | 10 ++++++++++ saddle-points/saddle_points_test.py | 27 +++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 saddle-points/example.py create mode 100644 saddle-points/saddle_points_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 756fb4e1f2f..a93fb8305fd 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -7,6 +7,7 @@ anagram beer-song nucleotide-count series +saddle-points largest-series-product octal ocr-numbers diff --git a/saddle-points/example.py b/saddle-points/example.py new file mode 100644 index 00000000000..11ee4266dbd --- /dev/null +++ b/saddle-points/example.py @@ -0,0 +1,10 @@ +def saddle_points(m): + if not m: + return set() + if any(len(r)!=len(m[0]) for r in m): + raise ValueError('irregular matrix') + mmax = [max(r) for r in m] + mmin = [min(c) for c in zip(*m)] + points = [(i,j) for i in range(len(m)) for j in range(len(m[0])) if mmax[i] == mmin[j]] + + return set(points) diff --git a/saddle-points/saddle_points_test.py b/saddle-points/saddle_points_test.py new file mode 100644 index 00000000000..3daa1ff761a --- /dev/null +++ b/saddle-points/saddle_points_test.py @@ -0,0 +1,27 @@ +from saddle_points import saddle_points + +import unittest + +class SaddlePointTest(unittest.TestCase): + def test_one_saddle(self): + inp = [[9,8,7],[5,3,2],[6,6,7]] + self.assertEqual(set([(1,0)]), saddle_points(inp)) + + def test_no_saddle(self): + self.assertEqual(set(), saddle_points([[2,1],[1,2]])) + + def test_mult_saddle(self): + inp = [[5,3,5,4],[6,4,7,3],[5,1,5,3]] + ans = set([(0,0),(0,2),(2,0),(2,2)]) + self.assertEqual(ans, saddle_points(inp)) + + def test_empty_matrix(self): + self.assertEqual(set(), saddle_points([])) + + def test_irregular_matrix(self): + with self.assertRaisesRegexp(ValueError, 'irregular matrix'): + saddle_points([[1,2,3],[2,3],[3,2,1]]) + + +if __name__ == '__main__': + unittest.main() From c97aa1346d3bc7aca8f774821f39cd690260c169 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Mon, 7 Apr 2014 15:49:24 -0300 Subject: [PATCH 20/29] New exercise: trinary --- EXERCISES.txt | 1 + trinary/example.py | 9 +++++++++ trinary/trinary_test.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 trinary/example.py create mode 100644 trinary/trinary_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index a93fb8305fd..9d9d83d9a0d 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -28,6 +28,7 @@ gigasecond palindrome-products meetup triangle +trinary scrabble-score secret-handshake sieve diff --git a/trinary/example.py b/trinary/example.py new file mode 100644 index 00000000000..a1a18e0324f --- /dev/null +++ b/trinary/example.py @@ -0,0 +1,9 @@ +def trinary(s): + if set(s) - set('012'): + return 0 + return reduce(lambda x,y:x*3 + int(y), s, 0) + +if __name__ == '__main__': + print trinary('102101') + print trinary('22222') + print trinary('10000') diff --git a/trinary/trinary_test.py b/trinary/trinary_test.py new file mode 100644 index 00000000000..204c166d7a1 --- /dev/null +++ b/trinary/trinary_test.py @@ -0,0 +1,29 @@ +from trinary import trinary + +import unittest + +class TrinaryTest(unittest.TestCase): + def test_valid_trinary1(self): + self.assertEqual(0, trinary('0')) + + def test_valid_trinary2(self): + self.assertEqual(1, trinary('1')) + + def test_valid_trinary3(self): + self.assertEqual(3, trinary('10')) + + def test_valid_trinary4(self): + self.assertEqual(307, trinary('102101')) + + def test_valid_trinary5(self): + self.assertEqual(242, trinary('22222')) + + def test_valid_trinary6(self): + self.assertEqual(81, trinary('10000')) + + def test_invalid_trinary(self): + self.assertEqual(0, trinary('13201')) + + +if __name__ == '__main__': + unittest.main() From 8e361b669d461c02c7b5ea5396a1451f39447cf0 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Mon, 7 Apr 2014 22:32:31 -0300 Subject: [PATCH 21/29] New exercise: hamming --- EXERCISES.txt | 1 + hamming/example.py | 2 ++ hamming/hamming_test.py | 42 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 hamming/example.py create mode 100644 hamming/hamming_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 9d9d83d9a0d..e8eac0641cb 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -41,3 +41,4 @@ raindrops atbash-cipher wordy pythagorean-triplet +hamming diff --git a/hamming/example.py b/hamming/example.py new file mode 100644 index 00000000000..20026498987 --- /dev/null +++ b/hamming/example.py @@ -0,0 +1,2 @@ +def hamming(s1,s2): + return sum(1 for a,b in map(None,s1,s2) if a != b) diff --git a/hamming/hamming_test.py b/hamming/hamming_test.py new file mode 100644 index 00000000000..00c3d191400 --- /dev/null +++ b/hamming/hamming_test.py @@ -0,0 +1,42 @@ +from hamming import hamming + +import unittest + +# If the sequences have different lengths, assume the shorter one is extended +# with nucleotides in such a way to guarantee the extra nucleotides are all +# different between the two strands. + +class hammingdecimalTest(unittest.TestCase): + def test_hamming_empty(self): + self.assertEqual(0, hamming('','')) + + def test_hamming_onenucleotide_same(self): + self.assertEqual(0, hamming('A','A')) + + def test_hamming_onenucleotide_different(self): + self.assertEqual(1, hamming('A','G')) + + def test_hamming_short1(self): + self.assertEqual(1, hamming('AT','CT')) + + def test_hamming_short2(self): + self.assertEqual(2, hamming('AG','CT')) + + def test_hamming_large(self): + self.assertEqual(4, hamming('GGATCG','CCTGCG')) + + def test_hamming_small(self): + self.assertEqual(1, hamming('GGACGA','GGTCGA')) + + def test_hamming_very_long(self): + self.assertEqual(9, hamming('GGACGGATTCTG','AGGACGGATTCT')) + + def test_hamming_different_length1(self): + self.assertEqual(4, hamming('AAGCTAC','ACGTT')) + + def test_hamming_different_length2(self): + self.assertEqual(5, hamming('AAGCTAC','ACGTTACGTC')) + + +if __name__ == '__main__': + unittest.main() From a4e50bb4a7386f61a7c8b172b526e79b6a3eb309 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Tue, 8 Apr 2014 00:17:34 -0300 Subject: [PATCH 22/29] New exercise: simple-cipher --- EXERCISES.txt | 1 + simple-cipher/example.py | 34 ++++++++++++++++++ simple-cipher/simple_cipher_test.py | 55 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 simple-cipher/example.py create mode 100644 simple-cipher/simple_cipher_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index e8eac0641cb..938463749ed 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -42,3 +42,4 @@ atbash-cipher wordy pythagorean-triplet hamming +simple-cipher diff --git a/simple-cipher/example.py b/simple-cipher/example.py new file mode 100644 index 00000000000..449331712be --- /dev/null +++ b/simple-cipher/example.py @@ -0,0 +1,34 @@ +from string import ascii_lowercase,punctuation,whitespace,digits +from time import time +import random + +class Cipher: + def __init__(self, k=None): + if k: + self.key = k.translate(None,punctuation+whitespace+digits).lower() + else: + random.seed(time()) + self.key = ''.join(random.choice(ascii_lowercase) for i in range(100)) + + def base_encode(self, s, shift): + xkey = self.key*(len(s)//len(self.key)+1) + return ''.join(shift(c,k) for c,k in zip(s,xkey)) + + def encode(self, s): + s = s.translate(None,punctuation+whitespace+digits).lower() + shift = lambda c,k: chr(((ord(c)+ord(k)-2*ord('a'))\ + % len(ascii_lowercase)) + ord('a')) + return self.base_encode(s, shift) + + def decode(self, s): + shift = lambda c,k: chr(((ord(c)-ord(k)+len(ascii_lowercase))\ + % len(ascii_lowercase)) + ord('a')) + return self.base_encode(s, shift) + +class Caesar(Cipher): + def __init__(self): + Cipher.__init__(self, 'd') + +if __name__ == '__main__': + print(Caesar().encode('venividivici')) + print(Caesar().encode('\'Twas the night before Christmas')) \ No newline at end of file diff --git a/simple-cipher/simple_cipher_test.py b/simple-cipher/simple_cipher_test.py new file mode 100644 index 00000000000..cb539b0e63a --- /dev/null +++ b/simple-cipher/simple_cipher_test.py @@ -0,0 +1,55 @@ +from cipher import Caesar, Cipher + +import unittest + +class CipherTest(unittest.TestCase): + def test_caesar_encode1(self): + self.assertEqual('lwlvdzhvrphsurjudpplqjlqsbwkrq', + Caesar().encode('itisawesomeprogramminginpython')) + + def test_caesar_encode2(self): + self.assertEqual('yhqlylglylfl', Caesar().encode('venividivici')) + + def test_caesar_encode3(self): + self.assertEqual('wzdvwkhqljkwehiruhfkulvwpdv', + Caesar().encode('\'Twas the night before Christmas')) + + def test_caesar_encode_with_numbers(self): + self.assertEqual('jr', Caesar().encode('1, 2, 3, Go!')) + + def test_caesar_decode(self): + self.assertEqual('venividivici', Caesar().decode('yhqlylglylfl')) + + def test_cipher_encode1(self): + c = Cipher('a') + self.assertEqual('itisawesomeprogramminginpython', + c.encode('itisawesomeprogramminginpython')) + + def test_cipher_encode2(self): + c = Cipher('aaaaaaaaaaaaaaaaaaaaaa') + self.assertEqual('itisawesomeprogramminginpython', + c.encode('itisawesomeprogramminginpython')) + + def test_cipher_encode3(self): + c = Cipher('dddddddddddddddddddddd') + self.assertEqual('yhqlylglylfl', c.encode('venividivici')) + + def test_cipher_encode4(self): + key = 'duxrceqyaimciuucnelkeoxjhdyduucpmrxmaivacmybmsdrzwqxvbxsygzsabdjmdjabeorttiwinfrpmpogvabiofqexnohrqu' + c = Cipher(key) + self.assertEqual('gccwkixcltycv', c.encode('diffiehellman')) + + def test_cipher_compositiion1(self): + key = 'duxrceqyaimciuucnelkeoxjhdyduucpmrxmaivacmybmsdrzwqxvbxsygzsabdjmdjabeorttiwinfrpmpogvabiofqexnohrqu' + plaintext = 'adaywithoutlaughterisadaywasted' + c = Cipher(key) + self.assertEqual(plaintext, c.decode(c.encode(plaintext))) + + def test_cipher_compositiion2(self): + plaintext = 'adaywithoutlaughterisadaywasted' + c = Cipher() + self.assertEqual(plaintext, c.decode(c.encode(plaintext))) + + +if __name__ == '__main__': + unittest.main() From dd624ca980a628a4666042fbbfd4d30f2746f92a Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Mon, 7 Apr 2014 23:38:09 -0300 Subject: [PATCH 23/29] New exercise: hexadecimal --- EXERCISES.txt | 1 + hexadecimal/example.py | 12 ++++++++++ hexadecimal/hexadecimal_test.py | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 hexadecimal/example.py create mode 100644 hexadecimal/hexadecimal_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 938463749ed..8ab901a75b3 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -43,3 +43,4 @@ wordy pythagorean-triplet hamming simple-cipher +hexadecimal diff --git a/hexadecimal/example.py b/hexadecimal/example.py new file mode 100644 index 00000000000..513c5e6dd09 --- /dev/null +++ b/hexadecimal/example.py @@ -0,0 +1,12 @@ +def hexa(s): + s = s.lower() + if set(s) - set('0123456789abcdef'): + raise ValueError('Invalid hexadecimal string') + l = [ord(c) - ord('a') + 10 if c in 'abcdef' else ord(c) - ord('0') + for c in s] + return reduce(lambda x,y:x*16 + y, l, 0) + +if __name__ == '__main__': + print hexa('19ACE') + print hexa('100') + print hexa('dead') \ No newline at end of file diff --git a/hexadecimal/hexadecimal_test.py b/hexadecimal/hexadecimal_test.py new file mode 100644 index 00000000000..08f13b1c1d2 --- /dev/null +++ b/hexadecimal/hexadecimal_test.py @@ -0,0 +1,42 @@ +# To avoid trivial solutions, try to solve this problem without the +# function int(s, base=16) + +from hexadecimal import hexa + +import unittest + +class HexadecimalTest(unittest.TestCase): + def test_valid_hexa1(self): + self.assertEqual(1, hexa('1')) + + def test_valid_hexa2(self): + self.assertEqual(12, hexa('c')) + + def test_valid_hexa3(self): + self.assertEqual(16, hexa('10')) + + def test_valid_hexa4(self): + self.assertEqual(175, hexa('af')) + + def test_valid_hexa5(self): + self.assertEqual(256, hexa('100')) + + def test_valid_hexa6(self): + self.assertEqual(105166, hexa('19ACE')) + + def test_valid_hexa7(self): + self.assertEqual(0, hexa('000000')) + + def test_valid_hexa8(self): + self.assertEqual(16776960, hexa('ffff00')) + + def test_valid_hexa9(self): + self.assertEqual(65520, hexa('00fff0')) + + def test_invalid_hexa(self): + with self.assertRaises(ValueError): + hexa('carrot') + + +if __name__ == '__main__': + unittest.main() From 9f47f55154ecab645331da7c73fee3f531cd5bb3 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Wed, 9 Apr 2014 14:20:52 -0300 Subject: [PATCH 24/29] New exercise: crypto-square --- EXERCISES.txt | 1 + crypto-square/crypto_square_test.py | 40 +++++++++++++++++++++++++++ crypto-square/example.py | 43 +++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 crypto-square/crypto_square_test.py create mode 100644 crypto-square/example.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 8ab901a75b3..cfb01c340e5 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -34,6 +34,7 @@ secret-handshake sieve nth-prime luhn +crypto-square roman-numerals binary prime-factors diff --git a/crypto-square/crypto_square_test.py b/crypto-square/crypto_square_test.py new file mode 100644 index 00000000000..91294ad5b4f --- /dev/null +++ b/crypto-square/crypto_square_test.py @@ -0,0 +1,40 @@ +from crypto_square import encode, decode + +import unittest + +class CryptoSquareTest(unittest.TestCase): + def test_empty_plain(self): + self.assertEqual('', encode('')) + + def test_perfect_square(self): + self.assertEqual('wliod drwe', encode('WorldWide')) + + def test_almost_perfect_square(self): + self.assertEqual('oasny selde', encode('One day less')) + + def test_punctuation(self): + msg = "1, 2, 3, Go! Go, for God's sake!" + ciph = '1gga2 ook3f degos ors' + self.assertEqual(ciph, encode(msg)) + + def test_long_string(self): + msg = "Be who you are and say what you feel, because those who mind "\ + "don't matter and those who matter don't mind." + ciph = 'betcw tttne ayahm htdwn ouoao ehdus mtsro sfeit edyae tnewo '\ + 'oyehd rhnuw lodao tahbs onmmr aeend ai' + self.assertEqual(ciph, encode(msg)) + + def test_decode(self): + ciph = 'woree iorhu ssmtp eefei aiafn ildjs ulenf eotse vdoor iecey '\ + 'nfima trott tenyu hhytd' + msg = 'wheneveryoufindyourselfonthesideofthemajorityitistimetopausea'\ + 'ndreflect' + self.assertEqual(msg, decode(ciph)) + + def test_encode_decode(self): + msg = 'tensioniswhoyouthinkyoushouldberelaxationiswhoyouare' + self.assertEqual(msg, decode(encode(msg))) + + +if __name__ == '__main__': + unittest.main() diff --git a/crypto-square/example.py b/crypto-square/example.py new file mode 100644 index 00000000000..768c08e8419 --- /dev/null +++ b/crypto-square/example.py @@ -0,0 +1,43 @@ +import math +from string import punctuation,whitespace + +def encode(msg): + msg = msg.strip().translate(None,punctuation+whitespace).lower() + sqrsz = int(math.sqrt(len(msg))) + if sqrsz*sqrsz < len(msg): + sqrsz += 1 + + cols = [msg[i1::sqrsz] for i1 in range(sqrsz)] + cols_str = ''.join(cols) + return ' '.join(cols_str[i1:i1+5] for i1 in range(0,len(cols_str),5)) + +def decode(ciph): + ciph = ciph.strip().translate(None,punctuation+whitespace).lower() + sqrsz = int(math.sqrt(len(ciph))) + if sqrsz*sqrsz < len(ciph): + sqrsz += 1 + colsz, nbr_full_cols = divmod(len(ciph),sqrsz) + + # The matrix produced by the plaintext is in general irregular, and the + # last row is usually shorter than the others. Extract this row first + full_cols_str = ciph[:(colsz+1)*nbr_full_cols] + partial_cols_str = ciph[(colsz+1)*nbr_full_cols:] + last_row = full_cols_str[colsz::colsz+1] + + # Compute the string of all concatenated columns of the colsz X sqrsz + # matrix consisting of the first colsz rows of the plaintext (irregular) + # matrix + trimmed_full_cols = [full_cols_str[i1:i1+colsz] + for i1 in range(0,len(full_cols_str),colsz+1)] + partial_cols = [partial_cols_str[i1:i1+colsz] + for i1 in range(0,len(partial_cols_str),colsz)] + uniform_cols_str = ''.join(trimmed_full_cols + partial_cols) + + other_rows = [uniform_cols_str[i1::colsz] for i1 in range(colsz)] + return ''.join(other_rows+[last_row]) + +if __name__ == '__main__': + msg = 'ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots' + ciph = 'imtgd vsfea rwerm ayoog oanou uiont nnlvt wttdd esaoh ghnss eoau' + print(encode(msg)) + print(decode(ciph)) From 917831a293a2107aef25224e0f1210f8b66d683a Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Thu, 10 Apr 2014 20:59:17 -0300 Subject: [PATCH 25/29] New exercise: strain --- EXERCISES.txt | 1 + strain/example.py | 14 +++++++++++++ strain/strain_test.py | 46 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 strain/example.py create mode 100644 strain/strain_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index cfb01c340e5..87847d025cc 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -23,6 +23,7 @@ etl leap sum-of-multiples space-age +strain grains gigasecond palindrome-products diff --git a/strain/example.py b/strain/example.py new file mode 100644 index 00000000000..6069fc751fd --- /dev/null +++ b/strain/example.py @@ -0,0 +1,14 @@ +def keep(seq, pred): + res = [] + for el in seq: + if pred(el): + res.append(el) + return res + + +def discard(seq, pred): + res = [] + for el in seq: + if not pred(el): + res.append(el) + return res diff --git a/strain/strain_test.py b/strain/strain_test.py new file mode 100644 index 00000000000..1ba9326b30d --- /dev/null +++ b/strain/strain_test.py @@ -0,0 +1,46 @@ +from strain import keep, discard + +import unittest + + +class StrainTest(unittest.TestCase): + def test_empty_sequence(self): + self.assertEqual([], keep([], lambda x: x % 2 == 0)) + + def test_empty_keep(self): + inp = [2, 4, 6, 8, 10] + out = [] + self.assertEqual(out, keep(inp, lambda x: x % 2 == 1)) + + def test_empty_discard(self): + inp = [2, 4, 6, 8, 10] + out = [] + self.assertEqual(out, discard(inp, lambda x: x % 2 == 0)) + + def test_keep_everything(self): + inp = [2, 4, 6, 8, 10] + self.assertEqual(inp, keep(inp, lambda x: x % 2 == 0)) + + def test_discard_endswith(self): + inp = ['dough', 'cash', 'plough', 'though', 'through', 'enough'] + out = ['cash'] + fn = lambda x: str.endswith(x, 'ough') + self.assertEqual(out, discard(inp, fn)) + + def test_keep_z(self): + inp = ['zebra', 'arizona', 'apple', 'google', 'mozilla'] + out = ['zebra', 'arizona', 'mozilla'] + self.assertEqual(out, keep(inp, lambda x: 'z' in x)) + + def test_keep_discard(self): + inp = ['1,2,3', 'one', 'almost!', 'love'] + self.assertEqual([], discard(keep(inp, str.isalpha), str.isalpha)) + + def test_keep_plus_discard(self): + inp = ['1,2,3', 'one', 'almost!', 'love'] + out = ['one', 'love', '1,2,3', 'almost!'] + self.assertEqual(out, keep(inp, str.isalpha)+discard(inp, str.isalpha)) + + +if __name__ == '__main__': + unittest.main() From 6321dd093e4f4f7acbe012e943e4a9e635c87fa9 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Thu, 10 Apr 2014 18:44:28 -0300 Subject: [PATCH 26/29] New exercise: accumulate --- EXERCISES.txt | 1 + accumulate/accumulate_test.py | 38 +++++++++++++++++++++++++++++++++++ accumulate/example.py | 8 ++++++++ 3 files changed, 47 insertions(+) create mode 100644 accumulate/accumulate_test.py create mode 100644 accumulate/example.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 87847d025cc..e451b7839ad 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -3,6 +3,7 @@ rna-transcription matrix word-count twelve-days +accumulate anagram beer-song nucleotide-count diff --git a/accumulate/accumulate_test.py b/accumulate/accumulate_test.py new file mode 100644 index 00000000000..9edc6fca547 --- /dev/null +++ b/accumulate/accumulate_test.py @@ -0,0 +1,38 @@ +from accumulate import accumulate + +import unittest + + +class AccumulateTest(unittest.TestCase): + def test_empty_sequence(self): + self.assertEqual([], accumulate([], lambda x: x/2)) + + def test_pow(self): + self.assertEqual([1, 4, 9, 16, 25], accumulate([1, 2, 3, 4, 5], + lambda x: x*x)) + + def test_divmod(self): + inp = [10, 17, 23] + out = [(1, 3), (2, 3), (3, 2)] + self.assertEqual(out, accumulate(inp, lambda x: divmod(x, 7))) + + def test_composition(self): + inp = [10, 17, 23] + fn1 = lambda x: divmod(x, 7) + fn2 = lambda x: 7*x[0]+x[1] + self.assertEqual(inp, accumulate(accumulate(inp, fn1), fn2)) + + def test_capitalize(self): + inp = ['hello', 'world'] + out = ['HELLO', 'WORLD'] + self.assertEqual(out, accumulate(inp, str.upper)) + + def test_recursive(self): + inp = list('abc') + out = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']] + fn = lambda x: accumulate(list('123'), lambda y: x+y) + self.assertEqual(out, accumulate(inp, fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/accumulate/example.py b/accumulate/example.py new file mode 100644 index 00000000000..ab9ca8054e8 --- /dev/null +++ b/accumulate/example.py @@ -0,0 +1,8 @@ +# [op(x) for x in seq] would be nice but trivial + + +def accumulate(seq,op): + res = [] + for el in seq: + res.append(op(el)) + return res From 39a6d408c561a4bc171c83f9a1f324deabb715e8 Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Thu, 10 Apr 2014 22:10:22 -0300 Subject: [PATCH 27/29] New exercise: proverb --- EXERCISES.txt | 1 + proverb/example.py | 7 ++++++ proverb/proverb_test.py | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 proverb/example.py create mode 100644 proverb/proverb_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index e451b7839ad..ea50444cf4d 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -14,6 +14,7 @@ octal ocr-numbers difference-of-squares point-mutations +proverb phone-number pascals-triangle allergies diff --git a/proverb/example.py b/proverb/example.py new file mode 100644 index 00000000000..dba9c9df952 --- /dev/null +++ b/proverb/example.py @@ -0,0 +1,7 @@ +def proverb(itens, qualifier=''): + phrases = ['For want of a {0} the {1} was lost.'.format(el1, el2) + for el1, el2 in zip(itens, itens[1:])] + qualifier += ' ' if qualifier else '' + phrases.append('And all for the want of a {0}{1}.'.format(qualifier, + itens[0])) + return '\n'.join(phrases) diff --git a/proverb/proverb_test.py b/proverb/proverb_test.py new file mode 100644 index 00000000000..26ac938187e --- /dev/null +++ b/proverb/proverb_test.py @@ -0,0 +1,55 @@ +from proverb import proverb + +import unittest + + +class ProverbTest(unittest.TestCase): + def test_a_single_consequence(self): + expected = 'For want of a nail the shoe was lost.\n'\ + 'And all for the want of a nail.' + self.assertEqual(expected, proverb(['nail', 'shoe'])) + + def test_short_list(self): + expected = 'For want of a nail the shoe was lost.\n'\ + 'For want of a shoe the horse was lost.\n'\ + 'And all for the want of a nail.' + self.assertEqual(expected, proverb(['nail', 'shoe', 'horse'])) + + def test_long_list(self): + expected = 'For want of a nail the shoe was lost.\n'\ + 'For want of a shoe the horse was lost.\n'\ + 'For want of a horse the rider was lost.\n'\ + 'And all for the want of a nail.' + self.assertEqual(expected, proverb(['nail', 'shoe', 'horse', 'rider'])) + + def test_new_itens(self): + expected = 'For want of a key the value was lost.\n'\ + 'And all for the want of a key.' + self.assertEqual(expected, proverb(['key', 'value'])) + + def test_whole_proverb(self): + expected = 'For want of a nail the shoe was lost.\n'\ + 'For want of a shoe the horse was lost.\n'\ + 'For want of a horse the rider was lost.\n'\ + 'For want of a rider the message was lost.\n'\ + 'For want of a message the battle was lost.\n'\ + 'For want of a battle the kingdom was lost.\n'\ + 'And all for the want of a nail.' + self.assertEqual(expected, proverb(['nail', 'shoe', 'horse', 'rider', + 'message', 'battle', 'kingdom'])) + + def test_qualifier(self): + expected = 'For want of a nail the shoe was lost.\n'\ + 'For want of a shoe the horse was lost.\n'\ + 'For want of a horse the rider was lost.\n'\ + 'For want of a rider the message was lost.\n'\ + 'For want of a message the battle was lost.\n'\ + 'For want of a battle the kingdom was lost.\n'\ + 'And all for the want of a horseshoe nail.' + self.assertEqual(expected, proverb(['nail', 'shoe', 'horse', 'rider', + 'message', 'battle', 'kingdom'], + qualifier='horseshoe')) + + +if __name__ == '__main__': + unittest.main() From 482d96b668a2c914b25d57a83c0d983a11d5ca78 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Fri, 11 Apr 2014 04:17:34 +0200 Subject: [PATCH 28/29] Add kindergarten-garden exercise --- EXERCISES.txt | 1 + kindergarten-garden/example.py | 18 +++++++++ .../kindergarten_garden_test.py | 37 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 kindergarten-garden/example.py create mode 100644 kindergarten-garden/kindergarten_garden_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index e451b7839ad..e5f7b9ffd07 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -28,6 +28,7 @@ strain grains gigasecond palindrome-products +kindergarten-garden meetup triangle trinary diff --git a/kindergarten-garden/example.py b/kindergarten-garden/example.py new file mode 100644 index 00000000000..0544c440b1c --- /dev/null +++ b/kindergarten-garden/example.py @@ -0,0 +1,18 @@ +class Garden(object): + + __plant_names = {"C": "Clover", "G": "Grass", + "R": "Radishes", "V": "Violets"} + + def __init__(self, diagram, + students=("Alice Bob Charlie David " + "Eve Fred Ginny Harriet " + "Ileana Joseph Kincaid Larry").split()): + self.plant_rows = diagram.split() + self.students = sorted(students) + + def plants(self, student): + slot_start = self.students.index(student) * 2 + slot = slice(slot_start, slot_start + 2) + return [self.__plant_names[abbrev] + for abbrev in (self.plant_rows[0][slot] + + self.plant_rows[1][slot])] diff --git a/kindergarten-garden/kindergarten_garden_test.py b/kindergarten-garden/kindergarten_garden_test.py new file mode 100644 index 00000000000..04011a0a1b4 --- /dev/null +++ b/kindergarten-garden/kindergarten_garden_test.py @@ -0,0 +1,37 @@ +import unittest +from garden import Garden + + +class KindergartenGardenTests(unittest.TestCase): + + def test_alices_garden(self): + self.assertEqual("Radishes Clover Grass Grass".split(), + Garden("RC\nGG").plants("Alice")) + + def test_bob_and_charlies_gardens(self): + garden = Garden("VVCCGG\nVVCCGG") + self.assertEqual(["Clover"] * 4, garden.plants("Bob")) + self.assertEqual(["Grass"] * 4, garden.plants("Charlie")) + + def test_full_garden(self): + garden = Garden("VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV") + self.assertEqual("Violets Radishes Violets Radishes".split(), + garden.plants("Alice")) + self.assertEqual("Clover Grass Clover Clover".split(), + garden.plants("Bob")) + self.assertEqual("Grass Clover Clover Grass".split(), + garden.plants("Kincaid")) + self.assertEqual("Grass Violets Clover Violets".split(), + garden.plants("Larry")) + + def test_disordered_test(self): + garden = Garden("VCRRGVRG\nRVGCCGCV", + students="Samantha Patricia Xander Roger".split()) + self.assertEqual("Violets Clover Radishes Violets".split(), + garden.plants("Patricia")) + self.assertEqual("Radishes Grass Clover Violets".split(), + garden.plants("Xander")) + + +if __name__ == '__main__': + unittest.main() From 5b3572670b6531cfa080d745bd71d41ac614deda Mon Sep 17 00:00:00 2001 From: Hermano Cabral Date: Wed, 9 Apr 2014 07:34:19 -0300 Subject: [PATCH 29/29] New exercise: sublist --- EXERCISES.txt | 1 + sublist/example.py | 33 +++++++++++++++++ sublist/sublist_test.py | 79 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 sublist/example.py create mode 100644 sublist/sublist_test.py diff --git a/EXERCISES.txt b/EXERCISES.txt index 2d570188343..4bd8150f1e6 100644 --- a/EXERCISES.txt +++ b/EXERCISES.txt @@ -22,6 +22,7 @@ grade-school robot-name minesweeper etl +sublist leap sum-of-multiples space-age diff --git a/sublist/example.py b/sublist/example.py new file mode 100644 index 00000000000..63470e27c0a --- /dev/null +++ b/sublist/example.py @@ -0,0 +1,33 @@ +SUBLIST = 0 +SUPERLIST = 1 +EQUAL = 2 +UNEQUAL = 3 + + +def check_lists(l1, l2): + if l1 == l2: + return EQUAL + if l1 == []: + return SUBLIST + if l2 == []: + return SUPERLIST + if is_sublist(l1, l2): + return SUBLIST + if is_sublist(l2, l1): + return SUPERLIST + return UNEQUAL + + +def is_sublist(l1, l2): + if len(l1) > len(l2): + return False + idx = -1 + while 1: + try: + idx = l2.index(l1[0], idx+1) + except ValueError: + return False + if len(l1) > len(l2) - idx: + return False + if all(el1 == el2 for el1, el2 in zip(l1, l2[idx:])): + return True diff --git a/sublist/sublist_test.py b/sublist/sublist_test.py new file mode 100644 index 00000000000..51d4cf3b01b --- /dev/null +++ b/sublist/sublist_test.py @@ -0,0 +1,79 @@ +from sublist import check_lists, SUBLIST, SUPERLIST, EQUAL, UNEQUAL + +import unittest + + +class SublistTest(unittest.TestCase): + def test_empty_lists(self): + self.assertEqual(EQUAL, check_lists([], [])) + + def test_empty_list_within(self): + self.assertEqual(SUBLIST, check_lists([], [1, 2, 3])) + + def test_within_empty_list(self): + self.assertEqual(SUPERLIST, check_lists([1], [])) + + def test_equal_lists(self): + l1 = [0, 1, 2] + l2 = [0, 1, 2] + self.assertEqual(EQUAL, check_lists(l1, l2)) + + def test_different_lists(self): + l1 = list(range(1000000)) + l2 = list(range(1, 1000001)) + self.assertEqual(UNEQUAL, check_lists(l1, l2)) + + def test_false_start(self): + l1 = [1, 2, 5] + l2 = [0, 1, 2, 3, 1, 2, 5, 6] + self.assertEqual(SUBLIST, check_lists(l1, l2)) + + def test_consecutive(self): + l1 = [1, 1, 2] + l2 = [0, 1, 1, 1, 2, 1, 2] + self.assertEqual(SUBLIST, check_lists(l1, l2)) + + def test_sublist_at_start(self): + l1 = [0, 1, 2] + l2 = [0, 1, 2, 3, 4, 5] + self.assertEqual(SUBLIST, check_lists(l1, l2)) + + def test_sublist_in_middle(self): + l1 = [2, 3, 4] + l2 = [0, 1, 2, 3, 4, 5] + self.assertEqual(SUBLIST, check_lists(l1, l2)) + + def test_sublist_at_end(self): + l1 = [3, 4, 5] + l2 = [0, 1, 2, 3, 4, 5] + self.assertEqual(SUBLIST, check_lists(l1, l2)) + + def test_at_start_of_superlist(self): + l1 = [0, 1, 2, 3, 4, 5] + l2 = [0, 1, 2] + self.assertEqual(SUPERLIST, check_lists(l1, l2)) + + def test_in_middle_of_superlist(self): + l1 = [0, 1, 2, 3, 4, 5] + l2 = [2, 3] + self.assertEqual(SUPERLIST, check_lists(l1, l2)) + + def test_at_end_of_superlist(self): + l1 = [0, 1, 2, 3, 4, 5] + l2 = [3, 4, 5] + self.assertEqual(SUPERLIST, check_lists(l1, l2)) + + def test_large_lists(self): + l1 = list(range(1000))*1000 + list(range(1000, 1100)) + l2 = list(range(900, 1050)) + self.assertEqual(SUPERLIST, check_lists(l1, l2)) + + def test_spread_sublist(self): + multiples_of_3 = list(range(3, 200, 3)) + multiples_of_15 = list(range(3, 200, 15)) + self.assertEqual(UNEQUAL, + check_lists(multiples_of_15, multiples_of_3)) + + +if __name__ == '__main__': + unittest.main()