#!/usr/bin/env tclsh9.0 proc input {} { global rows cols grid rr rc moves set rows 0 while {[gets stdin line] >= 0} { if {$line eq ""} break set cols [string length $line] lappend grid [split $line ""] incr rows } while {[gets stdin line] >= 0} { append moves $line } for {set r 0} {$r < $rows} {incr r} { for {set c 0} {$c < $cols} {incr c} { if {[lindex $grid $r $c] eq "@"} { set rr $r set rc $c lset grid $r $c . return } } } } proc show {} { global grid foreach row $grid { puts [join $row ""] } } proc move {} { global rows cols grid rr rc moves foreach move [split $moves ""] { # show; puts "" # If the target spot is a wall, do nothing. # If it's open space, move there. # Otherwise, project out the path of tiles from there to the first wall. switch -- $move { ^ {set dr -1; set dc 0} v {set dr 1; set dc 0} < {set dr 0; set dc -1} > {set dr 0; set dc 1} default continue } set target [lindex $grid $rr+$dr $rc+$dc] if {$target eq "#"} continue if {$target eq "."} { incr rr $dr incr rc $dc continue } # Path projection. set path "" set r $rr; set c $rc while 1 { incr r $dr; incr c $dc set target [lindex $grid $r $c] if {$target eq "#"} break append path $target } # The path projection is now a string of tile contents, starting with # "O". E.g. "O.O." or "OO" or "OOOO.". # If it's all O's, we can't move, so do nothing. # Otherwise, the location of the first . tells us how many boxes # we can push. set n [string first . $path] if {$n < 0} continue # Push n boxes. # What this really means is we put a box in the tile *after* the # last box, and clear the first box's tile. set r [expr {$rr + ($n+1)*$dr}] set c [expr {$rc + ($n+1)*$dc}] lset grid $r $c O lset grid $rr+$dr $rc+$dc . # And finally, move to the newly emptied tile. incr rr $dr incr rc $dc } } proc count {} { global rows cols grid set total 0 for {set r 0} {$r < $rows} {incr r} { for {set c 0} {$c < $cols} {incr c} { if {[lindex $grid $r $c] eq "O"} { incr total [expr {100*$r + $c}] } } } puts $total } input # show # puts "rows=$rows cols=$cols rr=$rr rc=$rc moves=$moves" move # show count