From: brett l. <wak...@gm...> - 2006-07-17 06:31:19
|
I've been thinking about how to approach implementing Undo/Redo. It seems to me that there are two basic strategies that we can attempt. In each of them, we need to create a stack to store actions. Then, we can place the stack in front of or after the code to execute the action. The basic flow would look something like this: Stack before Action (Stack as EventHandler): 1. Stack object receives call from UI to take an action. 2. Stack stores action taken 3. Stack object calls model object to resolve action. Stack after Action (Stack as a Listener): 1. Model code receives call to act. 2. Model resolves action 3. Model notifies Stack object of action just taken. I haven't really done much of an analysis of which approach would be more work or have additional implications. There also could be other approaches I haven't thought of, as well. What are your thoughts on this? Is there a solution with an obvious advantage? ----Brett. |
From: Erik V. <eri...@hc...> - 2006-07-17 19:13:10
|
I have also thought about this subject in the past weeks. Usually an action falls apart in several sub-action (which I tend to call moves). An Action can contain any number of moves; the determining factor is which combination of moves constitute an "atomic" action, i.e. a series of moves (changes) that must be executed and possibly undone as a whole. For instance, selling a share involves at least: 1. The movement of a certificate from a player's portfolio to the Bank Pool (another rportfolio), 2. The movement of some cash from the Bank to the selling player (both are CashHolders). 3. A price drop, accompanied by the movement of the company's token on the Stock Chart. One could express this in XML as follows (this does not mean that I want to store the Undo stack in that way, although it is an option): <Action> <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> <MoveCash amount=67 from=bank to=Player-1/> <MovePrice company=PRR from=G6 to=G7/> </Action> For many type of actions this is easy to implement, as many movements already exist in much this way in the existing code (see for instance Bank.transferCash() and Portfolio.transferCertificate()). Of course, it becomes tricky when state changes enter the picture. For instance, a just floated company must be unfloated in an Undo, and such an activity does not yet exist. I am thinking to build up an Action gradually. As soon as the user's request has been validated in StockRound or OperationRound, Action.start() is called, which creates a new (empty) Action object. Then the changes are executed, each being registered in the Action object as additional moves, e.g. with Action.add(new MoveCash (...)). Finally Action.end() is called, closing the action (and perhaps executing it, see below). Action.undo() should then undo the last action. Stacking can be easily added this way. One main decision to take is whether the changes should be executed parallel to creating the Action object (so that the existing code remains much the same), or that it is the Action object that, when finished, actually performs the changes. Perhaps the latter option is better, as it enforces developers to implement all changes, including state changes, in a symmetric way. I think this is a similar (or perhaps the same) choice as you have presented below. Erik. > -----Original Message----- > From: rai...@li... > [mailto:rai...@li...] On Behalf > Of brett lentz > Sent: 17 July 2006 07:31 > To: Development list for Rails: an 18xx game > Subject: [Rails-devel] Undo / Redo design > > I've been thinking about how to approach implementing Undo/Redo. > > It seems to me that there are two basic strategies that we > can attempt. > > In each of them, we need to create a stack to store actions. Then, we > can place the stack in front of or after the code to execute the > action. > > The basic flow would look something like this: > > Stack before Action (Stack as EventHandler): > 1. Stack object receives call from UI to take an action. > 2. Stack stores action taken > 3. Stack object calls model object to resolve action. > > Stack after Action (Stack as a Listener): > 1. Model code receives call to act. > 2. Model resolves action > 3. Model notifies Stack object of action just taken. > > > I haven't really done much of an analysis of which approach would be > more work or have additional implications. There also could be other > approaches I haven't thought of, as well. > > What are your thoughts on this? Is there a solution with an > obvious advantage? > > > ----Brett. > > > -------------------------------------------------------------- > ----------- > Using Tomcat but need to do more? Need to support web > services, security? > Get stuff done quickly with pre-integrated technology to make > your job easier > Download IBM WebSphere Application Server v.1.0.1 based on > Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057& dat=121642 > _______________________________________________ > Rails-devel mailing list > Rai...@li... > https://lists.sourceforge.net/lists/listinfo/rails-devel > > |
From: brett l. <wak...@gm...> - 2006-07-17 19:45:26
|
I was just thinking, that there's another option that exists. I'm thinking that it probably will require more work than the other options, but it may be beneficial for us to do it because of the advantages in simplifying some of the complexity of the application. We can define a parent object (Action) and/or interface (Actionable) for our model objects to inherit from. Each object then, inherits a basic Do and Undo methods that can be overridden when needed. For classes that do more than one thing, the Do method can take the name of the action to take, and call the associated methods that will take the desired action. Then, the UI code can be reworked to call these Do and Undo methods and we can make all other methods private to prevent them from being called directly. >From there, we can create a stack and assure that each Do method adds its parent object to the stack. This makes Undoing a matter of popping the object off the stack and calling the Undo method. Any calling parameters can be accessed via an array held by the object. ---Brett On 7/17/06, Erik Vos <eri...@hc...> wrote: > I have also thought about this subject in the past weeks. > > Usually an action falls apart in several sub-action > (which I tend to call moves). An Action can contain any > number of moves; the determining factor is which combination > of moves constitute an "atomic" action, i.e. a series of > moves (changes) that must be executed and possibly undone as a whole. > > For instance, selling a share involves at least: > 1. The movement of a certificate from a player's portfolio > to the Bank Pool (another rportfolio), > 2. The movement of some cash from the Bank to the selling > player (both are CashHolders). > 3. A price drop, accompanied by the movement of the > company's token on the Stock Chart. > > One could express this in XML as follows (this does not mean > that I want to store the Undo stack in that way, although > it is an option): > <Action> > <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> > <MoveCash amount=67 from=bank to=Player-1/> > <MovePrice company=PRR from=G6 to=G7/> > </Action> > > For many type of actions this is easy to implement, as many > movements already exist in much this way in the existing code > (see for instance Bank.transferCash() and Portfolio.transferCertificate()). > Of course, it becomes tricky when state changes enter the picture. > For instance, a just floated company must be unfloated in an Undo, > and such an activity does not yet exist. > > I am thinking to build up an Action gradually. > As soon as the user's request has been validated in StockRound or > OperationRound, Action.start() is called, which creates a new (empty) > Action object. > Then the changes are executed, each being registered in the > Action object as additional moves, > e.g. with Action.add(new MoveCash (...)). > Finally Action.end() is called, closing the action (and perhaps > executing it, see below). > > Action.undo() should then undo the last action. > > Stacking can be easily added this way. > > One main decision to take is whether the changes should be executed > parallel to creating the Action object (so that the existing code > remains much the same), or that it is the Action object that, > when finished, actually performs the changes. > > Perhaps the latter option is better, as it enforces developers > to implement all changes, including state changes, in a symmetric way. > > I think this is a similar (or perhaps the same) choice as you > have presented below. > > Erik. > > > > -----Original Message----- > > From: rai...@li... > > [mailto:rai...@li...] On Behalf > > Of brett lentz > > Sent: 17 July 2006 07:31 > > To: Development list for Rails: an 18xx game > > Subject: [Rails-devel] Undo / Redo design > > > > I've been thinking about how to approach implementing Undo/Redo. > > > > It seems to me that there are two basic strategies that we > > can attempt. > > > > In each of them, we need to create a stack to store actions. Then, we > > can place the stack in front of or after the code to execute the > > action. > > > > The basic flow would look something like this: > > > > Stack before Action (Stack as EventHandler): > > 1. Stack object receives call from UI to take an action. > > 2. Stack stores action taken > > 3. Stack object calls model object to resolve action. > > > > Stack after Action (Stack as a Listener): > > 1. Model code receives call to act. > > 2. Model resolves action > > 3. Model notifies Stack object of action just taken. > > > > > > I haven't really done much of an analysis of which approach would be > > more work or have additional implications. There also could be other > > approaches I haven't thought of, as well. > > > > What are your thoughts on this? Is there a solution with an > > obvious advantage? > > > > > > ----Brett. > > |
From: Erik V. <eri...@hc...> - 2006-07-17 20:23:57
|
Please also keep in mind, that some actions sometimes have side effects of a different nature. For instance, buying the first 4-train rusts all 2-trains. Undoing this buy also must move all these 2-trains back from the bit bucket (actually a Bank portfolio named scrapHeap) to the companies that last owned these. All these side effects must be done and undone as one action! It is not practical to define separate action classes for each possible combination of direct and indirect effects. It is much easier to work with very simple "movements" or whatever you would like to call these subactions. So I would propose: - An Action class, with do() and undo() methods, containing an ArrayList of Move objects. - An abtract Move class, which is the parent of all concrete Moves. - A bunch of XxxMove class, e.g. CashMove, TileMove, CertificateMove etc., each of which represents a specific type of minimal change. Each of the Move objects would also have do() and undo() methods, undo() being identical to do() with to and from swapped. Action.do() would call the do() method of each of the contained Move objects. Similar with undo. Erik. > -----Original Message----- > From: rai...@li... > [mailto:rai...@li...] On Behalf > Of brett lentz > Sent: 17 July 2006 20:44 > To: Development list for Rails: an 18xx game > Subject: Re: [Rails-devel] Undo / Redo design > > I was just thinking, that there's another option that exists. > > I'm thinking that it probably will require more work than the other > options, but it may be beneficial for us to do it because of the > advantages in simplifying some of the complexity of the application. > > We can define a parent object (Action) and/or interface (Actionable) > for our model objects to inherit from. > > Each object then, inherits a basic Do and Undo methods that can be > overridden when needed. For classes that do more than one thing, the > Do method can take the name of the action to take, and call the > associated methods that will take the desired action. > > Then, the UI code can be reworked to call these Do and Undo methods > and we can make all other methods private to prevent them from being > called directly. > > >From there, we can create a stack and assure that each Do method adds > its parent object to the stack. This makes Undoing a matter of popping > the object off the stack and calling the Undo method. Any calling > parameters can be accessed via an array held by the object. > > > ---Brett > > On 7/17/06, Erik Vos <eri...@hc...> wrote: > > I have also thought about this subject in the past weeks. > > > > Usually an action falls apart in several sub-action > > (which I tend to call moves). An Action can contain any > > number of moves; the determining factor is which combination > > of moves constitute an "atomic" action, i.e. a series of > > moves (changes) that must be executed and possibly undone > as a whole. > > > > For instance, selling a share involves at least: > > 1. The movement of a certificate from a player's portfolio > > to the Bank Pool (another rportfolio), > > 2. The movement of some cash from the Bank to the selling > > player (both are CashHolders). > > 3. A price drop, accompanied by the movement of the > > company's token on the Stock Chart. > > > > One could express this in XML as follows (this does not mean > > that I want to store the Undo stack in that way, although > > it is an option): > > <Action> > > <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> > > <MoveCash amount=67 from=bank to=Player-1/> > > <MovePrice company=PRR from=G6 to=G7/> > > </Action> > > > > For many type of actions this is easy to implement, as many > > movements already exist in much this way in the existing code > > (see for instance Bank.transferCash() and > Portfolio.transferCertificate()). > > Of course, it becomes tricky when state changes enter the picture. > > For instance, a just floated company must be unfloated in an Undo, > > and such an activity does not yet exist. > > > > I am thinking to build up an Action gradually. > > As soon as the user's request has been validated in StockRound or > > OperationRound, Action.start() is called, which creates a > new (empty) > > Action object. > > Then the changes are executed, each being registered in the > > Action object as additional moves, > > e.g. with Action.add(new MoveCash (...)). > > Finally Action.end() is called, closing the action (and perhaps > > executing it, see below). > > > > Action.undo() should then undo the last action. > > > > Stacking can be easily added this way. > > > > One main decision to take is whether the changes should be executed > > parallel to creating the Action object (so that the existing code > > remains much the same), or that it is the Action object that, > > when finished, actually performs the changes. > > > > Perhaps the latter option is better, as it enforces developers > > to implement all changes, including state changes, in a > symmetric way. > > > > I think this is a similar (or perhaps the same) choice as you > > have presented below. > > > > Erik. > > > > > > > -----Original Message----- > > > From: rai...@li... > > > [mailto:rai...@li...] On Behalf > > > Of brett lentz > > > Sent: 17 July 2006 07:31 > > > To: Development list for Rails: an 18xx game > > > Subject: [Rails-devel] Undo / Redo design > > > > > > I've been thinking about how to approach implementing Undo/Redo. > > > > > > It seems to me that there are two basic strategies that we > > > can attempt. > > > > > > In each of them, we need to create a stack to store > actions. Then, we > > > can place the stack in front of or after the code to execute the > > > action. > > > > > > The basic flow would look something like this: > > > > > > Stack before Action (Stack as EventHandler): > > > 1. Stack object receives call from UI to take an action. > > > 2. Stack stores action taken > > > 3. Stack object calls model object to resolve action. > > > > > > Stack after Action (Stack as a Listener): > > > 1. Model code receives call to act. > > > 2. Model resolves action > > > 3. Model notifies Stack object of action just taken. > > > > > > > > > I haven't really done much of an analysis of which > approach would be > > > more work or have additional implications. There also > could be other > > > approaches I haven't thought of, as well. > > > > > > What are your thoughts on this? Is there a solution with an > > > obvious advantage? > > > > > > > > > ----Brett. > > > > > -------------------------------------------------------------- > ----------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the > chance to share your > opinions on IT & business topics through brief surveys -- and > earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge > &CID=DEVDEV > _______________________________________________ > Rails-devel mailing list > Rai...@li... > https://lists.sourceforge.net/lists/listinfo/rails-devel > > |
From: brett l. <wak...@gm...> - 2006-07-17 20:50:07
|
I think that looks like it would hit most of the important points I was thinking of. I think that might work. ---Brett. On 7/17/06, Erik Vos <eri...@hc...> wrote: > Please also keep in mind, that some actions sometimes have side effects > of a different nature. For instance, buying the first 4-train > rusts all 2-trains. Undoing this buy also must move all these 2-trains > back from the bit bucket (actually a Bank portfolio named scrapHeap) > to the companies that last owned these. > All these side effects must be done and undone as one action! > > It is not practical to define separate action classes for each possible > combination of direct and indirect effects. It is much easier > to work with very simple "movements" or whatever you would > like to call these subactions. > > So I would propose: > - An Action class, with do() and undo() methods, containing an > ArrayList of Move objects. > - An abtract Move class, which is the parent of all concrete Moves. > - A bunch of XxxMove class, e.g. CashMove, TileMove, CertificateMove > etc., each of which represents a specific type of minimal change. > Each of the Move objects would also have do() and undo() methods, > undo() being identical to do() with to and from swapped. > > Action.do() would call the do() method of each of the > contained Move objects. Similar with undo. > > Erik. > > > -----Original Message----- > > From: rai...@li... > > [mailto:rai...@li...] On Behalf > > Of brett lentz > > Sent: 17 July 2006 20:44 > > To: Development list for Rails: an 18xx game > > Subject: Re: [Rails-devel] Undo / Redo design > > > > I was just thinking, that there's another option that exists. > > > > I'm thinking that it probably will require more work than the other > > options, but it may be beneficial for us to do it because of the > > advantages in simplifying some of the complexity of the application. > > > > We can define a parent object (Action) and/or interface (Actionable) > > for our model objects to inherit from. > > > > Each object then, inherits a basic Do and Undo methods that can be > > overridden when needed. For classes that do more than one thing, the > > Do method can take the name of the action to take, and call the > > associated methods that will take the desired action. > > > > Then, the UI code can be reworked to call these Do and Undo methods > > and we can make all other methods private to prevent them from being > > called directly. > > > > >From there, we can create a stack and assure that each Do method adds > > its parent object to the stack. This makes Undoing a matter of popping > > the object off the stack and calling the Undo method. Any calling > > parameters can be accessed via an array held by the object. > > > > > > ---Brett > > > > On 7/17/06, Erik Vos <eri...@hc...> wrote: > > > I have also thought about this subject in the past weeks. > > > > > > Usually an action falls apart in several sub-action > > > (which I tend to call moves). An Action can contain any > > > number of moves; the determining factor is which combination > > > of moves constitute an "atomic" action, i.e. a series of > > > moves (changes) that must be executed and possibly undone > > as a whole. > > > > > > For instance, selling a share involves at least: > > > 1. The movement of a certificate from a player's portfolio > > > to the Bank Pool (another rportfolio), > > > 2. The movement of some cash from the Bank to the selling > > > player (both are CashHolders). > > > 3. A price drop, accompanied by the movement of the > > > company's token on the Stock Chart. > > > > > > One could express this in XML as follows (this does not mean > > > that I want to store the Undo stack in that way, although > > > it is an option): > > > <Action> > > > <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> > > > <MoveCash amount=67 from=bank to=Player-1/> > > > <MovePrice company=PRR from=G6 to=G7/> > > > </Action> > > > > > > For many type of actions this is easy to implement, as many > > > movements already exist in much this way in the existing code > > > (see for instance Bank.transferCash() and > > Portfolio.transferCertificate()). > > > Of course, it becomes tricky when state changes enter the picture. > > > For instance, a just floated company must be unfloated in an Undo, > > > and such an activity does not yet exist. > > > > > > I am thinking to build up an Action gradually. > > > As soon as the user's request has been validated in StockRound or > > > OperationRound, Action.start() is called, which creates a > > new (empty) > > > Action object. > > > Then the changes are executed, each being registered in the > > > Action object as additional moves, > > > e.g. with Action.add(new MoveCash (...)). > > > Finally Action.end() is called, closing the action (and perhaps > > > executing it, see below). > > > > > > Action.undo() should then undo the last action. > > > > > > Stacking can be easily added this way. > > > > > > One main decision to take is whether the changes should be executed > > > parallel to creating the Action object (so that the existing code > > > remains much the same), or that it is the Action object that, > > > when finished, actually performs the changes. > > > > > > Perhaps the latter option is better, as it enforces developers > > > to implement all changes, including state changes, in a > > symmetric way. > > > > > > I think this is a similar (or perhaps the same) choice as you > > > have presented below. > > > > > > Erik. > > > > > > > > > > -----Original Message----- > > > > From: rai...@li... > > > > [mailto:rai...@li...] On Behalf > > > > Of brett lentz > > > > Sent: 17 July 2006 07:31 > > > > To: Development list for Rails: an 18xx game > > > > Subject: [Rails-devel] Undo / Redo design > > > > > > > > I've been thinking about how to approach implementing Undo/Redo. > > > > > > > > It seems to me that there are two basic strategies that we > > > > can attempt. > > > > > > > > In each of them, we need to create a stack to store > > actions. Then, we > > > > can place the stack in front of or after the code to execute the > > > > action. > > > > > > > > The basic flow would look something like this: > > > > > > > > Stack before Action (Stack as EventHandler): > > > > 1. Stack object receives call from UI to take an action. > > > > 2. Stack stores action taken > > > > 3. Stack object calls model object to resolve action. > > > > > > > > Stack after Action (Stack as a Listener): > > > > 1. Model code receives call to act. > > > > 2. Model resolves action > > > > 3. Model notifies Stack object of action just taken. > > > > > > > > > > > > I haven't really done much of an analysis of which > > approach would be > > > > more work or have additional implications. There also > > could be other > > > > approaches I haven't thought of, as well. > > > > > > > > What are your thoughts on this? Is there a solution with an > > > > obvious advantage? > > > > > > > > > > > > ----Brett. > > > > > > > > -------------------------------------------------------------- > > ----------- > > Take Surveys. Earn Cash. Influence the Future of IT > > Join SourceForge.net's Techsay panel and you'll get the > > chance to share your > > opinions on IT & business topics through brief surveys -- and > > earn cash > > http://www.techsay.com/default.php?page=join.php&p=sourceforge > > &CID=DEVDEV > > _______________________________________________ > > Rails-devel mailing list > > Rai...@li... > > https://lists.sourceforge.net/lists/listinfo/rails-devel > > > > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Rails-devel mailing list > Rai...@li... > https://lists.sourceforge.net/lists/listinfo/rails-devel > |
From: Erik V. <eri...@hc...> - 2006-07-17 22:03:54
|
I have committed some basic Action-related classes in a new package game.action. These classes should enable implementing an undo for simple share buying actions (without side effects), which I will try to do later this week. Erik. > -----Original Message----- > From: rai...@li... > [mailto:rai...@li...] On Behalf > Of brett lentz > Sent: 17 July 2006 21:43 > To: Development list for Rails: an 18xx game > Subject: Re: [Rails-devel] Undo / Redo design > > I think that looks like it would hit most of the important points I > was thinking of. > > I think that might work. > > ---Brett. > > > On 7/17/06, Erik Vos <eri...@hc...> wrote: > > Please also keep in mind, that some actions sometimes have > side effects > > of a different nature. For instance, buying the first 4-train > > rusts all 2-trains. Undoing this buy also must move all > these 2-trains > > back from the bit bucket (actually a Bank portfolio named scrapHeap) > > to the companies that last owned these. > > All these side effects must be done and undone as one action! > > > > It is not practical to define separate action classes for > each possible > > combination of direct and indirect effects. It is much easier > > to work with very simple "movements" or whatever you would > > like to call these subactions. > > > > So I would propose: > > - An Action class, with do() and undo() methods, containing an > > ArrayList of Move objects. > > - An abtract Move class, which is the parent of all concrete Moves. > > - A bunch of XxxMove class, e.g. CashMove, TileMove, CertificateMove > > etc., each of which represents a specific type of minimal change. > > Each of the Move objects would also have do() and undo() methods, > > undo() being identical to do() with to and from swapped. > > > > Action.do() would call the do() method of each of the > > contained Move objects. Similar with undo. > > > > Erik. > > > > > -----Original Message----- > > > From: rai...@li... > > > [mailto:rai...@li...] On Behalf > > > Of brett lentz > > > Sent: 17 July 2006 20:44 > > > To: Development list for Rails: an 18xx game > > > Subject: Re: [Rails-devel] Undo / Redo design > > > > > > I was just thinking, that there's another option that exists. > > > > > > I'm thinking that it probably will require more work than > the other > > > options, but it may be beneficial for us to do it because of the > > > advantages in simplifying some of the complexity of the > application. > > > > > > We can define a parent object (Action) and/or interface > (Actionable) > > > for our model objects to inherit from. > > > > > > Each object then, inherits a basic Do and Undo methods that can be > > > overridden when needed. For classes that do more than > one thing, the > > > Do method can take the name of the action to take, and call the > > > associated methods that will take the desired action. > > > > > > Then, the UI code can be reworked to call these Do and > Undo methods > > > and we can make all other methods private to prevent them > from being > > > called directly. > > > > > > >From there, we can create a stack and assure that each > Do method adds > > > its parent object to the stack. This makes Undoing a > matter of popping > > > the object off the stack and calling the Undo method. Any calling > > > parameters can be accessed via an array held by the object. > > > > > > > > > ---Brett > > > > > > On 7/17/06, Erik Vos <eri...@hc...> wrote: > > > > I have also thought about this subject in the past weeks. > > > > > > > > Usually an action falls apart in several sub-action > > > > (which I tend to call moves). An Action can contain any > > > > number of moves; the determining factor is which combination > > > > of moves constitute an "atomic" action, i.e. a series of > > > > moves (changes) that must be executed and possibly undone > > > as a whole. > > > > > > > > For instance, selling a share involves at least: > > > > 1. The movement of a certificate from a player's portfolio > > > > to the Bank Pool (another rportfolio), > > > > 2. The movement of some cash from the Bank to the selling > > > > player (both are CashHolders). > > > > 3. A price drop, accompanied by the movement of the > > > > company's token on the Stock Chart. > > > > > > > > One could express this in XML as follows (this does not mean > > > > that I want to store the Undo stack in that way, although > > > > it is an option): > > > > <Action> > > > > <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> > > > > <MoveCash amount=67 from=bank to=Player-1/> > > > > <MovePrice company=PRR from=G6 to=G7/> > > > > </Action> > > > > > > > > For many type of actions this is easy to implement, as many > > > > movements already exist in much this way in the existing code > > > > (see for instance Bank.transferCash() and > > > Portfolio.transferCertificate()). > > > > Of course, it becomes tricky when state changes enter > the picture. > > > > For instance, a just floated company must be unfloated > in an Undo, > > > > and such an activity does not yet exist. > > > > > > > > I am thinking to build up an Action gradually. > > > > As soon as the user's request has been validated in > StockRound or > > > > OperationRound, Action.start() is called, which creates a > > > new (empty) > > > > Action object. > > > > Then the changes are executed, each being registered in the > > > > Action object as additional moves, > > > > e.g. with Action.add(new MoveCash (...)). > > > > Finally Action.end() is called, closing the action (and perhaps > > > > executing it, see below). > > > > > > > > Action.undo() should then undo the last action. > > > > > > > > Stacking can be easily added this way. > > > > > > > > One main decision to take is whether the changes should > be executed > > > > parallel to creating the Action object (so that the > existing code > > > > remains much the same), or that it is the Action object that, > > > > when finished, actually performs the changes. > > > > > > > > Perhaps the latter option is better, as it enforces developers > > > > to implement all changes, including state changes, in a > > > symmetric way. > > > > > > > > I think this is a similar (or perhaps the same) choice as you > > > > have presented below. > > > > > > > > Erik. > > > > > > > > > > > > > -----Original Message----- > > > > > From: rai...@li... > > > > > [mailto:rai...@li...] On Behalf > > > > > Of brett lentz > > > > > Sent: 17 July 2006 07:31 > > > > > To: Development list for Rails: an 18xx game > > > > > Subject: [Rails-devel] Undo / Redo design > > > > > > > > > > I've been thinking about how to approach implementing > Undo/Redo. > > > > > > > > > > It seems to me that there are two basic strategies that we > > > > > can attempt. > > > > > > > > > > In each of them, we need to create a stack to store > > > actions. Then, we > > > > > can place the stack in front of or after the code to > execute the > > > > > action. > > > > > > > > > > The basic flow would look something like this: > > > > > > > > > > Stack before Action (Stack as EventHandler): > > > > > 1. Stack object receives call from UI to take an action. > > > > > 2. Stack stores action taken > > > > > 3. Stack object calls model object to resolve action. > > > > > > > > > > Stack after Action (Stack as a Listener): > > > > > 1. Model code receives call to act. > > > > > 2. Model resolves action > > > > > 3. Model notifies Stack object of action just taken. > > > > > > > > > > > > > > > I haven't really done much of an analysis of which > > > approach would be > > > > > more work or have additional implications. There also > > > could be other > > > > > approaches I haven't thought of, as well. > > > > > > > > > > What are your thoughts on this? Is there a solution with an > > > > > obvious advantage? > > > > > > > > > > > > > > > ----Brett. > > > > > > > > > > > -------------------------------------------------------------- > > > ----------- > > > Take Surveys. Earn Cash. Influence the Future of IT > > > Join SourceForge.net's Techsay panel and you'll get the > > > chance to share your > > > opinions on IT & business topics through brief surveys -- and > > > earn cash > > > http://www.techsay.com/default.php?page=join.php&p=sourceforge > > > &CID=DEVDEV > > > _______________________________________________ > > > Rails-devel mailing list > > > Rai...@li... > > > https://lists.sourceforge.net/lists/listinfo/rails-devel > > > > > > > > > > > > > > > -------------------------------------------------------------- > ----------- > > Take Surveys. Earn Cash. Influence the Future of IT > > Join SourceForge.net's Techsay panel and you'll get the > chance to share your > > opinions on IT & business topics through brief surveys -- > and earn cash > > > http://www.techsay.com/default.php?page=join.php&p=sourceforge > &CID=DEVDEV > > _______________________________________________ > > Rails-devel mailing list > > Rai...@li... > > https://lists.sourceforge.net/lists/listinfo/rails-devel > > > > -------------------------------------------------------------- > ----------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the > chance to share your > opinions on IT & business topics through brief surveys -- and > earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge > &CID=DEVDEV > _______________________________________________ > Rails-devel mailing list > Rai...@li... > https://lists.sourceforge.net/lists/listinfo/rails-devel > > |
From: Dave M. <da...@mi...> - 2006-07-18 02:17:00
|
On 7/17/2006 04:23 PM, Erik Vos wrote: >Please also keep in mind, that some actions sometimes have side effects >of a different nature. For instance, buying the first 4-train >rusts all 2-trains. Undoing this buy also must move all these 2-trains >back from the bit bucket (actually a Bank portfolio named scrapHeap) >to the companies that last owned these. >All these side effects must be done and undone as one action! > >It is not practical to define separate action classes for each possible >combination of direct and indirect effects. It is much easier >to work with very simple "movements" or whatever you would >like to call these subactions. > >So I would propose: >- An Action class, with do() and undo() methods, containing an >ArrayList of Move objects. >- An abtract Move class, which is the parent of all concrete Moves. >- A bunch of XxxMove class, e.g. CashMove, TileMove, CertificateMove >etc., each of which represents a specific type of minimal change. >Each of the Move objects would also have do() and undo() methods, >undo() being identical to do() with to and from swapped. > >Action.do() would call the do() method of each of the >contained Move objects. Similar with undo. > >Erik. Your example of a Train purchase/Phase advance shows that there is no easy way to Undo an action without knowing what was affected. e.g. how many trains get returned to whom? My take on this problem is that you will have to create a log stream which all the Do actions and Move action write to. This data will be the input to the Undo actions. You will want to structure it appropriately. You will want to write a text log anyways for the player's record. In my game I considered doing this with the actual text of the game log, I played with syntax; recognizable verbs for player actions, and character flags for resulting state changes, but I never built a parser. I implemented Undo, by just checkpointing the game state every player/corp turn, and only allowing a full turn roll back. Dave. > > -----Original Message----- > > From: rai...@li... > > [mailto:rai...@li...] On Behalf > > Of brett lentz > > Sent: 17 July 2006 20:44 > > To: Development list for Rails: an 18xx game > > Subject: Re: [Rails-devel] Undo / Redo design > > > > I was just thinking, that there's another option that exists. > > > > I'm thinking that it probably will require more work than the other > > options, but it may be beneficial for us to do it because of the > > advantages in simplifying some of the complexity of the application. > > > > We can define a parent object (Action) and/or interface (Actionable) > > for our model objects to inherit from. > > > > Each object then, inherits a basic Do and Undo methods that can be > > overridden when needed. For classes that do more than one thing, the > > Do method can take the name of the action to take, and call the > > associated methods that will take the desired action. > > > > Then, the UI code can be reworked to call these Do and Undo methods > > and we can make all other methods private to prevent them from being > > called directly. > > > > >From there, we can create a stack and assure that each Do method adds > > its parent object to the stack. This makes Undoing a matter of popping > > the object off the stack and calling the Undo method. Any calling > > parameters can be accessed via an array held by the object. > > > > > > ---Brett > > > > On 7/17/06, Erik Vos <eri...@hc...> wrote: > > > I have also thought about this subject in the past weeks. > > > > > > Usually an action falls apart in several sub-action > > > (which I tend to call moves). An Action can contain any > > > number of moves; the determining factor is which combination > > > of moves constitute an "atomic" action, i.e. a series of > > > moves (changes) that must be executed and possibly undone > > as a whole. > > > > > > For instance, selling a share involves at least: > > > 1. The movement of a certificate from a player's portfolio > > > to the Bank Pool (another rportfolio), > > > 2. The movement of some cash from the Bank to the selling > > > player (both are CashHolders). > > > 3. A price drop, accompanied by the movement of the > > > company's token on the Stock Chart. > > > > > > One could express this in XML as follows (this does not mean > > > that I want to store the Undo stack in that way, although > > > it is an option): > > > <Action> > > > <MoveCertificate company=PRR seqno=2 from=Player-1 to=Pool/> > > > <MoveCash amount=67 from=bank to=Player-1/> > > > <MovePrice company=PRR from=G6 to=G7/> > > > </Action> > > > > > > For many type of actions this is easy to implement, as many > > > movements already exist in much this way in the existing code > > > (see for instance Bank.transferCash() and > > Portfolio.transferCertificate()). > > > Of course, it becomes tricky when state changes enter the picture. > > > For instance, a just floated company must be unfloated in an Undo, > > > and such an activity does not yet exist. > > > > > > I am thinking to build up an Action gradually. > > > As soon as the user's request has been validated in StockRound or > > > OperationRound, Action.start() is called, which creates a > > new (empty) > > > Action object. > > > Then the changes are executed, each being registered in the > > > Action object as additional moves, > > > e.g. with Action.add(new MoveCash (...)). > > > Finally Action.end() is called, closing the action (and perhaps > > > executing it, see below). > > > > > > Action.undo() should then undo the last action. > > > > > > Stacking can be easily added this way. > > > > > > One main decision to take is whether the changes should be executed > > > parallel to creating the Action object (so that the existing code > > > remains much the same), or that it is the Action object that, > > > when finished, actually performs the changes. > > > > > > Perhaps the latter option is better, as it enforces developers > > > to implement all changes, including state changes, in a > > symmetric way. > > > > > > I think this is a similar (or perhaps the same) choice as you > > > have presented below. > > > > > > Erik. > > > > > > > > > > -----Original Message----- > > > > From: rai...@li... > > > > [mailto:rai...@li...] On Behalf > > > > Of brett lentz > > > > Sent: 17 July 2006 07:31 > > > > To: Development list for Rails: an 18xx game > > > > Subject: [Rails-devel] Undo / Redo design > > > > > > > > I've been thinking about how to approach implementing Undo/Redo. > > > > > > > > It seems to me that there are two basic strategies that we > > > > can attempt. > > > > > > > > In each of them, we need to create a stack to store > > actions. Then, we > > > > can place the stack in front of or after the code to execute the > > > > action. > > > > > > > > The basic flow would look something like this: > > > > > > > > Stack before Action (Stack as EventHandler): > > > > 1. Stack object receives call from UI to take an action. > > > > 2. Stack stores action taken > > > > 3. Stack object calls model object to resolve action. > > > > > > > > Stack after Action (Stack as a Listener): > > > > 1. Model code receives call to act. > > > > 2. Model resolves action > > > > 3. Model notifies Stack object of action just taken. > > > > > > > > > > > > I haven't really done much of an analysis of which > > approach would be > > > > more work or have additional implications. There also > > could be other > > > > approaches I haven't thought of, as well. > > > > > > > > What are your thoughts on this? Is there a solution with an > > > > obvious advantage? > > > > > > > > > > > > ----Brett. > > > > > > > > -------------------------------------------------------------- > > ----------- > > Take Surveys. Earn Cash. Influence the Future of IT > > Join SourceForge.net's Techsay panel and you'll get the > > chance to share your > > opinions on IT & business topics through brief surveys -- and > > earn cash > > http://www.techsay.com/default.php?page=join.php&p=sourceforge > > &CID=DEVDEV > > _______________________________________________ > > Rails-devel mailing list > > Rai...@li... > > https://lists.sourceforge.net/lists/listinfo/rails-devel > > > > > > > >------------------------------------------------------------------------- >Take Surveys. Earn Cash. Influence the Future of IT >Join SourceForge.net's Techsay panel and you'll get the chance to share your >opinions on IT & business topics through brief surveys -- and earn cash >http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV >_______________________________________________ >Rails-devel mailing list >Rai...@li... >https://lists.sourceforge.net/lists/listinfo/rails-devel |