Skip to content

Instantly share code, notes, and snippets.

@rhowe
Created December 16, 2019 23:02
Show Gist options
  • Save rhowe/cf1f47b0027f55a9570f1e0756c20b68 to your computer and use it in GitHub Desktop.
Save rhowe/cf1f47b0027f55a9570f1e0756c20b68 to your computer and use it in GitHub Desktop.
AOC2019day13
#!/bin/bash -eu
getloc() {
case $1 in
0) echo "$2" ;;
1) echo "Can't get location of immediate value" >&2 && exit 1 ;;
2) echo "$((rb + $2))" ;;
esac
}
getval() {
case $1 in
0) echo "${ram[$2]}" ;;
1) echo "$2" ;;
2) echo "${ram[rb+$2]}" ;;
esac
}
printinstr() {
local instr=$1 ; shift
while [ $# -gt 0 ]; do
case "$1" in
0) instr="$instr [$2]" ;;
1) instr="$instr $2" ;;
2) instr="$instr [$2 + rb($rb)]" ;;
esac
shift 2
done
echo "$0 $instr"
}
add() { ram[$(getloc "$5" "$6")]=$(($(getval "$1" "$2") + $(getval "$3" "$4"))) ; }
mul() { ram[$(getloc "$5" "$6")]=$(($(getval "$1" "$2") * $(getval "$3" "$4"))) ; }
cmpl() { ram[$(getloc "$5" "$6")]=$(($(getval "$1" "$2") < $(getval "$3" "$4") ? 1 : 0 )) ; }
cmpe() { ram[$(getloc "$5" "$6")]=$(($(getval "$1" "$2") == $(getval "$3" "$4") ? 1 : 0 )) ; }
jmpt() { [ "$(getval "$1" "$2")" -eq 0 ] || pc=$(getval "$3" "$4") ; }
jmpf() { [ "$(getval "$1" "$2")" -ne 0 ] || pc=$(getval "$3" "$4") ; }
addrb() { ((rb+=$(getval "$1" "$2"))) ; }
outb() { getval "$1" "$2" ; }
inb() { ram[$(getloc "$1" "$2")]=$(<joystick) ; }
bdb() {
local ramcopy=("${ram[@]}")
ramcopy[pc]="$(tput setaf 10)${ramcopy[pc]}$(tput setaf 15)<"
bdbout=$(
echo -e "$0\t$pc/$rb\t$(seq 0 15 | xargs | tr \ \\t)"
for addr in $(seq 0 16 "${#ramcopy[@]}"); do
echo "$0 $addr: ${ramcopy[*]:addr:16}" | tr \ \\t
done)
echo "$bdbout" >&2
}
run() {
local -ai program ram
IFS=, read -r -a program < "$1"
shift
inputs=("$@")
[ -z "${DEBUG:-}" ] || echo "$0: program start: ${inputs[*]}" >&2
ram=("${program[@]}" $(yes 0|head -n 128))
ram[0]=2
declare -i pc=0 rb=0
while : ; do
[ "${DEBUG:-}" != 2 ] || bdb
local opcode opfunc
local -i argc args=()
printf -v opcode %05d "${ram[pc++]}"
case "${opcode: -2:2}" in
01) opfunc=add argc=3 ;;
02) opfunc=mul argc=3 ;;
03) opfunc=inb argc=1 ;;
04) opfunc=outb argc=1 ;;
05) opfunc=jmpt argc=2 ;;
06) opfunc=jmpf argc=2 ;;
07) opfunc=cmpl argc=3 ;;
08) opfunc=cmpe argc=3 ;;
09) opfunc=addrb argc=1 ;;
99) break ;;
*)
echo "Unknown opcode $opcode at $((pc-1))" >&2
return 1
;;
esac
for ((arg=0; arg < argc; arg++)); do
args+=("${opcode: -3-arg:1}" "${ram[@]:pc++:1}")
done
[ -z "${DEBUG:-}" ] || printinstr "$opfunc" "${args[@]}" >&2
"$opfunc" "${args[@]}"
done
}
readonly -f add mul inb outb jmpt jmpf cmpl cmpe addrb run bdb getval getloc printinstr
export -f add mul inb outb jmpt jmpf cmpl cmpe addrb run bdb getval getloc printinstr
cols=38
rows=20
screensize=$((cols*rows))
score=0
screen=$(yes '·' | head -n "$screensize" | xargs | tr -d ' ')
draw() {
local go=0
local -a paddle=(0 0) ball=(0 0)
> log
tput clear
while true; do
read -r x
read -r y
read -r thing
echo "$thing $x $y" >> log
local -i offset=$((y*cols+x))
if [ "$x" -eq -1 ] && [ "$y" -eq 0 ]; then
score=$thing
else
case $thing in
0) screen="${screen:0:offset}·${screen:offset+1}" ;;
1) screen="${screen:0:offset}+${screen:offset+1}" ;;
2) screen="${screen:0:offset}#${screen:offset+1}" ;;
3) paddle=("$x" "$y") ;;
4) ball=("$x" "$y") ;;
esac
fi
echo -n "$((${ball[0]} < ${paddle[0]} ? -1 : ${ball[0]} > ${paddle[0]} ? 1 : 0))" > joystick
output=$(
tput cup 0 0
echo "Score: $score, ball=${ball[0]}, paddle=${paddle[0]}, joy=$(<joystick) "
for ((idx=0; idx < screensize; idx+=cols)); do
echo "${screen:idx:cols}"
done
tput cup "$((${paddle[1]}+1))" "${paddle[0]}"
echo -n '='
tput cup "$((${ball[1]}+1))" "${ball[0]}"
echo -n '*'
)
echo "$output"
done
}
echo -n 0 > joystick
run "$@" | draw
echo "Final score: $score"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment