#!/usr/local/bin/tclsh if {[llength $argv] < 1} { puts stderr "usage: $argv0 programfile ?inputs ...?" exit 1 } set programfile [lindex $argv 0] set input [lrange $argv 1 end] set fd [open $programfile r] set list [split [string trimright [read $fd] \n] ,] close $fd while {[llength $list] < 16384} { lappend list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } for {set i 0} {$i < 50} {incr i} { set memory($i) $list set pc($i) 0 set relbase($i) 0 set inputq($i) [list $i] set outputq($i) [list] } set inputq(255) [list] set nat [list 0 0] set idle 0 proc tick {vm} { global memory pc relbase inputq outputq nat idle set op [format %05d [lindex $memory($vm) $pc($vm)]] set mode1 [string index $op 2] set mode2 [string index $op 1] set mode3 [string index $op 0] set i [expr {$pc($vm) + 1}] set j [expr {$pc($vm) + 2}] set k [expr {$pc($vm) + 3}] switch -- $mode1 { 0 {set a [lindex $memory($vm) [lindex $memory($vm) $i]]} 1 {set a [lindex $memory($vm) $i]} 2 {set a [lindex $memory($vm) \ [expr {$relbase($vm) + [lindex $memory($vm) $i]}]]} } switch -- $mode2 { 0 {set b [lindex $memory($vm) [lindex $memory($vm) $j]]} 1 {set b [lindex $memory($vm) $j]} 2 {set b [lindex $memory($vm) \ [expr {$relbase($vm) + [lindex $memory($vm) $j]}]]} } switch -- $mode3 { 0 {set store [lindex $memory($vm) $k]} 2 {set store [expr {$relbase($vm) + [lindex $memory($vm) $k]}]} } if {[llength $inputq($vm)]} {set idle 0} switch -glob -- $op { *01 { lset memory($vm) $store [expr {$a + $b}] incr pc($vm) 4 } *02 { lset memory($vm) $store [expr {$a * $b}] incr pc($vm) 4 } *03 { if {[llength $inputq($vm)] == 0} { set inputq($vm) [list -1] incr idle } else { set idle 0 } # puts "$vm reading, input queue [join $inputq($vm) { }]" if {$mode1 == 0} { lset memory($vm) [lindex $memory($vm) $i] \ [lindex $inputq($vm) 0] } else { lset memory($vm) \ [expr {$relbase($vm) + [lindex $memory($vm) $i]}] \ [lindex $inputq($vm) 0] } set inputq($vm) [lrange $inputq($vm) 1 end] incr pc($vm) 2 } *04 { lappend outputq($vm) $a incr pc($vm) 2 if {[llength $outputq($vm)] == 3} { lassign $outputq($vm) to x y # puts "$vm sent: $to $x $y" if {$to == 255} { set nat [list $x $y] puts "$vm set nat $x $y" } else { lappend inputq($to) $x $y } set outputq($vm) [list] } set idle 0 } *05 { if {$a != 0} { set pc($vm) $b } else { incr pc($vm) 3 } } *06 { if {$a == 0} { set pc($vm) $b } else { incr pc($vm) 3 } } *07 { lset memory($vm) $store [expr {$a < $b}] incr pc($vm) 4 } *08 { lset memory($vm) $store [expr {$a == $b}] incr pc($vm) 4 } *09 { incr relbase($vm) $a incr pc($vm) 2 } *99 return } } set prev "" while 1 { for {set i 0} {$i < 50} {incr i} { tick $i } if {$idle >= 10000} { lassign $nat x y if {$y == $prev} { puts $y break } lappend inputq(0) $x $y set prev $y } }