170 lines
6.6 KiB
Bash
Executable File
170 lines
6.6 KiB
Bash
Executable File
# 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
|