Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/indexes/by-category.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ _No entries yet._

## SQL

_No entries yet._
_No entries yet._
2 changes: 1 addition & 1 deletion docs/indexes/by-difficulty.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ _No entries yet._

## Level 10

_No entries yet._
_No entries yet._
2 changes: 1 addition & 1 deletion docs/indexes/by-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ _No entries yet._

## SQL

_No entries yet._
_No entries yet._
2 changes: 1 addition & 1 deletion docs/indexes/by-topic.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ _No entries yet._

## Dynamic Programming

_No entries yet._
_No entries yet._
4 changes: 2 additions & 2 deletions problems/3400-3499/3484-divided-class/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 3484 — Divided Class
# 3484: Divided Class

## Link
https://judge.beecrowd.com/pt/problems/view/3484
Expand All @@ -9,7 +9,7 @@ https://judge.beecrowd.com/pt/problems/view/3484
- Platform: Beecrowd
- Category: Data Structures and Libraries
- Difficulty Level: 2
- Topics: binary search tree, tree depth, simulation
- Topics: Data Structures, Simulation
- Primary Language: C++
- Other Implementations: None
- Documentation Level: L2
Expand Down
11 changes: 9 additions & 2 deletions scripts/check_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
2. structure and metadata validation (validate_structure.py)
3. style and safety lint (lint_solutions.py)
4. build and run all test cases (run_tests.py)
5. tracker/index drift (sync_index.py --check)

Scope:
python scripts/check_all.py # whole repository
Expand All @@ -31,6 +32,7 @@

import lint_solutions
import run_tests
import sync_index
import validate_structure
from repo_lib import changed_files, find_problem_dirs, implementations, problem_dirs_for

Expand Down Expand Up @@ -97,12 +99,13 @@ def step(name: str, runner) -> None: # noqa: ANN001
else:
step("script unit tests", run_unit_tests)

common = ["--root", str(root)]
flags = (["--strict"] if args.strict else []) + (["--github"] if args.github else [])

if nothing_to_check:
print("\nNo problem folders changed: structure, lint and tests skipped.")
steps += [("structure validation", None), ("lint", None), ("solution tests", None)]
else:
common = ["--root", str(root)]
flags = (["--strict"] if args.strict else []) + (["--github"] if args.github else [])
step("structure validation", lambda: validate_structure.main([*common, *flags, *path_args]))

files = [str(f) for d in (dirs if dirs is not None else find_problem_dirs(root)) for f in implementations(d).values()]
Expand All @@ -115,6 +118,10 @@ def step(name: str, runner) -> None: # noqa: ANN001
) if on]
step("solution tests", lambda: run_tests.main([*common, *test_flags, *path_args]))

# Index drift is a whole-repository concern (sync_index.py has no concept
# of scope), so it always runs, regardless of --staged/--since.
step("index sync", lambda: sync_index.main([*common, "--check"]))

print("\n=== Summary ===")
failed = False
for name, code in steps:
Expand Down
16 changes: 12 additions & 4 deletions scripts/new_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
Usage:
python scripts/new_problem.py 3485 "Some Title" \\
--category "Data Structures and Libraries" --difficulty 3 \\
--topics "binary search tree,recursion" --lang cpp
--topics "Data Structures,Recursion" --lang cpp

python scripts/new_problem.py 2602 "Total Spent" --category SQL \\
--difficulty 2 --topics aggregation --lang sql --slug total-spent
--difficulty 2 --topics Math --lang sql --slug total-spent

Creates problems/<range>/<id>-<slug>/ with a README.md built from the right
L1/L2 template (L3 also gets deep-dive.md), a solutions/<lang>/main.<ext>
Expand All @@ -28,7 +28,7 @@
import sys
from pathlib import Path

from repo_lib import CATEGORIES, DOC_LEVELS, LANGUAGES, PRIORITIES, SLUG_RE, find_language
from repo_lib import CATEGORIES, DOC_LEVELS, LANGUAGES, PRIORITIES, SLUG_RE, TOPICS, find_language, find_topic

REPO_ROOT = Path(__file__).resolve().parent.parent
TEMPLATES = REPO_ROOT / "templates"
Expand Down Expand Up @@ -132,7 +132,15 @@ def main(argv: list[str] | None = None) -> int:
print(f"error: {problem_dir.relative_to(root)} already exists", file=sys.stderr)
return 1

topics = [t.strip() for t in args.topics.split(",") if t.strip()]
raw_topics = [t.strip() for t in args.topics.split(",") if t.strip()]
topics: list[str] = []
for raw in raw_topics:
resolved = find_topic(raw)
if resolved is None:
print(f"error: Topics entry '{raw}' must be one of: {', '.join(TOPICS)}", file=sys.stderr)
return 1
topics.append(resolved)

link = args.link or f"https://judge.beecrowd.com/en/problems/view/{args.id}"
values = {
"id": str(args.id),
Expand Down
33 changes: 33 additions & 0 deletions scripts/repo_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@
DOC_LEVELS: tuple[str, ...] = ("L1", "L2", "L3")
PRIORITIES: tuple[str, ...] = ("Low", "Medium", "High")

# Closed vocabulary for the "Topics" metadata field, same spirit as CATEGORIES:
# a fixed, curated list so docs/indexes/by-topic.md never drifts into one
# heading per slightly-different phrase. Add to this list deliberately.
TOPICS: tuple[str, ...] = (
"Input / Output",
"Arrays",
"Strings",
"Simulation",
"Math",
"Sorting",
"Binary Search",
"Greedy",
"Recursion",
"Backtracking",
"Data Structures",
"Graphs",
"Dynamic Programming",
)

# "Solved" must only be used for code that was really accepted by the judge.
STATUSES: tuple[str, ...] = ("Solved", "In Progress", "Improving", "To Review")

Expand Down Expand Up @@ -136,6 +155,20 @@ def parse_other_implementations(value: str) -> list[str]:
return [part.strip() for part in cleaned.split(",") if part.strip()]


def find_topic(value: str) -> str | None:
"""Map a Topics entry, case-insensitively, to its canonical spelling in TOPICS."""
wanted = value.strip().lower()
for topic in TOPICS:
if wanted == topic.lower():
return topic
return None


def parse_topics(value: str) -> list[str]:
"""`binary search, Math` -> ["binary search", "Math"], raw (not yet validated)."""
return [part.strip() for part in value.split(",") if part.strip()]


def find_problem_dirs(root: Path) -> list[Path]:
"""List every `problems/<range>/<problem>/` directory, sorted."""
problems_root = root / "problems"
Expand Down
Loading
Loading