Skip to main content

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
tip

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
note

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.

  1. Visualize the shape to determine the row lengths (1, 2, 3, ...).
  2. Calculate the indices: The gap between selected characters grows linearly.
  3. Validate inputs to prevent errors with None or whitespace.