Differences From Artifact [3fbaa7115d831a14]:
- File
src/solver.d
- 2012-07-15 23:06:48 - part of checkin [3c50d3dc78] on branch trunk - Solver_2 is fast enough. MasterSolver may not be needed. (user: kinaba) [annotate]
To Artifact [fc45f9bc575c213e]:
- File
src/solver.d
- 2012-07-16 00:21:59 - part of checkin [c5c6ef71be] on branch trunk - float up replanner. (user: kinaba) [annotate]
313 313 }
314 314 return (danger_ok ? [] : tryA()) ~ tryB() ~ tryC();
315 315 }
316 316 }
317 317
318 318 class Solver_2(SubSolver) : Solver
319 319 {
320 - static const PredictFuture = 10;
320 + // Parameters.
321 + static const PredictFuture = 10;
322 + const string[] RandomChoicePattern; // PF*RCP exhaustive search for RL steps
323 + const ReplanLength = 400; // O(PF*RCP*RL*SubSolver.single_step)
321 324
322 325 Game current_game;
323 326 SubSolver sub_solver;
324 327
325 328 enum {Tentative, Tentative_Stuck, Fixed};
326 329 string plan;
327 330 int plan_state;
331 + int replan_limit;
328 332
329 333 this(in Game g)
330 334 {
331 335 current_game = g.clone();
332 336 plan = "";
333 337 plan_state = Tentative;
338 + replan_limit = PredictFuture;
339 + if(g.map.W*g.map.H <= 400)
340 + RandomChoicePattern = ["UU","UD","UL","UR",
341 + "DU","DD","DL","DR",
342 + "LU","LD","LL","LR",
343 + "RU","RD","RL","RR","UUU","UUUU","UUUUU"];
344 + else if(g.map.W*g.map.H <= 4096)
345 + RandomChoicePattern = ["UUU","U","D","L","R","UD","DU","LR","RL"];
346 + else
347 + RandomChoicePattern = ["U","D","L","R"];
334 348 }
335 349
336 350 char single_step()
337 351 {
338 352 if(current_game.dead || current_game.cleared)
339 353 return 'A';
340 354
341 355 // Make enough prediction.
342 - while( plan_state==Tentative && plan.length<PredictFuture )
356 + while( plan_state==Tentative && plan.length<replan_limit )
343 357 single_step_predict();
344 358
345 359 // If the future is bad, correct.
346 - if( plan_state==Tentative_Stuck && plan.length<PredictFuture )
360 + if( plan_state==Tentative_Stuck && plan.length<replan_limit )
347 361 replan();
348 362
349 363 // Follow the predicted plan.
350 364 if( plan.empty )
351 365 return 'A';
352 366 stderr.writeln(plan, " ", plan_state);
353 367 char c = plan[0];
................................................................................
391 405 }
392 406
393 407 void replan()
394 408 {
395 409 stderr.writeln("replan!");
396 410 // Try to replace every step of the plan by another move.
397 411 Game g = current_game.clone();
398 - Tuple!(long, SubSolver, string, int) cand =
399 - tuple(sub_solver.g.score, sub_solver, plan, Tentative_Stuck);
412 + Tuple!(SubSolver, string, int) cand = tuple(sub_solver, plan, Tentative_Stuck);
413 + bool tiebreak_by_turn = false;
400 414 for(int i=0; i<plan.length; ++i) {
401 - foreach(string prefix; ["U","D","L","R","UD","DU","LR","RL"])
415 + foreach(string prefix; RandomChoicePattern)
402 416 if(prefix[0] != plan[i]) {
403 - Tuple!(long, SubSolver, string, int) r = try_plan(g, prefix);
404 - if(cand[0] < r[0]) {
405 - r[2] = plan[0..i] ~ prefix ~ r[2];
406 - cand = r;
417 + Tuple!(SubSolver, string, int) r = try_plan(g, prefix);
418 + r[1] = plan[0..i] ~ prefix ~ r[1];
419 + bool better = false, tbt=false;
420 + if(!cand[0].g.cleared && r[0].g.cleared)
421 + better = true;
422 + else if(cand[0].g.cleared && r[0].g.cleared) {
423 + better = cand[0].g.score < r[0].g.score;
424 + }
425 + else if(!cand[0].g.cleared && !r[0].g.cleared) {
426 + if(cand[0].g.map.collected_lambda < r[0].g.map.collected_lambda)
427 + better = true;
428 + else if(cand[0].g.map.collected_lambda == r[0].g.map.collected_lambda) {
429 + if(cand[0].g.dead && !r[0].g.dead)
430 + better = true;
431 + else if(cand[0].g.dead == r[0].g.dead) {
432 + better = (cand[1].length < r[1].length);
433 + tbt = true;
434 + }
435 + }
407 436 }
437 + if(better) {
438 + cand = r;
439 + tiebreak_by_turn = true;
440 +writeln(cand);
441 +}
408 442 }
409 443 g.command(plan[i]);
410 444 }
411 445
412 - sub_solver = cand[1];
413 - plan = cand[2];
414 - plan_state = (plan.length < PredictFuture ? Fixed : cand[3]);
446 + sub_solver = cand[0];
447 + plan = cand[1];
448 + plan_state = (plan.length < PredictFuture ? Fixed : cand[2]);
449 + replan_limit = tiebreak_by_turn ? min(PredictFuture, plan.length/2) : PredictFuture;
415 450 }
416 451
417 - Tuple!(long, SubSolver, string, int) try_plan(in Game g, string prefix)
452 + Tuple!(SubSolver, string, int) try_plan(in Game g, string prefix)
418 453 {
419 454 SubSolver s = new SubSolver(g);
420 455 foreach(char c; prefix)
421 456 s.force(c);
422 457 string log;
423 458 int state = Tentative;
424 - while(!s.g.cleared && !s.g.dead && log.length<=g.map.H*g.map.W) {
459 + while(!s.g.cleared && !s.g.dead && log.length<=ReplanLength && log.length<=g.map.W*g.map.H) {
425 460 char c = s.single_step();
426 461 if( c == 'A' ) {
427 462 state = Tentative_Stuck;
428 463 break;
429 464 }
430 465 log ~= c;
431 466 }
432 467 if(s.g.cleared) state = Fixed;
433 468 else if(s.g.dead) state = Tentative_Stuck;
434 - return tuple(s.g.score, s, log, state);
469 + return tuple(s, log, state);
435 470 }
436 471 }
437 -/*
438 -class MasterSolver : Solver
439 -{
440 - this(in Game g)
441 - {
442 - int SIZE = g.map.H * g.map.W;
443 - if( SIZE <= 32*32 )
444 - sub = new Solver_2!(Solver_1)(g);
445 - else if( SIZE <= 100*100 )
446 - sub = new Solver_1(g);
447 - else
448 - sub = new Solver_1(g);
449 - }
450 472
451 - private Solver sub;
452 - char single_step() { return sub.single_step(); }
453 - void force(char c) { sub.force(c); }
454 -}
455 -
456 -alias MasterSolver MainSolver;
457 -*/
458 473 alias Solver_2!(Solver_1) MainSolver;
459 474 //alias Solver_1 MainSolver;
460 475 //alias Solver_0 MainSolver;