Check-in [e02668367d]
Not logged in
Overview
SHA1 Hash:e02668367d4b486ef984673b1470e1f20de51904
Date: 2012-07-15 21:14:10
User: kinaba
Comment:Revert redesign in the trunk.
Timelines: family | ancestors | descendants | both | trunk
Diffs: redesign
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified score_memo.txt from [95f0626c958d6d31] to [d46da9814cb8619d].

1 1 contest1 212! 2 2 contest2 280? 3 3 contest3 275! 4 4 contest4 561? 5 5 contest5 1281? 6 -contest6 737 // deadend trap 6 +contest6 737 7 7 contest7 867? 8 -contest8 1245 // tricky 8 +contest8 1245 9 9 contest9 3042? 10 -contest10 2076 // * on lambda, must move * first 11 -flood1 569 // too slow, because of 1-left danger lambda 10 +contest10 2076 11 +flood1 569 12 12 flood2 280? 13 -flood3 802 // too slow, drown 14 -flood4 970 // incorrect order of digging 13 +flood3 802 14 +flood4 970 15 15 flood5 561? 16 -trampoline1 291 // * on trampoline. must move * first 16 +trampoline1 291 17 17 trampoline2 1728? 18 -trampoline3 698 // * on trampoline target. must move * first. 18 +trampoline3 698 19 19 beard1 856? 20 -beard2 2792 // hutsu-ni muzui 21 -beard3 811 // tricky. must hurry to cut hige. 22 -beard4 677 // deadend trap 20 +beard2 2792 21 +beard3 811 22 +beard4 677

Deleted src/driver.d version [3d15ff20e76164b8]

