From 4fe2b55fd510e6dc5a847a1da1ff36814b028f75 Mon Sep 17 00:00:00 2001 From: musharrafhamraz Date: Fri, 6 Feb 2026 12:35:09 +0500 Subject: [PATCH 01/44] feat(Bowling-Action-Tracking): Add bowling action tracking with pose detection - Add main.py with MediaPipe-based pose detection for bowling motion analysis - Implement wrist trajectory tracking using deque for motion history - Add gradient arc visualization for shoulder-elbow-wrist chain movement - Include video processing pipeline with frame resizing and RGB conversion - Add helper functions for coordinate conversion and gradient arc rendering - Include sample bowling video files (bowling.mp4 and bowling_action.mp4) - Enables real-time visualization of bowling arm motion with color-coded keypoints --- Bowling-Action-Tracking/main.py | 103 ++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 Bowling-Action-Tracking/main.py diff --git a/Bowling-Action-Tracking/main.py b/Bowling-Action-Tracking/main.py new file mode 100644 index 0000000..245fad8 --- /dev/null +++ b/Bowling-Action-Tracking/main.py @@ -0,0 +1,103 @@ +import cv2 +import mediapipe as mp +import numpy as np +from collections import deque + +# Initialize MediaPipe Pose +mp_pose = mp.solutions.pose +pose = mp_pose.Pose() +mp_drawing = mp.solutions.drawing_utils + +# Initialize video capture +cap = cv2.VideoCapture('bowling.mp4') + +# Store wrist trajectory and arcs +wrist_trajectory = deque(maxlen=100) # Main wrist trajectory +wrist_positions = deque(maxlen=20) # For arcs +elbow_positions = deque(maxlen=20) +shoulder_positions = deque(maxlen=20) + +# Function to convert normalized coordinates to pixel coordinates +def to_pixel_coords(landmark, frame): + return int(landmark.x * frame.shape[1]), int(landmark.y * frame.shape[0]) + +# Function to draw a gradient arc between two points +def draw_gradient_arc(frame, p1, p2, thickness, start_color, end_color): + num_segments = 50 + x_diff = (p2[0] - p1[0]) / num_segments + y_diff = (p2[1] - p1[1]) / num_segments + + for i in range(num_segments): + # Compute start and end points of each segment + start_point = (int(p1[0] + i * x_diff), int(p1[1] + i * y_diff)) + end_point = (int(p1[0] + (i + 1) * x_diff), int(p1[1] + (i + 1) * y_diff)) + + # Interpolate color between start and end + alpha = i / num_segments + color = ( + int(start_color[0] * (1 - alpha) + end_color[0] * alpha), + int(start_color[1] * (1 - alpha) + end_color[1] * alpha), + int(start_color[2] * (1 - alpha) + end_color[2] * alpha), + ) + cv2.line(frame, start_point, end_point, color, thickness) + +while cap.isOpened(): + ret, frame = cap.read() + if not ret: + break + frame = cv2.resize(frame, (1000, 600)) + # Convert the frame to RGB + rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + results = pose.process(rgb_frame) + + if results.pose_landmarks: + landmarks = results.pose_landmarks.landmark + + # Extract right-hand keypoints + right_shoulder = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER] + right_elbow = landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW] + right_wrist = landmarks[mp_pose.PoseLandmark.RIGHT_WRIST] + + # Convert normalized coordinates to pixel coordinates + shoulder_coords = to_pixel_coords(right_shoulder, frame) + elbow_coords = to_pixel_coords(right_elbow, frame) + wrist_coords = to_pixel_coords(right_wrist, frame) + + # Add wrist coordinates to the deque for trajectory + wrist_trajectory.append(wrist_coords) + + # Add coordinates for arcs + shoulder_positions.append(shoulder_coords) + elbow_positions.append(elbow_coords) + wrist_positions.append(wrist_coords) + + # Draw the wrist trajectory (main line) + for i in range(1, len(wrist_trajectory)): + cv2.line(frame, wrist_trajectory[i - 1], wrist_trajectory[i], (0, 255, 255), 3) + + # Draw dynamic arcs for the last few positions + for i in range(1, len(shoulder_positions)): + # Fade effect using index + thickness = max(2, 10 - (len(shoulder_positions) - i)) + + # Gradient arc for shoulder-to-elbow + draw_gradient_arc(frame, shoulder_positions[i - 1], elbow_positions[i - 1], thickness, (0, 255, 0), (255, 0, 0)) + # Gradient arc for elbow-to-wrist + draw_gradient_arc(frame, elbow_positions[i - 1], wrist_positions[i - 1], thickness, (255, 0, 0), (0, 0, 255)) + + # Draw keypoints + cv2.circle(frame, shoulder_coords, 10, (0, 255, 0), -1) # Shoulder + cv2.circle(frame, elbow_coords, 10, (255, 0, 0), -1) # Elbow + cv2.circle(frame, wrist_coords, 10, (0, 0, 255), -1) # Wrist + + # Display the frame + cv2.imshow('Dynamic Bowling Trajectory', frame) + + if cv2.waitKey(10) & 0xFF == ord('q'): + break + +cap.release() +cv2.destroyAllWindows() + + + From 152f53e0141d5d24b2d4d937f0418c3b96b27726 Mon Sep 17 00:00:00 2001 From: Tithi Joshi Date: Mon, 16 Feb 2026 11:26:16 +0530 Subject: [PATCH 02/44] refactor: improve structure and safety of auto clicker script --- Auto-Clicker/auto_clicker.py | 57 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/Auto-Clicker/auto_clicker.py b/Auto-Clicker/auto_clicker.py index c0c9d23..76f698b 100644 --- a/Auto-Clicker/auto_clicker.py +++ b/Auto-Clicker/auto_clicker.py @@ -2,33 +2,48 @@ import keyboard import time -clicking = False +def run_auto_clicker(delay: float = 0.01) -> None: + """ + Runs an auto clicker that can be controlled with keyboard hotkeys. -def start_clicking(): - global clicking - clicking = True - print("Auto clicker started") + Controls: + - Press 'S' to start clicking + - Press 'E' to stop clicking + - Press 'Q' to quit + """ + clicking = False + def start_clicking(): + nonlocal clicking + clicking = True + print("✅ Auto clicker started") -def stop_clicking(): - global clicking - clicking = False - print("Auto clicker stopped") + def stop_clicking(): + nonlocal clicking + clicking = False + print("⏹ Auto clicker stopped") + + keyboard.add_hotkey("s", start_clicking) + keyboard.add_hotkey("e", stop_clicking) + + print("Press 'S' to start clicking") + print("Press 'E' to stop clicking") + print("Press 'Q' to quit") + try: + while True: + if clicking: + pyautogui.click() + time.sleep(delay) -keyboard.add_hotkey("s", start_clicking) -keyboard.add_hotkey("e", stop_clicking) + if keyboard.is_pressed("q"): + print("👋 Exiting program") + break -print("Press 'S' to start clicking") -print("Press 'E' to stop clicking") -print("Press 'Q' to quit") + except KeyboardInterrupt: + print("\nProgram interrupted by user.") -while True: - if clicking: - pyautogui.click() - time.sleep(0.001) - if keyboard.is_pressed("q"): - print("Exiting program") - break +if __name__ == "__main__": + run_auto_clicker() From 5c12671766b863f73b91743da75c99b1b13f9af7 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 20 Feb 2026 11:41:31 +0300 Subject: [PATCH 03/44] Initil commit. This is a script used to either generate a password or check strength of your password. --- securepass/README.md | 117 ++++++++++++++++++++++++++++++++++++++ securepass/password.py | 126 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 securepass/README.md create mode 100644 securepass/password.py diff --git a/securepass/README.md b/securepass/README.md new file mode 100644 index 0000000..e79364b --- /dev/null +++ b/securepass/README.md @@ -0,0 +1,117 @@ +# Secure Password Manager + +A Python utility for generating secure passwords and checking the strength of existing passwords. + +## Features + +- **Password Generator**: Create secure passwords with multiple options + - Mix of numbers, letters, and symbols (Recommended) + - Numbers only + - Letters only + - Symbols only + - Customizable length (4-20 characters) + +- **Password Strength Checker**: Analyze password quality and get recommendations + - Check password length + - Analyze character composition (uppercase, lowercase, numbers, symbols) + - Receive suggestions for improvement + - Detailed password report + +## Installation + +No external dependencies are required. This script uses only Python standard library modules. + +```bash +# Clone or download the repository +# Navigate to the securepass directory +cd securepass + +# Run the script +python password.py +``` + +## Usage + +Run the script and follow the interactive prompts: + +```bash +python password.py +``` + +### Main Menu + +You'll be presented with two options: +1. **Generate a secure password** - Create a new password with custom specifications +2. **Check strength of my password** - Analyze an existing password + +### Generate Password Workflow + +1. Select the password type (1-4) +2. Enter desired length (4-20 characters) +3. View your generated password +4. Optionally get a detailed password report + +### Check Password Strength Workflow + +1. Enter the password you want to check +2. Receive a detailed report with recommendations + +## Example Output + +``` +What would you like to do: +1 Generate a secure password +2 Check strength of my password +> 1 + +Choose password type: +1 Mix of numbers, letters and symbols (Recommended) +2 Numbers only password +3 Letters only password +4 Symbols only password +> 1 + +Enter your desired length (between 4 and 20): 12 +Here is your password: aB3!xK9$mQ2@ + +Would you like a report for this password? (y/n): y +The password has a length of 12 characters, which meets or exceeds the recommended 8. +It has 2 uppercase letter(s), 2 lowercase letter(s), 3 number(s), and 3 symbol(s). +This password has a good mix of character types. +``` + +## Password Strength Criteria + +The password strength checker evaluates: + +- **Length**: Recommends a minimum of 8 characters +- **Character Diversity**: Checks for presence of: + - Uppercase letters + - Lowercase letters + - Numbers + - Symbols + +## Functions + +- `generate_number_only(length)` - Generates password with digits only +- `generate_letters_only(length)` - Generates password with letters only +- `generate_symbols_only(length)` - Generates password with symbols only +- `mix_of_all(length)` - Generates password with mix of all character types +- `password_report(password)` - Analyzes password strength and returns report + +## Requirements + +- Python 3.x +- No external packages required + +## Best Practices + +- Use "Mix of numbers, letters and symbols" for the strongest passwords +- Maintain a minimum length of 12 characters for sensitive accounts +- Store generated passwords securely (consider using a password manager) +- Regularly update passwords for important accounts +- Never share passwords or store them in plain text + +## License + +This project is part of the Python-Projects repository by Grow-with-Open-Source. diff --git a/securepass/password.py b/securepass/password.py new file mode 100644 index 0000000..e617355 --- /dev/null +++ b/securepass/password.py @@ -0,0 +1,126 @@ +import random +import string + + +def main(): + while True: + option = input( + "What would you like to do:\n" + "1 Generate a secure password\n" + "2 Check strength of my password\n> " + ) + if option not in ("1", "2"): + print("Please choose 1 or 2.") + continue + break + + if option == "1": + while True: + try: + choice = int( + input( + "Choose password type:\n" + "1 Mix of numbers, letters and symbols (Recommended)\n" + "2 Numbers only password\n" + "3 Letters only password\n" + "4 Symbols only password\n> " + ) + ) + length = int(input("Enter your desired length (between 4 and 20): ")) + except ValueError: + print("Invalid input, enter numbers only.") + continue + + if choice not in (1, 2, 3, 4) or length not in range(4, 21): + print("Invalid input, try again.") + continue + break + + if choice == 1: + passwd = mix_of_all(length) + elif choice == 2: + passwd = generate_number_only(length) + elif choice == 3: + passwd = generate_letters_only(length) + else: + passwd = generate_symbols_only(length) + + print("Here is your password:", passwd) + + if input("Would you like a report for this password? (y/n): ").lower() == "y": + print(password_report(passwd)) + + else: # option == "2" + existing = input("Enter the password you want to check: ") + print(password_report(existing)) + + +def generate_number_only(length): + digits = string.digits + return "".join(random.choice(digits) for _ in range(length)) + + +def generate_letters_only(length): + letters = string.ascii_letters + return "".join(random.choice(letters) for _ in range(length)) + + +def generate_symbols_only(length): + symbols = "!@#$%^&*()-_=+[]{};:,.<>?/\\|" + return "".join(random.choice(symbols) for _ in range(length)) + + +def mix_of_all(length): + pool = string.ascii_letters + string.digits + "!@#$%^&*()-_=+[]{};:,.<>?/\\|" + return "".join(random.choice(pool) for _ in range(length)) + + +def password_report(password: str) -> str: + recommended_length = 8 + + length = len(password) + upper = sum(1 for ch in password if ch.isupper()) + lower = sum(1 for ch in password if ch.islower()) + digits = sum(1 for ch in password if ch.isdigit()) + symbols = sum(1 for ch in password if not ch.isalnum()) + + parts = [] + + # Length report + diff = recommended_length - length + if diff > 0: + parts.append( + f"The password has a length of {length} characters, {diff} less than the recommended {recommended_length}." + ) + else: + parts.append( + f"The password has a length of {length} characters, which meets or exceeds the recommended {recommended_length}." + ) + + # Composition report + parts.append( + f"It has {upper} uppercase letter(s), {lower} lowercase letter(s), {digits} number(s), and {symbols} symbol(s)." + ) + + suggestions = [] + if upper == 0: + suggestions.append("add at least one uppercase letter") + if lower == 0: + suggestions.append("add at least one lowercase letter") + if digits == 0: + suggestions.append("add at least one number") + if symbols == 0: + suggestions.append("add a symbol for extra strength") + + if suggestions: + parts.append( + "To improve this password, you could " + ", ".join(suggestions) + "." + ) + else: + parts.append("This password has a good mix of character types.") + + return " ".join(parts) + + +if __name__ == '__main__': + main() From cd3c6611044fbcc16532dd0124a96918b2694849 Mon Sep 17 00:00:00 2001 From: Tithi Joshi Date: Sat, 21 Feb 2026 16:45:48 +0530 Subject: [PATCH 04/44] Refactor Pomodoro timer with countdown function Removed fragile modulo-based break detection - Introduced modular countdown function - Implemented session-based break handling - Added input validation and negative value checks - Added graceful KeyboardInterrupt handling - Improved readability and maintainability --- Pomodoro-Timer/pomodoro.py | 99 ++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/Pomodoro-Timer/pomodoro.py b/Pomodoro-Timer/pomodoro.py index 887c786..1b3cdf6 100644 --- a/Pomodoro-Timer/pomodoro.py +++ b/Pomodoro-Timer/pomodoro.py @@ -1,43 +1,72 @@ import time import datetime -# Create a function that acts as a countdown -def pomodoro_timer(task, h, m, s): - # Calculate the total number of seconds - total_seconds = h * 3600 + m * 60 + s - # Counter to keep track of the breaks - break_count = 0 +FOCUS_DURATION = 25 * 60 # 25 minutes +SHORT_BREAK = 5 * 60 # 5 minutes +LONG_BREAK = 20 * 60 # 20 minutes +SESSIONS_BEFORE_LONG_BREAK = 4 - while total_seconds > 0: - # Timer represents time left on the countdown - timer = datetime.timedelta(seconds=total_seconds) - # Prints the time left on the timer - print(f"Focusing on {task}... Session time left: {timer}", end="\r") - # Delays the program one second +def countdown(label, seconds): + """Runs a countdown timer.""" + while seconds > 0: + timer = datetime.timedelta(seconds=seconds) + print(f"{label} - Time left: {timer}", end="\r") time.sleep(1) + seconds -= 1 + print(f"\n{label} completed!\n") + + +def pomodoro_timer(task, total_seconds): + """Runs Pomodoro cycles based on total time.""" + sessions_completed = 0 + + while total_seconds > 0: + print(f"\nStarting focus session for: {task}") + session_time = min(FOCUS_DURATION, total_seconds) + countdown("Focus Session", session_time) + total_seconds -= session_time + sessions_completed += 1 + + if total_seconds <= 0: + break + + if sessions_completed % SESSIONS_BEFORE_LONG_BREAK == 0: + print("Starting Long Break...") + countdown("Long Break", LONG_BREAK) + else: + print("Starting Short Break...") + countdown("Short Break", SHORT_BREAK) + + print("Task Completed Successfully 🎉") + + +def get_user_input(): + """Handles validated user input.""" + try: + task = input("Enter the task to focus on: ") + + h = int(input("Enter hours: ")) + m = int(input("Enter minutes: ")) + s = int(input("Enter seconds: ")) + + if h < 0 or m < 0 or s < 0: + raise ValueError("Time values cannot be negative.") + + return task, h * 3600 + m * 60 + s + + except ValueError as e: + print(f"Invalid input: {e}") + return None, None + + +if __name__ == "__main__": + try: + task, total_seconds = get_user_input() + + if task and total_seconds: + pomodoro_timer(task, total_seconds) - # Reduces total time by one second - total_seconds -= 1 - - # Check if it's time for a break (only for the first 4 breaks) - if total_seconds > 0 and break_count < 4 and total_seconds % 1500 == 0: - print("\nNow on a short break!") - time.sleep(300) # Short break for 5 minutes - break_count += 1 - - # Check if it's time for a long break (after 4 sessions) - elif total_seconds > 0 and break_count == 4 and total_seconds % 1500 == 0: - print("\nNow on a long break!") - time.sleep(1200) # Long break for 20 minutes - break_count = 0 # Reset the break count for the next cycle - - print("\nTask Completed") - -# Inputs for hours, minutes, and seconds on the timer -task = input("Enter the task to focus on: ") -h = int(input("Enter the time in hours: ")) -m = int(input("Enter the time in minutes: ")) -s = int(input("Enter the time in seconds: ")) -pomodoro_timer(task, h, m, s) + except KeyboardInterrupt: + print("\nTimer stopped manually.") From dd21662fa85c1bd2653025a3b3643ff43c0079bc Mon Sep 17 00:00:00 2001 From: moon Date: Mon, 23 Feb 2026 21:41:32 +0000 Subject: [PATCH 05/44] add encryption project --- Encrypt_Message/README.md | 6 ++++ Encrypt_Message/encryption/aes.py | 13 ++++++++ Encrypt_Message/encryption/sha.py | 5 +++ Encrypt_Message/main.py | 54 +++++++++++++++++++++++++++++++ Encrypt_Message/requirements.txt | 1 + 5 files changed, 79 insertions(+) create mode 100644 Encrypt_Message/README.md create mode 100644 Encrypt_Message/encryption/aes.py create mode 100644 Encrypt_Message/encryption/sha.py create mode 100644 Encrypt_Message/main.py create mode 100644 Encrypt_Message/requirements.txt diff --git a/Encrypt_Message/README.md b/Encrypt_Message/README.md new file mode 100644 index 0000000..93db246 --- /dev/null +++ b/Encrypt_Message/README.md @@ -0,0 +1,6 @@ +# Encrypt Message + +A bad made Encrypt code that can Encrypt with: +SHA-256 +AES-128 +More soon \ No newline at end of file diff --git a/Encrypt_Message/encryption/aes.py b/Encrypt_Message/encryption/aes.py new file mode 100644 index 0000000..9fccb38 --- /dev/null +++ b/Encrypt_Message/encryption/aes.py @@ -0,0 +1,13 @@ +from Crypto.Cipher import AES + +def aes_enc(message: str, key: bytes): + mess = message.encode() + cipher = AES.new(key, AES.MODE_EAX) + nonce = cipher.nonce + mess_cipher, tag = cipher.encrypt_and_digest(mess) + return mess_cipher, nonce + +def aes_desc(message: bytes, key: bytes, nonce: bytes): + + cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) + return cipher.decrypt(message) \ No newline at end of file diff --git a/Encrypt_Message/encryption/sha.py b/Encrypt_Message/encryption/sha.py new file mode 100644 index 0000000..8d5eee3 --- /dev/null +++ b/Encrypt_Message/encryption/sha.py @@ -0,0 +1,5 @@ +import hashlib + +def sha256_enc(message: str): + + return hashlib.sha256(message.encode()).hexdigest() \ No newline at end of file diff --git a/Encrypt_Message/main.py b/Encrypt_Message/main.py new file mode 100644 index 0000000..30b282a --- /dev/null +++ b/Encrypt_Message/main.py @@ -0,0 +1,54 @@ +from encryption import sha, aes +import os + +def main(): + """ + This is the entry point of this Encryption Message + """ + + print("""Welcome to Encrypt Message!\n + Your options are:\n + 1 - AES\n + 2 - SHA\n +""") + + option = int(input()) + + match option: + case 1: + + print("""Do you want to encrypt or decrypt a message?\n + 1 - Encrypt + 2 - Decrypt""") + + enc_dec = int(input()) + + if enc_dec == 1: + + message = input("Which message you want to encrypt? ") + key = os.urandom(16) + + print(f"Your key is {key}\n*Save it!*") + + enc_mess, nonce = aes.aes_enc(message, key) + + print(f"{enc_mess}\n{nonce}\n*Save this*") + else: + message = eval(input("What's the message you want to decrypt? ")) + key = eval(input("What's the key? ")) + nonce = eval(input("What's the nonce? ")) + + desc_mess = aes.aes_desc(message, key, nonce) + + print(f"{desc_mess}") + + case 2: + message = input("What's the message you want to hide? (This method is unreversible)") + + enc_mess = sha.sha256_enc(message) + + print(f"{enc_mess}") + +if __name__ == "__main__": + main() + diff --git a/Encrypt_Message/requirements.txt b/Encrypt_Message/requirements.txt new file mode 100644 index 0000000..c21b6ec --- /dev/null +++ b/Encrypt_Message/requirements.txt @@ -0,0 +1 @@ +pycryptodome \ No newline at end of file From cbf6192cbaa0ff7847d3aa2dea95a170464a018e Mon Sep 17 00:00:00 2001 From: moon Date: Tue, 24 Feb 2026 19:09:21 +0000 Subject: [PATCH 06/44] added encryption project This is a project to make examples of how to encrypt using specific methods listed in the README --- Encrypt_Message/README.md | 6 -- Encrypt_Message/encryption/aes.py | 13 ----- Encrypt_Message/encryption/sha.py | 5 -- Encrypt_Message/main.py | 54 ------------------ Encrypt_Message/requirements.txt | 1 - Encryption_Project/README.md | 9 +++ Encryption_Project/encryption/aes.py | 22 ++++++++ Encryption_Project/encryption/base64.py | 16 ++++++ Encryption_Project/encryption/sha.py | 10 ++++ Encryption_Project/main.py | 73 +++++++++++++++++++++++++ Encryption_Project/requirements.txt | 1 + 11 files changed, 131 insertions(+), 79 deletions(-) delete mode 100644 Encrypt_Message/README.md delete mode 100644 Encrypt_Message/encryption/aes.py delete mode 100644 Encrypt_Message/encryption/sha.py delete mode 100644 Encrypt_Message/main.py delete mode 100644 Encrypt_Message/requirements.txt create mode 100644 Encryption_Project/README.md create mode 100644 Encryption_Project/encryption/aes.py create mode 100644 Encryption_Project/encryption/base64.py create mode 100644 Encryption_Project/encryption/sha.py create mode 100644 Encryption_Project/main.py create mode 100644 Encryption_Project/requirements.txt diff --git a/Encrypt_Message/README.md b/Encrypt_Message/README.md deleted file mode 100644 index 93db246..0000000 --- a/Encrypt_Message/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Encrypt Message - -A bad made Encrypt code that can Encrypt with: -SHA-256 -AES-128 -More soon \ No newline at end of file diff --git a/Encrypt_Message/encryption/aes.py b/Encrypt_Message/encryption/aes.py deleted file mode 100644 index 9fccb38..0000000 --- a/Encrypt_Message/encryption/aes.py +++ /dev/null @@ -1,13 +0,0 @@ -from Crypto.Cipher import AES - -def aes_enc(message: str, key: bytes): - mess = message.encode() - cipher = AES.new(key, AES.MODE_EAX) - nonce = cipher.nonce - mess_cipher, tag = cipher.encrypt_and_digest(mess) - return mess_cipher, nonce - -def aes_desc(message: bytes, key: bytes, nonce: bytes): - - cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) - return cipher.decrypt(message) \ No newline at end of file diff --git a/Encrypt_Message/encryption/sha.py b/Encrypt_Message/encryption/sha.py deleted file mode 100644 index 8d5eee3..0000000 --- a/Encrypt_Message/encryption/sha.py +++ /dev/null @@ -1,5 +0,0 @@ -import hashlib - -def sha256_enc(message: str): - - return hashlib.sha256(message.encode()).hexdigest() \ No newline at end of file diff --git a/Encrypt_Message/main.py b/Encrypt_Message/main.py deleted file mode 100644 index 30b282a..0000000 --- a/Encrypt_Message/main.py +++ /dev/null @@ -1,54 +0,0 @@ -from encryption import sha, aes -import os - -def main(): - """ - This is the entry point of this Encryption Message - """ - - print("""Welcome to Encrypt Message!\n - Your options are:\n - 1 - AES\n - 2 - SHA\n -""") - - option = int(input()) - - match option: - case 1: - - print("""Do you want to encrypt or decrypt a message?\n - 1 - Encrypt - 2 - Decrypt""") - - enc_dec = int(input()) - - if enc_dec == 1: - - message = input("Which message you want to encrypt? ") - key = os.urandom(16) - - print(f"Your key is {key}\n*Save it!*") - - enc_mess, nonce = aes.aes_enc(message, key) - - print(f"{enc_mess}\n{nonce}\n*Save this*") - else: - message = eval(input("What's the message you want to decrypt? ")) - key = eval(input("What's the key? ")) - nonce = eval(input("What's the nonce? ")) - - desc_mess = aes.aes_desc(message, key, nonce) - - print(f"{desc_mess}") - - case 2: - message = input("What's the message you want to hide? (This method is unreversible)") - - enc_mess = sha.sha256_enc(message) - - print(f"{enc_mess}") - -if __name__ == "__main__": - main() - diff --git a/Encrypt_Message/requirements.txt b/Encrypt_Message/requirements.txt deleted file mode 100644 index c21b6ec..0000000 --- a/Encrypt_Message/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pycryptodome \ No newline at end of file diff --git a/Encryption_Project/README.md b/Encryption_Project/README.md new file mode 100644 index 0000000..1992a90 --- /dev/null +++ b/Encryption_Project/README.md @@ -0,0 +1,9 @@ +# Encryption Project + +For now this project can only encrypt messages using the following methods: + +* SHA-256 +* AES-128 +* Base64 + +*If you want to understand how this works, this project comments all around it to make sure you understand what's happening* diff --git a/Encryption_Project/encryption/aes.py b/Encryption_Project/encryption/aes.py new file mode 100644 index 0000000..c284215 --- /dev/null +++ b/Encryption_Project/encryption/aes.py @@ -0,0 +1,22 @@ +# Let's start with AES +# AES is a type of encryption used mainly for things that require certain level of safety and later will be used +# There is a specific thing you shouldn't encrypt with AES that's Passkeys +# For passkeys you will use a method showed later that are the Hash Methods + +# In this example we using pycryptodome + +from Crypto.Cipher import AES + +def encrypt_aes(message: str, key: str): + encrypt_cipher = AES.new(key, AES.MODE_EAX) # This is the "configuration" for the encryption + + nonce = encrypt_cipher.nonce # Nonce aka Number Once is basically what makes the key random + + encrypted_message = encrypt_cipher.encrypt_and_digest(message) # Here we are truly encrypting the message + + return encrypted_message, nonce + +def decrypt_aes(message: bytes, key: bytes, nonce: bytes): + decrypt_cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) # Here we are Saying what's the key, type of encryption and nonce + decrypted_message = decrypt_cipher.decrypt(message) + return decrypted_message diff --git a/Encryption_Project/encryption/base64.py b/Encryption_Project/encryption/base64.py new file mode 100644 index 0000000..8bf15b4 --- /dev/null +++ b/Encryption_Project/encryption/base64.py @@ -0,0 +1,16 @@ +# Let's start +# Base64 is NOT a safe way to encrypt important things, it's used to encrypt binary data to text and doesn't have a key such as AES +# If you pretend encrypting something that you need to know later you should use AES +# Else you just want to encrypt something and doesn't care about the privacy Base64 might be a good choice + +# In this example we are using a pre-installed module from Python called "base64" + +import base64 + +def encrypt_base64(message: str): + encrypt_message = base64.b64encode(message.encode()).decode() + return encrypt_message + +def decrypt_base64(message: str): + decrypt_message = base64.b64decode(message).decode('utf-8') + return decrypt_message \ No newline at end of file diff --git a/Encryption_Project/encryption/sha.py b/Encryption_Project/encryption/sha.py new file mode 100644 index 0000000..1892060 --- /dev/null +++ b/Encryption_Project/encryption/sha.py @@ -0,0 +1,10 @@ +# Let's start with Hashes! (more specifically SHA256) +# Hashes are a way to encrypt thing in a irreversible way +# This means if you encrypt something using Hash Methods there is no way to know the content + +# In this example we using pre-installed module called "hashlib" + +import hashlib + +def encryption_sha(message: str): + return hashlib.sha256().digest() # This makes the encryption in SHA-256. This is the usually how your passkeys are encrypted diff --git a/Encryption_Project/main.py b/Encryption_Project/main.py new file mode 100644 index 0000000..d0b72d7 --- /dev/null +++ b/Encryption_Project/main.py @@ -0,0 +1,73 @@ +from encryption import sha, aes, base64 +import os + +def main(): + while True: + print("""Welcome to Encryption Project\n + 1 - SHA256\n + 2 - AES\n + 3 - Base64\n + 4 - Quit\n + More soon!\n""") + + encrypt_choice = int(input()) + + match encrypt_choice: + case 1: + message_to_encrypt = input("What's the message you want to encrypt?: ") + + encrypted_message = sha.encryption_sha(message_to_encrypt) + + print(f"The encrypted message is: {encrypted_message}") + + case 2: + aes_choice = int(input("1 - Encrypt\n2 - Decrypt\n")) + + if aes_choice == 1: + message_to_encrypt = input("What's the message you want to encrypt? ").encode('utf-8') + key = os.urandom(16) # if you are confused, this just guarantee the key will have 16 bytes + + encrypted_message, nonce = aes.encrypt_aes(message_to_encrypt, key) + + print(f"Encrypted message: {encrypted_message}\nnonce: {nonce}\nkey: {key}\n *Save those!*") + elif aes_choice == 2: + message_to_decrypt = eval(input("What's the message to decrypt? ")) + key = eval(input("What's the key? ")) + nonce = eval(input("What's the nonce? ")) + + decrypted_message = aes.decrypt_aes(message_to_decrypt, key, nonce) + + print(f"Message: {decrypted_message}") + + else: + print("Option does not exist") + + case 3: + base_choice = int(input("1 - Encrypt\n2 - Decrypt\n")) + + if base_choice == 1: + message_to_encrypt = input("What's the message you want to encrypt? ") + + encrypted_message = base64.encrypt_base64(message_to_encrypt) + + print(f"Message: {encrypted_message}") + + elif base_choice == 2: + message_to_decrypt = input("What's the message to decrypt? ") + + decrypted_message = base64.decrypt_base64(message_to_decrypt) + + print(f"Message: {decrypted_message}") + + else: + print("Option does not exist") + + case 4: + print("Bye!") + break + + case _: + print("This option is not available") + +if __name__ == "__main__": + main() diff --git a/Encryption_Project/requirements.txt b/Encryption_Project/requirements.txt new file mode 100644 index 0000000..acdfd20 --- /dev/null +++ b/Encryption_Project/requirements.txt @@ -0,0 +1 @@ +pycryptodome From f83bd28eb5f9e83b8e4c3953007c047328441697 Mon Sep 17 00:00:00 2001 From: Tithi Joshi Date: Wed, 25 Feb 2026 14:41:48 +0530 Subject: [PATCH 07/44] Add scoreboard feature and improve game state handling Refactor Tic Tac Toe game code to improve structure and add score tracking. --- TIC_TAC_TOE/TIC_TAC_TOE.py | 195 +++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 94 deletions(-) diff --git a/TIC_TAC_TOE/TIC_TAC_TOE.py b/TIC_TAC_TOE/TIC_TAC_TOE.py index c71c8c4..c49d3f9 100644 --- a/TIC_TAC_TOE/TIC_TAC_TOE.py +++ b/TIC_TAC_TOE/TIC_TAC_TOE.py @@ -1,117 +1,124 @@ from tkinter import * -import tkinter.messagebox +import tkinter.messagebox as messagebox tk = Tk() tk.title("Tic Tac Toe") tk.configure(bg='yellow') +# Player names p1 = StringVar() p2 = StringVar() -player1_name = Entry(textvariable=p1, bd=5, bg='white', width=40) +player1_name = Entry(tk, textvariable=p1, bd=5, bg='white', width=40) player1_name.grid(row=1, column=1, columnspan=8) player2_name = Entry(tk, textvariable=p2, bd=5, bg='white', width=40) player2_name.grid(row=2, column=1, columnspan=8) -bclick = True -flag = 0 -current_player_name = p1.get() if p1.get() else 'X' - - -def disableButton(): - for i in range(3): - for j in range(3): - buttons[i][j].configure(state=DISABLED) - - -def checkForWin(): - for i in range(3): - if buttons[i][0]["text"] == buttons[i][1]["text"] == buttons[i][2]["text"] != " ": - buttons[i][0].config(bg="green") - buttons[i][1].config(bg="green") - buttons[i][2].config(bg="green") - disableButton() - winner_name = p1.get( - ) if buttons[i][0]['text'] == 'X' else p2.get() - if not winner_name: - winner_name = 'Player 1' if buttons[i][0]['text'] == 'X' else 'Player 2' - tkinter.messagebox.showinfo("Tic-Tac-Toe", f"{winner_name} wins!") +# Score tracking +score_p1 = 0 +score_p2 = 0 + +current_player = "X" +moves_count = 0 + + +def update_scoreboard(): + score_label.config( + text=f"{p1.get() or 'Player 1'} (X): {score_p1} | {p2.get() or 'Player 2'} (O): {score_p2}" + ) + + +def disable_buttons(): + for row in buttons: + for button in row: + button.config(state=DISABLED) + + +def check_winner(): + global score_p1, score_p2 + + win_positions = [ + [(0, 0), (0, 1), (0, 2)], + [(1, 0), (1, 1), (1, 2)], + [(2, 0), (2, 1), (2, 2)], + [(0, 0), (1, 0), (2, 0)], + [(0, 1), (1, 1), (2, 1)], + [(0, 2), (1, 2), (2, 2)], + [(0, 0), (1, 1), (2, 2)], + [(0, 2), (1, 1), (2, 0)] + ] + + for combo in win_positions: + if buttons[combo[0][0]][combo[0][1]]["text"] == \ + buttons[combo[1][0]][combo[1][1]]["text"] == \ + buttons[combo[2][0]][combo[2][1]]["text"] != " ": + + winner_symbol = buttons[combo[0][0]][combo[0][1]]["text"] + + if winner_symbol == "X": + score_p1 += 1 + winner_name = p1.get() or "Player 1" + else: + score_p2 += 1 + winner_name = p2.get() or "Player 2" + + update_scoreboard() + disable_buttons() + messagebox.showinfo("Winner", f"{winner_name} wins!") + return True + + return False + + +def button_click(row, col): + global current_player, moves_count + + if buttons[row][col]["text"] == " ": + buttons[row][col]["text"] = current_player + moves_count += 1 + + if check_winner(): return - if buttons[0][i]["text"] == buttons[1][i]["text"] == buttons[2][i]["text"] != " ": - buttons[0][i].config(bg="green") - buttons[1][i].config(bg="green") - buttons[2][i].config(bg="green") - disableButton() - winner_name = p1.get( - ) if buttons[0][i]['text'] == 'X' else p2.get() - if not winner_name: - winner_name = 'Player 1' if buttons[0][i]['text'] == 'X' else 'Player 2' - tkinter.messagebox.showinfo("Tic-Tac-Toe", f"{winner_name} wins!") + + if moves_count == 9: + messagebox.showinfo("Tie", "It's a Tie!") return - if buttons[0][0]["text"] == buttons[1][1]["text"] == buttons[2][2]["text"] != " ": - buttons[0][0].config(bg="green") - buttons[1][1].config(bg="green") - buttons[2][2].config(bg="green") - disableButton() - winner_name = p1.get() if buttons[0][0]['text'] == 'X' else p2.get() - if not winner_name: - winner_name = 'Player 1' if buttons[0][0]['text'] == 'X' else 'Player 2' - tkinter.messagebox.showinfo("Tic-Tac-Toe", f"{winner_name} wins!") - return - if buttons[0][2]["text"] == buttons[1][1]["text"] == buttons[2][0]["text"] != " ": - buttons[0][2].config(bg="green") - buttons[1][1].config(bg="green") - buttons[2][0].config(bg="green") - disableButton() - winner_name = p1.get() if buttons[0][2]['text'] == 'X' else p2.get() - if not winner_name: - winner_name = 'Player 1' if buttons[0][2]['text'] == 'X' else 'Player 2' - tkinter.messagebox.showinfo("Tic-Tac-Toe", f"{winner_name} wins!") - return - if flag == 8: - tkinter.messagebox.showinfo("Tic-Tac-Toe", "It's a Tie") - - -def resetGame(): - global bclick, flag, current_player_name - for i in range(3): - for j in range(3): - buttons[i][j]["text"] = " " - buttons[i][j].config(bg='black', state=NORMAL) - bclick = True - flag = 0 - current_player_name = p1.get() if p1.get() else 'X' - - -Label(tk, text="Player 1:", font='Times 20 bold', bg='yellow', - fg='black', height=1, width=8).grid(row=1, column=0) -Label(tk, text="Player 2:", font='Times 20 bold', bg='yellow', - fg='black', height=1, width=8).grid(row=2, column=0) -buttons = [[Button(tk, text=' ', font='Times 20 bold', bg='black', - fg='white', height=4, width=8) for _ in range(3)] for _ in range(3)] - - -def btnClick(button): - global bclick, flag - if button["text"] == " ": - if bclick: - button["text"] = "X" - else: - button["text"] = "O" - bclick = not bclick - flag += 1 - checkForWin() + + current_player = "O" if current_player == "X" else "X" else: - tkinter.messagebox.showinfo("Tic-Tac-Toe", "Button already Clicked!") + messagebox.showinfo("Invalid Move", "Button already clicked!") + + +def reset_game(): + global current_player, moves_count + current_player = "X" + moves_count = 0 + for row in buttons: + for button in row: + button.config(text=" ", state=NORMAL) + + +Label(tk, text="Player 1:", font='Times 20 bold', bg='yellow').grid(row=1, column=0) +Label(tk, text="Player 2:", font='Times 20 bold', bg='yellow').grid(row=2, column=0) + +buttons = [[Button(tk, text=" ", font='Times 20 bold', bg='black', + fg='white', height=4, width=8, + command=lambda r=i, c=j: button_click(r, c)) + for j in range(3)] for i in range(3)] for i in range(3): for j in range(3): - buttons[i][j].configure(command=lambda row=i, - col=j: btnClick(buttons[row][col])) buttons[i][j].grid(row=i + 3, column=j) -reset_button = Button(tk, text="Reset Game", font='Times 16 bold', - bg='white', fg='black', command=resetGame) -reset_button.grid(row=6, column=0, columnspan=3) + +score_label = Label(tk, text="", font='Times 14 bold', bg='yellow') +score_label.grid(row=6, column=0, columnspan=3) + +update_scoreboard() + +reset_btn = Button(tk, text="Reset Game", font='Times 16 bold', + command=reset_game) +reset_btn.grid(row=7, column=0, columnspan=3) + tk.mainloop() From 30fbcbf9f64b93d2554798bfca2deeb34ee8659f Mon Sep 17 00:00:00 2001 From: Tannistha Pal Date: Sat, 7 Mar 2026 22:16:11 +0530 Subject: [PATCH 08/44] Add move history panel to track game moves --- TIC_TAC_TOE/TIC_TAC_TOE.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/TIC_TAC_TOE/TIC_TAC_TOE.py b/TIC_TAC_TOE/TIC_TAC_TOE.py index c71c8c4..714acf0 100644 --- a/TIC_TAC_TOE/TIC_TAC_TOE.py +++ b/TIC_TAC_TOE/TIC_TAC_TOE.py @@ -16,6 +16,8 @@ bclick = True flag = 0 +move_history = [] +move_number = 1 current_player_name = p1.get() if p1.get() else 'X' @@ -74,11 +76,17 @@ def checkForWin(): def resetGame(): - global bclick, flag, current_player_name + global bclick, flag, current_player_name, move_history, move_number + for i in range(3): for j in range(3): buttons[i][j]["text"] = " " buttons[i][j].config(bg='black', state=NORMAL) + + move_history = [] + move_number = 1 + history_box.delete(1.0, END) + bclick = True flag = 0 current_player_name = p1.get() if p1.get() else 'X' @@ -92,16 +100,31 @@ def resetGame(): fg='white', height=4, width=8) for _ in range(3)] for _ in range(3)] -def btnClick(button): - global bclick, flag +def btnClick(row, col): + global bclick, flag, move_number + + button = buttons[row][col] + if button["text"] == " ": + if bclick: button["text"] = "X" + player = p1.get() if p1.get() else "Player 1" else: button["text"] = "O" + player = p2.get() if p2.get() else "Player 2" + + # cleaner move history + move = f"{move_number}. {player} -> ({row+1},{col+1})" + move_history.append(move) + history_box.insert(END, move + "\n") + + move_number += 1 + bclick = not bclick flag += 1 checkForWin() + else: tkinter.messagebox.showinfo("Tic-Tac-Toe", "Button already Clicked!") @@ -109,9 +132,13 @@ def btnClick(button): for i in range(3): for j in range(3): buttons[i][j].configure(command=lambda row=i, - col=j: btnClick(buttons[row][col])) + col=j: btnClick(row, col)) buttons[i][j].grid(row=i + 3, column=j) reset_button = Button(tk, text="Reset Game", font='Times 16 bold', bg='white', fg='black', command=resetGame) reset_button.grid(row=6, column=0, columnspan=3) +Label(tk, text="Move History", font='Times 16 bold', bg='yellow').grid(row=0, column=10, padx=80) + +history_box = Text(tk, height=18, width=28, font=("Consolas", 11)) +history_box.grid(row=1, column=10, rowspan=6, padx=80) tk.mainloop() From 303f68aa47e59bb93682811c71de32cb96a5d80e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 19 Mar 2026 15:54:54 +0000 Subject: [PATCH 09/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index ceebeab..2ec53f4 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -309,5 +309,14 @@ "62" ], "demo-path": "Motion-Detection" + }, + "Bowling-Action-Tracking": { + "contributor-name": [ + "musharrafhamraz" + ], + "pull-request-number": [ + "67" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking" } } \ No newline at end of file diff --git a/index.md b/index.md index b781402..0dc8ba6 100644 --- a/index.md +++ b/index.md @@ -41,6 +41,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Auto-Clicker | [BasselDar](https://github.com/BasselDar "goto BasselDar profile") | [#54](https://github.com/Grow-with-Open-Source/Python-Projects/pull/54 "visit pr #54") | [/Grow-with-Open-Source/Python-Projects/Auto-Clicker/](Auto-Clicker "view the result of Auto-Clicker") | | Number-Plate-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#58](https://github.com/Grow-with-Open-Source/Python-Projects/pull/58 "visit pr #58") | [/Grow-with-Open-Source/Python-Projects/Number-Plate-Detection/](Number-Plate-Detection "view the result of Number-Plate-Detection") | | Motion-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#62](https://github.com/Grow-with-Open-Source/Python-Projects/pull/62 "visit pr #62") | [/Grow-with-Open-Source/Python-Projects/Motion-Detection/](Motion-Detection "view the result of Motion-Detection") | +| Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | From a559f062f06eef278aa33ba2358b76bb015b1ada Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 19 Mar 2026 15:57:47 +0000 Subject: [PATCH 10/44] Updated Contributors Details --- .github/data/contributors-log.json | 6 ++++-- index.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 2ec53f4..12feda1 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -285,10 +285,12 @@ }, "Auto-Clicker": { "contributor-name": [ - "BasselDar" + "BasselDar", + "Tithi234" ], "pull-request-number": [ - "54" + "54", + "70" ], "demo-path": "Auto-Clicker" }, diff --git a/index.md b/index.md index 0dc8ba6..0b30152 100644 --- a/index.md +++ b/index.md @@ -38,7 +38,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Temperature_Converter | [omprakash0702](https://github.com/omprakash0702 "goto omprakash0702 profile") | [#40](https://github.com/Grow-with-Open-Source/Python-Projects/pull/40 "visit pr #40") | [/Grow-with-Open-Source/Python-Projects/Temperature_Converter/](Temperature_Converter "view the result of Temperature_Converter") | | Image_watermark_Adder | [ramanuj-droid](https://github.com/ramanuj-droid "goto ramanuj-droid profile") | [#45](https://github.com/Grow-with-Open-Source/Python-Projects/pull/45 "visit pr #45") | [/Grow-with-Open-Source/Python-Projects/Image_watermark_Adder/](Image_watermark_Adder "view the result of Image_watermark_Adder") | | Binary-Gene-Classifier-Model | [venkamita](https://github.com/venkamita "goto venkamita profile") | [#49](https://github.com/Grow-with-Open-Source/Python-Projects/pull/49 "visit pr #49") | [/Grow-with-Open-Source/Python-Projects/Binary-Gene-Classifier-Model/](Binary-Gene-Classifier-Model "view the result of Binary-Gene-Classifier-Model") | -| Auto-Clicker | [BasselDar](https://github.com/BasselDar "goto BasselDar profile") | [#54](https://github.com/Grow-with-Open-Source/Python-Projects/pull/54 "visit pr #54") | [/Grow-with-Open-Source/Python-Projects/Auto-Clicker/](Auto-Clicker "view the result of Auto-Clicker") | +| Auto-Clicker | [BasselDar](https://github.com/BasselDar "goto BasselDar profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#54](https://github.com/Grow-with-Open-Source/Python-Projects/pull/54 "visit pr #54"), [#70](https://github.com/Grow-with-Open-Source/Python-Projects/pull/70 "visit pr #70") | [/Grow-with-Open-Source/Python-Projects/Auto-Clicker/](Auto-Clicker "view the result of Auto-Clicker") | | Number-Plate-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#58](https://github.com/Grow-with-Open-Source/Python-Projects/pull/58 "visit pr #58") | [/Grow-with-Open-Source/Python-Projects/Number-Plate-Detection/](Number-Plate-Detection "view the result of Number-Plate-Detection") | | Motion-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#62](https://github.com/Grow-with-Open-Source/Python-Projects/pull/62 "visit pr #62") | [/Grow-with-Open-Source/Python-Projects/Motion-Detection/](Motion-Detection "view the result of Motion-Detection") | | Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | From 195b740fe3b766fab22b69b44437551942a1541c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 19 Mar 2026 16:44:34 +0000 Subject: [PATCH 11/44] Updated Contributors Details --- .github/data/contributors-log.json | 6 ++++-- index.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 12feda1..b99d3ce 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -150,10 +150,12 @@ }, "Pomodoro-Timer": { "contributor-name": [ - "adedayoprcs" + "adedayoprcs", + "Tithi234" ], "pull-request-number": [ - "21" + "21", + "73" ], "demo-path": "Pomodoro-Timer" }, diff --git a/index.md b/index.md index 0b30152..4130bc4 100644 --- a/index.md +++ b/index.md @@ -24,7 +24,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | File_Organizer | [adedayoprcs](https://github.com/adedayoprcs "goto adedayoprcs profile") | [#15](https://github.com/Grow-with-Open-Source/Python-Projects/pull/15 "visit pr #15") | [/Grow-with-Open-Source/Python-Projects/File_Organizer/](File_Organizer "view the result of File_Organizer") | | Number-Guess | [adedayoprcs](https://github.com/adedayoprcs "goto adedayoprcs profile"), [sheylaghost](https://github.com/sheylaghost "goto sheylaghost profile"), [Achi-Vyshnavi](https://github.com/Achi-Vyshnavi "goto Achi-Vyshnavi profile") | [#19](https://github.com/Grow-with-Open-Source/Python-Projects/pull/19 "visit pr #19"), [#43](https://github.com/Grow-with-Open-Source/Python-Projects/pull/43 "visit pr #43"), [#57](https://github.com/Grow-with-Open-Source/Python-Projects/pull/57 "visit pr #57") | [/Grow-with-Open-Source/Python-Projects/Number-Guess/](Number-Guess "view the result of Number-Guess") | | Remove-Empty-Lines | [adedayoprcs](https://github.com/adedayoprcs "goto adedayoprcs profile") | [#20](https://github.com/Grow-with-Open-Source/Python-Projects/pull/20 "visit pr #20") | [/Grow-with-Open-Source/Python-Projects/Remove-Empty-Lines/](Remove-Empty-Lines "view the result of Remove-Empty-Lines") | -| Pomodoro-Timer | [adedayoprcs](https://github.com/adedayoprcs "goto adedayoprcs profile") | [#21](https://github.com/Grow-with-Open-Source/Python-Projects/pull/21 "visit pr #21") | [/Grow-with-Open-Source/Python-Projects/Pomodoro-Timer/](Pomodoro-Timer "view the result of Pomodoro-Timer") | +| Pomodoro-Timer | [adedayoprcs](https://github.com/adedayoprcs "goto adedayoprcs profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#21](https://github.com/Grow-with-Open-Source/Python-Projects/pull/21 "visit pr #21"), [#73](https://github.com/Grow-with-Open-Source/Python-Projects/pull/73 "visit pr #73") | [/Grow-with-Open-Source/Python-Projects/Pomodoro-Timer/](Pomodoro-Timer "view the result of Pomodoro-Timer") | | {others} | [iamwatchdogs](https://github.com/iamwatchdogs "goto iamwatchdogs profile") | [#22](https://github.com/Grow-with-Open-Source/Python-Projects/pull/22 "visit pr #22") | [/Grow-with-Open-Source/Python-Projects/.github](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/.github "view the result of {others}") | | 3d_pose_estimation | [mahipalimkar](https://github.com/mahipalimkar "goto mahipalimkar profile") | [#23](https://github.com/Grow-with-Open-Source/Python-Projects/pull/23 "visit pr #23") | [/Grow-with-Open-Source/Python-Projects/3d_pose_estimation/](3d_pose_estimation "view the result of 3d_pose_estimation") | | Coin-Poison | [niharikah005](https://github.com/niharikah005 "goto niharikah005 profile"), [Achi-Vyshnavi](https://github.com/Achi-Vyshnavi "goto Achi-Vyshnavi profile") | [#24](https://github.com/Grow-with-Open-Source/Python-Projects/pull/24 "visit pr #24"), [#55](https://github.com/Grow-with-Open-Source/Python-Projects/pull/55 "visit pr #55") | [/Grow-with-Open-Source/Python-Projects/Coin-Poison/](Coin-Poison "view the result of Coin-Poison") | From 643dabc3abd821f405562dd2a0339d90fdeeb2a5 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 19 Mar 2026 16:53:32 +0000 Subject: [PATCH 12/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index b99d3ce..82159f6 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -322,5 +322,14 @@ "67" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking" + }, + "Encryption_Project": { + "contributor-name": [ + "moonabys" + ], + "pull-request-number": [ + "75" + ], + "demo-path": "Encryption_Project" } } \ No newline at end of file diff --git a/index.md b/index.md index 4130bc4..4a79546 100644 --- a/index.md +++ b/index.md @@ -42,6 +42,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Number-Plate-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#58](https://github.com/Grow-with-Open-Source/Python-Projects/pull/58 "visit pr #58") | [/Grow-with-Open-Source/Python-Projects/Number-Plate-Detection/](Number-Plate-Detection "view the result of Number-Plate-Detection") | | Motion-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#62](https://github.com/Grow-with-Open-Source/Python-Projects/pull/62 "visit pr #62") | [/Grow-with-Open-Source/Python-Projects/Motion-Detection/](Motion-Detection "view the result of Motion-Detection") | | Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | +| Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | From a781572a74b948ecdd3d6aea2ca70d51663002c8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 19 Mar 2026 16:55:47 +0000 Subject: [PATCH 13/44] Updated Contributors Details --- .github/data/contributors-log.json | 6 ++++-- index.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 82159f6..6751d73 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -19,10 +19,12 @@ }, "TIC_TAC_TOE": { "contributor-name": [ - "06RAVI06" + "06RAVI06", + "Tithi234" ], "pull-request-number": [ - "7" + "7", + "77" ], "demo-path": "TIC_TAC_TOE" }, diff --git a/index.md b/index.md index 4a79546..a272ccc 100644 --- a/index.md +++ b/index.md @@ -11,7 +11,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | --- | --- | --- | --- | | {init} | [iamwatchdogs](https://github.com/iamwatchdogs "goto iamwatchdogs profile") | [#1](https://github.com/Grow-with-Open-Source/Python-Projects/pull/1 "visit pr #1") | [/Grow-with-Open-Source/Python-Projects/](https://github.com/Grow-with-Open-Source/Python-Projects "view the result of {init}") | | Language_Detector | [rahulch-1](https://github.com/rahulch-1 "goto rahulch-1 profile") | [#4](https://github.com/Grow-with-Open-Source/Python-Projects/pull/4 "visit pr #4") | [/Grow-with-Open-Source/Python-Projects/Language_Detector/](Language_Detector "view the result of Language_Detector") | -| TIC_TAC_TOE | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile") | [#7](https://github.com/Grow-with-Open-Source/Python-Projects/pull/7 "visit pr #7") | [/Grow-with-Open-Source/Python-Projects/TIC_TAC_TOE/](TIC_TAC_TOE "view the result of TIC_TAC_TOE") | +| TIC_TAC_TOE | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#7](https://github.com/Grow-with-Open-Source/Python-Projects/pull/7 "visit pr #7"), [#77](https://github.com/Grow-with-Open-Source/Python-Projects/pull/77 "visit pr #77") | [/Grow-with-Open-Source/Python-Projects/TIC_TAC_TOE/](TIC_TAC_TOE "view the result of TIC_TAC_TOE") | | Weather_Forecasting | [rahulch-1](https://github.com/rahulch-1 "goto rahulch-1 profile") | [#6](https://github.com/Grow-with-Open-Source/Python-Projects/pull/6 "visit pr #6") | [/Grow-with-Open-Source/Python-Projects/Weather_Forecasting/](Weather_Forecasting "view the result of Weather_Forecasting") | | Animal-Guess | [ShashiNova](https://github.com/ShashiNova "goto ShashiNova profile"), [Achi-Vyshnavi](https://github.com/Achi-Vyshnavi "goto Achi-Vyshnavi profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#8](https://github.com/Grow-with-Open-Source/Python-Projects/pull/8 "visit pr #8"), [#56](https://github.com/Grow-with-Open-Source/Python-Projects/pull/56 "visit pr #56"), [#69](https://github.com/Grow-with-Open-Source/Python-Projects/pull/69 "visit pr #69") | [/Grow-with-Open-Source/Python-Projects/Animal-Guess/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Animal-Guess "view the result of Animal-Guess") | | Wine-Quality-Analysis | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile") | [#9](https://github.com/Grow-with-Open-Source/Python-Projects/pull/9 "visit pr #9") | [/Grow-with-Open-Source/Python-Projects/Wine-Quality-Analysis/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Wine-Quality-Analysis "view the result of Wine-Quality-Analysis") | From 6e339f3c5308d4e4a85e59d169296a58f83c7c40 Mon Sep 17 00:00:00 2001 From: TANNISTHA PAL Date: Fri, 20 Mar 2026 00:00:04 +0530 Subject: [PATCH 14/44] minor enahncements --- TIC_TAC_TOE/TIC_TAC_TOE.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/TIC_TAC_TOE/TIC_TAC_TOE.py b/TIC_TAC_TOE/TIC_TAC_TOE.py index 0b893f2..bf0e07e 100644 --- a/TIC_TAC_TOE/TIC_TAC_TOE.py +++ b/TIC_TAC_TOE/TIC_TAC_TOE.py @@ -54,6 +54,10 @@ def check_winner(): buttons[combo[1][0]][combo[1][1]]["text"] == \ buttons[combo[2][0]][combo[2][1]]["text"] != " ": + # ✅ Highlight winning cells + for pos in combo: + buttons[pos[0]][pos[1]].config(bg="green") + winner_symbol = buttons[combo[0][0]][combo[0][1]]["text"] if winner_symbol == "X": @@ -75,7 +79,7 @@ def button_click(row, col): if buttons[row][col]["text"] == " ": buttons[row][col]["text"] = current_player - # ✅ YOUR FEATURE (Move History) + # ✅ Move History player = p1.get() if current_player == "X" else p2.get() player = player or ("Player 1" if current_player == "X" else "Player 2") @@ -83,8 +87,6 @@ def button_click(row, col): history_box.insert(END, move + "\n") move_number += 1 - - # ✅ GAME LOGIC moves_count += 1 if check_winner(): @@ -92,10 +94,14 @@ def button_click(row, col): if moves_count == 9: messagebox.showinfo("Tie", "It's a Tie!") + disable_buttons() # ✅ prevent extra clicks return current_player = "O" if current_player == "X" else "X" + else: + messagebox.showinfo("Invalid Move", "Button already clicked!") + def reset_game(): global current_player, moves_count, move_number @@ -107,9 +113,9 @@ def reset_game(): for i in range(3): for j in range(3): - buttons[i][j].config(text=" ", state=NORMAL) + buttons[i][j].config(text=" ", bg="black", state=NORMAL) -# Create buttons +# Create buttons (safe version) for i in range(3): for j in range(3): buttons[i][j] = Button( From 9ef154864cf454c08c3bc2a78973ebf9e538b917 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 20 Mar 2026 07:20:59 +0300 Subject: [PATCH 15/44] Update securepass/password.py Co-authored-by: Shamith Nakka --- securepass/password.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/securepass/password.py b/securepass/password.py index e617355..b68678c 100644 --- a/securepass/password.py +++ b/securepass/password.py @@ -79,10 +79,16 @@ def password_report(password: str) -> str: recommended_length = 8 length = len(password) - upper = sum(1 for ch in password if ch.isupper()) - lower = sum(1 for ch in password if ch.islower()) - digits = sum(1 for ch in password if ch.isdigit()) - symbols = sum(1 for ch in password if not ch.isalnum()) + upper = lower = digits = symbols = 0 + for letter in password: + if letter.isupper(): + upper += 1 + elif letter.islower(): + lower += 1 + elif letter.isdigit(): + digits += 1 + else: + symbols += 1 parts = [] From 18ec27d64a77db32166a99b86afe9d9aa9da5600 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 20 Mar 2026 07:21:14 +0300 Subject: [PATCH 16/44] Update securepass/password.py Co-authored-by: Shamith Nakka --- securepass/password.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/securepass/password.py b/securepass/password.py index b68678c..9dc51f9 100644 --- a/securepass/password.py +++ b/securepass/password.py @@ -3,16 +3,15 @@ def main(): - while True: + option = "" + while option not in ("1", "2"): option = input( "What would you like to do:\n" "1 Generate a secure password\n" - "2 Check strength of my password\n> " + "2 Check the strength of my password\n> " ) if option not in ("1", "2"): print("Please choose 1 or 2.") - continue - break if option == "1": while True: From 2ab490a508450c5cde75a0fdbf50d4bc0660ca68 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 20 Mar 2026 07:21:30 +0300 Subject: [PATCH 17/44] Update securepass/password.py Co-authored-by: Shamith Nakka --- securepass/password.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/securepass/password.py b/securepass/password.py index 9dc51f9..f663f47 100644 --- a/securepass/password.py +++ b/securepass/password.py @@ -14,7 +14,9 @@ def main(): print("Please choose 1 or 2.") if option == "1": - while True: + choice = None + length = None + while choice not in (1, 2, 3, 4): try: choice = int( input( @@ -25,15 +27,17 @@ def main(): "4 Symbols only password\n> " ) ) + if choice not in (1, 2, 3, 4): + print("Invalid choice, try again.") + except ValueError: + print("Invalid input, enter numbers only.") + while length not in range(4, 21): + try: length = int(input("Enter your desired length (between 4 and 20): ")) + if length not in range(4, 21): + print("Invalid length, try again.") except ValueError: print("Invalid input, enter numbers only.") - continue - - if choice not in (1, 2, 3, 4) or length not in range(4, 21): - print("Invalid input, try again.") - continue - break if choice == 1: passwd = mix_of_all(length) From 8d45c09d9e9a4cd3414a812c5eaa0f01a4dced21 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 20 Mar 2026 14:43:48 +0000 Subject: [PATCH 18/44] Updated Contributors Details --- .github/data/contributors-log.json | 6 ++++-- index.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 6751d73..43011b6 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -20,11 +20,13 @@ "TIC_TAC_TOE": { "contributor-name": [ "06RAVI06", - "Tithi234" + "Tithi234", + "paltannistha" ], "pull-request-number": [ "7", - "77" + "77", + "80" ], "demo-path": "TIC_TAC_TOE" }, diff --git a/index.md b/index.md index a272ccc..2287182 100644 --- a/index.md +++ b/index.md @@ -11,7 +11,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | --- | --- | --- | --- | | {init} | [iamwatchdogs](https://github.com/iamwatchdogs "goto iamwatchdogs profile") | [#1](https://github.com/Grow-with-Open-Source/Python-Projects/pull/1 "visit pr #1") | [/Grow-with-Open-Source/Python-Projects/](https://github.com/Grow-with-Open-Source/Python-Projects "view the result of {init}") | | Language_Detector | [rahulch-1](https://github.com/rahulch-1 "goto rahulch-1 profile") | [#4](https://github.com/Grow-with-Open-Source/Python-Projects/pull/4 "visit pr #4") | [/Grow-with-Open-Source/Python-Projects/Language_Detector/](Language_Detector "view the result of Language_Detector") | -| TIC_TAC_TOE | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#7](https://github.com/Grow-with-Open-Source/Python-Projects/pull/7 "visit pr #7"), [#77](https://github.com/Grow-with-Open-Source/Python-Projects/pull/77 "visit pr #77") | [/Grow-with-Open-Source/Python-Projects/TIC_TAC_TOE/](TIC_TAC_TOE "view the result of TIC_TAC_TOE") | +| TIC_TAC_TOE | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile"), [paltannistha](https://github.com/paltannistha "goto paltannistha profile") | [#7](https://github.com/Grow-with-Open-Source/Python-Projects/pull/7 "visit pr #7"), [#77](https://github.com/Grow-with-Open-Source/Python-Projects/pull/77 "visit pr #77"), [#80](https://github.com/Grow-with-Open-Source/Python-Projects/pull/80 "visit pr #80") | [/Grow-with-Open-Source/Python-Projects/TIC_TAC_TOE/](TIC_TAC_TOE "view the result of TIC_TAC_TOE") | | Weather_Forecasting | [rahulch-1](https://github.com/rahulch-1 "goto rahulch-1 profile") | [#6](https://github.com/Grow-with-Open-Source/Python-Projects/pull/6 "visit pr #6") | [/Grow-with-Open-Source/Python-Projects/Weather_Forecasting/](Weather_Forecasting "view the result of Weather_Forecasting") | | Animal-Guess | [ShashiNova](https://github.com/ShashiNova "goto ShashiNova profile"), [Achi-Vyshnavi](https://github.com/Achi-Vyshnavi "goto Achi-Vyshnavi profile"), [Tithi234](https://github.com/Tithi234 "goto Tithi234 profile") | [#8](https://github.com/Grow-with-Open-Source/Python-Projects/pull/8 "visit pr #8"), [#56](https://github.com/Grow-with-Open-Source/Python-Projects/pull/56 "visit pr #56"), [#69](https://github.com/Grow-with-Open-Source/Python-Projects/pull/69 "visit pr #69") | [/Grow-with-Open-Source/Python-Projects/Animal-Guess/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Animal-Guess "view the result of Animal-Guess") | | Wine-Quality-Analysis | [06RAVI06](https://github.com/06RAVI06 "goto 06RAVI06 profile") | [#9](https://github.com/Grow-with-Open-Source/Python-Projects/pull/9 "visit pr #9") | [/Grow-with-Open-Source/Python-Projects/Wine-Quality-Analysis/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Wine-Quality-Analysis "view the result of Wine-Quality-Analysis") | From a27c251bb7bf0f3650c73bbf175e3d21aca27ed9 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 20 Mar 2026 15:33:40 +0000 Subject: [PATCH 19/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 43011b6..62f9014 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -335,5 +335,14 @@ "75" ], "demo-path": "Encryption_Project" + }, + "securepass": { + "contributor-name": [ + "Lampard7crypt" + ], + "pull-request-number": [ + "72" + ], + "demo-path": "securepass" } } \ No newline at end of file diff --git a/index.md b/index.md index 2287182..cea0fd5 100644 --- a/index.md +++ b/index.md @@ -43,6 +43,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Motion-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#62](https://github.com/Grow-with-Open-Source/Python-Projects/pull/62 "visit pr #62") | [/Grow-with-Open-Source/Python-Projects/Motion-Detection/](Motion-Detection "view the result of Motion-Detection") | | Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | | Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | +| securepass | [Lampard7crypt](https://github.com/Lampard7crypt "goto Lampard7crypt profile") | [#72](https://github.com/Grow-with-Open-Source/Python-Projects/pull/72 "visit pr #72") | [/Grow-with-Open-Source/Python-Projects/securepass/](securepass "view the result of securepass") | From e762bb4f4f3576c1787ea70ecf2df900ee048dd5 Mon Sep 17 00:00:00 2001 From: moonabys <255314530+moonabys@users.noreply.github.com> Date: Sat, 28 Mar 2026 15:56:39 +0000 Subject: [PATCH 20/44] fixed small issue fixed sha.py not having proper function call --- Encryption_Project/encryption/sha.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Encryption_Project/encryption/sha.py b/Encryption_Project/encryption/sha.py index 1892060..d91a0b6 100644 --- a/Encryption_Project/encryption/sha.py +++ b/Encryption_Project/encryption/sha.py @@ -7,4 +7,5 @@ import hashlib def encryption_sha(message: str): - return hashlib.sha256().digest() # This makes the encryption in SHA-256. This is the usually how your passkeys are encrypted + encoded_message = message.encode() + return hashlib.sha256(encoded_message).digest() # This makes the encryption in SHA-256. This is the usually how your passkeys are encrypted From ad5ae9a1e7fabc344f212ca049d7ded85a85b075 Mon Sep 17 00:00:00 2001 From: Princee Date: Fri, 10 Apr 2026 12:15:17 +0545 Subject: [PATCH 21/44] Add input validation and success messaging --- Spell-Checker/Spell-Checker.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Spell-Checker/Spell-Checker.py b/Spell-Checker/Spell-Checker.py index 936b59d..bc64cb6 100644 --- a/Spell-Checker/Spell-Checker.py +++ b/Spell-Checker/Spell-Checker.py @@ -3,8 +3,14 @@ def check_spelling(): input_text = input_entry.get() - corrected_text = TextBlob(input_text).correct() - result_label.config(text="Corrected text: " + str(corrected_text)) + if not input_text: + result_label.config(text="TextBox cannot be empty!", fg="red") + return + corrected_text = str(TextBlob(input_text).correct()) + if input_text!=corrected_text: + result_label.config(text="Corrected text: " + corrected_text, fg="black") + return + result_label.config(text=f"{input_text} is Correct!", fg="green") def reset(): input_entry.delete(0, tk.END) From b2a9176984acbc9463764d1eab9c0bf8e6386be4 Mon Sep 17 00:00:00 2001 From: Princee Date: Fri, 10 Apr 2026 12:42:15 +0545 Subject: [PATCH 22/44] Relocate project to dedicated folder and restore default files --- Spell-Checker/Spell-Checker.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Spell-Checker/Spell-Checker.py b/Spell-Checker/Spell-Checker.py index bc64cb6..936b59d 100644 --- a/Spell-Checker/Spell-Checker.py +++ b/Spell-Checker/Spell-Checker.py @@ -3,14 +3,8 @@ def check_spelling(): input_text = input_entry.get() - if not input_text: - result_label.config(text="TextBox cannot be empty!", fg="red") - return - corrected_text = str(TextBlob(input_text).correct()) - if input_text!=corrected_text: - result_label.config(text="Corrected text: " + corrected_text, fg="black") - return - result_label.config(text=f"{input_text} is Correct!", fg="green") + corrected_text = TextBlob(input_text).correct() + result_label.config(text="Corrected text: " + str(corrected_text)) def reset(): input_entry.delete(0, tk.END) From 5e1c7748e33cc39d25c11721583d0a7c6356b6fe Mon Sep 17 00:00:00 2001 From: Princee Date: Fri, 10 Apr 2026 13:03:15 +0545 Subject: [PATCH 23/44] feat: implement core spell-checking logic using TextBlob --- Spell-Sense/logic.py | 12 ++++++++++++ Spell-Sense/requirements.txt | 1 + 2 files changed, 13 insertions(+) create mode 100644 Spell-Sense/logic.py create mode 100644 Spell-Sense/requirements.txt diff --git a/Spell-Sense/logic.py b/Spell-Sense/logic.py new file mode 100644 index 0000000..38bd71c --- /dev/null +++ b/Spell-Sense/logic.py @@ -0,0 +1,12 @@ +from textblob import TextBlob + +def get_correction(text): + if not text.strip(): + return None, False + + blob = TextBlob(text) + corrected = str(blob.correct()) + + # Check if the original matches the corrected version + is_correct = text.lower().strip() == corrected.lower().strip() + return corrected, is_correct \ No newline at end of file diff --git a/Spell-Sense/requirements.txt b/Spell-Sense/requirements.txt new file mode 100644 index 0000000..3f42dc3 --- /dev/null +++ b/Spell-Sense/requirements.txt @@ -0,0 +1 @@ +textblob \ No newline at end of file From 39f0fa6b566257c98d9361c6561dc5844133d55c Mon Sep 17 00:00:00 2001 From: Princee Date: Fri, 10 Apr 2026 13:04:01 +0545 Subject: [PATCH 24/44] feat: add Tkinter UI with keyboard bindings and color feedback --- Spell-Sense/main.py | 55 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Spell-Sense/main.py diff --git a/Spell-Sense/main.py b/Spell-Sense/main.py new file mode 100644 index 0000000..0ab991f --- /dev/null +++ b/Spell-Sense/main.py @@ -0,0 +1,55 @@ +import tkinter as tk +from logic import get_correction + +class SpellCheckerApp: + def __init__(self, root): + self.root = root + self.root.title("Spell Checker Pro") + self.root.geometry("400x300") + self.root.configure(bg='#f7f7f7') + + self.setup_ui() + self.root.bind('', lambda e: self.process_text()) + + def setup_ui(self): + # Label + tk.Label(self.root, text="Pro Spell Checker", font=("Arial", 14, "bold"), bg='#f7f7f7').pack(pady=10) + + # Entry + self.input_entry = tk.Entry(self.root, font=("Arial", 12), width=30) + self.input_entry.pack(pady=10) + self.input_entry.focus_set() + + # Buttons + btn_frame = tk.Frame(self.root, bg='#f7f7f7') + btn_frame.pack(pady=10) + + self.check_btn = tk.Button(btn_frame, text="Check", command=self.process_text, bg='#4CAF50', fg='white', width=10) + self.check_btn.pack(side=tk.LEFT, padx=5) + + self.reset_btn = tk.Button(btn_frame, text="Reset", command=self.reset_fields, bg='#f44336', fg='white', width=10) + self.reset_btn.pack(side=tk.LEFT, padx=5) + + # Result display + self.result_label = tk.Label(self.root, text="", font=("Arial", 11), bg='#f7f7f7', wraplength=350) + self.result_label.pack(pady=20) + + def process_text(self): + text = self.input_entry.get() + corrected, is_correct = get_correction(text) + + if corrected is None: + self.result_label.config(text="Please enter a word!", fg="orange") + elif is_correct: + self.result_label.config(text=f"✔ '{text}' is spelled correctly!", fg="green") + else: + self.result_label.config(text=f"✖ Suggestion: {corrected}", fg="blue") + + def reset_fields(self): + self.input_entry.delete(0, tk.END) + self.result_label.config(text="") + +if __name__ == "__main__": + root = tk.Tk() + app = SpellCheckerApp(root) + root.mainloop() \ No newline at end of file From d1fba5bdbb47f21a6be629dfe3e355263a1ab26e Mon Sep 17 00:00:00 2001 From: Princee Date: Fri, 10 Apr 2026 13:22:35 +0545 Subject: [PATCH 25/44] docs: add comprehensive documentation for Spell-Sense --- Spell-Sense/README.md | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Spell-Sense/README.md diff --git a/Spell-Sense/README.md b/Spell-Sense/README.md new file mode 100644 index 0000000..2716c58 --- /dev/null +++ b/Spell-Sense/README.md @@ -0,0 +1,49 @@ +# Spell-Sense: Advanced Spell Checker + +Spell-Sense is a professional, modular Python application that provides real-time spelling suggestions. Built with `Tkinter` and `TextBlob`, it improves upon basic implementations by adding robust error handling and a clean, user-friendly interface. + +## Features +- Smart Validation: Detects empty inputs and prevents unnecessary processing. +- Color-Coded Feedback: Uses visual cues (Green for success, Blue for suggestions, Red for errors). +- Modular Design: Separation of concerns between UI logic and processing logic. +- Keyboard Friendly: Press `Enter` to check spelling instantly without clicking. +- Auto-Focus: The cursor starts in the input box for immediate typing. + +## Project Structure +/Spell-Sense/ +├── main.py # Entry point and UI (Tkinter) +├── logic.py # Core NLP logic (TextBlob) +├── requirements.txt # Dependency list +└── README.md # Documentation + +🚀 Installation & Setup +Prerequisites +Python 3.6 or higher + +Setup +Navigate to your project directory: + +Bash +cd Spell-Sense +Install the required dependencies: + +Bash +pip install -r requirements.txt +🛠️ Usage +Run the script from your terminal: + +Bash +python main.py +Type a word into the input box. + +Press Enter or click Check. + +View the suggestion or success message below. + +Click Reset to clear the fields. + +📝 Credits +This project was developed as an enhanced alternative to basic scripts in this repository. It focuses on modularity, error handling, and improved User Experience (UX). + +License +This project is open-source and intended for educational use. \ No newline at end of file From b6ee9094a8a029ae601b54d32a1aedcc0750e1b3 Mon Sep 17 00:00:00 2001 From: cmodevcodes Date: Sat, 11 Apr 2026 14:25:04 -0400 Subject: [PATCH 26/44] Add new project --- Biosimilars_Finder/README.md | 48 +++++++ Biosimilars_Finder/biosimilars.py | 190 +++++++++++++++++++++++++ Biosimilars_Finder/requirements.txt | 5 + Biosimilars_Finder/test_biosimilars.py | 103 ++++++++++++++ 4 files changed, 346 insertions(+) create mode 100644 Biosimilars_Finder/README.md create mode 100644 Biosimilars_Finder/biosimilars.py create mode 100644 Biosimilars_Finder/requirements.txt create mode 100644 Biosimilars_Finder/test_biosimilars.py diff --git a/Biosimilars_Finder/README.md b/Biosimilars_Finder/README.md new file mode 100644 index 0000000..80ea0ca --- /dev/null +++ b/Biosimilars_Finder/README.md @@ -0,0 +1,48 @@ +# Biosimilars Finder +#### Description: + +Query FDA open API database as well as the most recent csv file posted on FDA's +Purple book website for available biologics and biosimilars information + +Class Drug is used to store particular information of a drug and available biosimilars info" + +get_brand() queries the FDA API for the openfda data associated with a drug and store info into the drug instance + +As the FDA API doesn't take RE query or provide detailed functionalities for drug brand name check, rf"^{name}(?![\w-])" is used to do a second round check if a drug is a valid drug given the FDA database. This helps to filter out cases like "name-xxxx" or "XX name" or "xxxnamexxx" + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + name (str): User input drug name to be checked with FDA database + + Raises: + KeyError: If a drug's brand name exist FDA's database but info such as generic/molecule name, route, or moa is not available (e.g. Humira) + ValueError : if the FDA API cannot be accessed + +get_biologics () finds the most recent PurpleBook CSV file and identify if a drug is biologics and if it has biosimilar. Retrieve biosimilars info and store in the Drug class instance if available" + +It automatically checks 24 months starting from the current month to find the most recent Purple Book csv. The function should be called only after get_brand () is called. + +It determines if a drug is biologics based on PurpleBook's cvs field - Proprietary Name. + +It determines if a drug is biologics based on PurpleBook's cvs field - Ref. Product Proprietary Name + +Class Drug property self._biosimilars stores all fields of the FDA PurpleBook csv file of a drug's biosimilars as Pandas DataFrame, not just the ones that prn_biosim() prints + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + name (str): User input drug name to be checked with the PurpleBook csv fil + + +prn_biosim() print a Drug instance's selected biosimilars information. Class Drug property self._biosimilars stores all fields of the FDA PurpleBook csv file of a drug's biosimilars as Pandas DataFrame, not just the ones that prn_biosim() prints so more info can be easily added to the output table if needed + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + + ValueError : if the drug is not biologics or if it doesn't have biosimilars info + + + +TODO +1. The three key functions - get_brand(), get_biologics(), prn_biosim() can be easily changed to instance method as they were designed as method for the class Drug +2. One can sometime access a PurpleBook CSV when it is not even officially posted on FDA's PurpleBook website. For example, in March, 2026. The most updated file should be February, 2026 based on PurpleBook's website but March, 2026 csv can already be accessed. This may/may not be the intended behavior of the program +3. The reason that the program has to automatically download the PurpleBook csv, hold it in memory for query etc is because FDA doesn't currently have an API for PurpleBook. It would be great to change the PurpleBook query to an APL query once an API is available diff --git a/Biosimilars_Finder/biosimilars.py b/Biosimilars_Finder/biosimilars.py new file mode 100644 index 0000000..7a78f1f --- /dev/null +++ b/Biosimilars_Finder/biosimilars.py @@ -0,0 +1,190 @@ +import requests +import pandas as pnds +import re +import time +from tabulate import tabulate +from datetime import datetime +from dateutil.relativedelta import relativedelta +from io import StringIO + + +def main () : + + """ + Query FDA open API database as well as the most recent csv data file on FDA's + Purple book website for available biologics and biosimilars information + + """ + + name= input("Brand Name: ").strip() + drug=Drug(name) + get_brand(drug,name) + if drug.is_drug : + get_biologics(drug,name) + print (drug) + + if drug.is_biologics and drug.has_biosimilar: + biosim= input ("Do you want more biosimilars info?[Y/N] ").lower().strip() + if biosim == "y" or biosim == "yes" : + prn_biosim(drug) + + +class Drug: + + """ + Class Drug is used to store particular information of a drug and available biosimilars info" + """ + + def __init__(self, brand_name=[]): + self.brand_name=brand_name + self.is_drug = False + self._generic_name="" + self._route="" + self._moa="" + self.is_biologics= False + self.has_biosimilar = False + self._biosimilars = [] + + def __str__(self): + if not self.is_drug : + s= f"{self.brand_name} is not a brand drug based on the FDA database" + else : + s= f"\nBrand Name: {self.brand_name}\n" + s += f"Molecule Name: {self._generic_name}\n" + s += f"Route: {self._route}\n" + s += f"Mechnism of Action: {self._moa}\n" + s += "Biologics: Yes\n" if self.is_biologics else "Biologics: N/A\n" + s += "Biosimilars: Yes" if self.has_biosimilar else "Biosimilars: N/A" + return s + + +def get_brand (drug,name): + + """ + Query the FDA API for the openfda data associated with a drug and store info into the drug instance + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + name (str): User input drug name to be checked with FDA database + + Raises: + KeyError: If a drug's brand name exist FDA's database but info such as generic/molecule + name, route, or moa is not available (e.g. Humira) + ValueError : if the FDA API cannot be accessed + """ + + url= f'https://api.fda.gov/drug/label.json?search=openfda.brand_name:"{name}"&limit=1' + + try : + r = requests.get(url, timeout=10) + except requests.exceptions.RequestException as e: + print("FDA API not avaialble") + + if r.status_code ==200 : + response = r.json() + results = response.get("results", []) + openfda = results[0].get("openfda",{}) + + fda_name = openfda["brand_name"][0].strip().capitalize () + pattern=rf"^{name}(?![\w-])" + + if match :=re.search(pattern,fda_name,re.I) : + drug.brand_name = fda_name.capitalize() + drug.is_drug=True + + try : + drug._generic_name=openfda["generic_name"][0].capitalize() + except KeyError : + drug._generic_name ="N/A" + try : + drug._route=openfda["route"][0].capitalize() + except KeyError : + drug._route ="N/A" + try : + drug._moa=openfda["pharm_class_moa"][0].capitalize()[:-6] # removing " [moa]" at the end of the return string + except KeyError : + drug._moa ="N/A" + else : + drug.is_drug=False + else : + drug.is_drug=False + + +def get_biologics (drug,name): + + """ + Finds the most recent PurpleBook CSV file and identify if a drug is biologics + and if it has biosimilar. Retrieve biosimilars info and store in the Drug class + instance if available" + + Automatically check 24 months starting from the current month to find the most + recent Purple Book csv + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + name (str): User input drug name to be checked with the PurpleBook csv file + """ + + now = datetime.now() + # number of months back from current to search purplebook data + num_months= 24 + base_url = "https://www.accessdata.fda.gov/drugsatfda_docs/PurpleBook" + headers = {"user-Agent": "Mozilla/5.0"} + + for i in range (num_months) : + past = now - relativedelta(months=i) + month_name = past.strftime("%B").capitalize() + year=str(past.year) + filename = f"purplebook-search-{month_name}-data-download.csv" + url = f"{base_url}/{year}/{filename}" + pb_read_success = False + # + try: + r= requests.get(url, headers=headers) + if r.status_code ==200 : + pb_read_success = True + pb = pnds.read_csv(StringIO(r.text), skiprows=3) + break + else : + time.sleep(2) + except Exception as e: + time.sleep(2) + + if pb_read_success : + biologics_matches = pb[pb["Proprietary Name"].str.contains(name, case=False, na=False)] + drug.is_biologics = not biologics_matches.empty + + if drug.is_biologics : + biosimilars_matches = pb[pb["Ref. Product Proprietary Name"].str.contains(name, case=False, na=False)] + drug.has_biosimilar = not biosimilars_matches.empty + if drug.has_biosimilar : + drug._biosimilars=biosimilars_matches + + +def prn_biosim(drug) : + + """ + Print a Drug instance's selected biosimilars information + + Parameters: + drug (Class Drug): Drug class instance that is used to store FDA query results + + ValueError : if the drug is not biologics or if it doesn't have biosimilars info + + """ + + if drug.has_biosimilar == True and drug.is_biologics == True : + print(tabulate( + drug._biosimilars[['Proprietary Name','Proper Name','Strength','Applicant','Approval Date']], + headers=['Brand Name','Molecule Name','Strength','Applicant','Approval Date'], + tablefmt="grid", + showindex=False, + maxcolwidths=[None,None,None,15,None] + )) + else : + raise ValueError ("The drug does not have biosimlar") + + +if __name__ == "__main__" : + main () + diff --git a/Biosimilars_Finder/requirements.txt b/Biosimilars_Finder/requirements.txt new file mode 100644 index 0000000..67890c1 --- /dev/null +++ b/Biosimilars_Finder/requirements.txt @@ -0,0 +1,5 @@ +requests +pandas +python-dateutil +tabulate +pytest diff --git a/Biosimilars_Finder/test_biosimilars.py b/Biosimilars_Finder/test_biosimilars.py new file mode 100644 index 0000000..28c21a7 --- /dev/null +++ b/Biosimilars_Finder/test_biosimilars.py @@ -0,0 +1,103 @@ +import pytest +import pandas as pnds +from biosimilars import Drug, get_brand, get_biologics, prn_biosim + + +def test_init () : + drug = Drug ("remicade") + assert drug.brand_name == "remicade" + assert drug.is_drug == False + assert drug.is_biologics == False + assert drug.has_biosimilar == False + with pytest.raises(TypeError) : + jar= Drug ("remicade", "rituximab") + + +def test_get_brand () : + drug = Drug () + get_brand (drug, "rituxan") + assert drug.is_drug == True + assert drug._generic_name == "Rituximab and hyaluronidase" + + drug = Drug () + get_brand (drug, "remicade") + assert drug.is_drug == True + + drug = Drug () + get_brand (drug, "HumiRa") + assert drug.is_drug == True + + drug = Drug () + get_brand (drug, "KeyTruda") + assert drug.is_drug == True + + drug = Drug () + get_brand (drug, "r") + assert drug.is_drug == False + + drug = Drug () + get_brand (drug, "re") + assert drug.is_drug == False + + drug = Drug () + get_brand (drug, "Not a Drug") + assert drug.is_drug == False + + drug = Drug () + get_brand (drug, "") + assert drug.is_drug == False + + with pytest.raises(TypeError) : + get_brand (drug) + with pytest.raises(TypeError) : + get_brand (drug,"xxx","XXX") + + +def test_get_biologics () : + drug = Drug () + get_brand (drug, "rituxan") + get_biologics (drug, "rituxan") + assert drug.is_biologics == True + assert drug.has_biosimilar == True + + drug = Drug () + get_brand (drug, "HuMira") + get_biologics (drug, "Humira") + assert drug.is_biologics == True + assert drug.has_biosimilar == True + assert isinstance(drug._biosimilars, pnds.DataFrame) + + drug = Drug () + get_brand (drug,"Remicade") + get_biologics (drug,"reMIcade") + assert drug.is_biologics == True + assert drug.has_biosimilar == True + assert isinstance(drug._biosimilars, pnds.DataFrame) + + drug = Drug () + get_brand (drug,"KeyTruda") + get_biologics (drug, "keytruda") + assert drug.is_biologics == True + assert drug.has_biosimilar == False + assert not isinstance(drug._biosimilars, pnds.DataFrame) + + drug = Drug () + get_brand (drug, "lipitor") + get_biologics (drug, "lipitor") + assert drug.is_biologics == False + assert drug.has_biosimilar == False + assert not isinstance(drug._biosimilars, pnds.DataFrame) + + with pytest.raises(TypeError) : + get_biologics (drug) + with pytest.raises(TypeError) : + get_biologics (drug,"xxx","XXX") + +def test_prn_biosim() : + with pytest.raises(TypeError) : + prn_biosim() + drug = Drug () + get_brand (drug, "lipitor") + get_biologics (drug, "lipitor") + with pytest.raises(ValueError) : + prn_biosim(drug) From 693f5fe4461ec9f0152200651350be2706781336 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 16 Apr 2026 01:39:24 +0000 Subject: [PATCH 27/44] Updated Contributors Details --- .github/data/contributors-log.json | 6 ++++-- index.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 62f9014..e230295 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -329,10 +329,12 @@ }, "Encryption_Project": { "contributor-name": [ - "moonabys" + "moonabys", + "yumicce" ], "pull-request-number": [ - "75" + "75", + "81" ], "demo-path": "Encryption_Project" }, diff --git a/index.md b/index.md index cea0fd5..e5325a3 100644 --- a/index.md +++ b/index.md @@ -42,7 +42,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Number-Plate-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#58](https://github.com/Grow-with-Open-Source/Python-Projects/pull/58 "visit pr #58") | [/Grow-with-Open-Source/Python-Projects/Number-Plate-Detection/](Number-Plate-Detection "view the result of Number-Plate-Detection") | | Motion-Detection | [iamdevdhanush](https://github.com/iamdevdhanush "goto iamdevdhanush profile") | [#62](https://github.com/Grow-with-Open-Source/Python-Projects/pull/62 "visit pr #62") | [/Grow-with-Open-Source/Python-Projects/Motion-Detection/](Motion-Detection "view the result of Motion-Detection") | | Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | -| Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | +| Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile"), [yumicce](https://github.com/yumicce "goto yumicce profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75"), [#81](https://github.com/Grow-with-Open-Source/Python-Projects/pull/81 "visit pr #81") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | | securepass | [Lampard7crypt](https://github.com/Lampard7crypt "goto Lampard7crypt profile") | [#72](https://github.com/Grow-with-Open-Source/Python-Projects/pull/72 "visit pr #72") | [/Grow-with-Open-Source/Python-Projects/securepass/](securepass "view the result of securepass") | From 11d5d14facc49cbd47d3463f8bcef1ca79a5d816 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 16 Apr 2026 01:42:48 +0000 Subject: [PATCH 28/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index e230295..81ef3e3 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -346,5 +346,14 @@ "72" ], "demo-path": "securepass" + }, + "Biosimilars_Finder": { + "contributor-name": [ + "cmodevcodes" + ], + "pull-request-number": [ + "83" + ], + "demo-path": "Biosimilars_Finder" } } \ No newline at end of file diff --git a/index.md b/index.md index e5325a3..29034bf 100644 --- a/index.md +++ b/index.md @@ -44,6 +44,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Bowling-Action-Tracking | [musharrafhamraz](https://github.com/musharrafhamraz "goto musharrafhamraz profile") | [#67](https://github.com/Grow-with-Open-Source/Python-Projects/pull/67 "visit pr #67") | [/Grow-with-Open-Source/Python-Projects/Bowling-Action-Tracking/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking "view the result of Bowling-Action-Tracking") | | Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile"), [yumicce](https://github.com/yumicce "goto yumicce profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75"), [#81](https://github.com/Grow-with-Open-Source/Python-Projects/pull/81 "visit pr #81") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | | securepass | [Lampard7crypt](https://github.com/Lampard7crypt "goto Lampard7crypt profile") | [#72](https://github.com/Grow-with-Open-Source/Python-Projects/pull/72 "visit pr #72") | [/Grow-with-Open-Source/Python-Projects/securepass/](securepass "view the result of securepass") | +| Biosimilars_Finder | [cmodevcodes](https://github.com/cmodevcodes "goto cmodevcodes profile") | [#83](https://github.com/Grow-with-Open-Source/Python-Projects/pull/83 "visit pr #83") | [/Grow-with-Open-Source/Python-Projects/Biosimilars_Finder/](Biosimilars_Finder "view the result of Biosimilars_Finder") | From 4d9084069087f77fecf2a67fc11a9002daace246 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 16 Apr 2026 01:44:06 +0000 Subject: [PATCH 29/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 81ef3e3..43ae688 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -355,5 +355,14 @@ "83" ], "demo-path": "Biosimilars_Finder" + }, + "Spell-Sense": { + "contributor-name": [ + "princechaudhary007" + ], + "pull-request-number": [ + "82" + ], + "demo-path": "Spell-Sense" } } \ No newline at end of file diff --git a/index.md b/index.md index 29034bf..d5226db 100644 --- a/index.md +++ b/index.md @@ -45,6 +45,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Encryption_Project | [moonabys](https://github.com/moonabys "goto moonabys profile"), [yumicce](https://github.com/yumicce "goto yumicce profile") | [#75](https://github.com/Grow-with-Open-Source/Python-Projects/pull/75 "visit pr #75"), [#81](https://github.com/Grow-with-Open-Source/Python-Projects/pull/81 "visit pr #81") | [/Grow-with-Open-Source/Python-Projects/Encryption_Project/](Encryption_Project "view the result of Encryption_Project") | | securepass | [Lampard7crypt](https://github.com/Lampard7crypt "goto Lampard7crypt profile") | [#72](https://github.com/Grow-with-Open-Source/Python-Projects/pull/72 "visit pr #72") | [/Grow-with-Open-Source/Python-Projects/securepass/](securepass "view the result of securepass") | | Biosimilars_Finder | [cmodevcodes](https://github.com/cmodevcodes "goto cmodevcodes profile") | [#83](https://github.com/Grow-with-Open-Source/Python-Projects/pull/83 "visit pr #83") | [/Grow-with-Open-Source/Python-Projects/Biosimilars_Finder/](Biosimilars_Finder "view the result of Biosimilars_Finder") | +| Spell-Sense | [princechaudhary007](https://github.com/princechaudhary007 "goto princechaudhary007 profile") | [#82](https://github.com/Grow-with-Open-Source/Python-Projects/pull/82 "visit pr #82") | [/Grow-with-Open-Source/Python-Projects/Spell-Sense/](Spell-Sense "view the result of Spell-Sense") | From 2de6829c102454b83c06296b5dc675c2c9511a11 Mon Sep 17 00:00:00 2001 From: AdyaTech Date: Thu, 7 May 2026 16:35:48 +0530 Subject: [PATCH 30/44] Contributing my Python project by the name of Story Generator in this repository. --- Story-Generator/story.py | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Story-Generator/story.py diff --git a/Story-Generator/story.py b/Story-Generator/story.py new file mode 100644 index 0000000..627ff7c --- /dev/null +++ b/Story-Generator/story.py @@ -0,0 +1,51 @@ +import random +when = [ + "A few years ago", + "Yesterday", + "Last night", + "A long time ago", + "On 20th January" +] +who = [ + "a rabbit", + "an elephant", + "a mouse", + "a turtle", + "a cat" +] +names = [ + "Ali", + "Miriam", + "Daniel", + "Houuk", + "Starwalker" +] +places = [ + "Barcelona", + "India", + "Germany", + "Venice", + "England" +] +went_to = [ + "cinema", + "university", + "seminar", + "school", + "laundry" +] +happened = [ + "made a lot of friends", + "ate a burger", + "found a secret key", + "solved a mystery", + "wrote a book" +] +story = ( + f"{random.choice(when)}, " + f"{random.choice(names)} the {random.choice(who)} " + f"from {random.choice(places)} went to the " + f"{random.choice(went_to)} and " + f"{random.choice(happened)}." +) +print(story) \ No newline at end of file From 54956ca9f60d5ec361a90a0af70170ca20204b0f Mon Sep 17 00:00:00 2001 From: AdyaTech Date: Thu, 7 May 2026 16:25:01 +0530 Subject: [PATCH 31/44] Contributing my Python project by the name of Dog Age Calculator in this repository. --- Dog-Age-Calculator/dogage.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Dog-Age-Calculator/dogage.py diff --git a/Dog-Age-Calculator/dogage.py b/Dog-Age-Calculator/dogage.py new file mode 100644 index 0000000..19026bf --- /dev/null +++ b/Dog-Age-Calculator/dogage.py @@ -0,0 +1,15 @@ +def calculate_dog_age(human_age): + if human_age < 0: + return None + if human_age <= 2: + return human_age * 10.5 + return 21 + (human_age - 2) * 4 + + +human_age = int(input("Enter a dog's age in human years: ")) +dog_age = calculate_dog_age(human_age) + +if dog_age is None: + print("Age must be a positive number.") +else: + print(f"The dog's age in dog years is {dog_age}.") \ No newline at end of file From b85de52efb5069386755a7356796e28a43c3880f Mon Sep 17 00:00:00 2001 From: AdyaTech Date: Wed, 6 May 2026 14:35:15 +0530 Subject: [PATCH 32/44] Contributing my Python project by the name of Birthday Paradox in this repository. --- Birthday-Paradox/birthdayparadox.py | 102 ++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 Birthday-Paradox/birthdayparadox.py diff --git a/Birthday-Paradox/birthdayparadox.py b/Birthday-Paradox/birthdayparadox.py new file mode 100644 index 0000000..2ecf9e2 --- /dev/null +++ b/Birthday-Paradox/birthdayparadox.py @@ -0,0 +1,102 @@ +import datetime, random + + +def getBirthdays(numberOfBirthdays): + """Returns a list of number random date objects for birthdays.""" + birthdays = [] + for i in range(numberOfBirthdays): + # The year is unimportant for our simulation, as long as all + # birthdays have the same year. + startOfYear = datetime.date(2001, 1, 1) + + # Get a random day into the year: + randomNumberOfDays = datetime.timedelta(random.randint(0, 364)) + birthday = startOfYear + randomNumberOfDays + birthdays.append(birthday) + return birthdays + + +def getMatch(birthdays): + """Returns the date object of a birthday that occurs more than once + in the birthdays list.""" + if len(birthdays) == len(set(birthdays)): + return None # All birthdays are unique, so return None. + + # Compare each birthday to every other birthday: + for a, birthdayA in enumerate(birthdays): + for b, birthdayB in enumerate(birthdays[a + 1 :]): + if birthdayA == birthdayB: + return birthdayA # Return the matching birthday. + + +# Display the intro: +print('''Birthday Paradox, by Al Sweigart al@inventwithpython.com + +The birthday paradox shows us that in a group of N people, the odds +that two of them have matching birthdays is surprisingly large. +This program does a Monte Carlo simulation (that is, repeated random +simulations) to explore this concept. + +(It's not actually a paradox, it's just a surprising result.) +''') + +# Set up a tuple of month names in order: +MONTHS = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') + +while True: # Keep asking until the user enters a valid amount. + print('How many birthdays shall I generate? (Max 100)') + response = input('> ') + if response.isdecimal() and (0 < int(response) <= 100): + numBDays = int(response) + break # User has entered a valid amount. +print() + +# Generate and display the birthdays: +print('Here are', numBDays, 'birthdays:') +birthdays = getBirthdays(numBDays) +for i, birthday in enumerate(birthdays): + if i != 0: + # Display a comma for each birthday after the first birthday. + print(', ', end='') + monthName = MONTHS[birthday.month - 1] + dateText = '{} {}'.format(monthName, birthday.day) + print(dateText, end='') +print() +print() + +# Determine if there are two birthdays that match. +match = getMatch(birthdays) + +# Display the results: +print('In this simulation, ', end='') +if match != None: + monthName = MONTHS[match.month - 1] + dateText = '{} {}'.format(monthName, match.day) + print('multiple people have a birthday on', dateText) +else: + print('there are no matching birthdays.') +print() + +# Run through 100,000 simulations: +print('Generating', numBDays, 'random birthdays 100,000 times...') +input('Press Enter to begin...') + +print('Let\'s run another 100,000 simulations.') +simMatch = 0 # How many simulations had matching birthdays in them. +for i in range(100000): + # Report on the progress every 10,000 simulations: + if i % 10000 == 0: + print(i, 'simulations run...') + birthdays = getBirthdays(numBDays) + if getMatch(birthdays) != None: + simMatch = simMatch + 1 +print('100,000 simulations run.') + +# Display simulation results: +probability = round(simMatch / 100000 * 100, 2) +print('Out of 100,000 simulations of', numBDays, 'people, there was a') +print('matching birthday in that group', simMatch, 'times. This means') +print('that', numBDays, 'people have a', probability, '% chance of') +print('having a matching birthday in their group.') +print('That\'s probably more than you would think!') From 5bebfb94caabd01e591f1dcd98afdb24a95680c3 Mon Sep 17 00:00:00 2001 From: AdyaTech Date: Wed, 6 May 2026 14:54:41 +0530 Subject: [PATCH 33/44] Contributing my Python project by the name of Bitmap Message in this repository. --- BitMap-Message/bitmapmessage.py | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 BitMap-Message/bitmapmessage.py diff --git a/BitMap-Message/bitmapmessage.py b/BitMap-Message/bitmapmessage.py new file mode 100644 index 0000000..59961fa --- /dev/null +++ b/BitMap-Message/bitmapmessage.py @@ -0,0 +1,47 @@ +import sys + +# (!) Try changing this multiline string to any image you like: + +# There are 68 periods along the top and bottom of this string: +# (You can also copy and paste this string from +# https://inventwithpython.com/bitmapworld.txt) +bitmap = """ +.................................................................... + ************** * *** ** * ****************************** + ********************* ** ** * * ****************************** * + ** ***************** ****************************** + ************* ** * **** ** ************** * + ********* ******* **************** * * + ******** *************************** * + * * **** *** *************** ****** ** * + **** * *************** *** *** * + ****** ************* ** ** * + ******** ************* * ** *** + ******** ******** * *** **** + ********* ****** * **** ** * ** + ********* ****** * * *** * * + ****** ***** ** ***** * + ***** **** * ******** + ***** **** ********* + **** ** ******* * + *** * * + ** * * +....................................................................""" + +print('Bitmap Message') +print('Enter the message to display with the bitmap.') +message = input('> ') +if message == '': + sys.exit() + +# Loop over each line in the bitmap: +for line in bitmap.splitlines(): + # Loop over each character in the line: + for i, bit in enumerate(line): + if bit == ' ': + # Print an empty space since there's a space in the bitmap: + print(' ', end='') + else: + # Print a character from the message: + print(message[i % len(message)], end='') + print() # Print a newline. From cdafca71524f2d55ac562ad04b799c0b7faeef0a Mon Sep 17 00:00:00 2001 From: AdyaTech Date: Thu, 7 May 2026 16:19:47 +0530 Subject: [PATCH 34/44] Contributing my Python project by the name of BouncingDVD in this repository. --- Bouncing-DVD/bouncingdvd.py | 140 ++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 Bouncing-DVD/bouncingdvd.py diff --git a/Bouncing-DVD/bouncingdvd.py b/Bouncing-DVD/bouncingdvd.py new file mode 100644 index 0000000..4e82ce8 --- /dev/null +++ b/Bouncing-DVD/bouncingdvd.py @@ -0,0 +1,140 @@ +import sys, random, time + +try: + import bext +except ImportError: + print('This program requires the bext module, which you') + print('can install by following the instructions at') + print('https://pypi.org/project/Bext/') + sys.exit() + +# Set up the constants: +WIDTH, HEIGHT = bext.size() +# We can't print to the last column on Windows without it adding a +# newline automatically, so reduce the width by one: +WIDTH -= 1 + +NUMBER_OF_LOGOS = 5 # (!) Try changing this to 1 or 100. +PAUSE_AMOUNT = 0.2 # (!) Try changing this to 1.0 or 0.0. +# (!) Try changing this list to fewer colors: +COLORS = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] + +UP_RIGHT = 'ur' +UP_LEFT = 'ul' +DOWN_RIGHT = 'dr' +DOWN_LEFT = 'dl' +DIRECTIONS = (UP_RIGHT, UP_LEFT, DOWN_RIGHT, DOWN_LEFT) + +# Key names for logo dictionaries: +COLOR = 'color' +X = 'x' +Y = 'y' +DIR = 'direction' + + +def main(): + bext.clear() + + # Generate some logos. + logos = [] + for i in range(NUMBER_OF_LOGOS): + logos.append({COLOR: random.choice(COLORS), + X: random.randint(1, WIDTH - 4), + Y: random.randint(1, HEIGHT - 4), + DIR: random.choice(DIRECTIONS)}) + if logos[-1][X] % 2 == 1: + # Make sure X is even so it can hit the corner. + logos[-1][X] -= 1 + + cornerBounces = 0 # Count how many times a logo hits a corner. + while True: # Main program loop. + for logo in logos: # Handle each logo in the logos list. + # Erase the logo's current location: + bext.goto(logo[X], logo[Y]) + print(' ', end='') # (!) Try commenting this line out. + + originalDirection = logo[DIR] + + # See if the logo bounces off the corners: + if logo[X] == 0 and logo[Y] == 0: + logo[DIR] = DOWN_RIGHT + cornerBounces += 1 + elif logo[X] == 0 and logo[Y] == HEIGHT - 1: + logo[DIR] = UP_RIGHT + cornerBounces += 1 + elif logo[X] == WIDTH - 3 and logo[Y] == 0: + logo[DIR] = DOWN_LEFT + cornerBounces += 1 + elif logo[X] == WIDTH - 3 and logo[Y] == HEIGHT - 1: + logo[DIR] = UP_LEFT + cornerBounces += 1 + + # See if the logo bounces off the left edge: + elif logo[X] == 0 and logo[DIR] == UP_LEFT: + logo[DIR] = UP_RIGHT + elif logo[X] == 0 and logo[DIR] == DOWN_LEFT: + logo[DIR] = DOWN_RIGHT + + # See if the logo bounces off the right edge: + # (WIDTH - 3 because 'DVD' has 3 letters.) + elif logo[X] == WIDTH - 3 and logo[DIR] == UP_RIGHT: + logo[DIR] = UP_LEFT + elif logo[X] == WIDTH - 3 and logo[DIR] == DOWN_RIGHT: + logo[DIR] = DOWN_LEFT + + # See if the logo bounces off the top edge: + elif logo[Y] == 0 and logo[DIR] == UP_LEFT: + logo[DIR] = DOWN_LEFT + elif logo[Y] == 0 and logo[DIR] == UP_RIGHT: + logo[DIR] = DOWN_RIGHT + + # See if the logo bounces off the bottom edge: + elif logo[Y] == HEIGHT - 1 and logo[DIR] == DOWN_LEFT: + logo[DIR] = UP_LEFT + elif logo[Y] == HEIGHT - 1 and logo[DIR] == DOWN_RIGHT: + logo[DIR] = UP_RIGHT + + if logo[DIR] != originalDirection: + # Change color when the logo bounces: + logo[COLOR] = random.choice(COLORS) + + # Move the logo. (X moves by 2 because the terminal + # characters are twice as tall as they are wide.) + if logo[DIR] == UP_RIGHT: + logo[X] += 2 + logo[Y] -= 1 + elif logo[DIR] == UP_LEFT: + logo[X] -= 2 + logo[Y] -= 1 + elif logo[DIR] == DOWN_RIGHT: + logo[X] += 2 + logo[Y] += 1 + elif logo[DIR] == DOWN_LEFT: + logo[X] -= 2 + logo[Y] += 1 + + # Display number of corner bounces: + bext.goto(5, 0) + bext.fg('white') + print('Corner bounces:', cornerBounces, end='') + + for logo in logos: + # Draw the logos at their new location: + bext.goto(logo[X], logo[Y]) + bext.fg(logo[COLOR]) + print('DVD', end='') + + bext.goto(0, 0) + + sys.stdout.flush() # (Required for bext-using programs.) + time.sleep(PAUSE_AMOUNT) + + +# If this program was run (instead of imported), run the game: +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print() + print('Bouncing DVD Logo, by Al Sweigart') + sys.exit() # When Ctrl-C is pressed, end the program. From 460b21d3138baa4d299e0b3ec7eafb9244733448 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 22 Jun 2026 12:19:37 +0000 Subject: [PATCH 35/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 43ae688..0c43400 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -364,5 +364,14 @@ "82" ], "demo-path": "Spell-Sense" + }, + "Birthday-Paradox": { + "contributor-name": [ + "AdyaTech" + ], + "pull-request-number": [ + "86" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox" } } \ No newline at end of file diff --git a/index.md b/index.md index d5226db..80e8c8a 100644 --- a/index.md +++ b/index.md @@ -46,6 +46,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | securepass | [Lampard7crypt](https://github.com/Lampard7crypt "goto Lampard7crypt profile") | [#72](https://github.com/Grow-with-Open-Source/Python-Projects/pull/72 "visit pr #72") | [/Grow-with-Open-Source/Python-Projects/securepass/](securepass "view the result of securepass") | | Biosimilars_Finder | [cmodevcodes](https://github.com/cmodevcodes "goto cmodevcodes profile") | [#83](https://github.com/Grow-with-Open-Source/Python-Projects/pull/83 "visit pr #83") | [/Grow-with-Open-Source/Python-Projects/Biosimilars_Finder/](Biosimilars_Finder "view the result of Biosimilars_Finder") | | Spell-Sense | [princechaudhary007](https://github.com/princechaudhary007 "goto princechaudhary007 profile") | [#82](https://github.com/Grow-with-Open-Source/Python-Projects/pull/82 "visit pr #82") | [/Grow-with-Open-Source/Python-Projects/Spell-Sense/](Spell-Sense "view the result of Spell-Sense") | +| Birthday-Paradox | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#86](https://github.com/Grow-with-Open-Source/Python-Projects/pull/86 "visit pr #86") | [/Grow-with-Open-Source/Python-Projects/Birthday-Paradox/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox "view the result of Birthday-Paradox") | From 8eb29df625f25e719025aa9765a534cfe457b8b0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 22 Jun 2026 12:23:08 +0000 Subject: [PATCH 36/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 0c43400..6f8c913 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -373,5 +373,14 @@ "86" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox" + }, + "BitMap-Message": { + "contributor-name": [ + "AdyaTech" + ], + "pull-request-number": [ + "87" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message" } } \ No newline at end of file diff --git a/index.md b/index.md index 80e8c8a..1d1b52f 100644 --- a/index.md +++ b/index.md @@ -47,6 +47,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Biosimilars_Finder | [cmodevcodes](https://github.com/cmodevcodes "goto cmodevcodes profile") | [#83](https://github.com/Grow-with-Open-Source/Python-Projects/pull/83 "visit pr #83") | [/Grow-with-Open-Source/Python-Projects/Biosimilars_Finder/](Biosimilars_Finder "view the result of Biosimilars_Finder") | | Spell-Sense | [princechaudhary007](https://github.com/princechaudhary007 "goto princechaudhary007 profile") | [#82](https://github.com/Grow-with-Open-Source/Python-Projects/pull/82 "visit pr #82") | [/Grow-with-Open-Source/Python-Projects/Spell-Sense/](Spell-Sense "view the result of Spell-Sense") | | Birthday-Paradox | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#86](https://github.com/Grow-with-Open-Source/Python-Projects/pull/86 "visit pr #86") | [/Grow-with-Open-Source/Python-Projects/Birthday-Paradox/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox "view the result of Birthday-Paradox") | +| BitMap-Message | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#87](https://github.com/Grow-with-Open-Source/Python-Projects/pull/87 "visit pr #87") | [/Grow-with-Open-Source/Python-Projects/BitMap-Message/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message "view the result of BitMap-Message") | From 7255ddeef27452b3ad2e96a63b7f1d3a5b313c29 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 22 Jun 2026 12:27:05 +0000 Subject: [PATCH 37/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 6f8c913..d84be49 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -382,5 +382,14 @@ "87" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message" + }, + "Bouncing-DVD": { + "contributor-name": [ + "AdyaTech" + ], + "pull-request-number": [ + "89" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD" } } \ No newline at end of file diff --git a/index.md b/index.md index 1d1b52f..d4eacf8 100644 --- a/index.md +++ b/index.md @@ -48,6 +48,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Spell-Sense | [princechaudhary007](https://github.com/princechaudhary007 "goto princechaudhary007 profile") | [#82](https://github.com/Grow-with-Open-Source/Python-Projects/pull/82 "visit pr #82") | [/Grow-with-Open-Source/Python-Projects/Spell-Sense/](Spell-Sense "view the result of Spell-Sense") | | Birthday-Paradox | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#86](https://github.com/Grow-with-Open-Source/Python-Projects/pull/86 "visit pr #86") | [/Grow-with-Open-Source/Python-Projects/Birthday-Paradox/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox "view the result of Birthday-Paradox") | | BitMap-Message | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#87](https://github.com/Grow-with-Open-Source/Python-Projects/pull/87 "visit pr #87") | [/Grow-with-Open-Source/Python-Projects/BitMap-Message/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message "view the result of BitMap-Message") | +| Bouncing-DVD | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#89](https://github.com/Grow-with-Open-Source/Python-Projects/pull/89 "visit pr #89") | [/Grow-with-Open-Source/Python-Projects/Bouncing-DVD/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD "view the result of Bouncing-DVD") | From 0ed45db2721b5ad6be68908c454aa212f60efa65 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 22 Jun 2026 12:29:02 +0000 Subject: [PATCH 38/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index d84be49..1499c25 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -391,5 +391,14 @@ "89" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD" + }, + "Dog-Age-Calculator": { + "contributor-name": [ + "AdyaTech" + ], + "pull-request-number": [ + "90" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Dog-Age-Calculator" } } \ No newline at end of file diff --git a/index.md b/index.md index d4eacf8..247a282 100644 --- a/index.md +++ b/index.md @@ -49,6 +49,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Birthday-Paradox | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#86](https://github.com/Grow-with-Open-Source/Python-Projects/pull/86 "visit pr #86") | [/Grow-with-Open-Source/Python-Projects/Birthday-Paradox/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Birthday-Paradox "view the result of Birthday-Paradox") | | BitMap-Message | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#87](https://github.com/Grow-with-Open-Source/Python-Projects/pull/87 "visit pr #87") | [/Grow-with-Open-Source/Python-Projects/BitMap-Message/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message "view the result of BitMap-Message") | | Bouncing-DVD | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#89](https://github.com/Grow-with-Open-Source/Python-Projects/pull/89 "visit pr #89") | [/Grow-with-Open-Source/Python-Projects/Bouncing-DVD/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD "view the result of Bouncing-DVD") | +| Dog-Age-Calculator | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#90](https://github.com/Grow-with-Open-Source/Python-Projects/pull/90 "visit pr #90") | [/Grow-with-Open-Source/Python-Projects/Dog-Age-Calculator/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Dog-Age-Calculator "view the result of Dog-Age-Calculator") | From 6a5aa140a1fdc8e84a2797156c7ba4cffe721361 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 22 Jun 2026 12:30:24 +0000 Subject: [PATCH 39/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 1499c25..44d1f9c 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -400,5 +400,14 @@ "90" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Dog-Age-Calculator" + }, + "Story-Generator": { + "contributor-name": [ + "AdyaTech" + ], + "pull-request-number": [ + "91" + ], + "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Story-Generator" } } \ No newline at end of file diff --git a/index.md b/index.md index 247a282..b1e4e22 100644 --- a/index.md +++ b/index.md @@ -50,6 +50,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | BitMap-Message | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#87](https://github.com/Grow-with-Open-Source/Python-Projects/pull/87 "visit pr #87") | [/Grow-with-Open-Source/Python-Projects/BitMap-Message/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/BitMap-Message "view the result of BitMap-Message") | | Bouncing-DVD | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#89](https://github.com/Grow-with-Open-Source/Python-Projects/pull/89 "visit pr #89") | [/Grow-with-Open-Source/Python-Projects/Bouncing-DVD/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD "view the result of Bouncing-DVD") | | Dog-Age-Calculator | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#90](https://github.com/Grow-with-Open-Source/Python-Projects/pull/90 "visit pr #90") | [/Grow-with-Open-Source/Python-Projects/Dog-Age-Calculator/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Dog-Age-Calculator "view the result of Dog-Age-Calculator") | +| Story-Generator | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#91](https://github.com/Grow-with-Open-Source/Python-Projects/pull/91 "visit pr #91") | [/Grow-with-Open-Source/Python-Projects/Story-Generator/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Story-Generator "view the result of Story-Generator") | From b928fdd2700d6a3ef7a867403a1c57d252cbc707 Mon Sep 17 00:00:00 2001 From: Stella Nyamekye Anyebayaaka Appiok Date: Mon, 22 Jun 2026 23:24:22 +0000 Subject: [PATCH 40/44] Adding code file --- slot-machine/slot_machine.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 slot-machine/slot_machine.py diff --git a/slot-machine/slot_machine.py b/slot-machine/slot_machine.py new file mode 100644 index 0000000..e69de29 From 2509bd7e8921fe5c071ffa67727812468f111e8f Mon Sep 17 00:00:00 2001 From: Stella Nyamekye Anyebayaaka Appiok Date: Mon, 22 Jun 2026 23:25:47 +0000 Subject: [PATCH 41/44] Adding ReadMe file with requirement and Project description --- slot-machine/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 slot-machine/README.md diff --git a/slot-machine/README.md b/slot-machine/README.md new file mode 100644 index 0000000..e69de29 From 13fbc086606fc05435e4a6bf39372934589fdf31 Mon Sep 17 00:00:00 2001 From: Stella Nyamekye Anyebayaaka Appiok Date: Mon, 22 Jun 2026 23:28:07 +0000 Subject: [PATCH 42/44] Finished code --- slot-machine/slot_machine.py | 162 +++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/slot-machine/slot_machine.py b/slot-machine/slot_machine.py index e69de29..69bd93b 100644 --- a/slot-machine/slot_machine.py +++ b/slot-machine/slot_machine.py @@ -0,0 +1,162 @@ +import random + +MAX_LINES = 3 +MAX_BET = 10 +MIN_BET = 1 + +ROWS = 3 +COLS = 3 + +symbol_count = { + "A": 2, + "B": 4, + "C": 6, + "D": 8 +} + +symbol_value = { + "A": 5, + "B": 4, + "C": 3, + "D": 2 +} + + +def deposit(): + while True: + amount = input("What would you like to deposit? $") + + if amount.isdigit(): + amount = int(amount) + + if amount > 0: + return amount + + print("Please enter a valid amount.") + + +def get_number_of_lines(): + while True: + lines = input(f"Enter the number of lines to bet on (1-{MAX_LINES}): ") + + if lines.isdigit(): + lines = int(lines) + + if 1 <= lines <= MAX_LINES: + return lines + + print("Enter a valid number.") + + +def get_bet(): + while True: + amount = input("What would you like to bet on each line? $") + + if amount.isdigit(): + amount = int(amount) + + if MIN_BET <= amount <= MAX_BET: + return amount + + print(f"Amount must be between ${MIN_BET} and ${MAX_BET}.") + + +def get_slot_machine_spin(rows, cols, symbols): + all_symbols = [] + + for symbol, symbol_count in symbols.items(): + for _ in range(symbol_count): + all_symbols.append(symbol) + + columns = [] + + for _ in range(cols): + current_symbols = all_symbols[:] + column = [] + + for _ in range(rows): + value = random.choice(current_symbols) + current_symbols.remove(value) + column.append(value) + + columns.append(column) + + return columns + + +def print_slot_machine(columns): + for row in range(len(columns[0])): + for i, column in enumerate(columns): + if i != len(columns) - 1: + print(column[row], end=" | ") + else: + print(column[row], end="") + + print() + + +def check_winnings(columns, lines, bet, values): + winnings = 0 + winning_lines = [] + + for line in range(lines): + symbol = columns[0][line] + + for column in columns: + symbol_to_check = column[line] + + if symbol != symbol_to_check: + break + else: + winnings += values[symbol] * bet + winning_lines.append(line + 1) + + return winnings, winning_lines + + +def spin(balance): + lines = get_number_of_lines() + + while True: + bet = get_bet() + total_bet = bet * lines + + if total_bet > balance: + print( + f"You do not have enough balance. Current balance: ${balance}") + else: + break + + print(f"\nYou are betting ${bet} on {lines} lines.") + print(f"Total bet: ${total_bet}\n") + + slots = get_slot_machine_spin(ROWS, COLS, symbol_count) + + print_slot_machine(slots) + + winnings, winning_lines = check_winnings( + slots, lines, bet, symbol_value) + + print(f"\nYou won ${winnings}.") + print(f"Winning lines: {winning_lines}") + + return winnings - total_bet + + +def main(): + balance = deposit() + + while True: + print(f"\nCurrent balance: ${balance}") + + answer = input("Press Enter to spin (q to quit): ") + + if answer.lower() == "q": + break + + balance += spin(balance) + + print(f"\nYou left with ${balance}") + + +main() From d303810d3fed482a6125575b289ad55703685166 Mon Sep 17 00:00:00 2001 From: Stella Nyamekye Anyebayaaka Appiok Date: Mon, 22 Jun 2026 23:31:31 +0000 Subject: [PATCH 43/44] Addind project requirement and description in the ReadMe fil --- slot-machine/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/slot-machine/README.md b/slot-machine/README.md index e69de29..5ec4360 100644 --- a/slot-machine/README.md +++ b/slot-machine/README.md @@ -0,0 +1,11 @@ +## What it does + +A fully functional terminal-based slot machine game. The player deposits +money, chooses how many lines to bet on (up to 3), sets a bet amount per +line, and spins. The machine generates a random 3x3 grid of symbols and +pays out based on matching symbols across each line. The game tracks +balance across multiple spins until the player quits. + +## Requirements + +None — uses only built-in random module From ef5523476d0de2192704c980be99c0a35d3adea2 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 24 Jun 2026 16:23:00 +0000 Subject: [PATCH 44/44] Updated Contributors Details --- .github/data/contributors-log.json | 9 +++++++++ index.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.github/data/contributors-log.json b/.github/data/contributors-log.json index 44d1f9c..3bba434 100644 --- a/.github/data/contributors-log.json +++ b/.github/data/contributors-log.json @@ -409,5 +409,14 @@ "91" ], "demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Story-Generator" + }, + "slot-machine": { + "contributor-name": [ + "appiokstella" + ], + "pull-request-number": [ + "93" + ], + "demo-path": "slot-machine" } } \ No newline at end of file diff --git a/index.md b/index.md index b1e4e22..4b27d11 100644 --- a/index.md +++ b/index.md @@ -51,6 +51,7 @@ Welcome to **Python-Projects**, your friendly initiation into the world of open- | Bouncing-DVD | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#89](https://github.com/Grow-with-Open-Source/Python-Projects/pull/89 "visit pr #89") | [/Grow-with-Open-Source/Python-Projects/Bouncing-DVD/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bouncing-DVD "view the result of Bouncing-DVD") | | Dog-Age-Calculator | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#90](https://github.com/Grow-with-Open-Source/Python-Projects/pull/90 "visit pr #90") | [/Grow-with-Open-Source/Python-Projects/Dog-Age-Calculator/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Dog-Age-Calculator "view the result of Dog-Age-Calculator") | | Story-Generator | [AdyaTech](https://github.com/AdyaTech "goto AdyaTech profile") | [#91](https://github.com/Grow-with-Open-Source/Python-Projects/pull/91 "visit pr #91") | [/Grow-with-Open-Source/Python-Projects/Story-Generator/](https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Story-Generator "view the result of Story-Generator") | +| slot-machine | [appiokstella](https://github.com/appiokstella "goto appiokstella profile") | [#93](https://github.com/Grow-with-Open-Source/Python-Projects/pull/93 "visit pr #93") | [/Grow-with-Open-Source/Python-Projects/slot-machine/](slot-machine "view the result of slot-machine") |