diff --git a/.gitignore b/.gitignore
index 992a27a3655d7bf345eb414cab412c0e3183ffb8..cd4671cc426262b4805a15c8dbc6ca97b9217b44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,4 @@
 *.pyo
 
 .idea
-.buildozer
 bin
diff --git a/least_suffix.py b/least_suffix.py
new file mode 100644
index 0000000000000000000000000000000000000000..7edb4965bf550e9d5aa73c29206c598ce892ec50
--- /dev/null
+++ b/least_suffix.py
@@ -0,0 +1,7 @@
+def least_suffix_helper(strings):
+    return ''.join(strings)  # Stub
+
+
+def least_suffix(strings):
+    result, _ = least_suffix_helper(strings)
+    return result
diff --git a/nim.py b/nim.py
index d4fcc9feb20f335dd60af23ffc648d3e54534560..2c3864880b93a50e53e95ec0ddee3c7696bf0b3c 100644
--- a/nim.py
+++ b/nim.py
@@ -11,6 +11,7 @@ class Evaluation(Enum):
 def convert_to_single_heap_using_builtin(heap_a, heap_b):
     """
     Convert a pair of Nim heap sizes to the size of an equivalent single heap.
+
     Python happens to have an operator (^) that works exactly as we need it to.
     """
     return heap_a ^ heap_b
@@ -19,64 +20,28 @@ def convert_to_single_heap_using_builtin(heap_a, heap_b):
 def convert_to_single_heap_recursively(heap_a, heap_b):
     """
     Convert a pair of Nim heap sizes to the size of an equivalent single heap.
-    This time, use recursion.
 
-    >>> convert_to_single_heap_recursively(0, 0)
-    0
-    >>> convert_to_single_heap_recursively(5, 0)
-    5
-    >>> convert_to_single_heap_recursively(0, 5)
-    5
-    >>> convert_to_single_heap_recursively(5, 6)
-    3
-    >>> convert_to_single_heap_recursively(9, 5)
-    12
-    >>> convert_to_single_heap_recursively(21, 10)
-    31
-    >>> convert_to_single_heap_recursively(21, 11)
-    30
+    This time, use recursion.
     """
     return 0  # Stub
 
 
 def evaluate(heap_sizes):
     """
-    Evaluate a Nim position given as a list of heap sizes, returning
-    Evaluation.LOSS if the player who just moved will lose under perfect play,
-    Evaluation.WIN if the player who just moved will win under perfect play.
-
-    >>> evaluate([])
-    <Evaluation.WIN: 'WIN'>
-    >>> evaluate([0])
-    <Evaluation.WIN: 'WIN'>
-    >>> evaluate([1])
-    <Evaluation.LOSS: 'LOSS'>
-    >>> evaluate([0, 1])
-    <Evaluation.LOSS: 'LOSS'>
-    >>> evaluate([1, 1])
-    <Evaluation.WIN: 'WIN'>
-    >>> evaluate([1, 2, 2])
-    <Evaluation.LOSS: 'LOSS'>
-    >>> evaluate([3, 2, 1])
-    <Evaluation.WIN: 'WIN'>
-    >>> evaluate([9, 12, 3, 6])
-    <Evaluation.WIN: 'WIN'>
-    >>> evaluate([9, 12, 3, 7])
-    <Evaluation.LOSS: 'LOSS'>
+    Evaluate a Nim position given as a list of heap sizes, returning:
+      Evaluation.LOSS if the player who just moved will lose under perfect play or
+      Evaluation.WIN if the player who just moved will win under perfect play.
     """
     if len(heap_sizes) > 1:
-        single_heap = convert_to_single_heap_using_builtin(heap_sizes[0],
-                                                           heap_sizes[1])
+        single_heap = convert_to_single_heap_using_builtin(heap_sizes[0], heap_sizes[1])
         return evaluate([single_heap] + heap_sizes[2:])
     else:
-        return Evaluation.WIN if len(heap_sizes) == 0 or heap_sizes[0] == 0 \
-            else Evaluation.LOSS
+        return Evaluation.WIN if len(heap_sizes) == 0 or heap_sizes[0] == 0 else Evaluation.LOSS
 
 
 def make_computer_move(position):
     """
-    Return a Nim position after the computer has made a move from the position
-    given.
+    Return a Nim position after the computer has made a move from the position given.
     """
     for i, heap_size in enumerate(position):
         next_position = copy(position)
@@ -88,13 +53,26 @@ def make_computer_move(position):
     return next_position
 
 
