Index: src/solver.d ================================================================== --- src/solver.d +++ src/solver.d @@ -144,10 +144,12 @@ if(c == 'W') wait_count++; else wait_count = 0; + if(wait_count==2) + c = 'A'; if(choke_count >= g.map.H) c = 'A'; bool[char] choice; foreach(t; cand) @@ -313,90 +315,125 @@ } } class Solver_2(SubSolver) : Solver { + static const PredictFuture = 10; + + Game current_game; + SubSolver sub_solver; + + enum {Tentative, Tentative_Stuck, Fixed}; string plan; - bool plan_broken = true; + int plan_state; - Game g; this(in Game g) { - this.g = g.clone(); - make_plan(g); + current_game = g.clone(); + plan = ""; + plan_state = Tentative; + } + + char single_step() + { + if(current_game.dead || current_game.cleared) + return 'A'; + + // Make enough prediction. + while( plan_state==Tentative && plan.length0 && plan[0]==c) + { + // If matching the plan, just go forward. + plan = plan[1..$]; + } + else + { + // Discard the plan, otherwise. + plan_state = Tentative; + plan = ""; + sub_solver = null; } - while(log.length>0 && log[$-1]=='W') - log.length--; - return tuple(s, log); + current_game.command(c); } - void make_plan(in Game g) { - plan_broken = false; - Tuple!(SubSolver,string) x = run_sub_solver(g); - plan = x[1]; - if(x[0].g.cleared) - return; - modify_plan(g, x[0].g.score); + void single_step_predict() + { + if(sub_solver is null) { + sub_solver = new SubSolver(current_game); + plan = ""; + } + + char c = sub_solver.single_step(); + if(c == 'A') + plan_state = Tentative_Stuck; + else { + plan ~= c; + plan_state = (sub_solver.g.dead ? Tentative_Stuck : + sub_solver.g.cleared ? Fixed : Tentative); + } } - void modify_plan(in Game ini, long unmod) + void replan() { - int bp = max(0, (cast(int)plan.length)-10); - Game g = ini.clone(); - for(int i=0; i