Skip to content
Snippets Groups Projects
Commit 8aa933af authored by Brady James Garvin's avatar Brady James Garvin
Browse files

Revised lab for 2019.

parent 5ffc5f99
Branches
No related tags found
No related merge requests found
...@@ -2,5 +2,4 @@ ...@@ -2,5 +2,4 @@
*.pyo *.pyo
.idea .idea
.buildozer
bin bin
def least_suffix_helper(strings):
return ''.join(strings) # Stub
def least_suffix(strings):
result, _ = least_suffix_helper(strings)
return result
...@@ -11,6 +11,7 @@ class Evaluation(Enum): ...@@ -11,6 +11,7 @@ class Evaluation(Enum):
def convert_to_single_heap_using_builtin(heap_a, heap_b): 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. 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. Python happens to have an operator (^) that works exactly as we need it to.
""" """
return heap_a ^ heap_b return heap_a ^ heap_b
...@@ -19,64 +20,28 @@ def convert_to_single_heap_using_builtin(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): 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. 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) This time, use recursion.
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
""" """
return 0 # Stub return 0 # Stub
def evaluate(heap_sizes): def evaluate(heap_sizes):
""" """
Evaluate a Nim position given as a list of heap sizes, returning 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.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. 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'>
""" """
if len(heap_sizes) > 1: if len(heap_sizes) > 1:
single_heap = convert_to_single_heap_using_builtin(heap_sizes[0], single_heap = convert_to_single_heap_using_builtin(heap_sizes[0], heap_sizes[1])
heap_sizes[1])
return evaluate([single_heap] + heap_sizes[2:]) return evaluate([single_heap] + heap_sizes[2:])
else: else:
return Evaluation.WIN if len(heap_sizes) == 0 or heap_sizes[0] == 0 \ return Evaluation.WIN if len(heap_sizes) == 0 or heap_sizes[0] == 0 else Evaluation.LOSS
else Evaluation.LOSS
def make_computer_move(position): def make_computer_move(position):
""" """
Return a Nim position after the computer has made a move from the position Return a Nim position after the computer has made a move from the position given.
given.
""" """
for i, heap_size in enumerate(position): for i, heap_size in enumerate(position):
next_position = copy(position) next_position = copy(position)
...@@ -88,13 +53,26 @@ def make_computer_move(position): ...@@ -88,13 +53,26 @@ def make_computer_move(position):
return next_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(): 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))] position = [randrange(1, 10) for _ in range(randrange(3, 7))]
while True: while True:
print('Heaps: {position}'.format(position=position)) print(f'Heaps: {position}')
if sum(position) == 0: if sum(position) == 0:
print('Human Wins!') print('Human Wins!')
print() print()
...@@ -102,13 +80,15 @@ def main(): ...@@ -102,13 +80,15 @@ def main():
print('Computer moves...') print('Computer moves...')
print() print()
position = make_computer_move(position) position = make_computer_move(position)
print('Heaps: {position}'.format(position=position)) print(f'Heaps: {position}')
if sum(position) == 0: if sum(position) == 0:
print('Computer Wins!') print('Computer Wins!')
print() print()
return return
index = int(input('Index at which to take stones? ')) index = ask_for_number('Index at which to take stones? ',
count = int(input('Number of stones to take? ')) 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() print()
position[index] -= count position[index] -= count
......
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()
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)
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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment