-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphilosophers.tcl
executable file
·378 lines (273 loc) · 8.52 KB
/
philosophers.tcl
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#!/usr/bin/wish
oo::class create Program {
constructor {} {
variable philosopherColor black
variable handColor yellow
variable tableColor red
variable forkColor blue
variable tableMiddleX
variable tableMiddleY
variable numPhilosophers 5
variable tableRadius 95
variable philosopherRadius 27
variable forkRadius 10
variable angle [expr {360/$numPhilosophers}]
variable radiansBetweenShapes [expr {$angle*0.0174532925}]
variable forkPoints
variable philoPoints
variable startActivity
# { Name, Remaining time, State }
# State ( 1 - Eating, 0 - Thinking )
variable tableState "
{Arystoteles [my getRandom] 0}
0
{Platon [my getRandom] 0}
0
{Kartezjusz [my getRandom] 0}
0
{Sokrates [my getRandom] 0}
0
{Augustyn [my getRandom] 0}
0
"
variable lastPhilosopherIndex [expr {[llength $tableState]-2}]
my createCanvas
}
method createCanvas {} {
canvas .can
.can configure -width 854
.can configure -height 480
pack .can
wm title . "Dinner"
my drawAllShapes
}
method drawAllShapes {} {
variable numPhilosophers
variable radiansBetweenShapes
variable philosopherRadius
variable forkRadius
variable forkColor
variable philosopherColor
variable forkPoints
variable philoPoints
my drawTable
set philosophersFromCenter 130
set initialAngle $radiansBetweenShapes
# Philosophers
set philoPoints\
[my drawShapes\
$initialAngle $philosophersFromCenter\
$philosopherRadius $philosopherColor]
set forksFromCenter 70
set initialAngle [expr {$radiansBetweenShapes/2}]
# Forks
set forkPoints\
[my drawShapes\
$initialAngle $forksFromCenter\
$forkRadius $forkColor]
}
method drawTable {} {
variable tableRadius
variable tableColor
variable tableMiddleX
variable tableMiddleY
# Table top-left and bottom-right
set x1 150 ; set y1 70
set tableDiameter [expr {$tableRadius*2}]
set x2 [expr {$x1+$tableDiameter}]
set y2 [expr {$y1+$tableDiameter}]
# Table center
set tableMiddleX [expr {$x1+$tableRadius}]
set tableMiddleY [expr {$y1+$tableRadius}]
# Draw table
.can create oval\
$x1 $y1 $x2 $y2\
-outline red -fill $tableColor
# Draw middle dot
.can create oval\
$tableMiddleX $tableMiddleY $tableMiddleX $tableMiddleY\
-outline red -fill red
}
method drawShapes {currentAngle distanceFromCenter radius color} {
variable tableMiddleX
variable tableMiddleY
variable radiansBetweenShapes
variable numPhilosophers
set points {}
for {set i 0} {$i < $numPhilosophers} {incr i} {
# Unit vector
set vecX [expr {cos($currentAngle)}] ; set vecY [expr {sin($currentAngle)}]
# Central point of philosopher/fork
set pointX\
[expr {$tableMiddleX+$vecX*$distanceFromCenter}]
set pointY\
[expr {$tableMiddleY-$vecY*$distanceFromCenter}]
# List of positions
lappend points "$pointX $pointY"
# Top left circle position
set newX\
[expr {$pointX-$radius}]
set newY\
[expr {$pointY-$radius}]
set shapeDiameter [expr {$radius*2}]
# Draw circle
.can create oval\
$newX $newY\
[expr {$newX+$shapeDiameter}]\
[expr {$newY+$shapeDiameter}]\
-outline $color -fill $color
# Angle for next shape
set currentAngle [expr {$currentAngle+$radiansBetweenShapes}]
}
# Return list of positions
return $points
}
method rnd {min max} { expr {int(rand()*($max+1-$min))+$min} }
method getRandom {} { return [my rnd 5 20] }
method update {} {
variable lastPhilosopherIndex
variable tableState
for {set j 0} {$j <= $lastPhilosopherIndex} {incr j 2} {
set startActivity 0
set remTime [lindex $tableState $j 1]
set activity [lindex $tableState $j 2]
if {1==$activity} {
my processEating $j
} else {
my processNonEating $j
}
# Dont decrement if remaining time
# is 0 or activity just started
if {!$startActivity&&$remTime > 0} {
lset tableState $j 1 [expr {$remTime-1}]
}
}
my line
}
method getNeighbourIndices {index} {
variable tableState
set lastP [expr {[llength $tableState]-2}]
set l [expr {0==$index ? $lastP : $index-2}]
set r [expr {$lastP==$index ? 0 : $index+2}]
return "$l $r"
}
method processNonEating {index} {
variable tableState
variable startActivity
set philo [lindex $tableState $index]
set name [lindex $philo 0]
set remTime [lindex $philo 1]
set rForkIndex [expr {$index+1}]
set lForkIndex [my getLForkIndex $index]
set neIndices [my getNeighbourIndices $index]
set leftNeIndex [lindex $neIndices 0]
set rightNeIndex [lindex $neIndices 1]
# Attempt to change state
if {0==$remTime} {
# Neighbours
set leftN [lindex $tableState $leftNeIndex]
set rightN [lindex $tableState $rightNeIndex]
# Someone is using left fork
if {[lindex $tableState $lForkIndex]==1} {
# Its neighbour
if {[lindex $leftN 2]==1} {
puts "$name nie może wziąć lewego widelca"
# Its me
} else {
# Get right fork if its free
if {[lindex $tableState $rForkIndex]!=1} {
puts "$name podnosi prawy widelec i zaczyna jeść"
my drawHand $index right
# Get right fork
lset tableState $rForkIndex 1
# Change status
lset tableState $index 2 1
# Set eating time
lset tableState $index 1 [my getRandom]
set startActivity 1
# I cant get right fork
} else {
puts "$name nie może wziąć prawego widelca"
}
}
} else {
# Get left fork
lset tableState $lForkIndex 1
puts "$name podnosi lewy widelec"
my drawHand $index left
}
} else {
puts "$name myśli ($remTime)"
}
}
method getLForkIndex {index} {
return [expr {0==$index ? 9 : $index-1}]
}
method processEating {index} {
variable tableState
variable startActivity
set philo [lindex $tableState $index]
set name [lindex $philo 0]
set remTime [lindex $philo 1]
set rForkIndex [expr {$index+1}]
set lForkIndex [my getLForkIndex $index]
if {$remTime==0} {
puts "$name skończył jeść i zaczyna myśleć"
# Change state to thinking
lset tableState $index 2 0
# Random thinking time
lset tableState $index 1 [my getRandom]
# Put forks down
lset tableState $lForkIndex 0
lset tableState $rForkIndex 0
my deleteForks $index
set startActivity 1
} else {
puts "$name jest w trakcie jedzenia ($remTime)"
}
}
method drawHand {index direction} {
variable forkPoints
variable philoPoints
variable handColor
# Philosopher center
set pIndex [expr {$index/2}]
set philoPoint [lindex $philoPoints $pIndex]
# Fork center
# Symbol identifies left/right fork
set fPoint {} ; set symbol {}
if {$direction=="right"} {
set symbol 1
if {4==$pIndex} {
set fPoint [lindex $forkPoints 0]
} else {
set fPoint [lindex $forkPoints [expr {$pIndex+1}]]
}
} elseif {$direction=="left"} {
set symbol 0
set fPoint [lindex $forkPoints $pIndex]
}
.can create line\
[lindex $philoPoint 0]\
[lindex $philoPoint 1]\
[lindex $fPoint 0]\
[lindex $fPoint 1]\
-fill $handColor -tag $pIndex-$symbol
}
# Delete both forks
method deleteForks {index} {
set pIndex [expr {$index/2}]
.can delete $pIndex-0
.can delete $pIndex-1
}
method line {} {
puts "-------------------------------------------------"
}
}
proc every {ms body} {
eval $body; after $ms [namespace code [info level 0]]
}
# ----------------------------------------------
set program [Program new]
every 25 { global program ; $program update }
# ----------------------------------------------