diff --git a/Python/sudoku_solver.py b/Python/sudoku_solver.py new file mode 100644 index 0000000..409e540 --- /dev/null +++ b/Python/sudoku_solver.py @@ -0,0 +1,307 @@ +from typing import List, Tuple, Optional +import tkinter as tk +from tkinter import ttk, messagebox +import math + +Grid = List[List[int]] + + +def find_empty(grid: Grid, N: int) -> Optional[Tuple[int, int]]: + for r in range(N): + for c in range(N): + if grid[r][c] == 0: + return r, c + return None + + +def is_valid(grid: Grid, row: int, col: int, num: int, N: int) -> bool: + if any(grid[row][c] == num for c in range(N)): + return False + if any(grid[r][col] == num for r in range(N)): + return False + b = math.isqrt(N) + br, bc = b * (row // b), b * (col // b) + for r in range(br, br + b): + for c in range(bc, bc + b): + if grid[r][c] == num: + return False + return True + + +def solve(grid: Grid, N: int) -> bool: + empty = find_empty(grid, N) + if not empty: + return True + r, c = empty + for n in range(1, N + 1): + if is_valid(grid, r, c, n, N): + grid[r][c] = n + if solve(grid, N): + return True + grid[r][c] = 0 + return False + + +def cell_text(val: int) -> str: + if val == 0: + return "" + if val <= 9: + return str(val) + return chr(ord('A') + val - 10) + + +class SudokuGUI: + def __init__(self, root: tk.Tk) -> None: + self.root = root + self.root.title("Sudoku Solver") + + self.N_options = [4, 9, 16] + self.N = 9 + self.grid: Grid = [[0 for _ in range(self.N)] for _ in range(self.N)] + self.selected: Optional[Tuple[int, int]] = None + self.fixed: List[List[bool]] = [[False for _ in range(self.N)] for _ in range(self.N)] + self.last_changed: Optional[Tuple[int, int]] = None + self.animating: bool = False + self.speed_var = tk.IntVar(value=60) + + self.size_var = tk.StringVar(value=str(self.N)) + + top = ttk.Frame(self.root) + top.pack(side=tk.TOP, fill=tk.X, padx=8, pady=8) + + ttk.Label(top, text="Grid size:").pack(side=tk.LEFT) + self.size_combo = ttk.Combobox( + top, + textvariable=self.size_var, + values=[str(n) for n in self.N_options], + state="readonly", + width=5, + ) + self.size_combo.pack(side=tk.LEFT, padx=(6, 12)) + + ttk.Button(top, text="New Grid", command=self.on_new_grid).pack(side=tk.LEFT) + ttk.Button(top, text="Solve", command=self.on_solve).pack(side=tk.LEFT, padx=6) + ttk.Button(top, text="Clear", command=self.on_clear).pack(side=tk.LEFT) + ttk.Button(top, text="Animate Solve", command=self.on_animate_solve).pack(side=tk.LEFT, padx=6) + tk.Scale(top, from_=10, to=300, orient=tk.HORIZONTAL, variable=self.speed_var, + label="Speed (ms)", length=140).pack(side=tk.LEFT, padx=6) + ttk.Button(top, text="Stop", command=self.on_stop_animation).pack(side=tk.LEFT) + + self.canvas = tk.Canvas(self.root, bg="white", highlightthickness=0) + self.canvas.pack(side=tk.TOP, padx=8, pady=8) + self.canvas.bind("", self.on_click) + self.canvas.bind("", self.on_key) + self.canvas.focus_set() + + self.redraw() + + def box_size(self) -> int: + return math.isqrt(self.N) + + def compute_sizes(self) -> Tuple[int, int]: + base = 540 + cell = max(28, base // self.N) + return cell, cell * self.N + + def redraw(self) -> None: + cell, total = self.compute_sizes() + self.canvas.config(width=total, height=total) + self.canvas.delete("all") + b = self.box_size() + + # Background highlights so grid lines remain visible + if self.selected is not None: + r, c = self.selected + self.canvas.create_rectangle(c * cell, r * cell, (c + 1) * cell, (r + 1) * cell, + fill="#fff9c4", outline="") + if self.last_changed is not None: + r2, c2 = self.last_changed + self.canvas.create_rectangle(c2 * cell, r2 * cell, (c2 + 1) * cell, (r2 + 1) * cell, + fill="#e3f2fd", outline="") + + for i in range(self.N + 1): + w = 3 if i % b == 0 else 1 + self.canvas.create_line(0, i * cell, total, i * cell, width=w, fill="#444") + self.canvas.create_line(i * cell, 0, i * cell, total, width=w, fill="#444") + + if self.selected is not None: + r, c = self.selected + self.canvas.create_rectangle( + c * cell + 1, + r * cell + 1, + (c + 1) * cell - 1, + (r + 1) * cell - 1, + outline="#d23", + width=2, + ) + + font_size = max(10, int(cell * 0.55)) + for r in range(self.N): + for c in range(self.N): + val = self.grid[r][c] + if val: + self.canvas.create_text( + c * cell + cell // 2, + r * cell + cell // 2, + text=cell_text(val), + font=("Helvetica", font_size, "bold"), + fill="#111" if self.fixed[r][c] else "#1a73e8", + anchor="center", + ) + + def on_click(self, event: tk.Event) -> None: + cell, total = self.compute_sizes() + c = min(self.N - 1, max(0, event.x // cell)) + r = min(self.N - 1, max(0, event.y // cell)) + self.selected = (r, c) + self.canvas.focus_set() + self.redraw() + + def on_key(self, event: tk.Event) -> None: + ks = event.keysym + + # Arrow key navigation + if ks in ("Up", "Down", "Left", "Right"): + r, c = self.selected if self.selected is not None else (0, 0) + if ks == "Up": + r = max(0, r - 1) + elif ks == "Down": + r = min(self.N - 1, r + 1) + elif ks == "Left": + c = max(0, c - 1) + elif ks == "Right": + c = min(self.N - 1, c + 1) + self.selected = (r, c) + self.redraw() + return + + # Editing values + if self.selected is None: + return + r, c = self.selected + ch = event.char + val: Optional[int] = None + + if ks in ("BackSpace", "Delete"): + val = 0 + elif ch and ch.isdigit(): + v = int(ch) + if 1 <= v <= min(9, self.N): + val = v + elif ch and ch.isalpha() and self.N > 9: + v = ord(ch.upper()) - ord('A') + 10 + if 10 <= v <= self.N: + val = v + + if val is not None: + self.grid[r][c] = val + self.last_changed = (r, c) + self.redraw() + + def on_new_grid(self) -> None: + try: + n = int(self.size_var.get()) + except ValueError: + messagebox.showerror("Error", "Grid size must be an integer.") + return + b = math.isqrt(n) + if b * b != n or n < 4: + messagebox.showerror("Error", "Grid size must be a perfect square (e.g., 4, 9, 16).") + return + self.N = n + self.grid = [[0 for _ in range(self.N)] for _ in range(self.N)] + self.selected = None + self.fixed = [[False for _ in range(self.N)] for _ in range(self.N)] + self.last_changed = None + self.animating = False + self.redraw() + + def on_clear(self) -> None: + for r in range(self.N): + for c in range(self.N): + self.grid[r][c] = 0 + self.selected = None + self.fixed = [[False for _ in range(self.N)] for _ in range(self.N)] + self.last_changed = None + self.animating = False + self.redraw() + + def on_solve(self) -> None: + if self.animating: + return + self.fixed = [[self.grid[r][c] != 0 for c in range(self.N)] for r in range(self.N)] + g = [row[:] for row in self.grid] + if solve(g, self.N): + self.grid = g + self.selected = None + self.last_changed = None + self.redraw() + else: + messagebox.showinfo("Result", "No solution found.") + + def on_animate_solve(self) -> None: + if self.animating: + return + # Prepare animation state + self.fixed = [[self.grid[r][c] != 0 for c in range(self.N)] for r in range(self.N)] + empties: List[Tuple[int, int]] = [] + for r in range(self.N): + for c in range(self.N): + if self.grid[r][c] == 0: + empties.append((r, c)) + self._anim_values = [0] * len(empties) + self._anim_empties = empties + self._anim_idx = 0 + self.animating = True + self.run_animation_step() + + def run_animation_step(self) -> None: + if not self.animating: + return + N = self.N + empties = self._anim_empties + values = self._anim_values + idx = self._anim_idx + + if idx == len(empties): + self.animating = False + self.last_changed = None + self.redraw() + messagebox.showinfo("Result", "Solved with animation.") + return + if idx < 0: + self.animating = False + self.last_changed = None + self.redraw() + messagebox.showinfo("Result", "No solution found.") + return + + r, c = empties[idx] + v = values[idx] + 1 + while v <= N and not is_valid(self.grid, r, c, v, N): + v += 1 + if v <= N: + values[idx] = v + self.grid[r][c] = v + self.last_changed = (r, c) + self._anim_idx = idx + 1 + else: + values[idx] = 0 + self.grid[r][c] = 0 + self.last_changed = (r, c) + self._anim_idx = idx - 1 + + self.redraw() + delay = max(1, int(self.speed_var.get())) + self.root.after(delay, self.run_animation_step) + + def on_stop_animation(self) -> None: + self.animating = False + self.last_changed = None + self.redraw() + + +if __name__ == "__main__": + root = tk.Tk() + SudokuGUI(root) + root.mainloop() \ No newline at end of file diff --git a/java/sorting/BubbleSort.java b/java/sorting/BubbleSort.java new file mode 100644 index 0000000..c65fc00 --- /dev/null +++ b/java/sorting/BubbleSort.java @@ -0,0 +1,33 @@ +public class BubbleSort { + public static void sort(int[] a) { + int n = a.length; + boolean swapped; + for (int i = 0; i < n - 1; i++) { + swapped = false; + for (int j = 0; j < n - i - 1; j++) { + if (a[j] > a[j + 1]) { + int t = a[j]; + a[j] = a[j + 1]; + a[j + 1] = t; + swapped = true; + } + } + if (!swapped) break; + } + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {5, 1, 4, 2, 8}; + sort(arr); + print(arr); + } +} \ No newline at end of file diff --git a/java/sorting/HeapSort.java b/java/sorting/HeapSort.java new file mode 100644 index 0000000..a28eaae --- /dev/null +++ b/java/sorting/HeapSort.java @@ -0,0 +1,41 @@ +public class HeapSort { + public static void sort(int[] a) { + int n = a.length; + for (int i = n / 2 - 1; i >= 0; i--) heapify(a, n, i); + for (int i = n - 1; i > 0; i--) { + int t = a[0]; + a[0] = a[i]; + a[i] = t; + heapify(a, i, 0); + } + } + + private static void heapify(int[] a, int n, int i) { + int largest = i; + int l = 2 * i + 1; + int r = 2 * i + 2; + if (l < n && a[l] > a[largest]) largest = l; + if (r < n && a[r] > a[largest]) largest = r; + if (largest != i) { + int t = a[i]; + a[i] = a[largest]; + a[largest] = t; + heapify(a, n, largest); + } + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {12, 11, 13, 5, 6, 7}; + sort(arr); + print(arr); + } +} \ No newline at end of file diff --git a/java/sorting/InsertionSort.java b/java/sorting/InsertionSort.java new file mode 100644 index 0000000..7115bec --- /dev/null +++ b/java/sorting/InsertionSort.java @@ -0,0 +1,28 @@ +public class InsertionSort { + public static void sort(int[] a) { + for (int i = 1; i < a.length; i++) { + int key = a[i]; + int j = i - 1; + while (j >= 0 && a[j] > key) { + a[j + 1] = a[j]; + j--; + } + a[j + 1] = key; + } + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {12, 11, 13, 5, 6}; + sort(arr); + print(arr); + } +} \ No newline at end of file diff --git a/java/sorting/MergeSort.java b/java/sorting/MergeSort.java new file mode 100644 index 0000000..c6107c2 --- /dev/null +++ b/java/sorting/MergeSort.java @@ -0,0 +1,41 @@ +public class MergeSort { + public static void sort(int[] a) { + if (a.length <= 1) return; + int[] tmp = new int[a.length]; + sort(a, tmp, 0, a.length - 1); + } + + private static void sort(int[] a, int[] tmp, int left, int right) { + if (left >= right) return; + int mid = left + (right - left) / 2; + sort(a, tmp, left, mid); + sort(a, tmp, mid + 1, right); + merge(a, tmp, left, mid, right); + } + + private static void merge(int[] a, int[] tmp, int left, int mid, int right) { + int i = left, j = mid + 1, k = left; + while (i <= mid && j <= right) { + if (a[i] <= a[j]) tmp[k++] = a[i++]; + else tmp[k++] = a[j++]; + } + while (i <= mid) tmp[k++] = a[i++]; + while (j <= right) tmp[k++] = a[j++]; + for (int p = left; p <= right; p++) a[p] = tmp[p]; + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {38, 27, 43, 3, 9, 82, 10}; + sort(arr); + print(arr); + } +} \ No newline at end of file diff --git a/java/sorting/QuickSort.java b/java/sorting/QuickSort.java new file mode 100644 index 0000000..723fa65 --- /dev/null +++ b/java/sorting/QuickSort.java @@ -0,0 +1,46 @@ +public class QuickSort { + public static void sort(int[] a) { + if (a.length <= 1) return; + quicksort(a, 0, a.length - 1); + } + + private static void quicksort(int[] a, int low, int high) { + if (low < high) { + int p = partition(a, low, high); + quicksort(a, low, p - 1); + quicksort(a, p + 1, high); + } + } + + private static int partition(int[] a, int low, int high) { + int pivot = a[high]; + int i = low - 1; + for (int j = low; j < high; j++) { + if (a[j] <= pivot) { + i++; + int t = a[i]; + a[i] = a[j]; + a[j] = t; + } + } + int t = a[i + 1]; + a[i + 1] = a[high]; + a[high] = t; + return i + 1; + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {10, 7, 8, 9, 1, 5}; + sort(arr); + print(arr); + } +} \ No newline at end of file diff --git a/java/sorting/SelectionSort.java b/java/sorting/SelectionSort.java new file mode 100644 index 0000000..27c7bd7 --- /dev/null +++ b/java/sorting/SelectionSort.java @@ -0,0 +1,29 @@ +public class SelectionSort { + public static void sort(int[] a) { + int n = a.length; + for (int i = 0; i < n - 1; i++) { + int minIdx = i; + for (int j = i + 1; j < n; j++) { + if (a[j] < a[minIdx]) minIdx = j; + } + int t = a[i]; + a[i] = a[minIdx]; + a[minIdx] = t; + } + } + + private static void print(int[] a) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < a.length; i++) { + if (i > 0) sb.append(" "); + sb.append(a[i]); + } + System.out.println(sb.toString()); + } + + public static void main(String[] args) { + int[] arr = {64, 25, 12, 22, 11}; + sort(arr); + print(arr); + } +} \ No newline at end of file