Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 307 additions & 0 deletions Python/sudoku_solver.py
Original file line number Diff line number Diff line change
@@ -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("<Button-1>", self.on_click)
self.canvas.bind("<Key>", 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()
33 changes: 33 additions & 0 deletions java/sorting/BubbleSort.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
41 changes: 41 additions & 0 deletions java/sorting/HeapSort.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading