@@ -11,10 +11,11 @@ public class Solver<T> : SolverStats where T : class{
1111 const string ZERO_COST_ERR = "Zero cost op is not allowed" ,
1212 NO_INIT = "Init state is null" ;
1313 //
14- public int maxNodes = 1000 ,
15- maxIter = 1000 ;
16- public float tolerance = 0f ;
17- public bool brfs = false ;
14+ public int maxNodes = 1000 ,
15+ maxIter = 1000 ;
16+ public float tolerance = 0f ;
17+ public bool brfs = false ;
18+ public bool cleanActions = true ;
1819 public PlanningState state { get ; private set ; }
1920 public int fxMaxNodes { get ; private set ; }
2021 public int I { get ; private set ; }
@@ -55,20 +56,29 @@ public Node<T> Iterate(int iter=-1){
5556 if ( avail . capacityExceeded ) {
5657 state = S . CapacityExceeded ;
5758 } else {
58- state = avail ? ( I < maxIter ? S . Running : S . MaxIterExceeded )
59- : S . Failed ;
59+ state = avail
60+ ? ( I < maxIter ? S . Running : S . MaxIterExceeded )
61+ : S . Failed ;
6062 }
6163 return null ;
6264 }
6365
6466 void ExpandActions ( Node < T > x , NodeSet < T > @out ) {
6567 if ( ! ( x . state is Agent p ) ) return ;
66- if ( p . Actions ( ) == null ) return ;
67- for ( int i = 0 ; i < p . Actions ( ) . Length ; i ++ ) {
68- var y = Clone ( x . state ) ;
68+ var count = p . Actions ( ) ? . Length ?? 0 ;
69+ if ( count == 0 ) return ;
70+ // Initially assume a dirty state, which just menans that
71+ // the canvas needs to be init'd from x.state.
72+ bool dirty = true ;
73+ T y = null ;
74+ for ( int i = 0 ; i < count ; i ++ ) {
75+ //y = Clone(x.state);
76+ if ( dirty ) { y = Clone ( x . state ) ; dirty = false ; }
6977 var q = y as Agent ;
7078 var r = q . Actions ( ) [ i ] ( ) ;
7179 if ( r . done ) {
80+ // Since the action succeeded, state is now dirty.
81+ dirty = true ;
7282 if ( ! brfs && ( r . cost <= 0 ) )
7383 throw new Ex ( ZERO_COST_ERR ) ;
7484 var name = p . Actions ( ) [ i ] . Method . Name ;
@@ -95,8 +105,15 @@ void ExpandMethods(Node<T> x, NodeSet<T> @out){
95105 }
96106 }
97107
98- internal T Clone ( T x ) => ( x is Clonable < T > c )
99- ? c . Clone ( storage = storage ?? c . Allocate ( ) )
100- : CloneUtil . DeepClone ( x ) ;
108+ // TODO: strictly call to Clone() is not needed if an action has
109+ // failed and did not touch the matching state. So, as an unsafe
110+ // optimization, can skip that.
111+ internal T Clone ( T x ) {
112+ if ( x is Clonable < T > c ) {
113+ return c . Clone ( storage = storage ?? c . Allocate ( ) ) ;
114+ } else {
115+ return CloneUtil . DeepClone ( x ) ;
116+ }
117+ }
101118
102119} }
0 commit comments