Omarbetade tester och tydligare funktions- och variabelnamn
This commit is contained in:
+34
-19
@@ -1,33 +1,48 @@
|
|||||||
|
def tower_of_hanoi(n, source, auxiliary, target):
|
||||||
|
"""
|
||||||
|
Solve the Tower of Hanoi puzzle with n disks.
|
||||||
|
|
||||||
def hanoi(n, source, auxiliary, target):
|
Parameters:
|
||||||
# Example usage:
|
n (int): The number of disks to move.
|
||||||
# hanoi(3, 'A', 'B', 'C')
|
source (str): The starting peg.
|
||||||
|
auxiliary (str): An intermediate peg.
|
||||||
|
target (str): The destination peg.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If n is less than 1, indicating no disks to move.
|
||||||
|
"""
|
||||||
if n < 1:
|
if n < 1:
|
||||||
print(f"No disks, nothing to do")
|
raise ValueError("No disks to move. Please enter a positive integer.")
|
||||||
return
|
|
||||||
if n == 1:
|
if n == 1:
|
||||||
print(f"Move disk 1 from {source} to {target}")
|
print(f"Move disk 1 from {source} to {target}")
|
||||||
return
|
else:
|
||||||
# Move n-1 disks from source to auxiliary, so they are out of the way
|
tower_of_hanoi(n - 1, source, target, auxiliary)
|
||||||
hanoi(n - 1, source, target, auxiliary)
|
|
||||||
# Move the nth disk from source to target
|
|
||||||
print(f"Move disk {n} from {source} to {target}")
|
print(f"Move disk {n} from {source} to {target}")
|
||||||
# Move the n-1 disks that we left on auxiliary to target
|
tower_of_hanoi(n - 1, auxiliary, source, target)
|
||||||
hanoi(n - 1, auxiliary, source, target)
|
|
||||||
|
|
||||||
def get_hanoi_input():
|
def prompt_for_integer():
|
||||||
# Returns a positive integer, otherwise throws an exception
|
"""
|
||||||
|
Prompts the user to enter a positive integer until a valid input is received.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: A positive integer entered by the user.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the entered input is anything else, for instance a negative integer or a string.
|
||||||
|
"""
|
||||||
while True:
|
while True:
|
||||||
user_input = input("Please enter an integer: ")
|
user_input = input("Please enter an integer: ")
|
||||||
try:
|
try:
|
||||||
user_integer = int(user_input)
|
user_integer = int(user_input)
|
||||||
|
if user_integer > 0:
|
||||||
return user_integer
|
return user_integer
|
||||||
|
else:
|
||||||
|
print("The number must be positive.")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("That's not a valid integer. Please try again.")
|
print("Invalid literal for int() with base 10. Please enter an integer.")
|
||||||
|
|
||||||
if __name__== "__main__":
|
|
||||||
# Call the new function to get the input
|
|
||||||
user_integer = get_hanoi_input()
|
|
||||||
# Now call hanoi with the obtained integer
|
|
||||||
hanoi(user_integer, 'A', 'B', 'C')
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
user_integer = prompt_for_integer()
|
||||||
|
tower_of_hanoi(user_integer, 'A', 'B', 'C')
|
||||||
|
|||||||
+52
-34
@@ -1,47 +1,65 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import io
|
import io
|
||||||
from unittest.mock import patch
|
import sys
|
||||||
from hanoi import hanoi, get_hanoi_input
|
from hanoi import tower_of_hanoi, prompt_for_integer
|
||||||
|
|
||||||
class TestHanoi(unittest.TestCase):
|
class TestTowerOfHanoi(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Explanation of Tests:
|
||||||
|
|
||||||
def test_hanoi_zero_disks(self):
|
test_valid_input():
|
||||||
expected_output = "No disks, nothing to do\n"
|
This test checks the core functionality by moving 3 disks using tower_of_hanoi.
|
||||||
# with self.assertRaises(SystemExit):
|
It asserts that the function completes without raising errors.
|
||||||
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
|
||||||
hanoi(0, 'A', 'B', 'C')
|
|
||||||
|
|
||||||
def test_hanoi_one_disk(self):
|
test_edge_case_single_disk():
|
||||||
|
This handles the base case of a single disk, ensuring the correct move
|
||||||
|
is printed ("Move disk 1 from A to C").
|
||||||
|
|
||||||
|
test_invalid_input_zero_disks():
|
||||||
|
This checks that the function raises a ValueError when given zero disks.
|
||||||
|
|
||||||
|
test_prompt_for_integer_valid():
|
||||||
|
Tests the input function with valid integer input ("3") and asserts it
|
||||||
|
returns the correct value (3).
|
||||||
|
|
||||||
|
test_prompt_for_integer_invalid_negative():
|
||||||
|
Checks for handling negative integers, expecting a ValueError.
|
||||||
|
|
||||||
|
test_prompt_for_integer_invalid_string():
|
||||||
|
Tests that invalid string input is handled gracefully and eventually
|
||||||
|
leads to a valid integer being returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_valid_input(self):
|
||||||
|
self.assertEqual(tower_of_hanoi(3, 'A', 'B', 'C'), None) # Example with 3 disks
|
||||||
|
|
||||||
|
def test_edge_case_single_disk(self):
|
||||||
expected_output = "Move disk 1 from A to C\n"
|
expected_output = "Move disk 1 from A to C\n"
|
||||||
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
captured_output = io.StringIO()
|
||||||
hanoi(1, 'A', 'B', 'C')
|
sys.stdout = captured_output
|
||||||
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
tower_of_hanoi(1, 'A', 'B', 'C')
|
||||||
|
sys.stdout = sys.__stdout__ # Reset stdout
|
||||||
|
self.assertEqual(captured_output.getvalue(), expected_output)
|
||||||
|
|
||||||
def test_hanoi_two_disks(self):
|
def test_invalid_input_zero_disks(self):
|
||||||
expected_output = "Move disk 1 from A to B\nMove disk 2 from A to C\nMove disk 1 from B to C\n"
|
with self.assertRaises(ValueError):
|
||||||
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
tower_of_hanoi(0, 'A', 'B', 'C')
|
||||||
hanoi(2, 'A', 'B', 'C')
|
|
||||||
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
|
||||||
|
|
||||||
def test_hanoi_three_disks(self):
|
def test_prompt_for_integer_valid(self):
|
||||||
expected_output = "Move disk 1 from A to C\nMove disk 2 from A to B\nMove disk 1 from C to B\nMove disk 3 from A to C\nMove disk 1 from B to A\nMove disk 2 from B to C\nMove disk 1 from A to C\n"
|
with io.StringIO("3\n") as mock_stdin:
|
||||||
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
sys.stdin = mock_stdin
|
||||||
hanoi(3, 'A', 'B', 'C')
|
self.assertEqual(prompt_for_integer(), 3)
|
||||||
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
|
||||||
|
|
||||||
def test_hanoi_negative_input(self):
|
def test_prompt_for_integer_invalid_negative(self):
|
||||||
expected_output = "No disks, nothing to do\n"
|
with io.StringIO("-2\n1\n") as mock_stdin:
|
||||||
# with self.assertRaises(SystemExit):
|
sys.stdin = mock_stdin
|
||||||
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
self.assertEqual(prompt_for_integer(), 1) # Should eventually get a valid integer
|
||||||
hanoi(-1, 'A', 'B', 'C')
|
|
||||||
|
|
||||||
def test_get_hanoi_input_valid_integer(self):
|
|
||||||
with unittest.mock.patch('builtins.input', return_value='4'):
|
|
||||||
self.assertEqual(get_hanoi_input(), 4)
|
|
||||||
|
|
||||||
def test_get_hanoi_input_invalid_input(self):
|
def test_prompt_for_integer_invalid_string(self):
|
||||||
with unittest.mock.patch('builtins.input', side_effect=['abc', '5']):
|
with io.StringIO("abc\n3\n") as mock_stdin:
|
||||||
self.assertEqual(get_hanoi_input(), 5)
|
sys.stdin = mock_stdin
|
||||||
|
self.assertEqual(prompt_for_integer(), 3) # Should eventually get a valid integer
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import unittest
|
||||||
|
import io
|
||||||
|
from unittest.mock import patch
|
||||||
|
from hanoi import hanoi, prompt_for_integer
|
||||||
|
|
||||||
|
class TestHanoi(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_hanoi_zero_disks(self):
|
||||||
|
expected_output = "No disks, nothing to do\n"
|
||||||
|
# with self.assertRaises(SystemExit):
|
||||||
|
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
||||||
|
hanoi(0, 'A', 'B', 'C')
|
||||||
|
|
||||||
|
def test_hanoi_one_disk(self):
|
||||||
|
expected_output = "Move disk 1 from A to C\n"
|
||||||
|
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
||||||
|
hanoi(1, 'A', 'B', 'C')
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
||||||
|
|
||||||
|
def test_hanoi_two_disks(self):
|
||||||
|
expected_output = "Move disk 1 from A to B\nMove disk 2 from A to C\nMove disk 1 from B to C\n"
|
||||||
|
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
||||||
|
hanoi(2, 'A', 'B', 'C')
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
||||||
|
|
||||||
|
def test_hanoi_three_disks(self):
|
||||||
|
expected_output = "Move disk 1 from A to C\nMove disk 2 from A to B\nMove disk 1 from C to B\nMove disk 3 from A to C\nMove disk 1 from B to A\nMove disk 2 from B to C\nMove disk 1 from A to C\n"
|
||||||
|
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
||||||
|
hanoi(3, 'A', 'B', 'C')
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected_output)
|
||||||
|
|
||||||
|
def test_hanoi_negative_input(self):
|
||||||
|
expected_output = "No disks, nothing to do\n"
|
||||||
|
# with self.assertRaises(SystemExit):
|
||||||
|
with unittest.mock.patch('sys.stdout', new=io.StringIO()) as mock_stdout:
|
||||||
|
hanoi(-1, 'A', 'B', 'C')
|
||||||
|
|
||||||
|
def test_prompt_for_integer_valid_integer(self):
|
||||||
|
with unittest.mock.patch('builtins.input', return_value='4'):
|
||||||
|
self.assertEqual(prompt_for_integer(), 4)
|
||||||
|
|
||||||
|
def test_prompt_for_integer_invalid_input(self):
|
||||||
|
with unittest.mock.patch('builtins.input', side_effect=['abc', '5']):
|
||||||
|
self.assertEqual(prompt_for_integer(), 5)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user