diff --git a/AREA OF TRIANGLE.py b/AREA OF TRIANGLE.py index 2aae5b0d645..db9b04a5a78 100644 --- a/AREA OF TRIANGLE.py +++ b/AREA OF TRIANGLE.py @@ -1,17 +1,20 @@ -# Python Program to find the area of triangle -# calculates area of traingle in efficient way!! -a = 5 -b = 6 -c = 7 +def get_valid_side(prompt:str): + while True: + try: + value = float(input(prompt)) + if value <=0: + print("Side must be positive") + continue + return value + except ValueError: + print("Invalid Input") -# Uncomment below to take inputs from the user -# a = float(input('Enter first side: ')) -# b = float(input('Enter second side: ')) -# c = float(input('Enter third side: ')) -# calculate the semi-perimeter -s = (a + b + c) / 2 +a = get_valid_side("Enter side 1: ") +b = get_valid_side("Enter side 2: ") +c = get_valid_side("Enter side 3: ") -# calculate the area -area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 +semi_perimeter = (a + b + c) / 2 + +area = sqrt((s * (s - a) * (s - b) * (s - c))) print("The area of the triangle is %0.2f" % area) diff --git a/image_compressor.py b/image_compressor.py new file mode 100644 index 00000000000..94d584136f6 --- /dev/null +++ b/image_compressor.py @@ -0,0 +1,51 @@ +import os +import sys +from PIL import Image + +def compress_image(image_path, quality=60): + """ + Compresses an image by reducing its quality. + + Args: + image_path (str): Path to the image file. + quality (int): Quality of the output image (1-100). Default is 60. + """ + try: + # Open the image + with Image.open(image_path) as img: + # Check if file is an image + if img.format not in ["JPEG", "PNG", "JPG"]: + print(f"Skipping {image_path}: Not a standard image format.") + return + + # Create output filename + filename, ext = os.path.splitext(image_path) + output_path = f"{filename}_compressed{ext}" + + # Save with reduced quality + # Optimize=True ensures the encoder does extra work to minimize size + img.save(output_path, quality=quality, optimize=True) + + # Calculate savings + original_size = os.path.getsize(image_path) + new_size = os.path.getsize(output_path) + savings = ((original_size - new_size) / original_size) * 100 + + print(f"[+] Compressed: {output_path}") + print(f" Original: {original_size/1024:.2f} KB") + print(f" New: {new_size/1024:.2f} KB") + print(f" Saved: {savings:.2f}%") + + except Exception as e: + print(f"[-] Error compressing {image_path}: {e}") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python image_compressor.py ") + print("Example: python image_compressor.py photo.jpg") + else: + target_file = sys.argv[1] + if os.path.exists(target_file): + compress_image(target_file) + else: + print(f"Error: File '{target_file}' not found.") \ No newline at end of file diff --git a/password_checker_code.py b/password_checker_code.py new file mode 100644 index 00000000000..788b928d6b7 --- /dev/null +++ b/password_checker_code.py @@ -0,0 +1,34 @@ +import string + +def check_password_strength(password): + strength = 0 + + # Criteria 1: Length (Must be at least 8 characters) + if len(password) >= 8: + strength += 1 + + # Criteria 2: Must contain Digits (0-9) + has_digit = False + for char in password: + if char.isdigit(): + has_digit = True + break + if has_digit: + strength += 1 + + # Criteria 3: Must contain Uppercase Letters (A-Z) + has_upper = False + for char in password: + if char.isupper(): + has_upper = True + break + if has_upper: + strength += 1 + + return strength + +if __name__ == "__main__": + print("--- Password Strength Checker ---") + # Note: We cannot run input() on the website, but this code is correct. + # If users download it, it will work. + print("Run this script locally to test your password!") diff --git a/photo_timestamp_renamer.py b/photo_timestamp_renamer.py new file mode 100644 index 00000000000..ba5df2ed9f1 --- /dev/null +++ b/photo_timestamp_renamer.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +""" +Author: Ivan Costa Neto +Date: 13-01-26 + +Auto-rename photos by timestamp, so you can organize those vacation trip photos!! + +Name format: YYYY-MM-DD_HH-MM-SS[_NN].ext + +Uses EXIF DateTimeOriginal when available (best for JPEG), +otherwise falls back to file modified time, + +i.e. + python rename_photos.py ~/Pictures/Trip --dry-run + python rename_photos.py ~/Pictures/Trip --recursive + python rename_photos.py . --prefix Japan --recursive +""" + +from __future__ import annotations +import argparse +from dataclasses import dataclass +from datetime import datetime +from pathlib import Path +import re +import sys + +SUPPORTED_EXTS = {".jpg", ".jpeg", ".png", ".heic", ".webp", ".tif", ".tiff"} + +# EXIF support is optional (w\ Pillow) +try: + from PIL import Image, ExifTags # type: ignore + PIL_OK = True +except Exception: + PIL_OK = False + + +def is_photo(p: Path) -> bool: + return p.is_file() and p.suffix.lower() in SUPPORTED_EXTS + + +def sanitize_prefix(s: str) -> str: + s = s.strip() + if not s: + return "" + s = re.sub(r"[^\w\-]+", "_", s) + return s[:50] + + +def exif_datetime_original(path: Path) -> datetime | None: + """ + Try to read EXIF DateTimeOriginal/DateTime from image. + Returns None if unavailable. + """ + if not PIL_OK: + return None + try: + img = Image.open(path) + exif = img.getexif() + if not exif: + return None + + # map EXIF tag ids -> names + tag_map = {} + for k, v in ExifTags.TAGS.items(): + tag_map[k] = v + + # common EXIF datetime tags + dto = None + dt = None + for tag_id, value in exif.items(): + name = tag_map.get(tag_id) + if name == "DateTimeOriginal": + dto = value + elif name == "DateTime": + dt = value + + raw = dto or dt + if not raw: + return None + + # EXIF datetime format: "YYYY:MM:DD HH:MM:SS" + raw = str(raw).strip() + return datetime.strptime(raw, "%Y:%m:%d %H:%M:%S") + except Exception: + return None + + +def file_mtime(path: Path) -> datetime: + return datetime.fromtimestamp(path.stat().st_mtime) + + +def unique_name(dest_dir: Path, base: str, ext: str) -> Path: + """ + If base.ext exists, append _01, _02, ... + """ + cand = dest_dir / f"{base}{ext}" + if not cand.exists(): + return cand + i = 1 + while True: + cand = dest_dir / f"{base}_{i:02d}{ext}" + if not cand.exists(): + return cand + i += 1 + + +@dataclass +class Options: + folder: Path + recursive: bool + dry_run: bool + prefix: str + keep_original: bool # if true, don't rename if it already matches our format + + +def already_formatted(name: str) -> bool: + # matches: YYYY-MM-DD_HH-MM-SS or with prefix and/or _NN + pattern = r"^(?:[A-Za-z0-9_]+_)?\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(?:_\d{2})?$" + return re.match(pattern, Path(name).stem) is not None + + +def gather_photos(folder: Path, recursive: bool) -> list[Path]: + if recursive: + return [p for p in folder.rglob("*") if is_photo(p)] + return [p for p in folder.iterdir() if is_photo(p)] + + +def rename_photos(opts: Options) -> int: + photos = gather_photos(opts.folder, opts.recursive) + photos.sort() + + if not photos: + print("No supported photo files found.") + return 0 + + if opts.prefix: + pref = sanitize_prefix(opts.prefix) + else: + pref = "" + + renamed = 0 + for p in photos: + if opts.keep_original and already_formatted(p.name): + continue + + dt = exif_datetime_original(p) or file_mtime(p) + base = dt.strftime("%Y-%m-%d_%H-%M-%S") + if pref: + base = f"{pref}_{base}" + + dest = unique_name(p.parent, base, p.suffix.lower()) + + if dest.name == p.name: + continue + + if opts.dry_run: + print(f"[DRY] {p.relative_to(opts.folder)} -> {dest.name}") + else: + p.rename(dest) + print(f"[OK ] {p.relative_to(opts.folder)} -> {dest.name}") + renamed += 1 + + if not opts.dry_run: + print(f"\nDone. Renamed {renamed} file(s).") + return renamed + + +def main(argv: list[str]) -> int: + ap = argparse.ArgumentParser(description="Auto-rename photos using EXIF date (or file modified time).") + ap.add_argument("folder", help="Folder containing photos") + ap.add_argument("--recursive", action="store_true", help="Process subfolders too") + ap.add_argument("--dry-run", action="store_true", help="Preview changes without renaming") + ap.add_argument("--prefix", default="", help="Optional prefix (e.g., Japan, RWTH, Trip)") + ap.add_argument("--keep-original", action="store_true", + help="Skip files that already match YYYY-MM-DD_HH-MM-SS naming") + args = ap.parse_args(argv) + + folder = Path(args.folder).expanduser() + if not folder.exists() or not folder.is_dir(): + print(f"Not a directory: {folder}", file=sys.stderr) + return 2 + + if not PIL_OK: + print("[Note] Pillow not installed; EXIF dates won't be read (mtime fallback only).") + print(" Install for best results: pip install pillow") + + opts = Options( + folder=folder, + recursive=args.recursive, + dry_run=args.dry_run, + prefix=args.prefix, + keep_original=args.keep_original, + ) + rename_photos(opts) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/requirements_with_versions.txt b/requirements_with_versions.txt index fefa2acb8b2..60d5414e0c8 100644 --- a/requirements_with_versions.txt +++ b/requirements_with_versions.txt @@ -28,7 +28,7 @@ requests==2.32.5 quo==2023.5.1 PyPDF2==3.0.1 pyserial==3.5 -twilio==9.9.0 +twilio==9.9.1 tabula==1.0.5 nltk==3.9.2 Pillow==12.1.0 @@ -41,7 +41,7 @@ tornado==6.5.4 obs==0.0.0 todo==0.1 oauth2client==4.1.3 -keras==3.13.0 +keras==3.13.1 pymongo==4.15.5 playsound==1.3.0 pyttsx3==2.99 @@ -49,16 +49,16 @@ auto-mix-prep==0.2.0 lib==4.0.0 pywifi==1.1.12 patterns==0.3 -openai==2.14.0 +openai==2.15.0 background==0.2.1 pydantic==2.12.5 openpyxl==3.1.2 pytesseract==0.3.13 requests-mock==1.12.1 pyglet==2.1.11 -urllib3==2.6.2 +urllib3==2.6.3 thirdai==0.9.33 -google-api-python-client==2.187.0 +google-api-python-client==2.188.0 sound==0.1.0 xlwt==1.3.0 pygame==2.6.1 @@ -81,7 +81,7 @@ Unidecode==1.4.0 Ball==0.2.9 pynput==1.8.1 gTTS==2.5.4 -ccxt==4.5.30 +ccxt==4.5.31 fitz==0.0.1.dev2 fastapi==0.128.0 Django==6.0 diff --git a/tic-tac-toe.py b/tic-tac-toe.py new file mode 100644 index 00000000000..30bc1c68ed8 --- /dev/null +++ b/tic-tac-toe.py @@ -0,0 +1,63 @@ +# Tic Tac Toe Game in Python + +board = [" " for _ in range(9)] + +def print_board(): + print() + print(f" {board[0]} | {board[1]} | {board[2]} ") + print("---|---|---") + print(f" {board[3]} | {board[4]} | {board[5]} ") + print("---|---|---") + print(f" {board[6]} | {board[7]} | {board[8]} ") + print() + +def check_winner(player): + win_conditions = [ + [0,1,2], [3,4,5], [6,7,8], # rows + [0,3,6], [1,4,7], [2,5,8], # columns + [0,4,8], [2,4,6] # diagonals + ] + for condition in win_conditions: + if all(board[i] == player for i in condition): + return True + return False + +def is_draw(): + return " " not in board + +current_player = "X" + +print("Welcome to Tic Tac Toe!") +print("Positions are numbered 1 to 9 as shown below:") +print(""" + 1 | 2 | 3 +---|---|--- + 4 | 5 | 6 +---|---|--- + 7 | 8 | 9 +""") + +while True: + print_board() + try: + move = int(input(f"Player {current_player}, choose position (1-9): ")) - 1 + if board[move] != " ": + print("That position is already taken. Try again.") + continue + except (ValueError, IndexError): + print("Invalid input. Enter a number between 1 and 9.") + continue + + board[move] = current_player + + if check_winner(current_player): + print_board() + print(f"🎉 Player {current_player} wins!") + break + + if is_draw(): + print_board() + print("🤝 It's a draw!") + break + + current_player = "O" if current_player == "X" else "X"