#!/usr/local/bin/obmsh # PUZZLE.GUI -- A simple number re-ordering puzzle, kinda like the one my # Dad would make me play on long car trips to shut me up.... # # History: 4/23/94 - written (MJF) # 4/25/94 - Added timer and move counter labels reset-server appInitialize puzzle Puzzle { Puzzle*objects:\ toplevel Paned puzzle\ puzzle Form tForm\ tForm Label timerLabel\ tForm Toggle pauseButton\ tForm Label movesLabel\ \ puzzle Form pForm\ pForm Command pos11\ pForm Command pos12\ pForm Command pos13\ pForm Command pos14\ pForm Command pos15\ pForm Command pos21\ pForm Command pos22\ pForm Command pos23\ pForm Command pos24\ pForm Command pos25\ pForm Command pos31\ pForm Command pos32\ pForm Command pos33\ pForm Command pos34\ pForm Command pos35\ pForm Command pos41\ pForm Command pos42\ pForm Command pos43\ pForm Command pos44\ pForm Command pos45\ pForm Command pos51\ pForm Command pos52\ pForm Command pos53\ pForm Command pos54\ pForm Command pos55\ \ puzzle Form pCmd\ pCmd Command newButton\ pCmd Command quitButton *tForm*background: bisque3 *tForm*showGrip: false *tForm*resizeable: false *tForm*Label.background: black *tForm*Label.foreground: red *tForm*Label.shadowWidth: 0 *tForm*Label.borderWidth: 0 *tForm*Command.background: grey80 *tForm*Toggle.background: grey80 *pForm*background: bisque3 *pForm*showGrip: false *pForm*resizeable: false *pForm*Command.background: grey80 *pCmd*background: bisque3 *pCmd*Command.background: grey80 *pCmd*resizeable: false *timerLabel.label: 0000 *timerLabel.height: 30 *timerLabel*font: *times-bold-r*24* *pauseButton.label: Pause *pauseButton.height: 30 *pauseButton.fromHoriz: timerLabel *pauseButton.horizDistance: 10 *pauseButton*font: *times-bold-r*18* *movesLabel.label: 0000 *movesLabel.height: 30 *movesLabel*font: *times-bold-r*24* *movesLabel.fromHoriz: pauseButton *movesLabel.horizDistance: 10 *pForm*width: 50 *pForm*height: 50 *pForm*horizDistance: 0 *pForm*vertDistance: 0 *pForm*Label.background: bisque3 *pForm*Label.shadowWidth: 0 *pForm*Label.borderWidth: 0 *pForm*font: *times-bold-r*24* *pos12.fromHoriz: pos11 *pos13.fromHoriz: pos12 *pos14.fromHoriz: pos13 *pos15.fromHoriz: pos14 *pos11.vertDistance: 2 *pos12.vertDistance: 2 *pos13.vertDistance: 2 *pos14.vertDistance: 2 *pos15.vertDistance: 2 *pos21.fromVert: pos11 *pos21.horizDistance: 1 *pos22.fromVert: pos12 *pos22.fromHoriz: pos21 *pos23.fromVert: pos13 *pos23.fromHoriz: pos22 *pos24.fromVert: pos14 *pos24.fromHoriz: pos23 *pos25.fromVert: pos15 *pos25.fromHoriz: pos24 *pos31.fromVert: pos21 *pos31.horizDistance: 1 *pos32.fromHoriz: pos31 *pos32.fromVert: pos22 *pos33.fromVert: pos23 *pos33.fromHoriz: pos32 *pos34.fromVert: pos24 *pos34.fromHoriz: pos33 *pos35.fromVert: pos25 *pos35.fromHoriz: pos34 *pos41.fromVert: pos31 *pos41.horizDistance: 1 *pos42.fromHoriz: pos41 *pos42.fromVert: pos32 *pos43.fromVert: pos33 *pos43.fromHoriz: pos42 *pos44.fromVert: pos34 *pos44.fromHoriz: pos43 *pos45.fromVert: pos35 *pos45.fromHoriz: pos44 *pos51.fromVert: pos41 *pos51.horizDistance: 1 *pos52.fromHoriz: pos51 *pos52.fromVert: pos42 *pos53.fromVert: pos43 *pos53.fromHoriz: pos52 *pos54.fromVert: pos44 *pos54.fromHoriz: pos53 *pos55.fromVert: pos45 *pos55.fromHoriz: pos54 *pCmd*Command.height: 30 *pCmd*Command.width: 50 *pCmd*Command.vertDistance: 12 *pCmd*Command*font: *times-bold-r*18* *newButton.label: New Game *quitButton.fromHoriz: newButton *quitButton.vertDistance: 5 *quitButton.label: Quit } # Crank 'er up... createObjects activate # Should be a better way to randomize the start. set space [ expr ( [pid] % 23 ) ] set random "17 8 13 19 22 21 12 18 15 9 23 5 3 20 6 4 1 7 24 10 14 16 2 11" # Quit the game. proc Quit args { global timerId if {[send pauseButton get state] == 0} { deleteTimedCallback $timerId } send client gkey q deactivate unmap } ; send quitButton addCallback Quit # Initialize the game board. proc Init args { global space random set k $space set ispace [ expr ($space / 5 + 1) ] set jspace [ expr ($space % 5 + 1) ] for { set i 1 } { $i<=5 } { incr i } { for { set j 1 } { $j<=5 } { incr j } { set val [lindex $random $k] if {[expr [expr $i == $ispace] && [expr $j == $jspace]]} { send pForm unmanage pos$i$j } else { send pos$i$j "set label $val" set k [ expr ($k == 23) ? 0 : [expr $k+1] ] } } } } ; Init # Define the game buttons and positions. set buttons { pos11 pos12 pos13 pos14 pos15 pos21 pos22 pos23 pos24 pos25 pos31 pos32 pos33 pos34 pos35 pos41 pos42 pos43 pos44 pos45 pos51 pos52 pos53 pos54 pos55 } set indx 0 for { set i 1 } { $i<=5 } { incr i } { for { set j 1 } { $j<=5 } { incr j } { set bpos(pos$i$j) "$i $j $indx" incr indx } } # Take action when hitting a button. proc Move { widget args } { global space buttons bpos # If we've paused the game then don't move anything. if {[send pauseButton get state] == 1} { return } # Get the position of the empty space. set ispace [ expr ($space / 5 + 1) ] set jspace [ expr ($space % 5 + 1) ] # Get the position of the current widget. set i [ lindex $bpos($widget) 0] set j [ lindex $bpos($widget) 1] # Now see if the current widget is next to the empty space, but not on # a corner. set xdiff [expr abs ([expr $ispace-$i])] set ydiff [expr abs ([expr $jspace-$j])] if { ! [expr [expr $xdiff == 1] && [expr $ydiff == 1]]} { if {[expr [expr $xdiff < 2] && [expr $ydiff < 2]]} { # Manage the empty space. manage_space $space # Set space label to current label. set lab [send $widget get label] send [lindex $buttons $space] "set label $lab" # Unmanage current space. unmanage_space [lindex $bpos($widget) 2] set space [lindex $bpos($widget) 2] # Update the number of times we've made a move. update_nmoves } } } ; foreach item $buttons { send $item addCallback Move } # Start a new game. proc New_Game args { global space time nmoves timerId # If we've paused the game then don't do anything. if {[send pauseButton get state] == 1} { return } manage_space $space new_space Init set nmoves -1 ; update_nmoves set time 0 deleteTimedCallback $timerId send timerLabel set label 0000 set timerId [postTimedCallback timer 1000] } ; send newButton addCallback New_Game # Get a new empty space. proc new_space args { global space random set space [lindex $random [ expr ($space >= 23) ? 0 : $space ] ] if {$space == 24} { set space 5 } } # Show a puzzle piece. proc manage_space { space args } { set ispace [ expr ($space / 5 + 1) ] set jspace [ expr ($space % 5 + 1) ] send pForm manage pos$ispace$jspace } # Remove a puzzle piece. proc unmanage_space { space args } { set ispace [ expr ($space / 5 + 1) ] set jspace [ expr ($space % 5 + 1) ] send pForm unmanage pos$ispace$jspace } # Install a timer so we can keep score of our best times. set timerId 0 set time 0 proc timer args { global timerId time send timerLabel set label [ format "%04d" $time ] incr time set timerId [postTimedCallback timer 1000] }; set timerId [postTimedCallback timer 1000] # Count the number of times we move a piece. set nmoves 0 proc update_nmoves args { global nmoves incr nmoves send movesLabel set label [ format "%04d" $nmoves ] } # Define a 'pause' command in case the boss walks in... proc pause_toggle args { global timerId if {[send pauseButton get state] == 0} { set timerId [postTimedCallback timer 1000] } else { deleteTimedCallback $timerId } } ; send pauseButton addCallback pause_toggle