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)