From 9102776b938d58e5101ea504303d7a206f191bac Mon Sep 17 00:00:00 2001 From: avyukth-fll <154710760+avyukth-fll@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:55:12 -0700 Subject: [PATCH 1/7] Baconian cipher with any 2 symbols Updated to allow encoding and decoding with any 2 characters --- ciphers/baconian_cipher.py | 217 +++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 72 deletions(-) diff --git a/ciphers/baconian_cipher.py b/ciphers/baconian_cipher.py index f146ba91b78f..5c4f9b607559 100644 --- a/ciphers/baconian_cipher.py +++ b/ciphers/baconian_cipher.py @@ -1,89 +1,162 @@ """ -Program to encode and decode Baconian or Bacon's Cipher -Wikipedia reference : https://en.wikipedia.org/wiki/Bacon%27s_cipher +Bacon's/Baconian Cipher Encoder and Decoder + + provides functions to encode and decode messages +using Bacon's/Baconian cipher with any 2 symbols, not just A & B. + +Source: https://en.wikipedia.org/wiki/Bacon's_cipher """ -encode_dict = { - "a": "AAAAA", - "b": "AAAAB", - "c": "AAABA", - "d": "AAABB", - "e": "AABAA", - "f": "AABAB", - "g": "AABBA", - "h": "AABBB", - "i": "ABAAA", - "j": "BBBAA", - "k": "ABAAB", - "l": "ABABA", - "m": "ABABB", - "n": "ABBAA", - "o": "ABBAB", - "p": "ABBBA", - "q": "ABBBB", - "r": "BAAAA", - "s": "BAAAB", - "t": "BAABA", - "u": "BAABB", - "v": "BBBAB", - "w": "BABAA", - "x": "BABAB", - "y": "BABBA", - "z": "BABBB", - " ": " ", +ENCODE_DICT = { + "a": "AAAAA", "b": "AAAAB", "c": "AAABA", "d": "AAABB", + "e": "AABAA", "f": "AABAB", "g": "AABBA", "h": "AABBB", + "i": "ABAAA", "j": "BBBAA", "k": "ABAAB", "l": "ABABA", + "m": "ABABB", "n": "ABBAA", "o": "ABBAB", "p": "ABBBA", + "q": "ABBBB", "r": "BAAAA", "s": "BAAAB", "t": "BAABA", + "u": "BAABB", "v": "BBBAB", "w": "BABAA", "x": "BABAB", + "y": "BABBA", "z": "BABBB", " ": " ", } +DECODE_DICT = {value: key for key, value in ENCODE_DICT.items()} -decode_dict = {value: key for key, value in encode_dict.items()} - -def encode(word: str) -> str: +def encode(message: str, symbols: tuple[str, str] = ("A", "B")) -> str: """ - Encodes to Baconian cipher - - >>> encode("hello") - 'AABBBAABAAABABAABABAABBAB' - >>> encode("hello world") - 'AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB' - >>> encode("hello world!") - Traceback (most recent call last): - ... - Exception: encode() accepts only letters of the alphabet and spaces + Encode a message using Bacon's cipher. + + Parameters + ---------- + message : str + The message to encode (letters and spaces only). + symbols : tuple[str, str], optional + Custom symbols to replace A and B, by default ("A", "B"). + + Returns + ------- + str + Encoded message using the chosen symbols. + + Raises + ------ + ValueError + If the message contains invalid characters. + + Examples + -------- + >>> encode("abc") + 'AAAAA AAAAB AAABA' + >>> encode("abc", symbols=("X", "Y")) + 'XXXXX XXXXY XXYXX' + >>> encode("hi there") + 'AABBB ABAAA BAABA AABBB AABAA BAAAA AABAA' """ - encoded = "" - for letter in word.lower(): - if letter.isalpha() or letter == " ": - encoded += encode_dict[letter] + a_sym, b_sym = symbols + encoded_message = "" + + for char in message.lower(): + if char.isalpha() or char == " ": + bacon = ENCODE_DICT[char] + encoded_message += bacon.replace("A", a_sym).replace("B", b_sym) else: - raise Exception("encode() accepts only letters of the alphabet and spaces") - return encoded + raise ValueError("Message can only contain letters and spaces.") + + return encoded_message -def decode(coded: str) -> str: +def decode(cipher: str, symbols: tuple[str, str] = ("A", "B")) -> str: """ - Decodes from Baconian cipher - - >>> decode("AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB") - 'hello world' - >>> decode("AABBBAABAAABABAABABAABBAB") - 'hello' - >>> decode("AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB!") - Traceback (most recent call last): - ... - Exception: decode() accepts only 'A', 'B' and spaces + Decode a Bacon's cipher message. + + Parameters + ---------- + cipher : str + The encoded message using two symbols. + symbols : tuple[str, str], optional + Symbols used in the cipher, by default ("A", "B"). + + Returns + ------- + str + Decoded message. + + Raises + ------ + ValueError + If the cipher contains invalid symbols or cannot be decoded. + + Examples + -------- + >>> decode("AAAAA AAAAB AAABA") + 'abc' + >>> decode("XXXXX XXXXY XXYXX", symbols=("X","Y")) + 'abc' """ - if set(coded) - {"A", "B", " "} != set(): - raise Exception("decode() accepts only 'A', 'B' and spaces") - decoded = "" - for word in coded.split(): - while len(word) != 0: - decoded += decode_dict[word[:5]] - word = word[5:] - decoded += " " - return decoded.strip() + sym1, sym2 = symbols + unique_symbols = set(cipher.replace(" ", "")) + if unique_symbols - {sym1, sym2}: + raise ValueError(f"Cipher must contain only symbols {sym1} and {sym2}.") + candidates = [] + for mapping in [(sym1, sym2), (sym2, sym1)]: + s1, s2 = mapping + standard = cipher.replace(s1, "A").replace(s2, "B") + try: + decoded = "" + for word in standard.split(): + while word: + chunk = word[:5] + if chunk not in DECODE_DICT: + raise ValueError + decoded += DECODE_DICT[chunk] + word = word[5:] + decoded += " " + candidates.append(decoded.strip()) + except ValueError: + candidates.append(None) -if __name__ == "__main__": - from doctest import testmod + for candidate in candidates: + if candidate is not None: + return candidate + + raise ValueError("No valid decoding found.") + + +def detect_unique_symbols(cipher: str) -> tuple[str, str]: + """ + Detects the two unique symbols used in a cipher. + + Parameters + ---------- + cipher : str + Encoded message containing exactly two unique symbols. - testmod() + Returns + ------- + tuple[str, str] + The two unique symbols found in the cipher. + + Raises + ------ + ValueError + If cipher does not contain exactly two unique symbols. + + Examples + -------- + >>> detect_unique_symbols("XXXYX YXXYX") + ('X', 'Y') + """ + letters_only = [char for char in set(cipher.replace(" ", "")) if char.isalpha()] + if len(letters_only) != 2: + raise ValueError("Cipher must contain exactly two unique alphabetic symbols.") + return tuple(letters_only) + + +if __name__ == "__main__": + # Example usage + cipher_text = ( + "FEEFE EEFFF EEFEE EFFFF FEEFF EFEEE EEEFE " + "EFEEF EEEEF FEEEE EFFEF FEFEE EFFEE EEFEF EFFEF FEFEF" + ) + sym1, sym2 = detect_unique_symbols(cipher_text) + decoded_message = decode(cipher_text, symbols=(sym1, sym2)) + print(decoded_message) # Expected: 'the quick brown fox' From 634532c4c61cd96e83c1b091eb4907aa30bd1885 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 06:12:36 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ciphers/baconian_cipher.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/ciphers/baconian_cipher.py b/ciphers/baconian_cipher.py index 5c4f9b607559..7ddaf29ff59c 100644 --- a/ciphers/baconian_cipher.py +++ b/ciphers/baconian_cipher.py @@ -8,13 +8,33 @@ """ ENCODE_DICT = { - "a": "AAAAA", "b": "AAAAB", "c": "AAABA", "d": "AAABB", - "e": "AABAA", "f": "AABAB", "g": "AABBA", "h": "AABBB", - "i": "ABAAA", "j": "BBBAA", "k": "ABAAB", "l": "ABABA", - "m": "ABABB", "n": "ABBAA", "o": "ABBAB", "p": "ABBBA", - "q": "ABBBB", "r": "BAAAA", "s": "BAAAB", "t": "BAABA", - "u": "BAABB", "v": "BBBAB", "w": "BABAA", "x": "BABAB", - "y": "BABBA", "z": "BABBB", " ": " ", + "a": "AAAAA", + "b": "AAAAB", + "c": "AAABA", + "d": "AAABB", + "e": "AABAA", + "f": "AABAB", + "g": "AABBA", + "h": "AABBB", + "i": "ABAAA", + "j": "BBBAA", + "k": "ABAAB", + "l": "ABABA", + "m": "ABABB", + "n": "ABBAA", + "o": "ABBAB", + "p": "ABBBA", + "q": "ABBBB", + "r": "BAAAA", + "s": "BAAAB", + "t": "BAABA", + "u": "BAABB", + "v": "BBBAB", + "w": "BABAA", + "x": "BABAB", + "y": "BABBA", + "z": "BABBB", + " ": " ", } DECODE_DICT = {value: key for key, value in ENCODE_DICT.items()} From 22c4c017ea9ed3185f44af3ba665b767b0b9a284 Mon Sep 17 00:00:00 2001 From: ashviz915 <154710760+avyukth-fll@users.noreply.github.com> Date: Tue, 21 Oct 2025 23:28:56 -0700 Subject: [PATCH 3/7] HSV Filter Tool allows users to interactively select an HSV color range from an image using trackbars and outputs the selected HSV values. Useful for finding thresholds for basic color filtration when trying to detect an object in an image --- computer_vision/hsv_threshold | 135 ++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 computer_vision/hsv_threshold diff --git a/computer_vision/hsv_threshold b/computer_vision/hsv_threshold new file mode 100644 index 000000000000..a5d165b1a42b --- /dev/null +++ b/computer_vision/hsv_threshold @@ -0,0 +1,135 @@ +""" +HSV Filter Tool + +This module allows the user to interactively select an HSV color range +from an image using trackbars and outputs the selected HSV values. + +Dependencies: +- OpenCV (cv2) +- NumPy + +Usage: +1. Set `IMAGE_PATH` to your image file. +2. Run the script. +3. Adjust the trackbars to select the desired HSV range. +4. Press Enter to print the HSV lower and upper bounds. +""" + +import cv2 +import numpy as np + +IMAGE_PATH = r"C:\Users\username\New folder\your_image.png" + + +def load_image(path: str) -> np.ndarray: + """ + Load an image from the specified path. + + Parameters + ---------- + path : str + Path to the image file. + + Returns + ------- + np.ndarray + Loaded BGR image. + + Raises + ------ + FileNotFoundError + If the image cannot be loaded. + """ + image = cv2.imread(path) + if image is None: + raise FileNotFoundError(f"Failed to load image at path: {path}") + return image + + +def create_hsv_trackbars(window_name: str) -> None: + """ + Create HSV trackbars for filtering. + + Parameters + ---------- + window_name : str + Name of the OpenCV window. + """ + cv2.createTrackbar("H Lower", window_name, 0, 179, lambda x: None) + cv2.createTrackbar("S Lower", window_name, 0, 255, lambda x: None) + cv2.createTrackbar("V Lower", window_name, 0, 255, lambda x: None) + cv2.createTrackbar("H Upper", window_name, 179, 179, lambda x: None) + cv2.createTrackbar("S Upper", window_name, 255, 255, lambda x: None) + cv2.createTrackbar("V Upper", window_name, 255, 255, lambda x: None) + + +def get_hsv_bounds(window_name: str) -> tuple[np.ndarray, np.ndarray]: + """ + Read the HSV lower and upper bounds from the trackbars. + + Parameters + ---------- + window_name : str + Name of the OpenCV window. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Lower and upper HSV bounds as NumPy arrays. + """ + lower_bound = np.array([ + cv2.getTrackbarPos("H Lower", window_name), + cv2.getTrackbarPos("S Lower", window_name), + cv2.getTrackbarPos("V Lower", window_name), + ]) + upper_bound = np.array([ + cv2.getTrackbarPos("H Upper", window_name), + cv2.getTrackbarPos("S Upper", window_name), + cv2.getTrackbarPos("V Upper", window_name), + ]) + return lower_bound, upper_bound + + +def main() -> None: + """ + Main function to run the HSV filter tool. + + Opens the image, creates trackbars, shows filtered results, + and prints the final HSV bounds when Enter is pressed. + """ + try: + image = load_image(IMAGE_PATH) + except FileNotFoundError as e: + print(e) + return + + window_name = "HSV Filter" + cv2.namedWindow(window_name) + create_hsv_trackbars(window_name) + + while True: + hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + + lower, upper = get_hsv_bounds(window_name) + + mask = cv2.inRange(hsv_image, lower, upper) + filtered_result = cv2.bitwise_and(image, image, mask=mask) + + cv2.imshow("Original", image) + cv2.imshow("Filtered", filtered_result) + + key = cv2.waitKey(1) & 0xFF + if key == 13: # Enter key + print(f"HSV Range (Lower): {lower}") + print(f"HSV Range (Upper): {upper}") + print( + f"CSV Format: {lower[0]},{lower[1]},{lower[2]}," + f"{upper[0]},{upper[1]},{upper[2]}" + ) + break + + cv2.destroyAllWindows() + + +if __name__ == "__main__": + main() From b2bca9e3c8eec6a81c80b9966fff3e7e92be3734 Mon Sep 17 00:00:00 2001 From: ashviz915 <154710760+avyukth-fll@users.noreply.github.com> Date: Tue, 21 Oct 2025 23:43:42 -0700 Subject: [PATCH 4/7] HSV filter tool interactive HSV filter tool that allows users to select HSV color ranges from an image using trackbars, and print hue, saturation, and value ranges.Useful for trying to find the right HSV range to use when doing basic color filtration --- computer_vision/hsv_threshold | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/computer_vision/hsv_threshold b/computer_vision/hsv_threshold index a5d165b1a42b..2986c500b0be 100644 --- a/computer_vision/hsv_threshold +++ b/computer_vision/hsv_threshold @@ -1,27 +1,23 @@ """ HSV Filter Tool -This module allows the user to interactively select an HSV color range -from an image using trackbars and outputs the selected HSV values. +This file lets the user to interactively select an HSV color range +from an image using trackbars and outputs the selected HSV range. -Dependencies: -- OpenCV (cv2) -- NumPy - -Usage: 1. Set `IMAGE_PATH` to your image file. 2. Run the script. 3. Adjust the trackbars to select the desired HSV range. -4. Press Enter to print the HSV lower and upper bounds. +4. Enter to print the HSV lower and upper bounds. """ import cv2 import numpy as np +#Example Path IMAGE_PATH = r"C:\Users\username\New folder\your_image.png" -def load_image(path: str) -> np.ndarray: +def load_image(path): """ Load an image from the specified path. @@ -46,7 +42,7 @@ def load_image(path: str) -> np.ndarray: return image -def create_hsv_trackbars(window_name: str) -> None: +def create_hsv_trackbars(window_name): """ Create HSV trackbars for filtering. @@ -63,7 +59,7 @@ def create_hsv_trackbars(window_name: str) -> None: cv2.createTrackbar("V Upper", window_name, 255, 255, lambda x: None) -def get_hsv_bounds(window_name: str) -> tuple[np.ndarray, np.ndarray]: +def get_hsv_bounds(window_name): """ Read the HSV lower and upper bounds from the trackbars. @@ -90,7 +86,7 @@ def get_hsv_bounds(window_name: str) -> tuple[np.ndarray, np.ndarray]: return lower_bound, upper_bound -def main() -> None: +def main(): """ Main function to run the HSV filter tool. From de8d2d7ba111e90214ac895b7f449e81c4805067 Mon Sep 17 00:00:00 2001 From: ashviz915 <154710760+avyukth-fll@users.noreply.github.com> Date: Tue, 21 Oct 2025 23:48:30 -0700 Subject: [PATCH 5/7] Fix typo Fix mix up of bubble_sort_inclusive and bubble_sort_recursive in docstring --- sorts/bubble_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/bubble_sort.py b/sorts/bubble_sort.py index 9ec3d5384f38..63b1f16a45cc 100644 --- a/sorts/bubble_sort.py +++ b/sorts/bubble_sort.py @@ -63,7 +63,7 @@ def bubble_sort_recursive(collection: list[Any]) -> list[Any]: Examples: >>> bubble_sort_recursive([0, 5, 2, 3, 2]) [0, 2, 2, 3, 5] - >>> bubble_sort_iterative([]) + >>> bubble_sort_recursive([]) [] >>> bubble_sort_recursive([-2, -45, -5]) [-45, -5, -2] From d2346f8a4051151d28447474f3435149ad6b82d1 Mon Sep 17 00:00:00 2001 From: ashviz915 <154710760+avyukth-fll@users.noreply.github.com> Date: Tue, 21 Oct 2025 23:59:13 -0700 Subject: [PATCH 6/7] Ellipse perimeter calculation Updated the perimeter calculation for Ellipse using Ramanujan's approximation, which is more accurate --- geometry/geometry.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/geometry/geometry.py b/geometry/geometry.py index a0be8eb3befc..6ea7b94d171c 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -103,9 +103,11 @@ def area(self) -> float: def perimeter(self) -> float: """ >>> Ellipse(5, 10).perimeter - 47.12388980384689 + 48.44222344723793 """ - return math.pi * (self.major_radius + self.minor_radius) + a, b = self.major_radius, self.minor_radius + #uses ramanujans approximation + return math.pi * (3*(a + b) - ((3*a + b)*(a + 3*b))**0.5) class Circle(Ellipse): From 2b6d8a0277e691178b4545651038b436a3bbeda4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 14:16:32 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- geometry/geometry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geometry/geometry.py b/geometry/geometry.py index 6ea7b94d171c..fd3fb2c500ef 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -106,8 +106,8 @@ def perimeter(self) -> float: 48.44222344723793 """ a, b = self.major_radius, self.minor_radius - #uses ramanujans approximation - return math.pi * (3*(a + b) - ((3*a + b)*(a + 3*b))**0.5) + # uses ramanujans approximation + return math.pi * (3 * (a + b) - ((3 * a + b) * (a + 3 * b)) ** 0.5) class Circle(Ellipse):