crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

select_puzzles.sh (3914B)


      1 #!/usr/bin/env bash
      2 set -euo pipefail
      3 
      4 COUNT="${1:-10}"
      5 DEFAULT_CANDIDATE_DIR="Generated"
      6 PICKMAKE_EXECUTABLE=".build/release/Pickmake"
      7 CLUEMAKE_EXECUTABLE=".build/release/Cluemake"
      8 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
      9 CROSSMAKE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
     10 CALLER_DIR="$(pwd)"
     11 OUTPUT_DIR="${CROSSMAKE_DIR}/Picked"
     12 CLEAN=false
     13 CLUE_AGENT="${CROSSMAKE_CLUE_AGENT:-codex}"
     14 CLUE_TIMEOUT="${CROSSMAKE_CLUE_TIMEOUT:-300}"
     15 CLUE_ATTEMPTS="${CROSSMAKE_CLUE_ATTEMPTS:-3}"
     16 CLUE_PUZZLES=true
     17 
     18 if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || ((10#$COUNT < 1)); then
     19   echo "Usage: $0 [positive-puzzle-count] [-o output-dir] [--clean] [--clue-agent codex|claude] [--clue-timeout seconds] [--skip-clues] [candidate-dir-or-xd-file ...]" >&2
     20   exit 1
     21 fi
     22 
     23 resolve_path() {
     24   if [[ "$1" = /* ]]; then
     25     echo "$1"
     26   else
     27     echo "${CALLER_DIR}/$1"
     28   fi
     29 }
     30 
     31 shift || true
     32 inputs=()
     33 while (($# > 0)); do
     34   case "$1" in
     35     -o|--into)
     36       if (($# < 2)); then
     37         echo "$1 requires a directory argument" >&2
     38         exit 1
     39       fi
     40       OUTPUT_DIR="$(resolve_path "$2")"
     41       shift 2
     42       ;;
     43     --clean)
     44       CLEAN=true
     45       shift
     46       ;;
     47     --clue-agent)
     48       if (($# < 2)); then
     49         echo "$1 requires codex or claude" >&2
     50         exit 1
     51       fi
     52       CLUE_AGENT="$2"
     53       shift 2
     54       ;;
     55     --clue-timeout)
     56       if (($# < 2)); then
     57         echo "$1 requires a timeout in seconds" >&2
     58         exit 1
     59       fi
     60       CLUE_TIMEOUT="$2"
     61       shift 2
     62       ;;
     63     --skip-clues)
     64       CLUE_PUZZLES=false
     65       shift
     66       ;;
     67     *)
     68       inputs+=("$(resolve_path "$1")")
     69       shift
     70       ;;
     71   esac
     72 done
     73 
     74 if [[ "$CLUE_AGENT" != "codex" && "$CLUE_AGENT" != "claude" ]]; then
     75   echo "Clue agent must be codex or claude" >&2
     76   exit 1
     77 fi
     78 
     79 if ! [[ "$CLUE_TIMEOUT" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
     80   echo "Clue timeout must be a positive number" >&2
     81   exit 1
     82 fi
     83 
     84 if ! [[ "$CLUE_ATTEMPTS" =~ ^[0-9]+$ ]] || ((10#$CLUE_ATTEMPTS < 1)); then
     85   echo "CROSSMAKE_CLUE_ATTEMPTS must be a positive integer" >&2
     86   exit 1
     87 fi
     88 
     89 if ((${#inputs[@]} == 0)); then
     90   inputs+=("${CROSSMAKE_DIR}/${DEFAULT_CANDIDATE_DIR}")
     91 fi
     92 
     93 cd "$CROSSMAKE_DIR"
     94 
     95 echo "Building Pickmake and Cluemake in release mode" >&2
     96 swift build -c release --product Pickmake --product Cluemake
     97 
     98 if [[ ! -x "$PICKMAKE_EXECUTABLE" ]]; then
     99   echo "Pickmake executable not found after build: $PICKMAKE_EXECUTABLE" >&2
    100   exit 1
    101 fi
    102 
    103 if [[ "$CLUE_PUZZLES" == true && ! -x "$CLUEMAKE_EXECUTABLE" ]]; then
    104   echo "Cluemake executable not found after build: $CLUEMAKE_EXECUTABLE" >&2
    105   exit 1
    106 fi
    107 
    108 selected_paths="$("$PICKMAKE_EXECUTABLE" --count "$COUNT" --verbose "${inputs[@]}")"
    109 
    110 if [[ -z "$selected_paths" ]]; then
    111   echo "No puzzles selected; nothing copied." >&2
    112   exit 1
    113 fi
    114 
    115 mkdir -p "$OUTPUT_DIR"
    116 
    117 if [[ "$CLEAN" == true ]]; then
    118   rm -f "$OUTPUT_DIR"/*.xd
    119   echo "Cleaned existing .xd files from ${OUTPUT_DIR}." >&2
    120 fi
    121 
    122 copied_count=0
    123 while IFS= read -r selected_path; do
    124   [[ -n "$selected_path" ]] || continue
    125   output_path="${OUTPUT_DIR}/${selected_path##*/}"
    126   cp "$selected_path" "$output_path"
    127   echo "Copied ${selected_path} -> ${output_path}"
    128   if [[ "$CLUE_PUZZLES" == true ]]; then
    129     echo "Generating clues for ${output_path} with ${CLUE_AGENT}" >&2
    130     clue_attempt=1
    131     until "$CLUEMAKE_EXECUTABLE" --agent "$CLUE_AGENT" --timeout "$CLUE_TIMEOUT" "$output_path"; do
    132       if ((clue_attempt >= 10#$CLUE_ATTEMPTS)); then
    133         echo "Failed to generate clues for ${output_path} after ${CLUE_ATTEMPTS} attempt(s)." >&2
    134         exit 1
    135       fi
    136       clue_attempt=$((clue_attempt + 1))
    137       echo "Retrying clues for ${output_path} (${clue_attempt}/${CLUE_ATTEMPTS})" >&2
    138     done
    139   fi
    140   copied_count=$((copied_count + 1))
    141 done <<<"$selected_paths"
    142 
    143 if [[ "$CLUE_PUZZLES" == true ]]; then
    144   echo "Copied and clued ${copied_count} puzzle(s) into ${OUTPUT_DIR}." >&2
    145 else
    146   echo "Copied ${copied_count} puzzle(s) into ${OUTPUT_DIR}." >&2
    147 fi