+def ask_for_number(prompt, predicate):
+    """
+    Prompt the user to enter an integer satisfying predicate, repeating the prompt if they do not enter a valid value.
+    """
+    while True:
+        try:
+            result = int(input(prompt))
+            if predicate(result):
+                return result
+        except ValueError:
+            pass
+
+
 def main():
     """
-    A simple command-line Nim game with no error handling.
+    A simple command-line Nim game.
     """
     position = [randrange(1, 10) for _ in range(randrange(3, 7))]
     while True:
-        print('Heaps: {position}'.format(position=position))
+        print(f'Heaps: {position}')
         if sum(position) == 0:
             print('Human Wins!')
             print()
@@ -102,13 +80,15 @@ def main():
         print('Computer moves...')
         print()
         position = make_computer_move(position)
-        print('Heaps: {position}'.format(position=position))
+        print(f'Heaps: {position}')
         if sum(position) == 0:
             print('Computer Wins!')
             print()
             return
-        index = int(input('Index at which to take stones? '))
-        count = int(input('Number of stones to take? '))
+        index = ask_for_number('Index at which to take stones? ',
+                               lambda value: 0 <= value < len(position) and position[value] > 0)
+        count = ask_for_number('Number of stones to take? ',
+                               lambda value: 0 < value <= position[index])
         print()
         position[index] -= count
 
diff --git a/palindrome.py b/palindrome.py
new file mode 100644
index 0000000000000000000000000000000000000000..81be78390b0dee01f5c05dc8ad8679ccb609e521
--- /dev/null
+++ b/palindrome.py
@@ -0,0 +1,11 @@
+def is_palindrome(string):
+    return False  # Stub
+
+
+def main():
+    string = input('Enter some text: ')
+    print(f'"{string}" {"is" if is_palindrome(string) else "is not"} a palindrome.')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/test_nim_evaluator.py b/test_nim_evaluator.py
new file mode 100644
index 0000000000000000000000000000000000000000..79bfe962e5c5c41f47a9419f5e5be54568a37ad0
--- /dev/null
+++ b/test_nim_evaluator.py
@@ -0,0 +1,34 @@
+from unittest import TestCase
+from nim import evaluate, Evaluation
+
+
+class TestNimEvaluator(TestCase):
+    def test_no_heaps(self):
+        self.assertEqual(evaluate([]), Evaluation.WIN)
+
+    def test_one_empty_heap(self):
+        self.assertEqual(evaluate([0]), Evaluation.WIN)
+
+    def test_multiple_empty_heaps(self):
+        self.assertEqual(evaluate([0, 0]), Evaluation.WIN)
+
+    def test_one_nonempty_heap(self):
+        self.assertEqual(evaluate([1]), Evaluation.LOSS)
+
+    def test_one_nonempty_heap_with_other_empty_heaps(self):
+        self.assertEqual(evaluate([0, 1]), Evaluation.LOSS)
+
+    def test_two_equal_heaps(self):
+        self.assertEqual(evaluate([1, 1]), Evaluation.WIN)
+
+    def test_pairs_of_equal_heaps_cancel(self):
+        self.assertEqual(evaluate([1, 2, 2]), Evaluation.WIN)
+
+    def test_three_distinct_heaps_that_cancel(self):
+        self.assertEqual(evaluate([3, 2, 1]), Evaluation.WIN)
+
+    def test_four_distinct_heaps_that_cancel(self):
+        self.assertEqual(evaluate([9, 12, 3, 6]), Evaluation.WIN)
+
+    def test_distinct_heaps_that_do_not_cancel(self):
+        self.assertEqual(evaluate([9, 12, 3, 7]), Evaluation.LOSS)
diff --git a/test_recursive_nim_simpifier.py b/test_recursive_nim_simpifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..19ace491b1bff3e5da3419b0c1dfd0b44b720044
--- /dev/null
+++ b/test_recursive_nim_simpifier.py
@@ -0,0 +1,25 @@
+from unittest import TestCase
+from nim import convert_to_single_heap_recursively
+
+
+class TestRecursiveNimSimplifier(TestCase):
+    def test_two_empty_heaps(self):
+        self.assertEqual(convert_to_single_heap_recursively(0, 0), 0)
+
+    def test_empty_left_heap(self):
+        self.assertEqual(convert_to_single_heap_recursively(0, 5), 5)
+
+    def test_empty_right_heap(self):
+        self.assertEqual(convert_to_single_heap_recursively(5, 0), 5)
+
+    def test_all_bit_pairs(self):
+        self.assertEqual(convert_to_single_heap_recursively(3, 5), 6)
+
+    def test_different_bit_lengths(self):
+        self.assertEqual(convert_to_single_heap_recursively(9, 5), 12)
+
+    def test_complements(self):
+        self.assertEqual(convert_to_single_heap_recursively(21, 10), 31)
+
+    def test_near_complements(self):
+        self.assertEqual(convert_to_single_heap_recursively(21, 11), 30)