blob: e43d04f424222659412bd256774221831f75a50f (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
#!/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
|