1 -import game; 2 -import util; 3 - 4 -interface GameObserver 5 -{ 6 - // this(in Game g); 7 - void on_game_changed(char c, in Game g, bool finished); 8 -} 9 - 10 -class Driver 11 -{ 12 - this(Game g) { this.game = g; } 13 - this(File game_data) { this(new Game(game_data)); } 14 - 15 - void command(char c) 16 - { 17 - if( finished ) 18 - return; 19 - if( c == 'A' ) 20 - aborted = true; 21 - else 22 - game.command(c); 23 - foreach(ob; observers) 24 - ob.on_game_changed(c, game, finished); 25 - } 26 - 27 - T addObserver(T)() 28 - { 29 - T t = new T(game); 30 - observers ~= t; 31 - return t; 32 - } 33 - 34 - @property bool finished() 35 - { 36 - return game.cleared || game.dead || aborted; 37 - } 38 - 39 -private: 40 - Game game; 41 - GameObserver[] observers; 42 - bool aborted = false; 43 -} 44 - 45 -unittest 46 -{ 47 - static class MockGame : Game { 48 - this() { super(null,null,null); } 49 - string log; 50 - void command(char c) { log ~= c; } 51 - } 52 - static class MockObserver : GameObserver { 53 - string log; 54 - this(in Game g) {} 55 - void on_game_changed(char c, in Game g, bool fin) { log~=c; if(fin)log~="$"; } 56 - } 57 - 58 - auto g = new MockGame; 59 - auto d = new Driver(g); 60 - auto o = d.addObserver!MockObserver(); 61 - foreach(char c; "UDLRSAUDLRSA") 62 - d.command(c); 63 - assert(g.log == "UDLRS"); 64 - assert(o.log == "UDLRSA$"); 65 -}

Modified src/game.d from [eaa7866c864bed8a] to [e25c75ea96d80507].

346 346 } 347 347 data = next; 348 348 return dead; 349 349 } 350 350 } 351 351 352 352 //////////////////////////////////////////////////////////////////////////////// 353 -/* 353 + 354 354 class Game 355 355 { 356 356 mixin DeriveShow; 357 357 358 358 static Game load(File input) 359 359 { 360 360 string[] raw_data; ................................................................................ 440 440 long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L) - turn; } 441 441 int water_level() { return water.level(turn); } 442 442 int water_until_rise() { return water.until_rise(turn); } 443 443 int hige_until_rise() { return map.hige.until_rise(turn); } 444 444 int hp() { return map.waterproof - under_water; } 445 445 } 446 446 } 447 -*/ 448 - 449 -//////////////////////////////////////////////////////////////////////////////// 450 - 451 -class Game 452 -{ 453 -public: 454 - this(File input) 455 - { 456 - // Read map data 457 - string[] map_data_lines; 458 - for(string line; !(line=input.readln().chomp()).empty; ) 459 - map_data_lines ~= line; 460 - 461 - // H*W 462 - H_ = map_data_lines.length; 463 - W_ = 0; 464 - foreach(mdl; map_data_lines) 465 - W_ = max(W_, mdl.length); 466 - 467 - // Copy to modifiable buffer and adjust coordinates. 468 - raw_data_ = new char[][H_+1]; 469 - foreach(i,mdl; map_data_lines) { 470 - char[] buf = new char[mdl.length+1]; 471 - buf[0] = '#'; 472 - buf[1..$] = mdl[]; 473 - raw_data_[H_-i] = buf; 474 - } 475 - 476 - // Detect objects 477 - for(int y=1; y<=H_; ++y) 478 - for(int x=1; x<raw_data_[y].length; ++x) 479 - { 480 - char c = raw_data_[y][x]; 481 - switch(c) 482 - { 483 - case '#': 484 - case '.': 485 - case ' ': 486 - break; 487 - case 'L': 488 - case 'O': 489 - lift_pos_ = new Pos(y,x); 490 - break; 491 - case 'A': .. case 'I': 492 - case '1': .. case '9': 493 - trampoline_pos_[c] = new Pos(y,x); 494 - break; 495 - case '!': 496 - razor_pos_ ~= new Pos(y,x); 497 - break; 498 - case '\\': 499 - lambda_pos_ ~= new Pos(y,x); 500 - break; 501 - 502 - // Moving objects are erased from raw_data_ 503 - case 'R': 504 - robot_pos_ = new Pos(y,x); 505 - raw_data_[y][x] = ' '; 506 - break; 507 - case '*': 508 - case 'W': 509 - dynamic_objects_[new Pos(y,x)] = c; 510 - raw_data_[y][x] = ' '; 511 - if(c=='*') 512 - may_update_[new Pos(y,x)] = true; 513 - break; 514 - default: 515 - assert(false); 516 - } 517 - } 518 - 519 - // Read other parameters 520 - for(string line; !(line=input.readln()).empty; ) 521 - { 522 - string[] ss = line.split(); 523 - if( ss.length == 2 ) 524 - switch(ss[0]) 525 - { 526 - case "Water": water_base_ = ss[1].to!int(); break; 527 - case "Flooding": water_pace_ = ss[1].to!int(); break; 528 - case "Waterproof": max_air_ = ss[1].to!int(); break; 529 - case "Growth": hige_pace_ = ss[1].to!int(); break; 530 - case "Razors": num_razor_ = ss[1].to!int(); break; 531 - default: assert(false); 532 - } 533 - if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" ) 534 - { 535 - char fr=ss[1][0], to=ss[3][0]; 536 - trampoline_[fr] = to; 537 - if(to !in trampoline_rev_) trampoline_rev_[to] = []; 538 - trampoline_rev_[to] ~= fr; 539 - } 540 - } 541 - 542 - air_left_ = max_air_; 543 - } 544 - 545 - @property const { 546 - int H() { return H_; } 547 - int W() { return W_; } 548 - char trampoline(char c) { return (c in trampoline_ ? trampoline_[c] : 0); } 549 - const(Pos)[] trampoline_rev(char c) { 550 - const(Pos)[] pp; 551 - if(c in trampoline_rev_) { 552 - foreach(ch; trampoline_rev_[c]) 553 - pp ~= trampoline_pos_[ch]; 554 - } 555 - return pp; 556 - } 557 - int water_level() { 558 - return water_pace_ ? water_base_ + turn_/water_pace_ : water_base_; 559 - } 560 - int water_until_rise() { 561 - return water_pace_ ? water_pace_ - turn_%water_pace_ : int.max; 562 - } 563 - int hige_until_rise() { 564 - return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.max; 565 - } 566 - bool is_hige_turn() { 567 - return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : false; 568 - } 569 - int hp() { return air_left_; } 570 - int num_razor() { return num_razor_; } 571 - bool cleared() { return cleared_; } 572 - bool dead() { return dead_; } 573 - long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L : 50L) - turn_; } 574 - const(Pos) robot() { return robot_pos_; } 575 - const(Pos) lift() { return lift_pos_; } 576 - Pos[] lambdas() { 577 - Pos[] pp; 578 - foreach(p; lambda_pos_) 579 - pp ~= p.clone(); 580 - return pp; 581 - } 582 - Pos[] razors() { 583 - Pos[] pp; 584 - foreach(p; razor_pos_) 585 - pp ~= p.clone(); 586 - return pp; 587 - } 588 - const(Pos)[] higes() { 589 - const(Pos)[] pp; 590 - foreach(p,c; dynamic_objects_) 591 - if(c=='W') 592 - pp ~= p; 593 - return pp; 594 - } 595 - } 596 - const { 597 - char opIndex(in Pos p) { return opIndex(p.y, p.x); } 598 - char opIndex(int y, int x) { return map_get(y, x); } 599 - } 600 - 601 -public: 602 - void command(char c) 603 - { 604 - if(dead || cleared) 605 - return; 606 - 607 - if(c == 'U') command_move(+1, 0); 608 - if(c == 'D') command_move(-1, 0); 609 - if(c == 'L') command_move(0, -1); 610 - if(c == 'R') command_move(0, +1); 611 - if(c == 'S') use_razor(); 612 - if(c == 'W') {} 613 - 614 - if(!cleared) 615 - { 616 - map_update(); 617 - water_update(); 618 - } 619 - turn_ ++; 620 - } 621 - 622 - void command_move(int dy, int dx) 623 - { 624 - int y = robot_pos_.y, x = robot_pos_.x; 625 - char c = this[y+dy, x+dx]; 626 - Pos p = new Pos(y+dy, x+dx); 627 - 628 - switch(c){ 629 - case 'O': 630 - cleared_ = true; 631 - move_robot_to(p); 632 - break; 633 - case '\\': 634 - take_lambda_at(p); 635 - move_robot_to(p); 636 - break; 637 - case '!': 638 - take_razor_at(p); 639 - move_robot_to(p); 640 - break; 641 - case 'A': .. case 'I': 642 - enter_trampoline_at(p, c); 643 - break; 644 - case ' ': 645 - case '.': 646 - move_robot_to(p); 647 - break; 648 - case '*': 649 - if(dy!=0 || this[y,x+dx*2]!=' ') 650 - break; 651 - move_robot_to(p); 652 - push_rock(p, new Pos(y,x+dx*2)); 653 - break; 654 - default: 655 - break; 656 - } 657 - } 658 - 659 - void use_razor() 660 - { 661 - if(num_razor_ == 0) 662 - return; 663 - num_razor_ --; 664 - 665 - for(int dy=-1; dy<=+1; ++dy) 666 - for(int dx=-1; dx<=+1; ++dx) if(dy||dx) 667 - { 668 - Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx); 669 - if(auto it = p in dynamic_objects_) 670 - if(*it == 'W') { 671 - something_gone(p); 672 - dynamic_objects_.remove(p); 673 - } 674 - } 675 - } 676 - 677 - void take_lambda_at(Pos p) 678 - { 679 - map_set_empty(p); 680 - num_lambda_ ++; 681 - lambda_pos_ = lambda_pos_.erase(p); 682 - } 683 - 684 - void take_razor_at(Pos p) 685 - { 686 - map_set_empty(p); 687 - num_razor_ ++; 688 - razor_pos_ = razor_pos_.erase(p); 689 - } 690 - 691 - void enter_trampoline_at(Pos p, char c) 692 - { 693 - char d = trampoline(c); 694 - foreach(cc; trampoline_rev_[d]) { 695 - Pos pp = trampoline_pos_[cc]; 696 - something_gone(pp); 697 - map_set_empty(pp); 698 - } 699 - move_robot_to(trampoline_pos_[d]); 700 - } 701 - 702 - void move_robot_to(Pos p) 703 - { 704 - something_gone(robot_pos_); 705 - map_set_empty(p.y, p.x); 706 - robot_pos_ = p; 707 - } 708 - 709 - void push_rock(Pos fr, Pos to) 710 - { 711 - dynamic_objects_.remove(fr); 712 - dynamic_objects_[to] = '*'; 713 - may_update_[to] = true; 714 - } 715 - 716 - void something_gone(Pos p) 717 - { 718 - for(int dy=0; dy<=+1; ++dy) 719 - for(int dx=-1; dx<=+1; ++dx) if(dy||dx) 720 - may_update_[new Pos(p.y+dy,p.x+dx)] = true; 721 - } 722 - 723 - void map_update() 724 - { 725 - Pos[] may_update_list; 726 - foreach(p,_; may_update_) 727 - if(this[p] == '*') 728 - may_update_list ~= p; 729 - may_update_ = null; 730 - 731 - if( is_hige_turn() ) 732 - foreach(p,c; dynamic_objects_) 733 - if(c == 'W') 734 - may_update_list ~= p; 735 - 736 - sort(may_update_list); 737 - char[Pos] to_be_written; 738 - foreach(p; may_update_list) 739 - if(is_hige_turn() && this[p]=='W') 740 - { 741 - for(int dy=-1; dy<=+1; ++dy) 742 - for(int dx=-1; dx<=+1; ++dx) { 743 - Pos q = new Pos(p.y+dy,p.x+dx); 744 - if( this[q] == ' ' ) 745 - to_be_written[q] = 'W'; 746 - } 747 - } 748 - else 749 - { 750 - int y = p.y; 751 - int x = p.x; 752 - char below = this[y-1,x]; 753 - // * 754 - // _ 755 - if(below==' ') { 756 - Pos q = new Pos(y-1,x); 757 - to_be_written[p] = ' '; 758 - to_be_written[q] = '*'; 759 - may_update_[q] = true; 760 - } 761 - // *_ *_ 762 - // *_ or \_ 763 - else if((below=='*'||below=='\\')&&this[y-1,x+1]==' '&&this[y,x+1]==' ') { 764 - Pos q = new Pos(y-1,x+1); 765 - to_be_written[p] = ' '; 766 - to_be_written[q] = '*'; 767 - may_update_[q] = true; 768 - } 769 - // _* 770 - // _* 771 - else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x-1]==' ') { 772 - Pos q = new Pos(y-1,x-1); 773 - to_be_written[p] = ' '; 774 - to_be_written[q] = '*'; 775 - may_update_[q] = true; 776 - } 777 - } 778 - 779 - foreach(p,c; to_be_written) { 780 - dynamic_objects_[p] = c; 781 - if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x) 782 - dead_ = true; 783 - } 784 - 785 - if(lambda_pos_.empty) 786 - raw_data_[lift_pos_.y][lift_pos_.x] = 'O'; 787 - } 788 - 789 - void water_update() 790 - { 791 - if( robot_pos_.y <= water_level() ) 792 - air_left_ --; 793 - else 794 - air_left_ = max_air_; 795 - if( air_left_ < 0 ) 796 - dead_ = true; 797 - } 798 - 799 -private: 800 - char map_get(int y, int x) const 801 - { 802 - if( y<1 || H<y || x<1 || W<x ) return '#'; 803 - Pos p = new Pos(y,x); 804 - if(p == robot_pos_) 805 - return 'R'; 806 - if(auto it = (p in dynamic_objects_)) 807 - return *it; 808 - if( x<0 || raw_data_[y].length<=x ) return ' '; 809 - return raw_data_[y][x]; 810 - } 811 - 812 - void map_set_empty(in Pos p) 813 - { 814 - return map_set_empty(p.y, p.x); 815 - } 816 - 817 - void map_set_empty(int y, int x) 818 - { 819 - if( y<1 || H<y || x<1 || W<x ) return; 820 - if( x<0 || raw_data_[y].length<=x ) return; 821 - raw_data_[y][x] = ' '; 822 - } 823 - 824 -public: 825 - Game clone() const { return new Game(this); } 826 - this(in Game g) { 827 - H_ = g.H_; 828 - W_ = g.W_; 829 - raw_data_ = new char[][g.raw_data_.length]; 830 - foreach(i,d; g.raw_data_) raw_data_[i] = d.dup; 831 - trampoline_pos_ = cast(Pos[char]) g.trampoline_pos_; 832 - razor_pos_ = (cast(Game)g).razor_pos_.dup; 833 - lambda_pos_ = (cast(Game)g).lambda_pos_.dup; 834 - lift_pos_ = g.lift_pos_.clone(); 835 - robot_pos_ = g.robot_pos_.clone(); 836 - dynamic_objects_ = dup(g.dynamic_objects_); 837 - trampoline_ = (cast(Game)g).trampoline_; 838 - trampoline_rev_ = (cast(Game)g).trampoline_rev_; 839 - water_base_ = g.water_base_; 840 - water_pace_ = g.water_pace_; 841 - max_air_ = g.max_air_; 842 - hige_pace_ = g.hige_pace_; 843 - num_razor_ = g.num_razor_; 844 - num_lambda_ = g.num_lambda_; 845 - turn_ = g.turn_; 846 - air_left_ = g.air_left_; 847 - cleared_ = g.cleared_; 848 - dead_ = g.dead_; 849 - may_update_ = dup(g.may_update_); 850 - } 851 - 852 - V[K] dup(V,K)(in V[K] aa) { 853 - V[K] aa2; 854 - foreach(k,v; aa) aa2[k] = v; 855 - return aa2; 856 - } 857 - 858 -private: 859 - int H_; 860 - int W_; 861 - char[][] raw_data_; 862 - Pos[char] trampoline_pos_; 863 - Pos[] razor_pos_; 864 - Pos[] lambda_pos_; 865 - Pos lift_pos_; 866 - Pos robot_pos_; 867 - char[Pos] dynamic_objects_; 868 - char[char] trampoline_; 869 - char[][char] trampoline_rev_; 870 - int water_base_ = 0; 871 - int water_pace_ = 0; 872 - int max_air_ = 10; 873 - int hige_pace_ = 25; 874 - int num_razor_ = 0; 875 - int num_lambda_ = 0; 876 - 877 - int turn_ = 0; 878 - int air_left_ = 0; 879 - bool cleared_ = false; 880 - bool dead_ = false; 881 - bool[Pos] may_update_; 882 -}

