#!/usr/bin/env tclsh set mask0 0 set mask1 0 set maskx {} proc setmask {mask} { global mask0 mask1 maskx set mask0 0 set mask1 0 set maskx {} set i 1 foreach bit [lreverse [split $mask {}]] { switch -- $bit { X { set mask0 [expr {$mask0 | $i}] lappend maskx $i } 0 {} 1 { set mask1 [expr {$mask1 | $i}] } } set i [expr {$i * 2}] } set mask0 [expr {0xfffffffff ^ $mask0}] } proc setval {addr val} { global mem maskx set base $addr # puts "setval addr=$addr val=$val" for {set i [expr {2**[llength $maskx]-1}]} {$i >= 0} {incr i -1} { # i is a bitmask indicating which elements of maskx to OR into addr set jj 1 set addr $base for {set j 0} {$j < [llength $maskx]} {incr j} { # j is an index into the maskx list # jj is 2^j if {$i & $jj} { set addr [expr {$addr | [lindex $maskx $j]}] } set jj [expr {$jj * 2}] } set mem($addr) $val # puts " mem($addr) = $mem($addr)" } } while {[gets stdin line] >= 0} { if {[scan $line {mem[%ld] = %ld} addr val] == 2} { set addr [expr {($addr | $mask1) & $mask0}] setval $addr $val } elseif {[scan $line {mask = %s} mask] == 1} { setmask $mask # puts "[format {masks = %x %x {%s}} $mask0 $mask1 $maskx]" } } set sum 0 foreach {addr val} [array get mem] { incr sum $val } puts $sum