diff --git a/Binary_Search_Tree/bst.py b/Binary_Search_Tree/bst.py index 78acfbb3..e844a7c7 100644 --- a/Binary_Search_Tree/bst.py +++ b/Binary_Search_Tree/bst.py @@ -1,89 +1,93 @@ class BST: - def __init__(self,val,left,right): + def __init__(self, val, left=None, right=None): self.val = val self.left = left self.right = right - def addHelper(self,root,data): - - # case for reaching current leafs, base cases - if root.val < data and root.right == None: - root.right = BST(data,None,None) - return "insertion completed" - elif root.val > data and root.left == None: - root.left = BST(data,None,None) - return "insertion completed" - - # else we continue tracing downwards - if root.val < data: - return self.add(root.right,data) - elif root.val > data: - return self.add(root.left,data) + def addHelper(self, root, data): + if data < root.val: + if root.left is None: + root.left = BST(data) + return "insertion completed" + else: + return self.addHelper(root.left, data) + elif data > root.val: + if root.right is None: + root.right = BST(data) + return "insertion completed" + else: + return self.addHelper(root.right, data) else: return "insertion failed: duplicate value" - - def add(self,root,data): - if root == None: - return "insertion failed: empty root" - return self.addHelper(root,data) - - def restructdata(self,root): - # base case: we reach a leaf - if root == None or (root.left == None and root.right == None): - root = None - return "restructure finished" - - # need dummy nodes to compare target value to children value - v1 = float('-inf') - v2 = float('inf') - if root.left != None: - v1 = root.left.val - if root.right != None: - v2 = root.right.val - - temp = root.val - if v1 > v2 or v2 == float('inf'): - root.val = root.left.val - root.left.val = temp - return self.restructdata(root.left) - else: - root.val = root.right.val - root.right.val = temp - return self.restructdata(root.right) - - - def removeHelper(self,root,data): - if root == None: - return "deletion failed: could not find value" - - # adhering to typical bst properties - if root.val < data: - return self.removeHelper(root.right,data) - elif root.val > data: - return self.removeHelper(root.left,data) + + def add(self, data, root=None): + if root is None: + root = self + return self.addHelper(root, data) + + def _get_min(self, root): + current = root + while current.left is not None: + current = current.left + return current.val + + def removeHelper(self, root, data): + if root is None: + return root, False + + deleted = False + if data < root.val: + root.left, deleted = self.removeHelper(root.left, data) + elif data > root.val: + root.right, deleted = self.removeHelper(root.right, data) else: - temp = root.val - v1 = float('-inf') - v2 = float('inf') - if root.left != None: - v1 = root.left.val - elif root.right != None: - v2 = root.right.val - - if v1 > v2 or v2 == float('inf'): - root.val = root.left.val - root.left.val = temp - return self.restructdata(root.left) - else: - root.val = root.right.val - root.right.val = temp - return self.restructdata(root.right) - - def remove(self,root,data): - if root == None: + deleted = True + # Case 1: Leaf node + if root.left is None and root.right is None: + return None, True + # Case 2: One child + if root.left is None: + return root.right, True + if root.right is None: + return root.left, True + # Case 3: Two children - replace with in-order successor + min_val = self._get_min(root.right) + root.val = min_val + root.right, _ = self.removeHelper(root.right, min_val) + + return root, deleted + + def remove(self, data, root=None): + if root is None: + root = self + + if root == self and self.val == data and self.left is None and self.right is None: return "deletion failed: deleting from an empty tree" - return self.removeHelper(root,data) + + _, deleted = self.removeHelper(root, data) + if deleted: + return "deletion completed" + return "deletion failed: could not find value" + + def search(self, data): + if data == self.val: + return True + elif data < self.val and self.left: + return self.left.search(data) + elif data > self.val and self.right: + return self.right.search(data) + return False + + def inorder(self): + result = [] + if self.left: + result.extend(self.left.inorder()) + result.append(self.val) + if self.right: + result.extend(self.right.inorder()) + return result + diff --git a/Caterpillar_Game/Caterpillar.py b/Caterpillar_Game/Caterpillar.py index 12dc9849..e400bc04 100644 --- a/Caterpillar_Game/Caterpillar.py +++ b/Caterpillar_Game/Caterpillar.py @@ -10,31 +10,27 @@ caterpillar.hideturtle() leaf = t.Turtle() -leaf_shape = ((0,0),(14,2),(18,6),(20,20),(6,18),(2,14)) +leaf_shape = ((0, 0), (14, 2), (18, 6), (20, 20), (6, 18), (2, 14)) t.register_shape('leaf', leaf_shape) leaf.shape('leaf') leaf.color('green') leaf.penup() leaf.hideturtle() -leaf.speed() game_started = False -text_turtle = False text_turtle = t.Turtle() -text_turtle.write('Press SPACE to start', align='center', font=('Arial', 18, 'bold')) text_turtle.hideturtle() +text_turtle.penup() score_turtle = t.Turtle() score_turtle.hideturtle() score_turtle.speed(0) -obstacle = t.Turtle() -obstacle.shape('circle') # You can choose any shape -obstacle.color('red') # Choose a distinct color for obstacles -obstacle.penup() -obstacle.hideturtle() +game_over_turtle = t.Turtle() +game_over_turtle.hideturtle() +game_over_turtle.penup() -num_obstacles = 5 # Number of obstacles +num_obstacles = 5 obstacles = [] for _ in range(num_obstacles): @@ -42,95 +38,133 @@ new_obstacle.shape('circle') new_obstacle.color('red') new_obstacle.penup() - new_obstacle.setposition(rd.randint(-200, 200), rd.randint(-200, 200)) - new_obstacle.showturtle() + new_obstacle.hideturtle() obstacles.append(new_obstacle) - def outside_window(): - left_wall = -t.window_width()/2 - right_Wall = t.window_width()/2 - top_wall = t.window_height()/2 - bottom_wall = -t.window_height()/2 - (x,y) = caterpillar.pos() - outside = x < left_wall or x > right_Wall or y > top_wall or y < bottom_wall - return outside + left_wall = -t.window_width() / 2 + right_wall = t.window_width() / 2 + top_wall = t.window_height() / 2 + bottom_wall = -t.window_height() / 2 + x, y = caterpillar.pos() + return x < left_wall or x > right_wall or y > top_wall or y < bottom_wall def game_over(): + global game_started + game_started = False caterpillar.color('yellow') leaf.color('yellow') - t.penup() - t.hideturtle() - t.write('GAME OVER !', align='center', font=('Arial', 30, 'normal') ) - t.onkey(start_game,'space') + game_over_turtle.clear() + game_over_turtle.goto(0, 0) + game_over_turtle.write('GAME OVER !', align='center', font=('Arial', 30, 'bold')) + text_turtle.goto(0, -50) + text_turtle.write('Press SPACE to restart', align='center', font=('Arial', 18, 'bold')) def display_score(current_score): score_turtle.clear() score_turtle.penup() - x = (t.window_width()/2) - 70 - y = (t.window_height()/2) - 70 - score_turtle.setpos(x,y) + x = (t.window_width() / 2) - 70 + y = (t.window_height() / 2) - 70 + score_turtle.setpos(x, y) score_turtle.write(str(current_score), align='right', font=('Arial', 40, 'bold')) def place_leaf(): leaf.hideturtle() - leaf.setx(rd.randint(-200,200)) - leaf.sety(rd.randint(-200,200)) + leaf.setx(rd.randint(-200, 200)) + leaf.sety(rd.randint(-200, 200)) leaf.showturtle() +def place_obstacles(): + for obs in obstacles: + obs.hideturtle() + obs.setposition(rd.randint(-200, 200), rd.randint(-200, 200)) + obs.showturtle() + +caterpillar_speed = 2 +caterpillar_length = 3 +score = 0 + def start_game(): - global game_started + global game_started, caterpillar_speed, caterpillar_length, score if game_started: return game_started = True - - score = 0 + text_turtle.clear() + game_over_turtle.clear() + score = 0 caterpillar_speed = 2 caterpillar_length = 3 - caterpillar.shapesize(1,caterpillar_length,1) + + caterpillar.goto(0, 0) + caterpillar.setheading(0) + caterpillar.color('black') + caterpillar.shapesize(1, caterpillar_length, 1) caterpillar.showturtle() + + leaf.color('green') display_score(score) place_leaf() + place_obstacles() + + game_loop() - while True: - caterpillar.forward(caterpillar_speed) - for obstacle in obstacles: - if caterpillar.distance(leaf) < 20: - place_leaf() - caterpillar_length = caterpillar_length + 1 - caterpillar.shapesize(1,caterpillar_length,1) - caterpillar_speed = caterpillar_speed + 1 - score = score + 10 - display_score(score) - game_over() - break - if outside_window(): +def game_loop(): + global game_started, caterpillar_speed, caterpillar_length, score + if not game_started: + return + + caterpillar.forward(caterpillar_speed) + + # Check leaf collision + if caterpillar.distance(leaf) < 20: + place_leaf() + caterpillar_length += 1 + caterpillar.shapesize(1, caterpillar_length, 1) + caterpillar_speed += 0.5 + score += 10 + display_score(score) + + # Check obstacle collision + for obstacle in obstacles: + if caterpillar.distance(obstacle) < 20: game_over() - break - + return + + # Check boundary collision + if outside_window(): + game_over() + return + + t.ontimer(game_loop, 50) def move_up(): + if caterpillar.heading() != 270: caterpillar.setheading(90) def move_down(): + if caterpillar.heading() != 90: caterpillar.setheading(270) def move_left(): + if caterpillar.heading() != 0: caterpillar.setheading(180) def move_right(): + if caterpillar.heading() != 180: caterpillar.setheading(0) - -def restart_game(): - start_game() - -t.onkey(start_game,'space') -t.onkey(restart_game,'Up') -t.onkey(move_up,'Up') -t.onkey(move_right,'Right') -t.onkey(move_down,'Down') -t.onkey(move_left,'Left') + +text_turtle.goto(0, 0) +text_turtle.write('Press SPACE to start', align='center', font=('Arial', 18, 'bold')) + +t.onkey(start_game, 'space') +t.onkey(move_up, 'Up') +t.onkey(move_right, 'Right') +t.onkey(move_down, 'Down') +t.onkey(move_left, 'Left') t.listen() -t.mainloop() + +if __name__ == '__main__': + t.mainloop() + diff --git a/Chess_Game/ChessEngine.py b/Chess_Game/ChessEngine.py index 3355cc86..db9e6527 100644 --- a/Chess_Game/ChessEngine.py +++ b/Chess_Game/ChessEngine.py @@ -13,7 +13,7 @@ def __init__(self): ["wR", "wN", "wB", "wQ", "wK", "wB", "wN", "wR"]] self.moveFunctions = {'p': self.getPawnMoves, 'R': self.getRookMoves, 'N': self.getKnightMoves, 'B': self.getBishopMoves, 'Q': self.getQueenMoves, 'K': self.getKingMoves} - self.whiteToMove = True, + self.whiteToMove = True self.moveLog = [] self.whiteKingLocation = (7, 4) self.blackKingLocation = (0, 4) @@ -44,6 +44,8 @@ def undoMove(self): self.whiteKingLocation = (move.startRow, move.startCol) if move.pieceMoved == "bK": self.blackKingLocation = (move.startRow, move.startCol) + self.checkMate = False + self.staleMate = False """ All move considering checks """ diff --git a/Chess_Game/ChessGame.py b/Chess_Game/ChessGame.py index d221caf9..0750d732 100644 --- a/Chess_Game/ChessGame.py +++ b/Chess_Game/ChessGame.py @@ -8,11 +8,6 @@ IMAGES = {} -icon = p.image.load("images\icon.ico") -p.display.set_icon(icon) - -p.display.set_caption("Chess Game") - def loadImages(): pieces = ['wp', 'wR', 'wN', 'wB', 'wQ', 'wK', 'bp', 'bR', 'bN', 'bB', 'bQ', 'bK' ] for piece in pieces: @@ -20,6 +15,12 @@ def loadImages(): def main(): p.init() + try: + icon = p.image.load("images/icon.ico") + p.display.set_icon(icon) + except Exception: + pass + p.display.set_caption("Chess Game") screen = p.display.set_mode((WIDTH, HEIGHT)) clock = p.time.Clock() screen.fill(p.Color("white")) @@ -66,6 +67,7 @@ def main(): gs.undoMove() moveMade = True animate = False + gameOver = False if e.key == p.K_r: gs = ChessEngine.GameState() validMoves = gs.getValidMoves() @@ -73,6 +75,7 @@ def main(): playerClicks = [] moveMade = False animate = False + gameOver = False if moveMade: if animate: animatedMoves(gs.moveLog[-1], screen, gs.board,clock) diff --git a/Color_Game/main.py b/Color_Game/main.py index 4d1e68d9..d2529073 100644 --- a/Color_Game/main.py +++ b/Color_Game/main.py @@ -1,3 +1,4 @@ +import os import random import tkinter as tk from tkinter import messagebox @@ -5,12 +6,15 @@ colours = ['Red', 'Blue', 'Green', 'Yellow', 'Orange', 'Purple', 'Pink', 'Black', 'White'] score = 0 timeleft = 30 +game_running = False + +HIGHEST_SCORE_FILE = os.path.join(os.path.dirname(__file__), "highest_score.txt") def next_colour(): global score, timeleft if timeleft > 0: - user_input = e.get().lower() + user_input = e.get().lower().strip() correct_color = colours[1].lower() if user_input == correct_color: @@ -21,60 +25,69 @@ def next_colour(): label.config(fg=colours[1], text=colours[0]) score_label.config(text=f"Score: {score}") - def countdown(): - global timeleft + global timeleft, game_running if timeleft > 0: timeleft -= 1 time_label.config(text=f"Time left: {timeleft}") time_label.after(1000, countdown) else: - # messagebox.showwarning ('Attention', 'Your time is out!!') + game_running = False scoreshow() - def record_highest_score(): highest_score = load_highest_score() if score > highest_score: - with open("highest_score.txt", "w") as file: + with open(HIGHEST_SCORE_FILE, "w") as file: file.write(str(score)) - - def load_highest_score(): try: - with open("highest_score.txt", "r") as file: - data = file.read() + with open(HIGHEST_SCORE_FILE, "r") as file: + data = file.read().strip() if data: return int(data) else: return 0 - except FileNotFoundError: + except (FileNotFoundError, ValueError): return 0 - def scoreshow(): record_highest_score() - window2 = tk.Tk() + window2 = tk.Toplevel(window) window2.title("HIGH SCORE") window2.geometry("300x200") - label = tk.Label(window2, text=f"Highest Score: {load_highest_score()}",font=(font, 12)) - - label.pack() + label_hs = tk.Label(window2, text=f"Highest Score: {load_highest_score()}", font=(font, 14, "bold")) + label_hs.pack(pady=40) - window2.mainloop() + score_label.config(text="Game Over! Press Enter to restart") def start_game(event): - global timeleft - if timeleft == 30: + global timeleft, score, game_running + if not game_running and timeleft <= 0: + score = 0 + timeleft = 30 + score_label.config(text=f"Score: {score}") + time_label.config(text=f"Time left: {timeleft}") + + if not game_running: + game_running = True countdown() + next_colour() window = tk.Tk() font = 'Helvetica' window.title("Color Game") -window.iconbitmap("color_game_icon.ico") + +icon_path = os.path.join(os.path.dirname(__file__), "color_game_icon.ico") +if os.path.exists(icon_path): + try: + window.iconbitmap(icon_path) + except Exception: + pass + window.geometry("375x250") window.resizable(False, False) @@ -83,17 +96,21 @@ def start_game(event): score_label = tk.Label(window, text="Press Enter to start", font=(font, 12)) score_label.pack() - + time_label = tk.Label(window, text=f"Time left: {timeleft}", font=(font, 12)) time_label.pack() label = tk.Label(window, font=(font, 60)) label.pack(pady=20) +random.shuffle(colours) +label.config(fg=colours[1], text=colours[0]) + e = tk.Entry(window) window.bind('', start_game) e.pack() e.focus_set() -window.mainloop() \ No newline at end of file +if __name__ == '__main__': + window.mainloop() \ No newline at end of file diff --git a/Converter/converter.py b/Converter/converter.py index c21fb90b..b4ef6f2e 100644 --- a/Converter/converter.py +++ b/Converter/converter.py @@ -1,36 +1,65 @@ -from converter_values import * # import required files +from converter_values import options, CATEGORIES def main(): print(options["help"]) # prints help menu - res = input("Response: ") + res = input("Response: ").strip() while res.lower() != "q": # program loop try: - res = res.strip().split(" ") + parts = res.split() - if len(res) == 1: - display_help(res[0]) # display help menu - elif len(res) == 4: - perform_conversion(res) # perform unit conversion + if len(parts) == 1: + display_help(parts[0]) # display help menu + elif len(parts) == 4: + perform_conversion(parts) # perform unit conversion else: - print("Invalid command") + print("Invalid command. Type 'help' for options.") except Exception as e: print("Error:", e) - res = input("\nResponse: ") + res = input("\nResponse: ").strip() def display_help(command): """Display help menu.""" - print(options[command]) + if command in options: + print(options[command]) + else: + print(f"Unknown command '{command}'. Type 'help' or 'symbols' for available options.") def perform_conversion(res): - """Perform unit conversion.""" - for i in res[3].split(','): - value = round(eval("{} * {}['{}'] / {}['{}']".format(res[2], res[0], i, res[0], res[1])), 6) # calculating - print("{} \t : {}".format(i, value)) # displaying + """Perform unit conversion safely without eval.""" + cat_code = res[0].upper() + from_unit = res[1] + + try: + val = float(res[2]) + except ValueError: + print(f"Invalid numerical value '{res[2]}'.") + return + + if cat_code not in CATEGORIES: + print(f"Invalid category '{res[0]}'. Available categories: {', '.join(CATEGORIES.keys())}.") + return + + unit_dict = CATEGORIES[cat_code] + + if from_unit not in unit_dict: + print(f"Invalid source unit '{from_unit}' for category {cat_code}.") + return + + target_units = [u.strip() for u in res[3].split(',') if u.strip()] + + for target_unit in target_units: + if target_unit not in unit_dict: + print(f"Invalid target unit '{target_unit}' for category {cat_code}.") + continue + + value = round(val * unit_dict[target_unit] / unit_dict[from_unit], 6) + print("{} \t : {}".format(target_unit, value)) if __name__ == "__main__": main() + diff --git a/Converter/converter_values.py b/Converter/converter_values.py index 3cc9c104..85e9b7af 100644 --- a/Converter/converter_values.py +++ b/Converter/converter_values.py @@ -7,7 +7,7 @@ inch : in kilometer : km meter : m -micrometer ; um +micrometer : um mile : mi millimeter : mm nanometer : nm @@ -115,3 +115,12 @@ "min":1440 , "sec":86400 } +CATEGORIES = { + 'L': L, + 'A': A, + 'V': V, + 'M': M, + 'T': T +} + + diff --git a/Converting_Roman_to_Integer/Converting_Roman_to_Integer.py b/Converting_Roman_to_Integer/Converting_Roman_to_Integer.py index 5ad1ef3b..6b2de838 100644 --- a/Converting_Roman_to_Integer/Converting_Roman_to_Integer.py +++ b/Converting_Roman_to_Integer/Converting_Roman_to_Integer.py @@ -1,28 +1,88 @@ -import sys - - -romanStr = sys.argv[1] -romanStr = str(romanStr) -dict = { - 'I':1, - 'V':5, - 'X':10, - 'L':50, - 'C':100, - 'D':500, - 'M':1000 -} - -num = 0 - -romanStr = romanStr.replace("IV","IIII") -romanStr = romanStr.replace("IX","VIIII") -romanStr = romanStr.replace("XL","XXXX") -romanStr = romanStr.replace("XC","LXXXX") -romanStr = romanStr.replace("CD","CCCC") -romanStr = romanStr.replace("CM","DCCCC") -myStr = list(romanStr) -for char in myStr: - num = num + dict[char] - -print(num) \ No newline at end of file +import sys +import re + +ROMAN_VALUES = { + 'I': 1, + 'V': 5, + 'X': 10, + 'L': 50, + 'C': 100, + 'D': 500, + 'M': 1000 +} + +INT_TO_ROMAN_MAP = [ + (1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'), + (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'), + (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I') +] + +def validate_roman_sequence(roman_str: str) -> bool: + """Validate Roman numeral sequence formatting rules.""" + if re.search(r'(V{2,}|L{2,}|D{2,})', roman_str): + return False + if re.search(r'(I{4,}|X{4,}|C{4,}|M{4,})', roman_str): + return False + return True + +def roman_to_int(roman_str: str) -> int: + roman_str = roman_str.strip().upper() + if not roman_str: + raise ValueError("No Roman numeral provided.") + + invalid_chars = [char for char in roman_str if char not in ROMAN_VALUES] + if invalid_chars: + raise ValueError(f"Invalid Roman numeral character(s): '{''.join(set(invalid_chars))}'.") + + if not validate_roman_sequence(roman_str): + raise ValueError(f"Invalid Roman numeral sequence: '{roman_str}'.") + + temp_str = roman_str + temp_str = temp_str.replace("IV", "IIII") + temp_str = temp_str.replace("IX", "VIIII") + temp_str = temp_str.replace("XL", "XXXX") + temp_str = temp_str.replace("XC", "LXXXX") + temp_str = temp_str.replace("CD", "CCCC") + temp_str = temp_str.replace("CM", "DCCCC") + + num = sum(ROMAN_VALUES[char] for char in temp_str) + return num + +def int_to_roman(num: int) -> str: + if not (1 <= num <= 3999): + raise ValueError("Integer out of range (must be 1 to 3999).") + + result = [] + for value, symbol in INT_TO_ROMAN_MAP: + while num >= value: + result.append(symbol) + num -= value + return "".join(result) + +def main(): + if len(sys.argv) > 1: + user_input = sys.argv[1] + else: + user_input = input("Enter a Roman numeral or Integer: ") + + user_input = str(user_input).strip() + + if not user_input: + print("Error: No input provided.") + sys.exit(1) + + try: + if user_input.isdigit(): + val = int(user_input) + roman_res = int_to_roman(val) + print(f"Integer: {val} -> Roman: {roman_res}") + else: + int_res = roman_to_int(user_input) + print(f"Roman: {user_input.upper()} -> Integer: {int_res}") + except ValueError as e: + print(f"Error: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() + \ No newline at end of file diff --git a/Converting_Roman_to_Integer/README.md b/Converting_Roman_to_Integer/README.md index 0fbaa13b..2bf15986 100644 --- a/Converting_Roman_to_Integer/README.md +++ b/Converting_Roman_to_Integer/README.md @@ -1,2 +1,22 @@ -Fixed issue #73, Convert Roman to Integer. -CLI python 3.10 script to convert the Roman to Integer. +# Roman & Integer Converter + +A Python script to convert Roman numerals to integers and integers to Roman numerals. + +## Features +- **Bidirectional Conversion**: Convert Roman numerals to integers (e.g. `XIV` -> `14`) and integers to Roman numerals (e.g. `1994` -> `MCMXCIV`). +- **Input Validation**: Validates characters and prevents invalid Roman numeral formatting sequences (e.g. `VV`, `IIII`). +- **Modular Design**: Provides reusable `roman_to_int(s)` and `int_to_roman(n)` functions. + +## Usage + +### Roman to Integer +```bash +python Converting_Roman_to_Integer/Converting_Roman_to_Integer.py XIV +# Output: Roman: XIV -> Integer: 14 +``` + +### Integer to Roman +```bash +python Converting_Roman_to_Integer/Converting_Roman_to_Integer.py 1994 +# Output: Integer: 1994 -> Roman: MCMXCIV +``` diff --git a/Convoys_GameofLife/GameOfLife.py b/Convoys_GameofLife/GameOfLife.py index de7a2f5d..cb1eda81 100644 --- a/Convoys_GameofLife/GameOfLife.py +++ b/Convoys_GameofLife/GameOfLife.py @@ -1,147 +1,148 @@ -#!/usr/bin/python3 - -import curses -import random -import time -import copy - - -def GameOfLife(stdscr): - k = 0 - cursor_x, cursor_y = 0, 0 - generations = 0 - grid = [] - height, width = stdscr.getmaxyx() - rows, cols = int(height-2), width - speed = .2 - pause = False - - stdscr.clear() - stdscr.refresh() - - # colors in curses - curses.start_color() - curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK) - curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) - curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) - - def initialize(): - return [[False for _ in range(cols)] for _ in range(rows)] - - def seed(): - grid = initialize() - for i in range(rows): - for j in range(cols): - if int(random.random() * 4) == 0: - grid[i][j] = True - return grid - - def play(grid): - noOfCellsAlive = 0 - nGrid = copy.deepcopy(grid) - dR = [1, 1, 1, -1, -1, -1, 0, 0] - dC = [1, 0, -1, -1, 0, 1, 1, -1] - - def isValid(r, c) -> bool: - return (r >= 0 and r < rows and c >= 0 and c < cols) - - for i in range(rows): - for j in range(cols): - count = 0 - for r1, c1 in zip(dR, dC): - r = r1+i - c = c1+j - - if isValid(r, c) and grid[r][c]: - count += 1 - - if grid[i][j] and (count < 2 or count > 3): - nGrid[i][j] = False - if grid[i][j] == False and count == 3: - nGrid[i][j] = True - - noOfCellsAlive += nGrid[i][j] - - return [nGrid, noOfCellsAlive] - - # Inception - grid = seed() - - while True: - # Initialization - stdscr.clear() - stdscr.nodelay(1) - nHeight, nWidth = stdscr.getmaxyx() - - generations += 1 - - # If windows dimension changes #responsive :) - if ((nHeight != height) or (nWidth != width)): - height, width = nHeight, nWidth - rows, cols = int(height-3), width - grid = seed() - - # Simulating Generations - grid, noOfCellsAlive = play(grid) - - # Menu Cmds - if k == ord('q'): - break - elif k == ord('r'): - grid = seed() - generations = 0 - elif k == ord('f'): - speed = 0.1 - elif k == ord('s'): - speed = 1 - - # Displaying grid - stdscr.attron(curses.color_pair(1)) - stdscr.attron(curses.A_BOLD) - for i in range(rows): - for j in range(cols): - stdscr.addstr(i, j, chr(0x2B1A) if grid[i][j] else ' ') - - stdscr.attroff(curses.color_pair(1)) - stdscr.attroff(curses.A_BOLD) - - # Declaration of strings - title = 'Game Of Life' - credits = 'By @zeal2end' - statusbarstr = "Exit: 'q' | Seed: 'r' | Fast: 'f' | Slow: 's' | Genration: {} | Alive Cells: {}".format( - generations, noOfCellsAlive) - - # calculations - start_x_title = 0 - start_x_credit = width - len(credits) - 1 - start_y = int(height - 2) - - # Render status bar - stdscr.attron(curses.color_pair(3)) - stdscr.addstr(height-1, 0, statusbarstr) - stdscr.attroff(curses.color_pair(3)) - - # Turning on attributes for title - stdscr.attron(curses.color_pair(2)) - - # Rendering title - stdscr.addstr(start_y, start_x_title, title) - stdscr.addstr(start_y, start_x_credit, credits) - - # Turning off attributes for title - stdscr.attroff(curses.color_pair(2)) - - # Refresh the screen - stdscr.refresh() - time.sleep(speed) - - # Wait for next input - k = stdscr.getch() - - -def main(): - curses.wrapper(GameOfLife) - - -if __name__ == "__main__": - main() \ No newline at end of file +#!/usr/bin/python3 + +import curses +import random +import time +import copy + + +def GameOfLife(stdscr): + k = 0 + generations = 0 + height, width = stdscr.getmaxyx() + rows, cols = max(1, height - 3), max(1, width - 1) + speed = 0.2 + pause = False + + stdscr.clear() + stdscr.refresh() + + # colors in curses + curses.start_color() + curses.use_default_colors() + curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK) + curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) + curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK) + + def initialize(): + return [[False for _ in range(cols)] for _ in range(rows)] + + def seed(): + grid = initialize() + for i in range(rows): + for j in range(cols): + if random.random() < 0.25: + grid[i][j] = True + return grid + + def play(grid): + noOfCellsAlive = 0 + nGrid = copy.deepcopy(grid) + dR = [1, 1, 1, -1, -1, -1, 0, 0] + dC = [1, 0, -1, -1, 0, 1, 1, -1] + + def isValid(r, c) -> bool: + return (0 <= r < rows and 0 <= c < cols) + + for i in range(rows): + for j in range(cols): + count = 0 + for r1, c1 in zip(dR, dC): + r = r1 + i + c = c1 + j + if isValid(r, c) and grid[r][c]: + count += 1 + + if grid[i][j] and (count < 2 or count > 3): + nGrid[i][j] = False + elif not grid[i][j] and count == 3: + nGrid[i][j] = True + + if nGrid[i][j]: + noOfCellsAlive += 1 + + return nGrid, noOfCellsAlive + + def safe_addstr(y, x, str_content, attr=0): + """Safely write string to curses window without boundary overflow crash.""" + if y < 0 or y >= height or x < 0 or x >= width: + return + max_len = width - x - 1 + if max_len <= 0: + return + try: + stdscr.addstr(y, x, str_content[:max_len], attr) + except curses.error: + pass + + # Inception + grid = seed() + noOfCellsAlive = sum(sum(1 for cell in row if cell) for row in grid) + + while True: + stdscr.clear() + stdscr.nodelay(1) + nHeight, nWidth = stdscr.getmaxyx() + + # Handle window resize + if (nHeight != height) or (nWidth != width): + height, width = nHeight, nWidth + rows, cols = max(1, height - 3), max(1, width - 1) + grid = seed() + + # Handle commands + if k == ord('q'): + break + elif k == ord('r'): + grid = seed() + generations = 0 + pause = False + elif k == ord('f'): + speed = 0.05 + elif k == ord('s'): + speed = 0.5 + elif k == ord('p') or k == ord(' '): + pause = not pause + + # Simulate Generation if not paused + if not pause: + generations += 1 + grid, noOfCellsAlive = play(grid) + + # Displaying grid + color_attr = curses.color_pair(1) | curses.A_BOLD + for i in range(min(rows, height - 3)): + for j in range(min(cols, width - 1)): + if grid[i][j]: + safe_addstr(i, j, '#', color_attr) + + # Status strings + title = 'Game Of Life' + credits = 'By @zeal2end' + pause_str = ' [PAUSED]' if pause else '' + statusbarstr = "Exit: 'q' | Reset: 'r' | Pause: 'p'/'Space' | Fast: 'f' | Slow: 's' | Gen: {}{} | Alive: {}".format( + generations, pause_str, noOfCellsAlive) + + start_x_title = 0 + start_x_credit = max(0, width - len(credits) - 1) + start_y = max(0, height - 2) + + # Render status bar + safe_addstr(height - 1, 0, statusbarstr, curses.color_pair(3)) + + # Render title & credits + safe_addstr(start_y, start_x_title, title, curses.color_pair(2)) + safe_addstr(start_y, start_x_credit, credits, curses.color_pair(2)) + + stdscr.refresh() + time.sleep(speed) + + k = stdscr.getch() + + +def main(): + curses.wrapper(GameOfLife) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Dice_Rolling_Stimulator/dice_stimulator.py b/Dice_Rolling_Stimulator/dice_stimulator.py index 1263bb6e..5905c648 100644 --- a/Dice_Rolling_Stimulator/dice_stimulator.py +++ b/Dice_Rolling_Stimulator/dice_stimulator.py @@ -1,71 +1,83 @@ -import random -#CATEGORIZING OUTCOME INTO A LIST - -one = """ - ("===========") - ("| |") - ("| O |") - ("| |") - ("===========")\n - - """ - -two = """ - ("===========") - ("| |") - ("| O O |") - ("| |") - ("===========")\n - - """ - - - -three = """ - ("===========") - ("| O |") - ("| O |") - ("| O |") - ("===========")\n - - """ - -four = """ - ("===========") - ("| O O |") - ("| 0 |") - ("| O O |") - ("===========")\n - - """ - -five = """ - ("===========") - ("| O O |") - ("| 0 |") - ("| O O |") - ("===========")\n - - """ - -six = """ - ("===========") - ("| O O |") - ("| O O |") - ("| O O |") - ("===========") \n - """ - - - -outcomes_list = [one, two, three, four, five, six] - - -print("This is a dice stimulator") -x = "y" -while x == "y": - randon_outcome = random.sample(outcomes_list, 2) - for outcome in randon_outcome: - print(outcome) - - x = input("Press y to roll again ") \ No newline at end of file +import random + +one = """ ++-----------+ +| | +| O | +| | ++-----------+ +""" + +two = """ ++-----------+ +| O | +| | +| O | ++-----------+ +""" + +three = """ ++-----------+ +| O | +| O | +| O | ++-----------+ +""" + +four = """ ++-----------+ +| O O | +| | +| O O | ++-----------+ +""" + +five = """ ++-----------+ +| O O | +| O | +| O O | ++-----------+ +""" + +six = """ ++-----------+ +| O O | +| O O | +| O O | ++-----------+ +""" + +DICE_FACES = { + 1: one, + 2: two, + 3: three, + 4: four, + 5: five, + 6: six +} + +def roll_dice(num_dice=2): + """Roll a specified number of independent dice with replacement.""" + return [random.randint(1, 6) for _ in range(num_dice)] + +def main(): + print("=================================") + print(" Welcome to Dice Simulator ") + print("=================================") + + rolling = True + while rolling: + dice_values = roll_dice(2) + + print(f"\nYou rolled: {dice_values[0]} and {dice_values[1]} (Total: {sum(dice_values)})") + for val in dice_values: + print(DICE_FACES[val]) + + response = input("Press [Enter] or 'y' to roll again, or 'q' to quit: ").strip().lower() + if response in ('q', 'quit', 'n', 'no', 'exit'): + rolling = False + print("Thanks for playing!") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/csv_to_json/README.md b/csv_to_json/README.md index a89b566d..a3554253 100644 --- a/csv_to_json/README.md +++ b/csv_to_json/README.md @@ -5,22 +5,26 @@ # CSV TO JSON ## 🛠️ Description - -This script helps to convert a csv file to a json file. +This script converts CSV files to formatted JSON files. -## ⚙️ Languages or Frameworks Used - -language used - python3. -Packages required - csv and json. -if not already installed use pip3 install csv and pip3 install json. -(If there are a lot of them, including a `requirements.txt` file will work better.) +## 🚀 Features +- **Dynamic Output Naming**: Automatically derives JSON filename from input (e.g. `users.csv` -> `users.json`). +- **CLI & Interactive Mode**: Accepts command-line arguments or prompts interactively. +- **Smart Data Parsing**: Auto-parses numeric and boolean values into native JSON types. +- **UTF-8 Encoding**: Handles special characters and UTF-8 BOM encoding. ## 🌟 How to run - -python3 csv_to_json.py. +### Command Line +```bash +python csv_to_json.py input.csv [output.json] +``` +### Interactive Mode +```bash +python csv_to_json.py +``` ## 🤖 Author - Rajit Gupta. + diff --git a/csv_to_json/csv_to_json.py b/csv_to_json/csv_to_json.py index 2baed6b5..cfb4d2d5 100644 --- a/csv_to_json/csv_to_json.py +++ b/csv_to_json/csv_to_json.py @@ -1,20 +1,74 @@ -import csv -import json - -# Function to convert csv to json -def csv_to_json(file_name): - with open(file_name , 'r') as csv_file: - csv_data=csv.DictReader(csv_file) - data_list=[row for row in csv_data] - json_data = json.dumps(data_list, indent=4) - - with open('data.json','w') as json_file: - json_file.write(json_data) - -# main function -def main(): - file_name=input() - csv_to_json(file_name) - -if __name__ == '__main__': - main() \ No newline at end of file +import csv +import json +import os +import sys + +def parse_value(val: str): + """Parse string value into native Python/JSON data types.""" + if val is None: + return None + val_str = val.strip() + if val_str == "": + return None + if val_str.lower() == "true": + return True + if val_str.lower() == "false": + return False + + try: + return int(val_str) + except ValueError: + pass + + try: + return float(val_str) + except ValueError: + pass + + return val + +def csv_to_json(input_file: str, output_file: str = None, parse_types: bool = True) -> str: + """Convert CSV file to JSON format.""" + if not os.path.exists(input_file): + raise FileNotFoundError(f"Input file '{input_file}' not found.") + + if not output_file: + base_name, _ = os.path.splitext(input_file) + output_file = f"{base_name}.json" + + with open(input_file, mode='r', encoding='utf-8-sig') as csv_file: + csv_reader = csv.DictReader(csv_file) + data_list = [] + for row in csv_reader: + if parse_types: + parsed_row = {k: parse_value(v) for k, v in row.items()} + data_list.append(parsed_row) + else: + data_list.append(dict(row)) + + with open(output_file, mode='w', encoding='utf-8') as json_file: + json.dump(data_list, json_file, indent=4, ensure_ascii=False) + + return output_file + +def main(): + if len(sys.argv) > 1: + input_file = sys.argv[1] + output_file = sys.argv[2] if len(sys.argv) > 2 else None + else: + input_file = input("Enter CSV file path: ").strip() + output_file = None + + if not input_file: + print("Error: No input CSV file provided.") + sys.exit(1) + + try: + out_path = csv_to_json(input_file, output_file) + print(f"Successfully converted '{input_file}' to '{out_path}'.") + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + +if __name__ == '__main__': + main() \ No newline at end of file