Modified src/gui.d from [e84cacd6262f93a7] to [d4577900b4db97c1].

4 4 import driver; 5 5 6 6 class GUI(Solver) : Form, GameObserver 7 7 { 8 8 this(in Game g) 9 9 { 10 10 this.solver = new Solver(g); 11 - setup_size(g.W, g.H); 11 + setup_size(g.map.W, g.map.H); 12 12 setup_resources(g); 13 13 draw(g); 14 14 } 15 15 16 16 private void delegate(char c) fn; 17 17 void set_fn(F)(F f) { this.fn = f; } 18 18 ................................................................................ 79 79 this.render['\\'] = "λ"; 80 80 this.render['R'] = "☃"; 81 81 this.render['d'] = "☠"; 82 82 this.render['L'] = "☒"; 83 83 this.render['O'] = "☐"; 84 84 this.render['W'] = "ꔣ"; 85 85 this.render['!'] = "✄"; 86 - foreach(char c; 'A'..'J') this.render[c] = [cast(dchar)('☢'+g.trampoline(c)-'1')].to!string(); 86 + foreach(c,tp; g.map.tr_target) { 87 + char d = g.map[tp]; 88 + this.render[c] = [cast(dchar)('☢'+d-'1')].to!string(); 89 + } 87 90 foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1')].to!string(); 88 91 this.paint ~= (Control c, PaintEventArgs ev) { 89 92 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clientSize.height)); 90 93 }; 91 94 } 92 95 93 96 void draw(in Game g) ................................................................................ 99 102 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH)); 100 103 101 104 // Fill water. 102 105 int w = g.water_level(); 103 106 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell*w-1, scrW, cell*w+1)); 104 107 105 108 // Paint map. 106 - for(int y=1; y<=g.H; ++y) 107 - for(int x=1; x<=g.W; ++x) { 109 + for(int y=1; y<=g.map.H; ++y) 110 + for(int x=1; x<=g.map.W; ++x) { 108 111 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 109 - char c = g[y,x]; 112 + char c = g.map[y,x]; 110 113 if( c != ' ' ) { 111 114 if( c == 'R' && g.dead ) 112 115 c = 'd'; 113 116 graphicContext.drawText(this.render[c], font, this.colors[c], r); 114 117 } 115 118 } 116 119 117 120 // Update textual info. 118 121 this.text = .text( 119 122 "Score: ", g.score, 120 123 " Air: ", g.hp, 121 124 " Tide: ", g.water_until_rise, 122 125 " Wadler: ", g.hige_until_rise, 123 - " Razor: ", g.num_razor); 126 + " Razor: ", g.map.razor); 124 127 invalidate(); 125 128 } 126 129 127 130 private: 128 131 void setup_keyhandling() 129 132 { 130 133 noMessageFilter();

Modified src/output.d from [e2d0d7db868c3a44] to [045b845268918546].

31 31 override void on_game_changed(char c, in Game g, bool finished) 32 32 { 33 33 if(flushed) 34 34 return; 35 35 36 36 log ~= c; 37 37 score_log ~= g.score; 38 - if(finished || log.length+1==g.W*g.H) 38 + if(finished || log.length+1==g.map.W*g.map.H) 39 39 flush(); 40 40 } 41 41 42 42 private: 43 43 string log; 44 44 long[] score_log; 45 45 bool flushed;

Modified src/solver.d from [22c356ff1975e92f] to [393baf841678f948].

13 13 int wait_count = 0; 14 14 int choke_count = 0; 15 15 16 16 Game g; 17 17 this(in Game g) 18 18 { 19 19 this.g = g.clone(); 20 - forbidden_cell = new bool[][](g.H+2, g.W+2); 20 + forbidden_cell = new bool[][](g.map.H+2, g.map.W+2); 21 21 } 22 22 23 23 char single_step() 24 24 { 25 25 Tuple!(string,int) de = death_move(g); 26 26 char c = act(g, de[0], de[1]); 27 27 force(c); ................................................................................ 39 39 string death; 40 40 int choice = 0; 41 41 foreach(char c; "UDLRW") { 42 42 Game gg = g.clone(); 43 43 gg.command(c); 44 44 if( !gg.cleared && gg.dead ) 45 45 death ~= c; 46 - else if( gg.robot != g.robot ) 46 + else if( gg.map.robot != g.map.robot ) 47 47 choice++; 48 48 else if( c != 'W' ) // meaningless move 49 49 death ~= c; 50 50 } 51 51 return tuple(death, choice); 52 52 } 53 53 54 54 Tuple!(Pos, int)[] log; 55 55 bool[][] forbidden_cell; 56 56 57 57 char act(const(Game) g, string death, int breath) 58 58 { 59 - const Pos ro = g.robot; 60 - const Pos li = g.lift; 61 - Pos[] la = g.lambdas(); 59 + const Pos ro = g.map.robot; 60 + const Pos li = g.map.lift; 61 + Pos[] la = g.map.lambdas(); 62 62 sort!((Pos a,Pos b){ 63 63 int ad=abs(a.y-li.y)+abs(a.x-li.x); 64 64 int bd=abs(b.y-li.y)+abs(b.x-li.x); 65 65 return ad>bd;; 66 66 })(la); 67 - Pos[] ra = g.razors(); 68 - const(Pos)[] hi = g.higes(); 67 + Pos[] ra = g.map.razors(); 68 + const(Pos)[] hi = g.map.objects('W'); 69 69 70 70 Tuple!(char,int)[] cand; 71 71 char c = 'W'; 72 72 if( la.empty ) { 73 73 cand = search(g, ro, [li], death); 74 74 } else { 75 75 cand ~= search(g, ro, la~ra, death); 76 76 } 77 77 78 78 // 'higesori' mode 79 - if( !hi.empty && g.num_razor>0 ) { 79 + if( !hi.empty && g.map.razor>0 ) { 80 80 int his = 0; 81 81 for(int dy=-1; dy<=+1; ++dy) 82 82 for(int dx=-1; dx<=+1; ++dx) 83 - if(g[ro.y+dy,ro.x+dx] == 'W') 83 + if(g.map[ro.y+dy,ro.x+dx] == 'W') 84 84 his++; 85 85 86 86 if(his>=2 || his==hi.length) 87 87 cand = [tuple('S',int.max)]; 88 88 if(cand.empty) { 89 89 const(Pos)[] tgt; 90 - for(int y=1; y<=g.H; ++y) 91 - for(int x=1; x<=g.W; ++x) 92 - if(g[y,x]=='.'||g[y,x]==' ') { 90 + for(int y=1; y<=g.map.H; ++y) 91 + for(int x=1; x<=g.map.W; ++x) 92 + if(g.map[y,x]=='.'||g.map[y,x]==' ') { 93 93 his = 0; 94 94 for(int dy=-1; dy<=+1; ++dy) 95 95 for(int dx=-1; dx<=+1; ++dx) 96 - if(g[y+dy,x+dx] == 'W') 96 + if(g.map[y+dy,x+dx] == 'W') 97 97 his++; 98 98 if(his>=2) 99 99 tgt ~= new Pos(y,x); 100 100 } 101 101 cand ~= search(g, ro, tgt, death, true); 102 102 } 103 103 } 104 104 105 105 // 'dig' mode 106 106 if(cand.empty) { 107 107 const(Pos)[] tgt; 108 - for(int y=1; y<=g.H; ++y) 109 - for(int x=1; x<=g.W; ++x) 110 - if(g[y,x]=='.') 111 - if(g[y+1,x]=='*'||g[y+1,x-1]=='*'||g[y+1,x+1]=='*' 112 - ||g[y,x+1]=='*'||g[y,x-1]=='*') 108 + for(int y=1; y<=g.map.H; ++y) 109 + for(int x=1; x<=g.map.W; ++x) 110 + if(g.map[y,x]=='.') 111 + if(g.map[y+1,x]=='*'||g.map[y+1,x-1]=='*'||g.map[y+1,x+1]=='*' 112 + ||g.map[y,x+1]=='*'||g.map[y,x-1]=='*') 113 113 tgt ~= new Pos(y,x); 114 114 cand ~= search(g, ro, tgt, death, true); 115 115 } 116 116 117 117 if(cand.empty) { 118 118 choke_count++; 119 119 cand ~= tuple('W',int.max); ................................................................................ 133 133 } 134 134 } 135 135 136 136 if(c == 'W') 137 137 wait_count++; 138 138 else 139 139 wait_count = 0; 140 - if(choke_count >= g.H) 140 + if(choke_count >= g.map.H) 141 141 c = 'A'; 142 142 143 143 bool[char] choice; 144 144 foreach(t; cand) 145 145 choice[t[0]] = true; 146 146 log ~= tuple(ro.clone(), cast(int)choice.length); 147 147 if(log.length > 5) ................................................................................ 157 157 return c; 158 158 } 159 159 160 160 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death, bool danger_ok=false) 161 161 { 162 162 bool danger(int y, int x) 163 163 { 164 - if(g[y,x] == ' ' || g[y,x] == 'R') 164 + if(g.map[y,x] == ' ' || g.map[y,x] == 'R') 165 165 return false; 166 - if(g[y+1,x] == '*') 166 + if(g.map[y+1,x] == '*') 167 + return true; 168 + if(g.map[y+1,x-1]=='*' && (g.map[y,x-1]=='\\'||g.map[y,x-1]=='*') && (g.map[y+1,x]==' '||g.map[y+1,x]=='R')) 167 169 return true; 168 - if(g[y+1,x-1]=='*' && (g[y,x-1]=='\\'||g[y,x-1]=='*') && (g[y+1,x]==' '||g[y+1,x]=='R')) 170 + if(g.map[y+1,x+1]=='*' && (g.map[y,x+1]=='*') && (g.map[y+1,x]==' '||g.map[y+1,x]=='R')) 169 171 return true; 170 - if(g[y+1,x+1]=='*' && (g[y,x+1]=='*') && (g[y+1,x]==' '||g[y+1,x]=='R')) 172 + if(g.map[y,x-1]=='*' && (g.map[y-1,x-1]=='\\'||g.map[y-1,x-1]=='*') && (g.map[y-1,x]==' '||g.map[y-1,x]=='R')) 171 173 return true; 172 - if(g[y,x-1]=='*' && (g[y-1,x-1]=='\\'||g[y-1,x-1]=='*') && (g[y-1,x]==' '||g[y-1,x]=='R')) 173 - return true; 174 - if(g[y,x+1]=='*' && (g[y-1,x+1]=='*') && (g[y-1,x]==' '||g[y-1,x]=='R')) 174 + if(g.map[y,x+1]=='*' && (g.map[y-1,x+1]=='*') && (g.map[y-1,x]==' '||g.map[y-1,x]=='R')) 175 175 return true; 176 176 return false; 177 177 } 178 178 179 179 // avoid directly below '*' 180 180 Tuple!(char,int)[] tryA() { 181 181 const(Pos)[] q; 182 182 foreach(p; gs) 183 183 if(!danger(p.y,p.x)) 184 184 q ~= p; 185 - bool[][] v = new bool[][](g.H+2, g.W+2); 185 + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 186 186 foreach(p; q) v[p.y][p.x]=true; 187 187 for(int step=1; q.length; ++step) { 188 188 Pos[] q2; 189 189 foreach(p; q) { 190 190 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 191 191 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 192 192 for(int i=0; i<yyy.length; ++i) { 193 193 int y = yyy[i]; 194 194 int x = xxx[i]; 195 - if('1'<=g[y,x]&&g[y,x]<='9') { 196 - foreach(ppp; g.trampoline_rev(g[y,x])) { 195 + if('1'<=g.map[y,x]&&g.map[y,x]<='9') { 196 + foreach(ppp; g.map.tr_source[g.map[y,x]]) { 197 197 yyy ~= ppp.y; 198 198 xxx ~= ppp.x; 199 199 } 200 200 continue; 201 201 } 202 202 if(v[y][x]) continue; 203 203 if(y==s.y && x==s.x && i<4) { 204 204 char c = "UDRL"[i]; 205 205 if( death.count(c) == 0 ) 206 206 return [tuple(c,step)]; 207 207 } else if(forbidden_cell[y][x]){ 208 - } else if(g[y,x]==' '||g[y,x]=='\\'||g[y,x]=='.'||g[y,x]=='!'||i>=4) { 208 + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='!'||i>=4) { 209 209 if(danger(y,x)) 210 210 continue; 211 211 q2 ~= new Pos(y,x); 212 212 v[y][x]=true; 213 213 } 214 214 } 215 215 } ................................................................................ 218 218 return []; 219 219 } 220 220 221 221 // any empty space is my ground 222 222 Tuple!(char,int)[] tryB() { 223 223 const(Pos)[] q; 224 224 foreach(p; gs) q ~= p; 225 - bool[][] v = new bool[][](g.H+2, g.W+2); 225 + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 226 226 foreach(p; q) v[p.y][p.x]=true; 227 227 for(int step=10; q.length; ++step) { 228 228 Pos[] q2; 229 229 foreach(p; q) { 230 230 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 231 231 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 232 232 for(int i=0; i<yyy.length; ++i) { 233 233 int y = yyy[i]; 234 234 int x = xxx[i]; 235 - if('1'<=g[y,x]&&g[y,x]<='9') { 236 - foreach(ppp; g.trampoline_rev(g[y,x])) { 235 + if('1'<=g.map[y,x]&&g.map[y,x]<='9') { 236 + foreach(ppp; g.map.tr_source[g.map[y,x]]) { 237 237 yyy ~= ppp.y; 238 238 xxx ~= ppp.x; 239 239 } 240 240 continue; 241 241 } 242 242 if(v[y][x]) continue; 243 243 if(y==s.y && x==s.x && i<4) { 244 244 char c = "UDRL"[i]; 245 245 if( death.count(c) == 0 ) 246 246 return [tuple(c,step)]; 247 247 } else if(forbidden_cell[y][x]){ 248 - } else if(g[y,x]==' '||g[y,x]=='\\'||g[y,x]=='.'||g[y,x]=='!'||i>=4) { 248 + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='!'||i>=4) { 249 249 q2 ~= new Pos(y,x); 250 250 v[y][x]=true; 251 251 } 252 252 } 253 253 } 254 254 q = q2; 255 255 } ................................................................................ 256 256 return []; 257 257 } 258 258 259 259 // push rocks! 260 260 Tuple!(char,int)[] tryC() { 261 261 const(Pos)[] q; 262 262 foreach(p; gs) q ~= p; 263 - bool[][] v = new bool[][](g.H+2, g.W+2); 263 + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 264 264 foreach(p; q) v[p.y][p.x]=true; 265 265 for(int step=20; q.length; ++step) { 266 266 Pos[] q2; 267 267 foreach(p; q) { 268 268 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 269 269 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 270 270 for(int i=0; i<yyy.length; ++i) { 271 271 int y = yyy[i]; 272 272 int x = xxx[i]; 273 - if(g[p] == '*') { 273 + if(g.map[p] == '*') { 274 274 if(i>=4)continue; 275 275 if(y!=p.y)continue; 276 - if(g[y,p.x+(p.x-x)]!=' '&&g[y,p.x+(p.x-x)]!='R')continue; 276 + if(g.map[y,p.x+(p.x-x)]!=' '&&g.map[y,p.x+(p.x-x)]!='R')continue; 277 277 } 278 - if('1'<=g[y,x]&&g[y,x]<='9') { 279 - foreach(ppp; g.trampoline_rev(g[y,x])) { 278 + if('1'<=g.map[y,x]&&g.map[y,x]<='9') { 279 + foreach(ppp; g.map.tr_source[g.map[y,x]]) { 280 280 yyy ~= ppp.y; 281 281 xxx ~= ppp.x; 282 282 } 283 283 continue; 284 284 } 285 285 if(v[y][x]) continue; 286 286 if(y==s.y && x==s.x && i<4) { 287 287 char c = "UDRL"[i]; 288 288 if( death.count(c) == 0 ) 289 289 return [tuple(c,step)]; 290 290 } else if(forbidden_cell[y][x]){ 291 - } else if(g[y,x]==' '||g[y,x]=='\\'||g[y,x]=='.'||g[y,x]=='*'||g[y,x]=='!'||i>=4) { 291 + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='*'||g.map[y,x]=='!'||i>=4) { 292 292 q2 ~= new Pos(y,x); 293 293 v[y][x]=true; 294 294 } 295 295 } 296 296 } 297 297 q = q2; 298 298 } ................................................................................ 314 314 make_plan(g); 315 315 } 316 316 317 317 Tuple!(Solver,string) run_sub_solver(in Game g) 318 318 { 319 319 string log; 320 320 auto s = new Solver(g); 321 - while(!g.cleared && !g.dead && plan.length<=g.H*g.W) { 321 + while(!g.cleared && !g.dead && plan.length<=g.map.H*g.map.W) { 322 322 char c = s.single_step(); 323 323 if( c == 'A' ) 324 324 break; 325 325 log ~= c; 326 326 } 327 327 while(log.length>0 && log[$-1]=='W') 328 328 log.length--;

Modified src/util.d from [b76be1f6ad977d56] to [41ba420d0c49ce8d].

4 4 public import std.range; 5 5 public import std.stdio; 6 6 public import std.string; 7 7 public import std.typecons; 8 8 public import std.math; 9 9 import std.c.stdlib; 10 10 11 -T[] erase(T,V)(T[] xs, V y) 12 -{ 13 - foreach(i,x; xs) 14 - if(x == y) 15 - return xs[0..i]~xs[i+1..$]; 16 - return xs; 17 -} 18 - 19 11 // To avoide the following ICE: 20 12 // src\phobos\std\algorithm.d(4552): 21 13 // Error: function std.algorithm.count!("a == b",string,char).count 22 14 // compiler error, parameter 'value', bugzilla 2962? 23 15 // Assertion failure: '0' on line 717 in file 'glue.c' 24 16 int count(T,V)(T[] a, V v) 25 17 {