updated project 2
This commit is contained in:
@@ -9,6 +9,8 @@ GREEN='\033[0;32m'
|
|||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
BOLD='\033[1m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
# Error handling
|
# Error handling
|
||||||
@@ -19,6 +21,35 @@ set -o pipefail # Exit on pipe failure
|
|||||||
# Trap errors and provide error message
|
# Trap errors and provide error message
|
||||||
trap 'echo -e "${RED}Error: Command failed at line $LINENO${NC}" >&2' ERR
|
trap 'echo -e "${RED}Error: Command failed at line $LINENO${NC}" >&2' ERR
|
||||||
|
|
||||||
|
# Function to show spinner while executing command
|
||||||
|
show_spinner() {
|
||||||
|
local pid=$1
|
||||||
|
local delay=0.1
|
||||||
|
local spinstr='|/-\'
|
||||||
|
while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
|
||||||
|
local temp=${spinstr#?}
|
||||||
|
printf " [%c] " "$spinstr"
|
||||||
|
local spinstr=$temp${spinstr%"$temp"}
|
||||||
|
sleep $delay
|
||||||
|
printf "\b\b\b\b\b\b"
|
||||||
|
done
|
||||||
|
printf " \b\b\b\b"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print banner
|
||||||
|
print_banner() {
|
||||||
|
clear
|
||||||
|
cat << "EOF"
|
||||||
|
_____ _
|
||||||
|
| |___ _____ _____ ___ ___ _____ ___ | |
|
||||||
|
| --| . | | | .'| | | . ||_|
|
||||||
|
|_____|___|_|_|_|_|_|_|__,|_|_|_|_|_| |
|
||||||
|
|___|
|
||||||
|
EOF
|
||||||
|
echo -e "${BOLD}Command Line Mastery Challenge${NC}"
|
||||||
|
echo "=============================="
|
||||||
|
}
|
||||||
|
|
||||||
# Function to check if command exists
|
# Function to check if command exists
|
||||||
check_command() {
|
check_command() {
|
||||||
if ! command -v "$1" &>/dev/null; then
|
if ! command -v "$1" &>/dev/null; then
|
||||||
@@ -134,9 +165,93 @@ validate_challenge_id() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to handle commands with improved feedback
|
||||||
|
handle_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
shift # Remove first argument, leaving remaining args
|
||||||
|
|
||||||
|
case "$cmd" in
|
||||||
|
"verify"|"verify-challenge"|"v")
|
||||||
|
echo -e "${CYAN}Verifying your solution...${NC}"
|
||||||
|
"$CHALLENGE_DIR/.tracking/verify-challenge.sh" "$@"
|
||||||
|
;;
|
||||||
|
"hint"|"show-hint"|"h")
|
||||||
|
echo -e "${CYAN}Getting hint...${NC}"
|
||||||
|
"$CHALLENGE_DIR/.tracking/show-hint.sh" "$@"
|
||||||
|
;;
|
||||||
|
"status"|"show-status"|"s")
|
||||||
|
echo -e "${CYAN}Showing status...${NC}"
|
||||||
|
"$CHALLENGE_DIR/.tracking/show-status.sh" "$@"
|
||||||
|
;;
|
||||||
|
"progress"|"check-progress"|"p")
|
||||||
|
echo -e "${CYAN}Checking progress...${NC}"
|
||||||
|
"$CHALLENGE_DIR/.tracking/check-progress.sh" "$@"
|
||||||
|
;;
|
||||||
|
"clear"|"cls"|"c")
|
||||||
|
clear
|
||||||
|
print_challenge_header "$CURRENT_CHALLENGE_ID"
|
||||||
|
;;
|
||||||
|
"reset"|"r")
|
||||||
|
echo -e "${YELLOW}Resetting current challenge...${NC}"
|
||||||
|
setup_challenge_env "$CURRENT_CHALLENGE_ID"
|
||||||
|
;;
|
||||||
|
"exit"|"quit"|"q")
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
"help"|"?")
|
||||||
|
print_help_menu
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
# Empty command, just continue
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Unknown command: $cmd${NC}"
|
||||||
|
echo -e "Type ${YELLOW}help${NC} or ${YELLOW}?${NC} for available commands"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print help menu
|
||||||
|
print_help_menu() {
|
||||||
|
echo -e "\n${BOLD}Available Commands:${NC}"
|
||||||
|
echo -e " ${YELLOW}verify, v${NC} - Check your solution"
|
||||||
|
echo -e " ${YELLOW}hint, h${NC} - Get a hint"
|
||||||
|
echo -e " ${YELLOW}status, s${NC} - Show challenge status"
|
||||||
|
echo -e " ${YELLOW}progress, p${NC} - Check overall progress"
|
||||||
|
echo -e " ${YELLOW}clear, c${NC} - Clear screen"
|
||||||
|
echo -e " ${YELLOW}reset, r${NC} - Reset current challenge"
|
||||||
|
echo -e " ${YELLOW}help, ?${NC} - Show this help message"
|
||||||
|
echo -e " ${YELLOW}exit, q${NC} - Exit the challenge"
|
||||||
|
echo -e "\n${BOLD}Tips:${NC}"
|
||||||
|
echo -e "- Commands can be abbreviated (e.g., 'v' for verify)"
|
||||||
|
echo -e "- Use TAB for command completion"
|
||||||
|
echo -e "- Use arrow keys for command history"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print challenge header
|
||||||
|
print_challenge_header() {
|
||||||
|
local challenge_id=$1
|
||||||
|
echo -e "${GREEN}🎮 Challenge $challenge_id${NC}"
|
||||||
|
echo -e "${BLUE}$(get_challenge_description "$challenge_id")${NC}"
|
||||||
|
echo -e "${YELLOW}Type 'help' or '?' for available commands${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to setup challenge environment
|
||||||
|
setup_challenge_env() {
|
||||||
|
local challenge_id=$1
|
||||||
|
if ! bash "$CHALLENGE_DIR/.tracking/level1-setup.sh" > /dev/null 2>&1; then
|
||||||
|
echo -e "${RED}Error: Failed to setup challenge environment${NC}"
|
||||||
|
echo -e "${YELLOW}Try running: $0 clean && $0 setup${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# Function to start a challenge
|
# Function to start a challenge
|
||||||
start_challenge() {
|
start_challenge() {
|
||||||
local challenge_id=$1
|
local challenge_id=$1
|
||||||
|
export CURRENT_CHALLENGE_ID=$challenge_id
|
||||||
|
|
||||||
# Validate challenge ID
|
# Validate challenge ID
|
||||||
if ! validate_challenge_id "$challenge_id"; then
|
if ! validate_challenge_id "$challenge_id"; then
|
||||||
@@ -144,24 +259,17 @@ start_challenge() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Source required scripts with error checking
|
# Source required scripts with error checking
|
||||||
local required_scripts=(common.sh challenges.sh)
|
if ! source_required_scripts; then
|
||||||
for script in "${required_scripts[@]}"; do
|
|
||||||
if ! source "$CHALLENGE_DIR/.tracking/$script" 2>/dev/null; then
|
|
||||||
echo -e "${RED}Error: Required script not found: $script${NC}"
|
|
||||||
echo -e "${YELLOW}Running setup first...${NC}"
|
|
||||||
setup_environment
|
|
||||||
if ! source "$CHALLENGE_DIR/.tracking/$script" 2>/dev/null; then
|
|
||||||
echo -e "${RED}Error: Failed to source $script even after setup${NC}"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
clear
|
print_banner
|
||||||
echo -e "${GREEN}🎮 Command Line Mastery Challenge${NC}"
|
|
||||||
echo "=============================="
|
# Setup challenge environment
|
||||||
|
echo -e "${BLUE}Setting up challenge environment...${NC}"
|
||||||
|
setup_challenge_env "$challenge_id" &
|
||||||
|
show_spinner $!
|
||||||
|
|
||||||
# Setup challenge environment with error checking
|
|
||||||
if ! get_challenge_details "$challenge_id" 2>/dev/null; then
|
if ! get_challenge_details "$challenge_id" 2>/dev/null; then
|
||||||
echo -e "${RED}Error: Challenge $challenge_id not found${NC}"
|
echo -e "${RED}Error: Challenge $challenge_id not found${NC}"
|
||||||
echo -e "${YELLOW}Available challenges:${NC}"
|
echo -e "${YELLOW}Available challenges:${NC}"
|
||||||
@@ -169,29 +277,36 @@ start_challenge() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! bash "$CHALLENGE_DIR/.tracking/level1-setup.sh" 2>/dev/null; then
|
# Record challenge start
|
||||||
echo -e "${RED}Error: Failed to setup challenge environment${NC}"
|
|
||||||
echo -e "${YELLOW}Try running: $0 clean && $0 setup${NC}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Record challenge start with error checking
|
|
||||||
local start_time=$(date +%s)
|
local start_time=$(date +%s)
|
||||||
if ! echo "$challenge_id,$start_time" > "$CHALLENGE_DIR/.tracking/current_challenge" 2>/dev/null; then
|
echo "$challenge_id,$start_time" > "$CHALLENGE_DIR/.tracking/current_challenge"
|
||||||
echo -e "${RED}Error: Failed to record challenge start${NC}"
|
|
||||||
return 1
|
print_challenge_header "$challenge_id"
|
||||||
|
|
||||||
|
# Enable command history and tab completion
|
||||||
|
bind 'set completion-ignore-case on' 2>/dev/null || true
|
||||||
|
bind 'set show-all-if-ambiguous on' 2>/dev/null || true
|
||||||
|
|
||||||
|
# Start command loop with improved prompt
|
||||||
|
local cmd_count=0
|
||||||
|
while true; do
|
||||||
|
cmd_count=$((cmd_count + 1))
|
||||||
|
echo -ne "\n${GREEN}challenge${BLUE}[$challenge_id]${GREEN}>${NC} "
|
||||||
|
read -e -r cmd args # -e enables readline for command history
|
||||||
|
history -s "$cmd $args" # Add command to history
|
||||||
|
if ! handle_command "$cmd" $args; then
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Create command aliases
|
# Record challenge end
|
||||||
alias verify="$CHALLENGE_DIR/.tracking/verify-challenge.sh"
|
local end_time=$(date +%s)
|
||||||
alias hint="$CHALLENGE_DIR/.tracking/show-hint.sh"
|
local duration=$((end_time - start_time))
|
||||||
alias status="$CHALLENGE_DIR/.tracking/track-progress.sh"
|
echo "$challenge_id,$duration" >> "$CHALLENGE_DIR/.tracking/data/time.csv"
|
||||||
|
|
||||||
echo -e "\n${GREEN}Challenge ready!${NC}"
|
echo -e "\n${GREEN}Challenge session ended!${NC}"
|
||||||
echo -e "Commands available:"
|
echo -e "Time spent: $(printf '%dm %ds' $((duration/60)) $((duration%60)))"
|
||||||
echo -e " ${YELLOW}verify${NC} - Check your solution"
|
echo -e "Commands used: $cmd_count"
|
||||||
echo -e " ${YELLOW}hint${NC} - Get a hint"
|
|
||||||
echo -e " ${YELLOW}status${NC} - Show progress"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to show help
|
# Function to show help
|
||||||
|
|||||||
@@ -9,6 +9,18 @@ declare -A CHALLENGE_CATEGORIES=(
|
|||||||
["text"]="Text Processing"
|
["text"]="Text Processing"
|
||||||
["proc"]="Process Management"
|
["proc"]="Process Management"
|
||||||
["net"]="Network Operations"
|
["net"]="Network Operations"
|
||||||
|
["pipe"]="Pipelines & Redirection"
|
||||||
|
["shell"]="Shell Scripting"
|
||||||
|
["git"]="Git Operations"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Challenge difficulty descriptions
|
||||||
|
declare -A DIFFICULTY_DESCRIPTIONS=(
|
||||||
|
[1]="Beginner - Basic command usage"
|
||||||
|
[2]="Intermediate - Combined commands"
|
||||||
|
[3]="Advanced - Complex operations"
|
||||||
|
[4]="Expert - System administration"
|
||||||
|
[5]="Master - Advanced scripting"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Challenge definitions with metadata
|
# Challenge definitions with metadata
|
||||||
@@ -181,19 +193,40 @@ verify_result() {
|
|||||||
local end_time=$(date +%s)
|
local end_time=$(date +%s)
|
||||||
|
|
||||||
if [[ "$actual" == "$expected" ]]; then
|
if [[ "$actual" == "$expected" ]]; then
|
||||||
log_message "SUCCESS" "Challenge $challenge_id: $message"
|
log_message "SUCCESS" "Challenge $challenge_id completed successfully!"
|
||||||
update_challenge_status "$challenge_id" "1" "$end_time"
|
echo -e "\n${GREEN}🎉 Congratulations! Challenge completed!${NC}"
|
||||||
|
echo -e "${BLUE}Summary:${NC}"
|
||||||
|
echo -e "- Time taken: $(format_duration $((end_time - start_time)))"
|
||||||
|
echo -e "- Commands used: $(get_command_count "$challenge_id")"
|
||||||
|
|
||||||
# Calculate bonus points
|
# Calculate and award points
|
||||||
local duration=$((end_time - start_time))
|
local duration=$((end_time - start_time))
|
||||||
local command_count=$(get_command_count "$challenge_id")
|
local command_count=$(get_command_count "$challenge_id")
|
||||||
local bonus_points=$(calculate_bonus_points "$duration" "$command_count")
|
local bonus_points=$(calculate_bonus_points "$duration" "$command_count")
|
||||||
|
local total_points=$((100 + bonus_points))
|
||||||
|
|
||||||
|
echo -e "\n${YELLOW}Points earned:${NC}"
|
||||||
|
echo -e "- Base points: 100"
|
||||||
|
echo -e "- Time bonus: $time_bonus"
|
||||||
|
echo -e "- Efficiency bonus: $efficiency_bonus"
|
||||||
|
echo -e "- Total points: $total_points"
|
||||||
|
|
||||||
|
# Update progress
|
||||||
|
update_challenge_status "$challenge_id" "1" "$end_time"
|
||||||
|
award_points "$challenge_id" "$total_points"
|
||||||
|
|
||||||
|
# Show next challenge suggestion
|
||||||
|
suggest_next_challenge "$challenge_id"
|
||||||
|
|
||||||
award_points "$challenge_id" "$((100 + bonus_points))"
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log_message "ERROR" "Challenge $challenge_id: Completed $actual/$expected checks"
|
log_message "ERROR" "Challenge incomplete: $actual/$expected requirements met"
|
||||||
update_challenge_status "$challenge_id" "0" "$end_time"
|
echo -e "\n${RED}Challenge not completed yet.${NC}"
|
||||||
|
echo -e "Progress: $actual/$expected requirements met"
|
||||||
|
echo -e "\n${YELLOW}Tips:${NC}"
|
||||||
|
echo -e "- Use 'hint' command for guidance"
|
||||||
|
echo -e "- Check your work carefully"
|
||||||
|
echo -e "- Try breaking down the task into smaller steps"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -264,3 +297,119 @@ list_challenges() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to add new challenge
|
||||||
|
add_challenge() {
|
||||||
|
local id=$1
|
||||||
|
local type=$2
|
||||||
|
local name=$3
|
||||||
|
local difficulty=$4
|
||||||
|
local skills=$5
|
||||||
|
local task=$6
|
||||||
|
local hints=$7
|
||||||
|
local requirements=$8
|
||||||
|
local criteria=$9
|
||||||
|
|
||||||
|
# Validate challenge ID format
|
||||||
|
if [[ ! $id =~ ^[1-9]\.[1-5]$ ]]; then
|
||||||
|
log_message "ERROR" "Invalid challenge ID format. Must be level.number (e.g., 1.1)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate challenge type
|
||||||
|
if [[ -z "${CHALLENGE_CATEGORIES[$type]}" ]]; then
|
||||||
|
log_message "ERROR" "Invalid challenge type. Available types: ${!CHALLENGE_CATEGORIES[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate difficulty
|
||||||
|
if ((difficulty < 1 || difficulty > 5)); then
|
||||||
|
log_message "ERROR" "Invalid difficulty. Must be between 1 and 5"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add challenge to CHALLENGES array
|
||||||
|
CHALLENGES[$id]="${type}|${name}|${difficulty}|${skills}|${task}|${hints}|${requirements}|${criteria}"
|
||||||
|
log_message "SUCCESS" "Added challenge $id: $name"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to list available challenges by category
|
||||||
|
list_challenges_by_category() {
|
||||||
|
local category=${1:-all}
|
||||||
|
|
||||||
|
echo -e "\n${BOLD}Available Challenges:${NC}"
|
||||||
|
echo "===================="
|
||||||
|
|
||||||
|
if [[ "$category" == "all" ]]; then
|
||||||
|
for cat in "${!CHALLENGE_CATEGORIES[@]}"; do
|
||||||
|
echo -e "\n${BLUE}${CHALLENGE_CATEGORIES[$cat]}:${NC}"
|
||||||
|
for id in "${!CHALLENGES[@]}"; do
|
||||||
|
IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$id]}"
|
||||||
|
if [[ ${type%%_*} == "$cat" ]]; then
|
||||||
|
echo -e "${YELLOW}$id${NC} ($(printf '★%.0s' $(seq 1 "$difficulty"))) - $name"
|
||||||
|
echo -e " ${CYAN}Skills:${NC} $skills"
|
||||||
|
echo -e " ${CYAN}Task:${NC} $task"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
else
|
||||||
|
if [[ -z "${CHALLENGE_CATEGORIES[$category]}" ]]; then
|
||||||
|
log_message "ERROR" "Invalid category. Available categories: ${!CHALLENGE_CATEGORIES[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}${CHALLENGE_CATEGORIES[$category]}:${NC}"
|
||||||
|
for id in "${!CHALLENGES[@]}"; do
|
||||||
|
IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$id]}"
|
||||||
|
if [[ ${type%%_*} == "$category" ]]; then
|
||||||
|
echo -e "${YELLOW}$id${NC} ($(printf '★%.0s' $(seq 1 "$difficulty"))) - $name"
|
||||||
|
echo -e " ${CYAN}Skills:${NC} $skills"
|
||||||
|
echo -e " ${CYAN}Task:${NC} $task"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to suggest next challenge
|
||||||
|
suggest_next_challenge() {
|
||||||
|
local current_id=$1
|
||||||
|
local level=${current_id%.*}
|
||||||
|
local number=${current_id#*.}
|
||||||
|
|
||||||
|
echo -e "\n${BLUE}What's next?${NC}"
|
||||||
|
|
||||||
|
# Suggest next challenge in same level
|
||||||
|
local next_number=$((number + 1))
|
||||||
|
local next_id="${level}.${next_number}"
|
||||||
|
|
||||||
|
if [[ -n "${CHALLENGES[$next_id]:-}" ]]; then
|
||||||
|
IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$next_id]}"
|
||||||
|
echo -e "→ Try challenge ${YELLOW}$next_id${NC}: $name"
|
||||||
|
else
|
||||||
|
# Suggest first challenge of next level
|
||||||
|
local next_level=$((level + 1))
|
||||||
|
local next_id="${next_level}.1"
|
||||||
|
if [[ -n "${CHALLENGES[$next_id]:-}" ]]; then
|
||||||
|
IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$next_id]}"
|
||||||
|
echo -e "→ Ready for next level? Try ${YELLOW}$next_id${NC}: $name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to format duration
|
||||||
|
format_duration() {
|
||||||
|
local seconds=$1
|
||||||
|
local minutes=$((seconds / 60))
|
||||||
|
local hours=$((minutes / 60))
|
||||||
|
minutes=$((minutes % 60))
|
||||||
|
seconds=$((seconds % 60))
|
||||||
|
|
||||||
|
if ((hours > 0)); then
|
||||||
|
printf "%dh %dm %ds" $hours $minutes $seconds
|
||||||
|
elif ((minutes > 0)); then
|
||||||
|
printf "%dm %ds" $minutes $seconds
|
||||||
|
else
|
||||||
|
printf "%ds" $seconds
|
||||||
|
fi
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user