Skip to content

Commit 53fa48f

Browse files
Add progress generator and CI
1 parent 1c78e51 commit 53fa48f

4 files changed

Lines changed: 144 additions & 93 deletions

File tree

.github/workflows/check.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Check
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Check out repository
13+
uses: actions/checkout@v4
14+
15+
- name: Set up Java 21
16+
uses: actions/setup-java@v4
17+
with:
18+
distribution: temurin
19+
java-version: "21"
20+
21+
- name: Generate progress
22+
run: python3 scripts/generate_progress.py
23+
24+
- name: Check generated progress is up to date
25+
run: git diff --exit-code PROGRESS.md
26+
27+
- name: Compile Java solutions
28+
shell: bash
29+
run: |
30+
set -euo pipefail
31+
while IFS= read -r -d '' file; do
32+
out_dir="$(mktemp -d)"
33+
tmp_file="$out_dir/Solution.java"
34+
printf 'import java.util.*;\n' > "$tmp_file"
35+
cat "$file" >> "$tmp_file"
36+
javac --release 21 -d "$out_dir" "$tmp_file"
37+
rm -rf "$out_dir"
38+
done < <(find leetcode/java -name Solution.java -print0)

PROGRESS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Progress
2+
3+
| Platform | Difficulty | Problem | Language | Solution | Notes |
4+
|---|---|---|---|---|---|
5+
| leetcode | easy | 0001. two sum | Java | [Solution.java](leetcode/java/easy/0001-two-sum/Solution.java) | [notes.md](leetcode/java/easy/0001-two-sum/notes.md) |
6+
| leetcode | easy | 0125. valid palindrome | Java | [Solution.java](leetcode/java/easy/0125-valid-palindrome/Solution.java) | [notes.md](leetcode/java/easy/0125-valid-palindrome/notes.md) |
7+
| leetcode | easy | 0228. summary ranges | Java | [Solution.java](leetcode/java/easy/0228-summary-ranges/Solution.java) | [notes.md](leetcode/java/easy/0228-summary-ranges/notes.md) |
8+
| leetcode | easy | 0283. move zeroes | Java | [Solution.java](leetcode/java/easy/0283-move-zeroes/Solution.java) | [notes.md](leetcode/java/easy/0283-move-zeroes/notes.md) |
9+
| leetcode | easy | 1446. consecutive characters | Java | [Solution.java](leetcode/java/easy/1446-consecutive-characters/Solution.java) | [notes.md](leetcode/java/easy/1446-consecutive-characters/notes.md) |
10+
| leetcode | medium | 0443. string compression | Java | [Solution.java](leetcode/java/medium/0443-string-compression/Solution.java) | [notes.md](leetcode/java/medium/0443-string-compression/notes.md) |
11+
| leetcode | medium | 0560. subarray sum equals k | Java | [Solution.java](leetcode/java/medium/0560-subarray-sum-equals-k/Solution.java) | [notes.md](leetcode/java/medium/0560-subarray-sum-equals-k/notes.md) |
12+
| leetcode | medium | 1493. longest subarray of 1s after deleting one element | Java | [Solution.java](leetcode/java/medium/1493-longest-subarray-of-1s-after-deleting-one-element/Solution.java) | [notes.md](leetcode/java/medium/1493-longest-subarray-of-1s-after-deleting-one-element/notes.md) |

scripts/generate_progress.py

Lines changed: 66 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,131 +2,104 @@
22
import re
33
import sys
44

5-
ROOT = Path(__file__).resolve().parents[1]
6-
7-
PLATFORMS = ["leetcode"]
8-
DIFFICULTIES = ["easy", "medium", "hard"]
9-
10-
LANGUAGE_NAMES = {
11-
"java": "Java",
12-
"python": "Python",
13-
"cpp": "C++",
14-
}
15-
16-
SOLUTION_FILES = {
17-
"java": "Solution.java",
18-
"python": "solution.py",
19-
"cpp": "solution.cpp",
20-
}
215

6+
ROOT = Path(__file__).resolve().parents[1]
7+
PLATFORM = "leetcode"
8+
LANGUAGE = "java"
9+
LANGUAGE_LABEL = "Java"
10+
DIFFICULTIES = ("easy", "medium", "hard")
11+
SOLUTION_FILE = "Solution.java"
12+
NOTES_FILE = "notes.md"
2213

23-
def parse_problem_name(folder_name: str):
24-
match = re.match(r"^(\d+)[-_](.+)$", folder_name)
2514

15+
def title_from_folder(folder_name: str) -> str:
16+
match = re.match(r"^(\d{4})-(.+)$", folder_name)
2617
if not match:
27-
return None, folder_name.replace("-", " ")
18+
return folder_name
2819

29-
problem_id = match.group(1)
30-
title = match.group(2).replace("-", " ").replace("_", " ")
20+
problem_id, slug = match.groups()
21+
title = slug.replace("-", " ")
22+
return f"{problem_id}. {title}"
3123

32-
return int(problem_id), f"{problem_id}. {title}"
3324

34-
35-
def path_link(path: Path) -> str:
25+
def repo_path(path: Path) -> str:
3626
return path.relative_to(ROOT).as_posix()
3727

3828

39-
def main():
29+
def build_rows() -> tuple[list[dict[str, str]], list[str]]:
4030
rows = []
4131
errors = []
32+
java_root = ROOT / PLATFORM / LANGUAGE
4233

