add collatz exercise, simplify names, update readme

This commit is contained in:
James Greenwood 2025-08-30 13:03:31 +01:00
parent 26667a2559
commit 6488ea0ede
10 changed files with 183 additions and 61 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
__pycache__
.venv

122
README.md Normal file
View File

@ -0,0 +1,122 @@
# Turner & Townsend backend assessment
These programs need Python 3.10+ and pytest.
Original assessment: https://github.com/turner-townsend/backend-assessment
## The Collatz Conjecture
Takes numeric input and calculates the number of steps in the Collatz sequence needed to reach 1
## Usage
```shell
python collatz/collatz.py
```
### Example
```
Please enter a whole number: 1
Result: 0 steps needed to reach 1
Please enter a whole number: 3
Step #1: odd, multiply by 3 and add 1 -> 10
Step #2: even, divide by 2 -> 5
Step #3: odd, multiply by 3 and add 1 -> 16
Step #4: even, divide by 2 -> 8
Step #5: even, divide by 2 -> 4
Step #6: even, divide by 2 -> 2
Step #7: even, divide by 2 -> 1
Result: 8 steps needed to reach 3
Please enter a whole number: 0
Result: 0 steps needed to reach 0
Please enter a whole number: !£$
ERROR: integer required
```
## Tests
```bash
pytest collatz
```
## Roman Numerals
A simple Roman numerals number converter
## Usage
```shell
python roman/roman.py
```
### Example
```
Please enter some Roman numerals: I
I = 1
Please enter some Roman numerals: IV
IV = 1 + 5 = 6
Please enter some Roman numerals: MCMXCIV
MCMXCIV = 1000 + 100 + 1000 + 10 + 100 + 1 + 5 = 2216
Please enter some Roman numerals: !£$
ERROR: Invalid input
```
## Tests
```bash
pytest roman
```
## Fifth Stack
A simple stack-based language called Fifth
## Usage
```shell
python stack/stack.py
```
### Commands
- `PUSH <n>` - push integer onto stack
- `POP` - remove top element
- `SWAP` - swap top two elements
- `DUP` - duplicate top element
- `+`, `-`, `*`, `/` - arithmetic operations
- `EXIT` - quit
### Example
```
stack is []
PUSH 3
stack is [3]
PUSH 11
stack is [3, 11]
+
stack is [14]
DUP
stack is [14, 14]
PUSH 2
stack is [14, 14, 2]
*
stack is [14, 28]
SWAP
stack is [28, 14]
/
stack is [2]
+
ERROR: two numbers required
POP
stack is []
EXIT
```
## Tests
```bash
pytest stack
```

30
collatz/collatz.py Normal file
View File

@ -0,0 +1,30 @@
import readline
class CollatzCalculator:
def calculate_steps(self, n: int) -> int:
if n <= 1:
return 0
steps = 0
while n != 1:
if n % 2 == 0:
n //= 2
print(f"Step #{steps + 1}: even, divide by 2 -> {n}")
else:
n = 3 * n + 1
print(f"Step #{steps + 1}: odd, multiply by 3 and add 1 -> {n}")
steps += 1
return steps + 1
def main():
calculator = CollatzCalculator()
while True:
try:
n = input("Please enter a whole number: ")
print(f"Result: {calculator.calculate_steps(int(n))} steps needed to reach {n}")
except ValueError:
print("ERROR: integer required")
except (EOFError, KeyboardInterrupt):
break
if __name__ == "__main__":
main()

27
collatz/test_collatz.py Normal file
View File

@ -0,0 +1,27 @@
import pytest
from collatz import CollatzCalculator
def test_calculate_steps_for_1():
calc = CollatzCalculator()
assert calc.calculate_steps(1) == 0
def test_calculate_steps_for_2():
calc = CollatzCalculator()
assert calc.calculate_steps(2) == 2 # 2 -> 1 (even), returns 2 steps
def test_calculate_steps_for_3():
calc = CollatzCalculator()
assert calc.calculate_steps(3) == 8 # 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
def test_calculate_steps_for_6():
calc = CollatzCalculator()
assert calc.calculate_steps(6) == 9 # 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
def test_calculate_steps_for_large_number():
calc = CollatzCalculator()
assert calc.calculate_steps(27) == 112
def test_calculate_steps_for_zero_and_negative():
calc = CollatzCalculator()
assert calc.calculate_steps(0) == 0
assert calc.calculate_steps(-5) == 0

View File

@ -1,57 +0,0 @@
# Fifth Stack
A simple stack-based language called Fifth
## Usage
```shell
python fifth_stack.py
```
### Commands
- `PUSH <n>` - push integer onto stack
- `POP` - remove top element
- `SWAP` - swap top two elements
- `DUP` - duplicate top element
- `+`, `-`, `*`, `/` - arithmetic operations
- `EXIT` - quit
### Example
```
stack is []
PUSH 3
stack is [3]
PUSH 11
stack is [3, 11]
+
stack is [14]
DUP
stack is [14, 14]
PUSH 2
stack is [14, 14, 2]
*
stack is [14, 28]
SWAP
stack is [28, 14]
/
stack is [2]
+
ERROR: two numbers required
POP
stack is []
EXIT
```
## Tests
```bash
pip install pytest
pytest -v test_fifth_stack.py
```
## Requirements
- Python 3.10+
- pytest

View File

@ -3,7 +3,7 @@ import readline
def convert_to_number(numerals: str) -> str:
filtered = list(filter(lambda x: x in "IVXCM", list(numerals.upper())))
if len(filtered) == 0:
return "Invalid input"
return "ERROR: Invalid input"
values: list[int] = []
for i in range(len(filtered)):

View File

@ -1,5 +1,5 @@
import pytest
from roman_numerals import convert_to_number
from roman import convert_to_number
def test_valid_single_numerals():
assert convert_to_number("I") == "I = 1"

View File

@ -1,5 +1,5 @@
import pytest
from fifth_stack import FifthStack
from stack import FifthStack
# Test the functions