How to Decrypt a Triangle Cipher in Python
A triangle cipher is a transposition cipher where characters are arranged in a right-angled triangle. To decrypt it, we extract the last character of every row to form the hidden message. This guide implements a robust decryption function in Python that handles arithmetic sequences and edge cases like whitespace or empty inputs.
Understanding the Triangle Logic
Visualizing the cipher is crucial before coding. Given the string "Tcudctsdxosdxcr", the characters fill a triangle row by row, increasing the row length by 1 each time.
Row 1 (1 char): T -> Last char: T
Row 2 (2 chars): c u -> Last char: u
Row 3 (3 chars): d c t -> Last char: t
Row 4 (4 chars): s d x o -> Last char: o
Row 5 (5 chars): s d x c r -> Last char: r
Decrypted Message: "Tutor"
We need to jump through the string indices based on an increasing step size (1, 2, 3, 4, ...).
Step 1: Input Validation and Cleaning
Before processing, we must ensure the input is valid. The function should handle None types gracefully and strip unnecessary whitespace that might affect index calculations.
Handling None and Whitespace:
def prepare_text(text):
# ⛔️ Incorrect: Calling string methods on None causes a crash
# cleaned = text.strip()
# ✅ Correct: Check for existence first
if text:
# Manual stripping logic (or simply use text.strip())
while text.startswith(" "):
text = text[1:]
while text.endswith(" "):
text = text[:-1]
return text
else:
return None
While the manual while loops above work, Python's built-in text.strip() method is the standard, most efficient way to remove leading and trailing whitespace.
Step 2: Implementing the Decryption Loop
The core logic involves calculating the index of the last character of each row. We start at index 0, and the gap between the ends of rows increases by 1 in every iteration.
The Index Jumping Algorithm:
text = "Tcudctsdxosdxcr"
decryption_text = ""
i = 0 # Current index
step = 1 # Size of the current row
# Iterate while the index is within bounds
while i < len(text):
# Capture the character at the current "end of row"
decryption_text += text[i]
# Calculate the next index:
# Current Index + 1 (move to next char) + Step (skip the rest of the new row)
i = i + 1 + step
# Increase the size of the next row
step += 1
# Handle incomplete triangles (leftover characters)
# If the loop overshot the length but didn't land exactly at the end
if i - step + 1 != len(text):
decryption_text += text[-1]
print(f"Result: {decryption_text}")
Output:
Result: Tutor
The condition if i - step + 1 != len(text) handles "imperfect" triangles where the last row might not be fully complete according to the arithmetic sequence, ensuring the absolute last character is captured if missed.
Complete Code Solution
Here is the fully functional script combining validation, cleaning, and the arithmetic logic.
from typing import Optional
def triangle_decryption(text: Optional[str]) -> Optional[str]:
"""
Decrypts a string arranged in a right-triangle pattern by
extracting the last character of each row.
"""
decryption_text = ""
# 1. Validate Input
if text:
# 2. Clean Input (Remove whitespace)
while text.startswith(" "):
text = text[1:]
while text.endswith(" "):
text = text[:-1]
# 3. Decryption Loop
i = 0
step = 1
while i < len(text):
decryption_text += text[i]
# Jump to the end of the next row
# logic: current_pos + 1 (start of next row) + step (length of next row)
i = i + 1 + step
step += 1
# 4. Handle Edge Case (Incomplete last row)
# Check if the calculated 'i' perfectly matches the end or if we missed the last char
# Previous i was (i - step - 1).
if i - step + 1 != len(text):
decryption_text += text[-1]
else:
# Handle None input
decryption_text = None
return decryption_text
if __name__ == "__main__":
# Test Case 1: Perfect Triangle
print(f"Input: 'Tcudctsdxosdxcr' -> {triangle_decryption('Tcudctsdxosdxcr')}")
# Test Case 2: Imperfect Triangle
print(f"Input: 'Tcudc' -> {triangle_decryption('Tcudc')}")
# Test Case 3: Leading Whitespace
print(f"Input: ' Tcudctsdxosdxcr'-> {triangle_decryption(' Tcudctsdxosdxcr')}")
# Test Case 4: None
print(f"Input: None -> {triangle_decryption(None)}")
Output:
Input: 'Tcudctsdxosdxcr' -> Tutor
Input: 'Tcudc' -> Tuc
Input: ' Tcudctsdxosdxcr'-> Tutor
Input: None -> None
Conclusion
Decrypting a triangle cipher is an exercise in identifying arithmetic progressions within string indices.
- Visualize the shape to determine the row lengths (
1, 2, 3, ...). - Calculate the indices: The gap between selected characters grows linearly.
- Validate inputs to prevent errors with
Noneor whitespace.