Created
December 7, 2019 21:18
-
-
Save rhowe/3a6c11f38377e8be04ec5d9f4f386b6e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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