@@ -342,9 +342,9 @@ "DU","DD","DL","DR", "LU","LD","LL","LR", "RU","RD","RL","RR","UUU","UUUU","UUUUU"]; PredictFuture = 20; - clear_improvement = 3; + clear_improvement = 1; } else if(g.map.W*g.map.H <= 4096) { RandomChoicePattern = ["UUU","U","D","L","R","UD","DU","LR","RL"]; PredictFuture = 10; @@ -374,9 +374,8 @@ // Follow the predicted plan. if( plan.empty ) return 'A'; -stderr.writeln(plan, " ", plan_state); char c = plan[0]; plan = plan[1..$]; int b_lambda = current_game.map.collected_lambda; current_game.command(c); @@ -428,14 +427,12 @@ } void replan() { -stderr.writeln("replan!"); // Try to replace every step of the plan by another move. Game g = current_game.clone(); Tuple!(SubSolver, string, int) cand = tuple(sub_solver, plan, Tentative_Stuck); int insertion_point = plan.length; -writeln(cand, " ", cand[0].g.map.collected_lambda); bool tiebreak_by_turn = false; int consider_length = min(ReplanLength, g.map.W*g.map.H); if(cand[0].g.cleared) consider_length = min(consider_length, cand[1].length); @@ -466,9 +463,8 @@ cand = r; tiebreak_by_turn = true; insertion_point = i+prefix.length; if(r[0].g.cleared) consider_length = min(consider_length, r[1].length); -writeln(cand, " ", cand[0].g.map.collected_lambda); } } g.command(plan[i]); } @@ -510,7 +506,173 @@ return tuple(s, log, state); } } -alias Solver_2!(Solver_1) MainSolver; +class Queue(T) +{ + alias Tuple!(T,int) t; + + t[] cur, next; + + void push(T v, int p) { (cur.empty ? cur : next) ~= tuple(v,p); } + bool empty() { return cur.empty; } + t pop() { + t v = cur[0]; cur = cur[1..$]; + if(cur.empty) { cur = next; next = null; } + return v; + } +} + +class Solver_3 : Solver +{ + Game g; + this(in Game g) + { + this.g = g.clone(); + } + + char single_step() + { + char c = think(g); + if(c != 'A') + g.command(c); + return c; + } + + void force(char c) + { +stderr.writeln(death_move(g)); + if(c != 'A') + g.command(c); + } + + bool is_spacy(char c) { + return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O'; + } + bool is_rocky(char c) { + return c=='*' || c=='@'; + } + bool is_true_space(char c) { + return c==' '; + } + bool is_trampoline_source(char c) { + return 'A'<=c && c<='I'; + } + bool is_rocklambda(char c) { + return is_rocky(c) || c=='\\'; + } + + string death_move(in Game g) + { + // TODO: S + string death; + int y = g.map.robot.y; + int x = g.map.robot.x; + int[5] dy_=[-1,+1,0,0,0]; + int[5] dx_=[0,0,-1,+1,0]; + char[] ds=['D','U','L','R','W']; + for(int i=0; i<5; ++i) + { + bool after_move_death(int y, int x, char tr_tgt) + { + bool is_spacy_t(char c) { + if(is_spacy(c) || c==tr_tgt) + return true; + return ('A'<=c && c<='I' && g.tr.target_of(c)==tr_tgt); + } + + // check water + if( g.hp==0 && y<=g.water_level ) + return true; + + // check falling rock. + int yy=y+1, xx=x; + if( is_spacy_t(g.map[yy, xx]) ) + { + if( is_rocky(g.map[yy+1,xx]) ) + return true; + if( is_spacy_t(g.map[yy+1,xx]) && is_rocky(g.map[yy+1,xx+1]) && is_rocky(g.map[yy,xx+1]) ) { + if( is_spacy_t(g.map[yy+1,xx+2]) && is_spacy_t(g.map[yy,xx+2]) ) + return false; + return true; + } + if( is_spacy_t(g.map[yy+1,xx]) && is_rocky(g.map[yy+1,xx-1]) && is_rocklambda(g.map[yy,xx-1]) ) { + if(g.hige_until_rise == 1 && g.map[yy+1,xx+1]=='W') + return false; + return true; + } + } + return false; + } + + int dy=dy_[i], dx=dx_[i]; + if( is_spacy(g.map[y+dy,x+dx]) + || dy==0 && is_rocky(g.map[y,x+dx]) && is_true_space(g.map[y,x+2*dx]) ) + { + if( after_move_death(y+dy, x+dx, char.init) ) + death ~= ds[i]; + } + else if( is_trampoline_source(g.map[y+dy,x+dx]) ) + { + Pos p = g.tr.target_pos(g.map[y+dy,x+dx]); + if( after_move_death(p.y, p.x, g.tr.target_of(g.map[y+dy,x+dx])) ) + death ~= ds[i]; + } + else + { + death ~= ds[i]; + } + } + return death; + } + + char think(in Game g) + { + string s = death_move(g); + stderr.writeln(s); + + auto Q = new Queue!(Tuple!(Pos,Pos)); + Q.push(tuple(g.map.robot.clone(), g.map.robot.clone()), 0); + Pos[][] V = new Pos[][](g.map.H+2, g.map.W+2); + while(!Q.empty) { + auto tup = Q.pop(); + Pos p = tup[0][0]; + Pos prev = tup[0][1]; + int dist = tup[1]; + if(V[p.y][p.x]) + continue; + V[p.y][p.x] = prev; + if(g.map[p]=='\\' || g.map[p]=='O') + { + Pos goback(Pos p) { + return V[p.y][p.x]; + } + for(;;) { + Pos q = goback(p); + if(q == g.map.robot) + if(q.y==p.y) + return q.x