#!/bin/bash source "$(dirname "$0")/common.sh" # Challenge categories and levels declare -A CHALLENGE_CATEGORIES=( ["file"]="File System Operations" ["perm"]="Permissions & Security" ["text"]="Text Processing" ["proc"]="Process Management" ["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 # Format: type|name|difficulty|skills|task|hints|setup_requirements|verification_criteria declare -A CHALLENGES=( ["1.1"]="file_search|Find Recent Files|1|file_ops,search|Find all .conf files modified in the last 24 hours and save the list to recent_configs.txt|Try using find with -mtime|none|output_file=recent_configs.txt;file_count=10" ["1.2"]="file_count|File Statistics|1|file_ops,search|Generate a report showing count of files by extension|Consider using find and awk|none|report_exists=true;extension_count=5" ["1.3"]="file_organize|Smart File Organizer|2|file_ops|Create directories for different file types and sort files accordingly|Look into file command|none|dir_structure=complete;files_sorted=true" ["1.4"]="file_cleanup|System Cleanup|2|file_ops,search|Find and list all empty files and zero-byte files|Combine find with size tests|none|empty_files_found=true;report_generated=true" ["1.5"]="file_dedup|Duplicate Hunter|3|file_ops,search|Find and handle duplicate files using md5sum|Consider using sort and uniq|none|duplicates_identified=true;report_accurate=true" # Level 2: Permissions ["2.1"]="perm_basic|Permission Fundamentals|1|permissions|Set up basic file permissions following security best practices|Remember user-group-others order|users=app_user1|permissions_correct=true;ownership_correct=true" ["2.2"]="perm_acl|ACL Master|2|permissions|Implement complex ACL rules for multiple users|Look into setfacl usage|users=app_user1,app_user2|acl_rules_correct=true" ["2.3"]="perm_special|Special Permission Bits|2|permissions|Configure SUID/SGID permissions correctly|Understanding special bits|none|special_bits_correct=true" ["2.4"]="perm_recursive|Directory Tree Fix|3|permissions|Fix permissions recursively while maintaining security|Consider find with exec|none|tree_permissions_correct=true" ["2.5"]="perm_audit|Security Auditor|3|permissions|Perform security audit and generate detailed report|Use stat and lsattr|none|audit_complete=true;report_detailed=true" # Level 3: Text Processing ["3.1"]="text_search|Log Detective|1|text_proc,search|Find and analyze specific patterns in log files|grep with context|none|patterns_found=true;count_correct=true" ["3.2"]="text_extract|Data Extraction Pro|2|text_proc|Extract and format specific fields from log files|awk is your friend|none|fields_extracted=true;format_correct=true" ["3.3"]="text_transform|Format Converter|2|text_proc|Transform data between different formats|sed for substitution|none|transformation_correct=true" ["3.4"]="text_report|Report Generator|3|text_proc|Create a detailed system report from various logs|Combine multiple tools|none|report_complete=true;format_valid=true" ["3.5"]="text_analyze|Pattern Analyzer|3|text_proc,search|Analyze complex error patterns and generate statistics|Use grep with perl regex|none|analysis_complete=true;stats_accurate=true" ) # Challenge verification functions verify_challenge() { local challenge_id=$1 local start_time=$2 IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$challenge_id]}" # Check prerequisites if ! check_requirements "$requirements"; then log_message "ERROR" "Challenge prerequisites not met" return 1 fi # Record attempt record_attempt "$challenge_id" "$start_time" # Run specific verification local category=${type%%_*} case "$category" in "file") verify_file_challenge "$challenge_id" "$criteria" ;; "perm") verify_permission_challenge "$challenge_id" "$criteria" ;; "text") verify_text_challenge "$challenge_id" "$criteria" ;; *) log_message "ERROR" "Unknown challenge category: $category" ;; esac } # Check challenge prerequisites check_requirements() { local requirements=$1 [[ "$requirements" == "none" ]] && return 0 IFS=';' read -ra REQS <<< "$requirements" for req in "${REQS[@]}"; do IFS='=' read -r key value <<< "$req" case "$key" in "users") for user in ${value//,/ }; do if ! id "$user" &>/dev/null; then log_message "ERROR" "Required user $user not found" return 1 fi done ;; # Add more requirement checks as needed esac done return 0 } # Verify file-related challenges verify_file_challenge() { local challenge_id=$1 local criteria=$2 local result=0 IFS=';' read -ra CHECKS <<< "$criteria" for check in "${CHECKS[@]}"; do IFS='=' read -r key value <<< "$check" case "$key" in "output_file") [[ -f "$value" ]] && ((result++)) ;; "file_count") [[ "$(find "$CHALLENGE_DIR/files" -type f | wc -l)" -eq "$value" ]] && ((result++)) ;; # Add more specific checks esac done verify_result "$challenge_id" "$result" "${#CHECKS[@]}" "File challenge verification" } # Verify permission-related challenges verify_permission_challenge() { local challenge_id=$1 local criteria=$2 local result=0 IFS=';' read -ra CHECKS <<< "$criteria" for check in "${CHECKS[@]}"; do IFS='=' read -r key value <<< "$check" case "$key" in "users") for user in ${value//,/ }; do if ! id "$user" &>/dev/null; then log_message "ERROR" "Required user $user not found" return 1 fi done ;; # Add more permission checks as needed esac done verify_result "$challenge_id" "$result" "${#CHECKS[@]}" "Permission challenge verification" } # Verify text-related challenges verify_text_challenge() { local challenge_id=$1 local criteria=$2 local result=0 IFS=';' read -ra CHECKS <<< "$criteria" for check in "${CHECKS[@]}"; do IFS='=' read -r key value <<< "$check" case "$key" in "patterns_found") [[ "$(grep -c "$value" "$CHALLENGE_DIR/files/logs/"*.log)" -ge 1 ]] && ((result++)) ;; "count_correct") [[ "$(grep -c "$value" "$CHALLENGE_DIR/files/logs/"*.log)" -eq "$value" ]] && ((result++)) ;; # Add more text checks as needed esac done verify_result "$challenge_id" "$result" "${#CHECKS[@]}" "Text challenge verification" } # Record challenge attempt record_attempt() { local challenge_id=$1 local start_time=$2 local duration=$(($(date +%s) - start_time)) local command_count=$(grep -c "^$start_time" "$COMMAND_LOG") echo "$challenge_id,$(get_attempt_number "$challenge_id"),$start_time,$command_count,$duration,0" >> "$ATTEMPT_FILE" } # Get attempt number for challenge get_attempt_number() { local challenge_id=$1 local attempts=$(grep -c "^$challenge_id," "$ATTEMPT_FILE") echo $((attempts + 1)) } # Enhanced result verification with detailed feedback verify_result() { local challenge_id=$1 local actual=$2 local expected=$3 local message=$4 local end_time=$(date +%s) if [[ "$actual" == "$expected" ]]; then log_message "SUCCESS" "Challenge $challenge_id completed successfully!" 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 and award points local duration=$((end_time - start_time)) local command_count=$(get_command_count "$challenge_id") 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" return 0 else log_message "ERROR" "Challenge incomplete: $actual/$expected requirements met" 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 fi } # Calculate bonus points based on time and efficiency calculate_bonus_points() { local duration=$1 local command_count=$2 local time_bonus=0 local efficiency_bonus=0 # Time bonus if [[ "$duration" -lt 60 ]]; then time_bonus=50 elif [[ "$duration" -lt 120 ]]; then time_bonus=25 fi # Efficiency bonus if [[ "$command_count" -le 3 ]]; then efficiency_bonus=50 elif [[ "$command_count" -le 5 ]]; then efficiency_bonus=25 fi echo $((time_bonus + efficiency_bonus)) } # Get challenge details get_challenge_details() { local challenge_id=$1 if [[ -n "${CHALLENGES[$challenge_id]:-}" ]]; then IFS='|' read -r type name difficulty skills task hints requirements criteria <<< "${CHALLENGES[$challenge_id]}" echo -e "${BLUE}Challenge $challenge_id:${NC} $name" echo -e "${BLUE}Difficulty:${NC} $(printf '★%.0s' $(seq 1 "$difficulty"))" echo -e "${BLUE}Skills:${NC} $skills" echo -e "${BLUE}Task:${NC} $task" return 0 fi return 1 } # Update challenge status update_challenge_status() { local challenge_id=$1 local success=$2 local end_time=$3 # Update attempt status sed -i "$ s/,0$/,$success/" "$ATTEMPT_FILE" # Record completion if successful if [[ "$success" == "1" ]]; then echo "$challenge_id,$end_time,completed,${CHALLENGES[$challenge_id]}" >> "$PROGRESS_FILE" fi } # List available challenges list_challenges() { echo -e "\n${BLUE}Available Challenges:${NC}" for challenge_id in "${!CHALLENGES[@]}"; do if ! is_challenge_completed "$challenge_id"; then IFS='|' read -r type name difficulty skills task _ <<< "${CHALLENGES[$challenge_id]}" echo -e "\n${YELLOW}Challenge $challenge_id${NC} ($difficulty★)" echo "Type: $type" echo "Skills: $skills" echo "Task: $task" fi 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 }