ラムダを使用して pygame アプリケーションで元に戻すとやり直しを実装しようとしていますが、参照と関係があるか、実装についての私の理解list.remove()
が原因でプログラムがクラッシュしています。取り消し可能なアクションを作成するコードは次のとおりです。
elif MOUSEBUTTONUP == event.type:
x, y = pygame.mouse.get_pos()
if leftClick:
if len( objects ) > 0 and objects[ -1 ].is_open():
actions.do( \
[ lambda: objects[ -1 ].add( Point( x, y, 0 ) ) ], \
[ lambda: objects[ -1 ].remove( Point( x, y, 0 ) ) ] \
)
else:
actions.do( \
[ lambda: objects.append( Polygon( ( 255, 255, 255 ) ).add( Point( x, y, 0 ) ) ) ],
[ lambda: objects.pop() ] \
)
ここで、objects は のリストでありPolygon
、次のように定義されます。
class Polygon:
def __init__( self, colour, width = 0 ):
self._points = []
self._colour = colour
self._isopen = True
self._width = width
def get_colour( self ):
return self._colour
def add( self, point ):
self._points.append( point )
return self
def remove( self, point ):
print "List contains " + str( self._points )
print "Trying to remove " + str( point )
self._points.remove( point )
return self
def num_points( self ):
return len( self._points )
def get_points( self ):
""" Returns a copy of the points in this vector as a list. """
return self._points[:]
def open( self ):
self._isopen = True
return self
def close( self ):
self._isopen = False
return self
def is_open( self ):
return self._isopen
def set_width( self, width ):
self._width = width
return self
def get_width( self ):
return self._width
def is_filled( self ):
return self._filled
追加されるポイントは次のように定義されます。
class Point:
def __init__( self, x, y, z ):
self.x = x
self.y = y
self.z = z
def rel_to( self, point ):
x = self.move( point.z, point.x, self.z, self.x )
y = self.move( point.z, point.y, self.z, self.y )
return ( x, y )
def move( self, viewer_d, displacement, object_d, object_h ):
over = object_h * viewer_d + object_d * displacement
under = object_d + viewer_d + 1
return over / under
def __str__( self ):
return "(%d, %d, %d)" % ( self.x, self.y, self.z )
def __eq__( self, other ):
return self.x == other.x and self.y == other.y and self.z == other.z
def __ne__( self, other ):
return not ( self == other )
actions
最初のスニペットの は のインスタンスでありAction
、その定義は次のとおりです。
class Actions:
#TODO implement immutability where possible
def __init__( self ):
self.undos = []
self.redos = []
def do( self, do_steps, undo_steps ):
for do_step in do_steps:
do_step()
self.undos.append( ( do_steps, undo_steps ) )
self.redos = []
def can_undo( self ):
return len( self.undos ) > 0
def undo( self ):
if self.can_undo():
action = self.undos.pop()
_, undo_steps = action
for undo_step in undo_steps:
undo_step()
self.redos.append( action )
def can_redo( self ):
return len( self.redos ) > 0
def redo( self ):
if self.can_redo():
action = self.redos.pop()
redo_steps, _ = action
for redo_step in redo_steps:
redo_step()
self.undos.append( action )
したがって、問題は、2回以上クリックして電話をかけようとすると、リストに存在しないというactions.undo()
例外が発生することです。同じポイントを2回削除しようとするためだと思います。最初の 2 回のクリックの前にこれが発生しない理由は、最初の元に戻す操作では最新のポイントを削除しようとするのに対し、2 回目の元に戻す操作ではポリゴンをオブジェクト スタックからポップするだけだからです。私の質問は、最初のポイントがスタックからポップされてスタックにプッシュされているはずなのに、同じポイントを 2 回削除しようとするのはなぜですか? フィードバックをお寄せいただきありがとうございます。list.remove(x)
x
Point
actions.undo()
self.undos
self.redos