Skip to content

Commit c8239ea

Browse files
author
Zerline
committed
Flipping dominos example interactivity: unlink before creating the new dominos.
1 parent a91e0d6 commit c8239ea

File tree

1 file changed

+107
-48
lines changed

1 file changed

+107
-48
lines changed

examples/dominos/flipping_dominos.py

Lines changed: 107 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def set_cell(self, obj, pos, val, dirty={}):
2222
we prepare a possible flip
2323
or we try to complete the flip if it has been prepared previously
2424
"""
25+
#print("in the adapter for pos =", pos, "val =", val, "dirty =", dirty)
2526
# Find out the relevant matching for 'pos'
2627
d1 = obj.domino_for_position(pos)
2728
if dirty: # if i'm a neighbor, then flip and return a new obj ; else return an error
@@ -34,7 +35,9 @@ def set_cell(self, obj, pos, val, dirty={}):
3435
continue
3536
if d2 in d1.neighbors():
3637
# Do the flip
38+
print("before flipping :", d1, d2)
3739
obj.flip(d1, d2)
40+
print("after flipping :", d1, d2)
3841
return obj
3942
return Exception("Please select a second domino!")
4043
else:
@@ -43,7 +46,7 @@ def set_cell(self, obj, pos, val, dirty={}):
4346

4447
class ddlink(dlink):
4548
"""Double directional link with logic = or/and/none.
46-
Double_source is a tuple of (source, target) tuples
49+
`double_source` is a tuple of (source, traitname) tuples
4750
Usage: b1 = Button(description = 'B1')
4851
b2 = Button(description = 'B2')
4952
b3 = Button(description = 'B3')
@@ -101,6 +104,9 @@ def _busy_updating(self):
101104
def _update(self, change):
102105
#if self.updating or self.target[0].donottrack:
103106
# return
107+
#if self.target[0].donottrack:
108+
# print("on sort ici !!!")
109+
# return
104110
with self._busy_updating():
105111
if self.logic == 'and':
106112
if self.intermediate_value == False: # aucun bouton pressé avant
@@ -142,22 +148,26 @@ class Domino(HasTraits):
142148
boutons qu'il contient étant, eux, des widgets"""
143149
value = Bool()
144150

145-
def __init__(self, parent, b1, b2):
151+
def __init__(self, parent, b1, b2, link=True):
146152
"""A domino has a parent widget and is made of 2 buttons"""
153+
b1.link = None
154+
b2.link = None
155+
b1.value = False
156+
b2.value = False
147157
super(Domino, self).__init__()
158+
self.value = False
148159
self.geometry = DominoGeometry(b1.position, b2.position)
149160
self.parent = parent
150161
self.key = None
151162
self.first = b1
152163
self.second = b2
153164
self.buttons = (b1,b2)
154-
b1.link = dlink((b1, 'value'), (b2, 'value'))
155-
b2.link = dlink((b2, 'value'), (b1, 'value'))
156165
self.link = None
157166
self.direction = None
158167
self.orientation = None
159168
self.compute()
160-
self.donottrack = False
169+
if link:
170+
self.set_links()
161171

162172
def __repr__(self):
163173
if self.value:
@@ -168,7 +178,6 @@ def compute(self, css_classes=['b0', 'b1', 'b2', 'b3', 'b4']):
168178
"""Compute buttons relative positions.
169179
Create double directional link from both buttons"""
170180
self.geometry.compute()
171-
#print(self.geometry.__dict__)
172181
if css_classes:
173182
for cl in css_classes:
174183
self.first.remove_class(cl)
@@ -196,26 +205,21 @@ def compute(self, css_classes=['b0', 'b1', 'b2', 'b3', 'b4']):
196205
elif self.geometry.orientation == -1:
197206
self.first.add_class('bottom')
198207
self.second.add_class('top')
208+
209+
def set_links(self):
210+
self.first.link = dlink((self.first, 'value'), (self.second, 'value'))
211+
self.second.link = dlink((self.second, 'value'), (self.first, 'value'))
199212
self.link = ddlink(((self.first, 'value'), (self.second, 'value')), (self, 'value'), logic='and', set_at_init=False) # Fresh ddlink
200213

201214
def is_pressed(self):
202215
"""Is the domino pressed?"""
203216
return self.value
204217

205-
# def set_value(self, value):
206-
# """Set domino value
207-
# As we have a directional link,
208-
# the domino value will also be set.
209-
# """
210-
# self.link.unlink()
211-
# self.first.value = value
212-
# self.second.value = value
213-
# self.link = ddlink(((self.first, 'value'), (self.second, 'value')), (self, 'value'), logic='and', set_at_init=False) # Fresh ddlink
214-
215-
def reset(self):
216-
"""Full domino reset"""
217-
#self.set_value(False)
218+
def unlink(self):
219+
"""Full domino unlink"""
218220
self.link.unlink()
221+
self.first.link.unlink()
222+
self.second.link.unlink()
219223

220224
def flip(self, other):
221225
"""Flip self with some neighboring domino"""
@@ -246,6 +250,8 @@ def __init__(self, g, css_classes=['b0', 'b1', 'b2', 'b3', 'b4']):
246250
with flipping aztec diamond graph `g`
247251
"""
248252
self.css_classes = css_classes
253+
#self.resetting = None
254+
#self.resetting = True
249255
super(FlippingDominosWidget, self).__init__(g, adapter = FlippingDominosAdapter(),
250256
cell_layout = smallblyt,
251257
cell_widget_classes=[styled_button_cell(),
@@ -256,6 +262,8 @@ def __init__(self, g, css_classes=['b0', 'b1', 'b2', 'b3', 'b4']):
256262
],
257263
cell_widget_class_index=make_cell_widget_class_index(g),
258264
blank_widget_class = BlankButton)
265+
self.resetting_cells = []
266+
259267
def draw(self):
260268
self.dominos = {}
261269
super(FlippingDominosWidget, self).draw()
@@ -279,8 +287,10 @@ def apply_matching(self, matching):
279287
"""Apply a matching"""
280288
self.dominos = {}
281289
for d in matching:
282-
self.match(self.children[d.first[0]].children[d.first[1]],
283-
self.children[d.second[0]].children[d.second[1]])
290+
self.match(
291+
self.children[d.first[0]].children[d.first[1]],
292+
self.children[d.second[0]].children[d.second[1]]
293+
)
284294

285295
def update(self):
286296
self.apply_matching(self.value.matching)
@@ -292,14 +302,8 @@ def domino_for_position(self, pos):
292302
geometry = self.value.domino_for_position(pos)
293303
for t in (geometry.first, geometry.second):
294304
if t in self.dominos:
295-
print("domino for position", t, ":", self.dominos[t].geometry, self.dominos[t].value)
296305
return self.dominos[t]
297306

298-
def not_tracking(self, value):
299-
self.donottrack = value
300-
for d in self.dominos.values():
301-
d.donottrack = value
302-
303307
@observe(All)
304308
def set_cell(self, change):
305309
if self.donottrack:
@@ -309,37 +313,92 @@ def set_cell(self, change):
309313
else:
310314
print("set_cell()", change.name)
311315
# Try to reset everything right now to avoid unwanted propagations
312-
domino = self.domino_for_position(extract_coordinates(change.name))
313-
# First, we want to make the pressed domino visible to the user
314-
self.not_tracking(True)
315-
domino.first.value = True
316-
domino.second.value = True
317-
# Any pressed neighbor?
316+
click_pos = extract_coordinates(change.name)
317+
domino = self.domino_for_position(click_pos)
318+
if not domino: # or domino.donottrack:
319+
return
320+
# The domino must be entirely pressed
321+
if not domino.first.value or not domino.second.value:
322+
return
323+
# The domino must have a pressed neighbor
318324
other = None
319325
if self.dirty:
320326
for pos in self.dirty:
327+
if other and other.geometry!=self.domino_for_position(pos).geometry:
328+
raise Exception("on a un double dans les voisins pressés: %s et %s" % (
329+
other.geometry, self.domino_for_position(pos).geometry))
321330
other = self.domino_for_position(pos)
322331
if other and not other.geometry in domino.geometry.neighbors():
323332
other = None
324333
continue # we don't have to reset everything, I guess(hope)
325334
if not other:
335+
# Feed the 'dirty' dict and return
326336
self.dirty[domino.geometry.first] = True
327337
self.dirty[domino.geometry.second] = True
328-
self.not_tracking(False)
329338
return
330-
if domino.link:
331-
domino.link.unlink()
332-
if other.link:
333-
other.link.unlink()
334-
self.not_tracking(False)
339+
# Do the flip
335340
super(FlippingDominosWidget, self).set_cell(change)
336-
self.not_tracking(True)
337-
# And now, we want to reset everything before the flip
338-
domino.first.value = False
339-
domino.second.value = False
340-
other.first.value = False
341-
other.second.value = False
342-
# Now, recreate the 2 dominos and compute style
341+
# Unlink
342+
self.donottrack = True
343+
domino.unlink()
344+
other.unlink()
345+
# Build our new dominos
346+
new_domino, new_other = None, None
347+
for g1 in self.value.matching:
348+
if g1.first == domino.geometry.first or g1.first == other.geometry.first:
349+
d1, d2 = domino.geometry, other.geometry
350+
if g1.first == domino.geometry.first:
351+
new_domino = Domino(
352+
self,
353+
self.children[g1.first[0]].children[g1.first[1]],
354+
self.children[g1.second[0]].children[g1.second[1]],
355+
link = False
356+
)
357+
self.dominos[domino.key] = new_domino
358+
for g2 in g1.neighbors():
359+
if not g2 in self.value.matching:
360+
continue
361+
if (other.key in (g2.first, g2.second)) or \
362+
(other.key == g1.second and domino.geometry.second in (g2.first, g2.second)):
363+
new_other = Domino(
364+
self,
365+
self.children[g2.first[0]].children[g2.first[1]],
366+
self.children[g2.second[0]].children[g2.second[1]],
367+
link = False
368+
)
369+
self.dominos[other.key] = new_other
370+
break
371+
elif g1.first == other.geometry.first:
372+
new_other = Domino(
373+
self,
374+
self.children[g1.first[0]].children[g1.first[1]],
375+
self.children[g1.second[0]].children[g1.second[1]],
376+
link = False
377+
)
378+
self.dominos[other.key] = new_other
379+
for g2 in g1.neighbors():
380+
if not g2 in self.value.matching:
381+
continue
382+
if (domino.key in (g2.first, g2.second)) or \
383+
(domino.key == g1.second and other.geometry.second in (g2.first, g2.second)):
384+
new_domino = Domino(
385+
self,
386+
self.children[g2.first[0]].children[g2.first[1]],
387+
self.children[g2.second[0]].children[g2.second[1]],
388+
link = False
389+
)
390+
self.dominos[domino.key] = new_domino
391+
break
392+
if new_domino and new_other:
393+
break
394+
# Check that new dominos are sound and the flip has actually been performed
395+
assert(new_domino is not None and new_other is not None)
396+
assert(new_domino.geometry != domino.geometry and new_other.geometry != other.geometry)
397+
# Compute the dominos
398+
new_domino.compute()
399+
new_other.compute()
400+
new_domino.set_links()
401+
new_other.set_links()
402+
# Reset
343403
self.reset_dirty()
344-
self.update()
345-
self.not_tracking(False)
404+
self.donottrack = False

0 commit comments

Comments
 (0)