43-
for platform in PLATFORMS:
44-
platform_dir = ROOT / platform
45-
46-
if not platform_dir.exists():
34+
for difficulty in DIFFICULTIES:
35+
difficulty_dir = java_root / difficulty
36+
if not difficulty_dir.exists():
4737
continue
4838

49-
for lang_dir in platform_dir.iterdir():
50-
if not lang_dir.is_dir():
39+
for problem_dir in sorted(difficulty_dir.iterdir(), key=lambda path: path.name):
40+
if not problem_dir.is_dir():
5141
continue
5242

53-
lang = lang_dir.name
54-
lang_name = LANGUAGE_NAMES.get(lang, lang)
55-
56-
for difficulty in DIFFICULTIES:
57-
difficulty_dir = lang_dir / difficulty
58-
59-
if not difficulty_dir.exists():
60-
continue
61-
62-
for problem_dir in sorted(difficulty_dir.iterdir()):
63-
if not problem_dir.is_dir():
64-
continue
65-
66-
problem_id, problem_title = parse_problem_name(problem_dir.name)
67-
68-
expected_solution = SOLUTION_FILES.get(lang)
69-
solution_path = problem_dir / expected_solution if expected_solution else None
70-
notes_path = problem_dir / "notes.md"
71-
72-
if expected_solution and not solution_path.exists():
73-
errors.append(
74-
f"Missing {expected_solution}: {path_link(problem_dir)}"
75-
)
43+
solution_path = problem_dir / SOLUTION_FILE
44+
notes_path = problem_dir / NOTES_FILE
45+
46+
if not solution_path.exists():
47+
errors.append(f"Missing {SOLUTION_FILE}: {repo_path(problem_dir)}")
48+
if not notes_path.exists():
49+
errors.append(f"Missing {NOTES_FILE}: {repo_path(problem_dir)}")
50+
51+
rows.append(
52+
{
53+
"platform": PLATFORM,
54+
"difficulty": difficulty,
55+
"problem": title_from_folder(problem_dir.name),
56+
"language": LANGUAGE_LABEL,
57+
"solution": (
58+
f"[{SOLUTION_FILE}]({repo_path(solution_path)})"
59+
if solution_path.exists()
60+
else "-"
61+
),
62+
"notes": (
63+
f"[{NOTES_FILE}]({repo_path(notes_path)})"
64+
if notes_path.exists()
65+
else "-"
66+
),
67+
}
68+
)
7669

77-
if not notes_path.exists():
78-
errors.append(
79-
f"Missing notes.md: {path_link(problem_dir)}"
80-
)
70+
return rows, errors
8171

82-
solution_cell = (
83-
f"[{expected_solution}]({path_link(solution_path)})"
84-
if solution_path and solution_path.exists()
85-
else "—"
86-
)
8772

88-
notes_cell = (
89-
f"[notes.md]({path_link(notes_path)})"
90-
if notes_path.exists()
91-
else "—"
92-
)
93-
94-
rows.append({
95-
"platform": platform.capitalize(),
96-
"difficulty": difficulty.capitalize(),
97-
"problem": problem_title,
98-
"language": lang_name,
99-
"solution": solution_cell,
100-
"notes": notes_cell,
101-
"sort_id": problem_id if problem_id is not None else 10**9,
102-
})
103-
104-
rows.sort(key=lambda row: (row["platform"], row["language"], row["difficulty"], row["sort_id"], row["problem"]))
105-
106-
progress = []
107-
progress.append("# Progress")
108-
progress.append("")
109-
progress.append(f"Total solved: **{len(rows)}**")
110-
progress.append("")
111-
progress.append("| Platform | Difficulty | Problem | Language | Solution | Notes |")
112-
progress.append("|---|---|---|---|---|---|")
73+
def render_progress(rows: list[dict[str, str]]) -> str:
74+
lines = [
75+
"# Progress",
76+
"",
77+
"| Platform | Difficulty | Problem | Language | Solution | Notes |",
78+
"|---|---|---|---|---|---|",
79+
]
11380

11481
for row in rows:
115-
progress.append(
82+
lines.append(
11683
f"| {row['platform']} | {row['difficulty']} | {row['problem']} | "
11784
f"{row['language']} | {row['solution']} | {row['notes']} |"
11885
)
11986

120-
progress.append("")
87+
lines.append("")
88+
return "\n".join(lines)
12189

122-
(ROOT / "PROGRESS.md").write_text("\n".join(progress), encoding="utf-8")
90+
91+
def main() -> int:
92+
rows, errors = build_rows()
93+
(ROOT / "PROGRESS.md").write_text(render_progress(rows), encoding="utf-8")
12394

12495
if errors:
12596
print("Repository structure errors:")
12697
for error in errors:
12798
print(f"- {error}")
128-
sys.exit(1)
99+
return 1
100+
101+
return 0
129102

130103

131104
if __name__ == "__main__":
132-
main()
105+
sys.exit(main())

templates/notes-template.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Problem title
2+
3+
## Link
4+
5+
LeetCode:
6+
7+
## Pattern
8+
9+
-
10+
11+
## Idea
12+
13+
### Rus
14+
15+
Краткое объяснение идеи решения.
16+
17+
### Eng
18+
19+
Brief explanation of the solution idea.
20+
21+
## Complexity
22+
23+
- Time: O(...)
24+
- Space: O(...)
25+
26+
## Problems
27+
28+
-

0 commit comments

Comments
 (0)