Skip to content

Instantly share code, notes, and snippets.

@rhowe
Created December 7, 2019 21:18
Show Gist options
  • Save rhowe/3a6c11f38377e8be04ec5d9f4f386b6e to your computer and use it in GitHub Desktop.
Save rhowe/3a6c11f38377e8be04ec5d9f4f386b6e to your computer and use it in GitHub Desktop.
#!/bin/bash
# This program has some kind of deadlock/race condition
# There are some hacks to let you rerun it and make continual progress so you can:
# while true; do ./7.sh input & sleep 10; kill %1; done
set -eu
getval() {
case $1 in
0) echo "${ram[$2]}" ;;
1) echo "$2" ;;
esac
}
jmpt() {
local addrmode; addrmode=$1
local arg; arg=$(getval "${addrmode:0:1}" "$2")
local dest; dest=$(getval "${addrmode:1:1}" "$3")
if [ "$arg" -ne 0 ]; then
pc=$dest
else
pc=$((pc+2))
fi
}
jmpf() {
local addrmode; addrmode=$1
local arg; arg=$(getval "${addrmode:0:1}" "$2")
local dest;dest=$(getval "${addrmode:1:1}" "$3")
if [ "$arg" -eq 0 ]; then
pc=$dest
else
pc=$((pc+2))
fi
}
add() {
local addrmode; addrmode=$1
local src1; src1=$(getval "${addrmode:0:1}" "$2")
local src2; src2=$(getval "${addrmode:1:1}" "$3")
local dest; dest=$4
ram[$dest]=$((src1 + src2))
pc=$((pc+3))
}
mul() {
local addrmode; addrmode=$1
local src1; src1=$(getval "${addrmode:0:1}" "$2")
local src2; src2=$(getval "${addrmode:1:1}" "$3")
local dest; dest=$4
ram[$dest]=$((src1 * src2))
pc=$((pc+3))
}
cmpl() {
local addrmode; addrmode=$1
local src1; src1=$(getval "${addrmode:0:1}" "$2")
local src2; src2=$(getval "${addrmode:1:1}" "$3")
local dest; dest=$4
if [ "$src1" -lt "$src2" ]; then
ans=1
else
ans=0
fi
ram[$dest]=$ans
pc=$((pc+3))
}
cmpe() {
local addrmode; addrmode=$1
local src1; src1=$(getval "${addrmode:0:1}" "$2")
local src2; src2=$(getval "${addrmode:1:1}" "$3")
local dest; dest=$4
if [ "$src1" -eq "$src2" ]; then
local ans=1
else
local ans=0
fi
ram[$dest]=$ans
pc=$((pc+3))
}
inb() {
local addrmode; addrmode=$1
local dest; dest=$2
if [ -z "${inputs:-}" ]; then
read -r input
[ -z "${DEBUG:-}" ] || echo "$0 inb $dest (ext: $input)" >&2
ram[$dest]=$input
else
ram[$dest]=${inputs[0]}
inputs=("${inputs[@]:1}")
fi
pc=$((pc+1))
}
outb() {
local addrmode; addrmode=$1
local src; src=$(getval "${addrmode:0:1}" "$2")
[ -z "${DEBUG:-}" ] || echo "$0 outb $src" >&2
echo "$src"
echo "$src" > "io/$0.tap"
pc=$((pc+1))
}
gdb() {
ramcopy=("${ram[@]}")
ramcopy[$pc]="${ramcopy[$pc]}*"
gdbout=$(
echo -e "$0\t$pc\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 "$gdbout" >&2
}
run() {
IFS=, read -r -a program < "$1"
shift
inputs=("$@")
[ -z "${DEBUG:-}" ] || echo "$0: program start: ${inputs[@]}" >&2
pc=0
ram=("${program[@]}")
while true; do
local opcode; opcode=$(printf %04d "${ram[$pc]}")
local addrmode; addrmode=${opcode: -3:1}${opcode: -4:1}
[ -z "${DEBUG:-}" ] || gdb
pc=$((pc+1))
case "${opcode: -2}" in
01) add "$addrmode" "${ram[@]:$pc:3}" ;;
02) mul "$addrmode" "${ram[@]:$pc:3}" ;;
03) inb "$addrmode" "${ram[@]:$pc:1}" ;;
04) outb "$addrmode" "${ram[@]:$pc:1}" ;;
05) jmpt "$addrmode" "${ram[@]:$pc:2}" ;;
06) jmpf "$addrmode" "${ram[@]:$pc:2}" ;;
07) cmpl "$addrmode" "${ram[@]:$pc:3}" ;;
08) cmpe "$addrmode" "${ram[@]:$pc:3}" ;;
99) break ;;
*)
echo "Unknown opcode $opcode at $pc" >&2
return 1
;;
esac
done
}
cd "$(dirname "$0")"
export -f add mul inb outb jmpt jmpf cmpl cmpe run gdb getval
export DEBUG
rm -rf io
mkdir io
for amp in A B C D E F; do
mkfifo io/$amp.in
done
fratricide() {
kill $A_PID $B_PID $C_PID $D_PID $E_PID $F_PID
}
trap fratricide EXIT
highestoutput=0
if [ ! -f phases ]; then
for phases in {5,6,7,8,9},{5,6,7,8,9},{5,6,7,8,9},{5,6,7,8,9},{5,6,7,8,9}; do
IFS=, read -r -a phasearray <<<"$phases"
if [ "$(xargs -n1 echo <<<"${phasearray[@]}" | sort -u)" != "$(xargs -n1 echo <<<"${phasearray[@]}" | sort)" ]; then
continue
fi
echo $phases >> phases
done
fi
for phases in $(<phases); do
if grep -q "$phases" results; then
echo "already got a result for $phases"
continue
fi
IFS=, read -r -a phasearray <<<"$phases"
bash -c "run \"$1\" \"${phasearray[0]}\"" A <io/A.in >io/B.in &
A_PID=$!
sleep 0.2
bash -c "run \"$1\" \"${phasearray[1]}\"" B <io/B.in >io/C.in &
B_PID=$!
sleep 0.2
bash -c "run \"$1\" \"${phasearray[2]}\"" C <io/C.in >io/D.in &
C_PID=$!
sleep 0.2
bash -c "run \"$1\" \"${phasearray[3]}\"" D <io/D.in >io/E.in &
D_PID=$!
sleep 0.2
bash -c "run \"$1\" \"${phasearray[4]}\"" E <io/E.in >io/F.in &
E_PID=$!
sleep 0.2
bash -c "tee io/F.tap" F <io/F.in >io/A.in &
F_PID=$!
sleep 0.2
echo 0 > io/F.in
set +e
jobs
echo pids: $A_PID $B_PID $C_PID $D_PID $E_PID $F_PID
wait $A_PID $B_PID $C_PID $D_PID $E_PID $F_PID || :
acc=$(< io/E.tap)
echo "$phases,$acc" >> results
echo "$phases got $acc (max $highestoutput)"
if [ "$acc" -gt "$highestoutput" ]; then
highestoutput=$acc
fi
done
sort -n -t , -k 6 results | tail -n1 | cut -d , -f 6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment