# 1. 讓腳本可執行: # chmod +x utils/leetcode_helper.sh # 2. 建立新題目: # ./utils/leetcode_helper.sh problem 1 two-sum Easy # ./utils/leetcode_helper.sh problem 3000 maximum-area-rectangle Medium # 3. 建立月度日誌: # ./utils/leetcode_helper.sh log 2025-09 # 4. 更新README: # ./utils/leetcode_helper.sh readme #!/bin/bash set -euo pipefail # 路徑設定 SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) TEMPLATES_DIR="$ROOT_DIR/templates" # kebab-case -> Title Case(two-sum -> Two Sum) to_title_case() { local s="${1//-/ }" echo "$s" | awk '{for(i=1;i<=NF;i++){ $i=toupper(substr($i,1,1)) substr($i,2) } print }' } # 渲染模板到目的檔 # 變數:{{NUMBER}}, {{NUMBER_PAD}}, {{NAME_SLUG}}, {{NAME_TITLE}}, {{DIFFICULTY}}, {{DATE}}, {{YEAR_MONTH}} render_template() { local src="$1"; shift local dest="$1"; shift local number="${1:-}"; shift || true local number_pad="${1:-}"; shift || true local name_slug="${1:-}"; shift || true local name_title="${1:-}"; shift || true local difficulty="${1:-}"; shift || true local today="${1:-}"; shift || true local year_month="${1:-}"; shift || true mkdir -p "$(dirname "$dest")" sed -e "s/{{NUMBER}}/${number}/g" \ -e "s/{{NUMBER_PAD}}/${number_pad}/g" \ -e "s/{{NAME_SLUG}}/${name_slug}/g" \ -e "s/{{NAME_TITLE}}/${name_title}/g" \ -e "s/{{DIFFICULTY}}/${difficulty}/g" \ -e "s/{{DATE}}/${today}/g" \ -e "s/{{YEAR_MONTH}}/${year_month}/g" \ "$src" > "$dest" } # 建立測試檔案(來自 templates/problem/test/*) create_test_files() { local problem_dir="$1"; local number="$2"; local name_slug="$3"; local difficulty="$4" local number_pad=$(printf "%04d" "$number") local name_title=$(to_title_case "$name_slug") local today=$(date +%Y-%m-%d) local year_month=$(date +%Y-%m) render_template "$TEMPLATES_DIR/problem/test/SolutionTests.cs.tmpl" \ "$problem_dir/test/SolutionTests.cs" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/TestProject.csproj.tmpl" \ "$problem_dir/test/TestProject.csproj" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/main_test.go.tmpl" \ "$problem_dir/test/main_test.go" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/edge_cases.md.tmpl" \ "$problem_dir/test/edge_cases.md" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/input1.txt.tmpl" "$problem_dir/test/input1.txt" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/output1.txt.tmpl" "$problem_dir/test/output1.txt" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/input2.txt.tmpl" "$problem_dir/test/input2.txt" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/output2.txt.tmpl" "$problem_dir/test/output2.txt" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/test/run_tests.sh.tmpl" \ "$problem_dir/test/run_tests.sh" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" chmod +x "$problem_dir/test/run_tests.sh" } # 建立新題目 create_problem() { local number="$1"; local name_slug="$2"; local difficulty="$3" if [[ -z "${number:-}" || -z "${name_slug:-}" || -z "${difficulty:-}" ]]; then echo "使用方法: $0 problem <題號> <題目名稱-kebab> <難度>"; exit 1 fi local number_pad=$(printf "%04d" "$number") local folder_name="${number_pad}-${name_slug}" local problem_dir="$ROOT_DIR/problems/${folder_name}" local name_title=$(to_title_case "$name_slug") local today=$(date +%Y-%m-%d) local year_month=$(date +%Y-%m) mkdir -p "$problem_dir/csharp" "$problem_dir/go" "$problem_dir/test" # README render_template "$TEMPLATES_DIR/problem/README.md.tmpl" \ "$problem_dir/README.md" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" # C# render_template "$TEMPLATES_DIR/problem/csharp/Program.cs.tmpl" \ "$problem_dir/csharp/Program.cs" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" render_template "$TEMPLATES_DIR/problem/csharp/csharp.csproj.tmpl" \ "$problem_dir/csharp/csharp.csproj" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" # Go render_template "$TEMPLATES_DIR/problem/go/main.go.tmpl" \ "$problem_dir/go/main.go" \ "$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month" (cd "$problem_dir/go" && go mod init "leetcode-$number" >/dev/null 2>&1 || true) # Tests create_test_files "$problem_dir" "$number" "$name_slug" "$difficulty" echo "✅ 已建立題目: $problem_dir" echo "C#: cd problems/${folder_name}/csharp && dotnet run" echo "Go: cd problems/${folder_name}/go && go run main.go" echo "測試: cd problems/${folder_name}/test && ./run_tests.sh" } # 更新主 README(目前僅統計列印) update_readme() { echo "🔄 更新主 README 統計..." local total_problems=$(find "$ROOT_DIR/problems" -maxdepth 1 -type d | wc -l) total_problems=$((total_problems - 1)) local completed_problems=$(find "$ROOT_DIR/problems" -name "README.md" -exec grep -l "✅" {} \; | wc -l) echo "📊 題目總數: $total_problems,標記完成: $completed_problems" } # 建立月度日誌(由模板 logs-template.md.tmpl 渲染) create_monthly_log() { local year_month="${1:-}" if [[ -z "$year_month" ]]; then year_month=$(date +%Y-%m); fi local dest="$ROOT_DIR/logs/${year_month}.md" if [[ -f "$dest" ]]; then echo "⚠️ 已存在: $dest"; return 1; fi mkdir -p "$ROOT_DIR/logs" render_template "$TEMPLATES_DIR/logs-template.md.tmpl" "$dest" "" "" "" "" "" "" "$year_month" echo "✅ 已建立月度日誌: $dest" } # 入口 case "${1:-}" in problem) create_problem "${2:-}" "${3:-}" "${4:-}" ;; readme) update_readme ;; log) create_monthly_log "${2:-}" ;; *) echo "LeetCode Practice Helper" echo "使用:" echo " $0 problem <題號> <題目名稱-kebab> <難度>" echo " $0 readme" echo " $0 log [YYYY-MM]" ;; esac