initial commit
commit
02ba7c97f9
|
@ -0,0 +1 @@
|
|||
/cookie
|
|
@ -0,0 +1,79 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# install me in your crontab!
|
||||
# 0 5 1-25 12 * $HOME/adventofcode2023/cron.sh auto
|
||||
|
||||
year=2023
|
||||
root=~/adventofcode${year}
|
||||
|
||||
getinput() {
|
||||
curl -fsS -b "$root/cookie" -O "https://adventofcode.com/$year/day/$1/input"
|
||||
}
|
||||
|
||||
getsamples() {
|
||||
curl -fsS "https://adventofcode.com/$year/day/$1" |
|
||||
awk '/<pre><code>/ {sub("<pre><code>", ""); CODE=1; IDX+=1} /<\/code>/ {CODE=0} CODE {print > sprintf("sample%d.in", IDX)}'
|
||||
}
|
||||
|
||||
if [[ "$*" = "auto" ]]; then
|
||||
# get the current day in UTC with and without zero padding.
|
||||
# UTC is a few hours ahead of US Eastern time, so
|
||||
# it should match the day of the current puzzle even
|
||||
# if the clocks on tilde.town and AoC aren't synced exactly
|
||||
day_unpadded=$(TZ=UTC date '+%-d')
|
||||
day_padded=$(TZ=UTC date '+%0d')
|
||||
dir=$root/day$day_padded
|
||||
elif (( $# == 1 || $# == 2 )); then
|
||||
day_unpadded=$(printf "%d" "$1")
|
||||
day_padded=$(printf "%02d" "$1")
|
||||
dir=${2:-}
|
||||
else
|
||||
echo >&2 "usage: $0 day [out_dir]"
|
||||
echo >&2 " $0 auto"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z "$dir" ]]; then
|
||||
dir=$root/day$day_padded
|
||||
fi
|
||||
|
||||
if test -e "$dir"; then
|
||||
echo >&2 "'$dir' already exists! refusing to continue"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! test -e "$root/cookie"; then
|
||||
echo >&2 "warning: cookiefile '$root/cookie' not found. consider creating it"
|
||||
fi
|
||||
|
||||
cwd=${PWD:-$(pwd)}
|
||||
mkdir "$dir"
|
||||
cd "$dir" || exit 1
|
||||
|
||||
error=0
|
||||
|
||||
if ! getinput "$day_unpadded"; then
|
||||
echo >&2 "error: failed to get input for day $day_unpadded"
|
||||
error=1
|
||||
fi
|
||||
|
||||
if ! getsamples "$day_unpadded"; then
|
||||
echo >&2 "error: failed to get sample inputs for day $day_unpadded"
|
||||
error=1
|
||||
fi
|
||||
|
||||
if [[ $error -ne 0 ]]; then
|
||||
# we might not have managed to grab any files
|
||||
# at all. try to clean up after ourselves by removing
|
||||
# the directory (if it's empty)
|
||||
if cd "$cwd" && rmdir --ignore-fail-on-non-empty "$dir" >&2; then
|
||||
if ! test -d "$dir"; then
|
||||
echo "cleaning up '$dir'"
|
||||
else
|
||||
echo "not cleaning up '$dir'"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
exit $error
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
curl -b ../cookie -O "https://adventofcode.com/2024/day/$1/input"
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
curl -fsS https://adventofcode.com/2024/day/"$1" | awk '/<pre><code>/ {sub("<pre><code>", ""); CODE=1; IDX+=1} /<\/code>/ {CODE=0} CODE {print > sprintf("sample%d.in", IDX)}'
|
|
@ -0,0 +1,112 @@
|
|||
package require Tcl 8.6
|
||||
#package require textutil ;# from tcllib
|
||||
namespace import tcl::mathfunc::min
|
||||
namespace import tcl::mathfunc::max
|
||||
|
||||
#puts "prelude [info script]"
|
||||
|
||||
proc {#} args {}
|
||||
|
||||
# short aliases for common things
|
||||
|
||||
proc llen {lst} { return [llength $lst] }
|
||||
proc slen {str} { return [string length $str] }
|
||||
proc trim args { return [uplevel [concat string trim $args]] }
|
||||
proc replace {str args} { return [string map $args $str] }
|
||||
|
||||
# sum and product
|
||||
|
||||
proc ladd {list} {
|
||||
set t 0
|
||||
foreach x $list { incr t $x }
|
||||
return $t
|
||||
}
|
||||
|
||||
proc lmul {list} {
|
||||
set p 1
|
||||
foreach x $list { set p [expr {$p * $x}] }
|
||||
return $p
|
||||
}
|
||||
|
||||
# split s on a substring
|
||||
proc splitstr {s sep} {
|
||||
# replace $sep with ascii char 30, aka "record separator"
|
||||
return [split [replace $s $sep "\x1E"] "\x1E"]
|
||||
}
|
||||
|
||||
proc must_regexp args {
|
||||
if {! [uplevel [concat regexp $args]]} {
|
||||
error "regexp failed"
|
||||
}
|
||||
}
|
||||
|
||||
proc regsplit {re str {varname {}}} {
|
||||
set result [textutil::split::splitx $str $re]
|
||||
if {$varname ne ""} {
|
||||
upvar $varname dest
|
||||
set dest $result
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# transpose a list of strings
|
||||
#
|
||||
# % transpose {abc 123}
|
||||
# a1 b2 c3
|
||||
# % transpose a1 b2 c3
|
||||
# abc 123
|
||||
#
|
||||
proc transpose strings {
|
||||
set out {}
|
||||
set C [slen [lindex $strings 0]]
|
||||
for {set i 0} {$i < $C} {incr i} {
|
||||
set column {}
|
||||
foreach row $strings {
|
||||
lappend column [string index $row $i]
|
||||
}
|
||||
lappend out [join $column ""]
|
||||
}
|
||||
return $out
|
||||
}
|
||||
|
||||
# transpose a list of lists
|
||||
#
|
||||
# % ltranspose {{a b c} {1 2 3}}
|
||||
# {a 1} {b 2} {c 3}
|
||||
# % ltranspose {{a 1} {b 2} {c 3}}
|
||||
# {a b c} {1 2 3}
|
||||
#
|
||||
proc ltranspose lists {
|
||||
set out {}
|
||||
set C [llen [lindex $lists 0]]
|
||||
for {set i 0} {$i < $C} {incr i} {
|
||||
set column {}
|
||||
foreach row $lists {
|
||||
lappend column [lindex $row $i]
|
||||
}
|
||||
lappend out $column
|
||||
}
|
||||
return $out
|
||||
}
|
||||
|
||||
# extracts one or more indexes from a strided list
|
||||
# e.g.
|
||||
# % set l {0 1 2 a b c x y z}
|
||||
# % lextract $l 3 0
|
||||
# 0 a x
|
||||
# % lextract $l 3 {1 2}
|
||||
# 1 2 b c y z
|
||||
#
|
||||
# equivalent to [lmap {a b c} $lst {list $b $c}] except that
|
||||
# you don't have to name the list elements
|
||||
proc lextract {lst stride index} {
|
||||
set i 0
|
||||
set out {}
|
||||
if {$stride <= 0} { error "stride must be positive: $stride" }
|
||||
for {set i 0} {$i < [llength $lst]} {incr i $stride} {
|
||||
foreach j $index {
|
||||
lappend out [lindex $lst $i+$j]
|
||||
}
|
||||
}
|
||||
return $out
|
||||
}
|
Loading…
Reference in New Issue