Check-in Differences
Not logged in

Difference From:

[fc9286dad1] uum (user: kinaba, tags: redesign, date: 2012-07-15 12:11:33)

To:

[310a3c5d41] speed testing... 100x100 no-op is fast enough... (user: kinaba, tags: trunk, date: 2012-07-15 15:42:31)

Added maps/80x60.map version [b22e0d0f5c688ed4]

1 +############################################################ 2 +#L\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*.*.*.*.*.*.*.*.*.*# 3 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*W*.*.*.*.*.*.*.*.*.# 4 +#.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*# 5 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*W*.*.*.*.*.*.*.*.*.# 6 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*.*.*.*.*.*.*.*.*.*# 7 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 8 +#.\.\.\.\.\.\.\.\.@.\.\.@.\.\.\.\.\.\.\.*.*.*.*.*.*.*.*.*.*# 9 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 10 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*.*.*.*.*.*.*.*.*.*# 11 +#.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*# 12 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*.*.*.*.*.*.*.*.*.*# 13 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 14 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*W*.*.*.*.*.*.*.*.*.# 15 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*W*.*.*.*.*.*.*.*.*.# 16 +#.\.\.\.\.\.\.\.\.\W\.\.\.\.\.\.\.\.\.\*W*.*.*.*.*.*.*.*.*.# 17 +#.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.**W*.*.*.*.*.*.*.*.*.# 18 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*W*.*.*.*.*.*.*.*.*.# 19 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.*W*.*.*.*.*.*.*.*.*.# 20 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*W*.*.*.*.*.*.*.*.*.# 21 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 22 +#.\.\.\.\!\.\.\.\.\.\.\.\W\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 23 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 24 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 25 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 26 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 27 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 28 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 29 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 30 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 31 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\!\.\..*.*.*.*.*.*.*.*.*.*# 32 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 33 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 34 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 35 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\!\.\..*.*.*.*.*.*.*.*.*.*# 36 +#.\.\.\.\.\.\.\.\W\.\.\.\.\.\.\.\.\.\.\*!*.*.*.*.*.*.*.*.*.# 37 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 38 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.R*!*.*.*.*.*.*.*.*.*.# 39 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 40 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.A*!*.*.*.*.*.*.*.*.*.# 41 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 42 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.B*!*.*.*.*.*.*.*.*.*.# 43 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 44 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.C*!*.*.*.*.*.*.*.*.*.# 45 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 46 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.D*!*.*.*.*.*.*.*.*.*.# 47 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 48 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.E*!*.*.*.*.*.*.*.*.*.# 49 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 50 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.F*!*.*.*.*.*.*.*.*.*.# 51 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 52 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.G*!*.*.*.*.*.*.*.*.*.# 53 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 54 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.H*!*.*.*.*.*.*.*.*.*.# 55 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 56 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.I*!*.*.*.*.*.*.*.*.*.# 57 +#\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\..*.*.*.*.*.*.*.*.*.*# 58 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 59 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 60 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 61 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 62 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 63 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 64 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 65 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 66 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 67 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 68 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 69 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 70 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 71 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 72 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 73 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 74 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 75 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 76 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 77 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 78 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.W*!*.*.*.*.*.*.*.*.*.# 79 +#.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.1*!*.*.*.*.*.*.*.*.*.# 80 +############################################################ 81 + 82 +Flooding 80 83 +Trampoline A targets 1 84 +Trampoline B targets 1 85 +Trampoline C targets 1 86 +Trampoline D targets 1 87 +Trampoline E targets 1 88 +Trampoline F targets 1 89 +Trampoline G targets 1 90 +Trampoline H targets 1 91 +Trampoline I targets 1

Added maps/beard5.map version [7639fcdcf36705e1]

1 + ########## 2 + ####..******#### 3 + ###.. 3ABCDEF...### 4 + ## ## 5 + ### ## 6 + ###.....\\\...\\\.....### 7 + #.. \\\ * \\\ ## 8 + ## * ## 9 + ### *** ## 10 + #*****************## 11 + ###..............## 12 + ###...........## 13 + ####WR..W#### 14 + ##L#### 15 + ..... 16 + ###### ###### 17 + ##1\! G##2 !\H## 18 + ###### ###### 19 + 20 +Trampoline A targets 1 21 +Trampoline B targets 1 22 +Trampoline C targets 1 23 +Trampoline D targets 1 24 +Trampoline E targets 1 25 +Trampoline F targets 1 26 +Trampoline G targets 2 27 +Trampoline H targets 3 28 +Growth 5 29 +Razors 0

Added maps/horock1.map version [7e25f07bad607ab0]

1 +#####L###### 2 +#....R....A# 3 +#..........# 4 +#\. #@\ ..# 5 +#\...#* ### 6 +#\.........# 7 +#\..*.@....# 8 +####@@. ..# 9 +#....#.. ### 10 +#....#..**.# 11 +#.1..# .\\# 12 +############ 13 + 14 +Trampoline A targets 1

Added maps/horock2.map version [2fb25272ef9314ea]

1 +################# 2 +#A .@@@@@@# 3 +# .. #*...*1# 4 +# .##########*## 5 +# ..@ \\\\#* # 6 +# ..# #####*.# 7 +# .##### * # 8 +#LR ....... . # 9 +################# 10 + 11 +Trampoline A targets 1 12 +Flooding 10 13 +Water 0

Added maps/horock3.map version [d80af0f6153d8208]

1 +################# 2 +# \\\\# * * # 3 +# ## !!#..@. #### 4 +#* @...####.....# 5 +#\\ \@...........# 6 +#\ # .\@ # #.######## 7 +#\ # ..\@ # .. # 8 +#\ # .. \@ # .. # 9 +#\ # *.. \@ ####### # 10 +#\ # ### \@ # #W # 11 +### # \@ # ##L# 12 +#...#@@**@@**\@ # 13 +#R ..........!\## 14 +################# 15 + 16 +Growth 25

Modified score_memo.txt from [95f0626c958d6d31] to [0e695941ab7be6d2].

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 // 岩が落ちてきてデッドエンド 23 +beard5 665 // これクリアできるの 24 +horock1 333 25 +horock2 235 26 +horock3 1542

Modified src/Makefile from [01a4f7a0531dae71] to [de085b8055253640].

1 1 # To build, the following packages are needed. 2 -# wget http://ftp.digitalmars.com/dmd_2.059-0_i386.deb 3 -# sudo apt-get install gcc gcc-multilib 4 -# sudo pkg -i dmd_2.059-0_i386.deb 2 +# $ wget http://ftp.digitalmars.com/dmd_2.059-0_i386.deb 3 +# $ sudo apt-get install gcc gcc-multilib 4 +# $ sudo pkg -i dmd_2.059-0_i386.deb 5 +# 6 +# Optional GUI is Windows only. Need to install DFL (http://github.com/Rayerd/dfl). 7 + 8 +cui: 9 + dmd -O -release -inline -oflifter main.d driver.d game.d output.d solver.d util.d 10 + 11 +gui: 12 + dmd -O -release -inline -ofgui gui_main.d gui.d driver.d game.d output.d solver.d util.d 5 13 6 -all: 7 - dmd -O -release -inline -oflifter cui_auto_main.d driver.d game.d output.d solver.d util.d 14 +clean: 15 + rm *.obj *.o *.exe *.deps

Deleted src/cui_auto_main.d version [b38d60ea39d11e6e]

1 -import util; 2 -import game; 3 -import output; 4 -import driver; 5 -import solver; 6 - 7 -class CUI(Solver) : GameObserver 8 -{ 9 - this(in Game g) { solver = new Solver(g); } 10 - Solver solver; 11 - bool fin; 12 - override void on_game_changed(char c, in Game g, bool finished) 13 - { 14 - fin = finished; 15 - } 16 -} 17 - 18 -void main(string[] args) 19 -{ 20 - Driver d = new Driver(stdin); 21 - d.addObserver!(GuardedOutput)(); 22 - auto c = d.addObserver!(CUI!MainSolver)(); 23 - while(!c.fin) 24 - d.command(c.solver.single_step()); 25 -}

Modified src/game.d from [fc05481901940844] to [b141e39ade797d94].

6 6 { 7 7 public immutable int y, x; 8 8 mixin DeriveCreate; 9 9 mixin DeriveCompare; 10 10 mixin DeriveShow; 11 11 Pos clone() const { return cast(Pos) this; } 12 12 13 -@property: 13 +const @property: 14 14 Pos wait() { return this.clone(); } 15 15 Pos up() { return new Pos(y+1, x); } 16 16 Pos down() { return new Pos(y-1, x); } 17 17 Pos left() { return new Pos(y, x-1); } 18 18 Pos right() { return new Pos(y, x+1); } 19 19 alias wait W,w; 20 20 alias up U,u; ................................................................................ 39 39 40 40 //////////////////////////////////////////////////////////////////////////////// 41 41 42 42 class Water 43 43 { 44 44 public immutable int base, pace; 45 45 mixin DeriveCreate; 46 - mixin DeriveCompare; 47 46 mixin DeriveShow; 48 - Water clone() const { return cast(Water)this; } 47 + Water clone() const { return cast(Water) this; } 49 48 50 49 static load(string[string] params) 51 50 { 52 51 return new Water(params.get("Water", "0").to!int(), 53 52 params.get("Flooding", "0").to!int()); 54 53 } 55 54 56 - int level(int number_of_update) const 55 + int level(int turn) const 57 56 { 58 - return pace ? base+(number_of_update/pace) : base; 57 + return pace ? base+(turn/pace) : base; 59 58 } 60 59 61 - int until_rise(int number_of_update) const 60 + int until_rise(int turn) const 62 61 { 63 - return pace ? pace-number_of_update%pace : int.max; 62 + return pace ? pace-turn%pace : int.max; 64 63 } 65 64 } 66 65 67 66 unittest 68 67 { 69 68 Water w = new Water(1, 3); 70 69 assert( 1 == w.level(0) ); ................................................................................ 86 85 87 86 //////////////////////////////////////////////////////////////////////////////// 88 87 89 88 class Hige 90 89 { 91 90 public immutable int pace; 92 91 mixin DeriveCreate; 93 - mixin DeriveCompare; 94 92 mixin DeriveShow; 95 93 Hige clone() const { return cast(Hige)this; } 96 94 97 95 static load(string[string] params) 98 96 { 99 97 return new Hige(params.get("Growth", "25").to!int()); 100 98 } ................................................................................ 108 106 { 109 107 return pace ? pace-turn%pace : int.max; 110 108 } 111 109 } 112 110 113 111 //////////////////////////////////////////////////////////////////////////////// 114 112 115 -class Map 113 +class Trampoline 116 114 { 115 + private immutable char[] target_of_; 116 + private immutable char[][] source_of_; 117 + private immutable Pos[] position_of_; 118 + private immutable char[] source_list_; 119 + private immutable char[] target_list_; 117 120 mixin DeriveShow; 118 - 119 - static Map load(string[] raw_data, string[string] params, char[char] trampo) 121 + Trampoline clone() const { return cast(Trampoline) this; } 122 + this(Map m, char[char] tramparam) 120 123 { 121 - // TODO: choose optimal representation. 122 - return new Map(raw_data, params, trampo); 124 + auto ta = new char['I'+1]; 125 + auto sr = new char[]['9'+1]; 126 + auto po = new Pos[max('I','9')+1]; 127 + char[] sl, tl; 128 + foreach(fr,to; tramparam) { 129 + ta[fr] = to; 130 + sr[to] ~= fr; 131 + } 132 + for(int y=1; y<=m.H; ++y) 133 + for(int x=1; x<=m.W; ++x) { 134 + char c = m[y,x]; 135 + if('A'<=c && c<='I') { 136 + sl ~= c; 137 + po[c] = new Pos(y,x); 138 + } 139 + if('1'<=c && c<='9') { 140 + tl ~= c; 141 + po[c] = new Pos(y,x); 142 + } 143 + } 144 + target_of_ = cast(immutable) ta; 145 + source_of_ = cast(immutable) sr; 146 + position_of_ = cast(immutable) po; 147 + source_list_ = cast(immutable) sl; 148 + target_list_ = cast(immutable) tl; 123 149 } 124 150 151 +@property const: 152 + const(char[]) source_list() { return source_list_; } 153 + const(char[]) target_list() { return target_list_; } 154 + const(char[]) source_of(char c) { return source_of_[c]; } 155 + char target_of(char c) { return target_of_[c]; } 156 + Pos[] source_pos(char c) { 157 + Pos[] ps; 158 + foreach(s; source_of(c)) 159 + ps ~= position_of_[s].clone(); 160 + return ps; 161 + } 162 + Pos target_pos(char c) { return position_of_[target_of_[c]].clone(); } 163 +} 164 + 165 +//////////////////////////////////////////////////////////////////////////////// 166 + 167 +class Map 168 +{ 169 + mixin DeriveShow; 170 + 125 171 char[][] data; 126 172 Pos robot; 127 173 Pos lift; 128 174 int waterproof; 129 - Pos[char] tr_target; 130 - Pos[][char] tr_source; 131 - const(Hige) hige; 132 175 int razor; 176 + int collected_lambda; 177 + int total_lambda; 178 + bool cleared; 179 + Pos[] may_update; 133 180 134 181 Map clone() const { return new Map(this); } 135 182 this(in Map m) { 136 183 foreach(s; m.data) 137 184 this.data ~= s.dup; 138 185 this.robot = m.robot.clone(); 139 186 this.lift = m.lift.clone(); 140 187 this.waterproof = m.waterproof; 141 - this.tr_target = cast(Pos[char])m.tr_target; 142 - this.tr_source = cast(Pos[][char])m.tr_source; 143 - this.hige = m.hige.clone(); 144 188 this.razor = m.razor; 189 + this.collected_lambda = m.collected_lambda; 190 + this.total_lambda = m.total_lambda; 191 + this.may_update = (cast(Map)m).may_update.dup; 192 + this.cleared = m.cleared; 145 193 } 146 194 147 195 this(string[] raw_data, string[string] params, char[char] trampo) 148 196 { 149 197 int width = 0; 150 198 foreach(r; raw_data) 151 199 width = max(width, r.length); ................................................................................ 157 205 158 206 for(int y=1; y<=H; ++y) 159 207 for(int x=1; x<=W; ++x) { 160 208 if(this[y,x] == 'R') 161 209 this.robot = new Pos(y,x); 162 210 if(this[y,x] == 'L' || this[y,x] == 'O') 163 211 this.lift = new Pos(y,x); 164 - } 165 - 166 - Pos[char] tr_pos; 167 - for(int y=1; y<=H; ++y) 168 - for(int x=1; x<=W; ++x) { 169 - char c = this[y,x]; 170 - if('1'<=c && c<='9' || 'A'<=c&&c<='I') 171 - tr_pos[c] = new Pos(y,x); 212 + if(this[y,x] == '\\' || this[y,x] == '@') 213 + total_lambda++; 214 + if(this[y,x] == '*' || this[y,x] == '@') 215 + may_update ~= new Pos(y,x); 172 216 } 173 217 174 218 this.waterproof = params.get("Waterproof", "5").to!int(); 175 - foreach(fr,to; trampo) { 176 - tr_target[fr] = tr_pos[to]; 177 - if(to !in tr_source) tr_source[to] = []; 178 - tr_source[to] ~= tr_pos[fr]; 179 - } 180 - 181 - this.hige = Hige.load(params); 182 219 this.razor = params.get("Razors", "0").to!int(); 183 220 } 184 221 185 222 const @property { 186 223 int H() { return data.length; } 187 224 int W() { return data[0].length; } 188 225 } ................................................................................ 225 262 ans ~= new Pos(y,x); 226 263 return ans; 227 264 } 228 265 229 266 Pos[] razors() const { return objects('!'); } 230 267 Pos[] lambdas() const { return objects('\\'); } 231 268 232 - bool cleared() const 233 - { 234 - for(int y=1; y<=H; ++y) 235 - for(int x=1; x<=W; ++x) 236 - if(this[y,x] == 'L' || this[y,x] == 'O') 237 - return false; 238 - return true; 239 - } 240 - 241 - Tuple!(int,bool) command(char c, int turn) 269 + bool command(char c, int turn, bool hige_day, in Trampoline tr) 242 270 { 243 271 assert( this[robot] == 'R' ); 244 - if(c=='R') return move( 0, +1, turn); 245 - if(c=='L') return move( 0, -1, turn); 246 - if(c=='U') return move(+1, 0, turn); 247 - if(c=='D') return move(-1, 0, turn); 248 - if(c=='W') return move( 0, 0, turn); 249 - if(c=='S') return use_razor(turn); 272 + if(c=='R') return move( 0, +1, hige_day, tr); 273 + if(c=='L') return move( 0, -1, hige_day, tr); 274 + if(c=='U') return move(+1, 0, hige_day, tr); 275 + if(c=='D') return move(-1, 0, hige_day, tr); 276 + if(c=='W') return move( 0, 0, hige_day, tr); 277 + if(c=='S') return use_razor(hige_day); 250 278 assert(false); 251 279 } 252 280 253 - Tuple!(int, bool) use_razor(int turn) 281 + bool use_razor(bool hige_day) 254 282 { 255 283 if(razor) { 256 284 razor--; 257 285 for(int dy=-1; dy<=+1; ++dy) 258 286 for(int dx=-1; dx<=+1; ++dx) 259 - if(this[robot.y+dy,robot.x+dx] == 'W') 287 + if(this[robot.y+dy,robot.x+dx] == 'W') { 288 + emptified(new Pos(robot.y+dy,robot.x+dx)); 260 289 this[robot.y+dy,robot.x+dx] = ' '; 290 + } 261 291 } 262 292 263 - bool dead = update(turn); 264 - return tuple(0,dead); 293 + return update(hige_day); 265 294 } 266 295 267 - Tuple!(int, bool) move(int dy, int dx, int turn) 296 + bool rocky(char c) { return c=='*' || c=='@'; } 297 + 298 + void emptified(Pos p) { 299 + for(int dy=0; dy<=+1; ++dy) 300 + for(int dx=-1; dx<=+1; ++dx) 301 + may_update ~= new Pos(p.y+dy, p.x+dx); 302 + } 303 + 304 + bool move(int dy, int dx, bool hige_day, in Trampoline tr) 268 305 { 306 + emptified(robot); 307 + 269 308 int y = robot.y; 270 309 int x = robot.x; 271 - int lambda = 0; 272 310 if( '\\' == this[y+dy,x+dx] ) 273 - lambda++; 311 + collected_lambda++; 274 312 if( '!' == this[y+dy,x+dx] ) 275 313 razor++; 314 + if( 'O' == this[y+dy,x+dx] ) 315 + cleared = true; 276 316 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 277 317 this[y,x]=' '; 278 318 this[y+dy,x+dx]='R'; 279 319 robot = new Pos(y+dy,x+dx); 280 - } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx*2]) { 320 + } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+dx*2]) { 321 + char rock = this[y+dy,x+dx]; 281 322 this[y,x]=' '; 282 323 this[y+dy,x+dx]='R'; 283 - this[y+dy*2,x+dx*2]='*'; 324 + this[y+dy*2,x+dx*2]=rock; 284 325 robot = new Pos(y+dy,x+dx); 285 326 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { 286 327 this[y,x]=' '; 287 - Pos tp = tr_target[this[y+dy,x+dx]]; 288 - foreach(p; tr_source[this[tp]]) 328 + Pos tp = tr.target_pos(this[y+dy,x+dx]); 329 + foreach(p; tr.source_pos(this[tp])) { 330 + emptified(p); 289 331 this[p] = ' '; 332 + } 290 333 this[tp] = 'R'; 291 334 robot = tp; 292 335 } 293 - bool dead = update(turn); 294 - return tuple(lambda,dead); 336 + return update(hige_day); 295 337 } 296 338 297 - bool update(int turn) 339 + bool update(bool hige_day) 298 340 { 341 + // Write after all the updates are processed. 342 + Tuple!(int,int,char)[] write_buffer; 343 + void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); } 344 + void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c); } 345 + scope(exit) { 346 + may_update.length = 0; 347 + foreach(wr; write_buffer) { 348 + this[wr[0],wr[1]] = wr[2]; 349 + if(rocky(wr[2])) 350 + may_update ~= new Pos(wr[0],wr[1]); 351 + if(wr[2]==' ') 352 + emptified(new Pos(wr[0], wr[1])); 353 + } 354 + } 355 + 356 + if(collected_lambda == total_lambda) 357 + if(this[lift]=='L') 358 + this[lift] = 'O'; 359 + 299 360 bool dead = false; 361 + if( hige_day ) { 362 + for(int y=1; y<=H; ++y) 363 + for(int x=1; x<=W; ++x) 364 + if(this[y,x]=='W') 365 + may_update ~= new Pos(y,x); 366 + } 300 367 301 - char[][] next; 302 - foreach(y,s; data) 303 - next ~= s.dup; 304 - 305 - ref char access(Pos p) { return next[H-p.y][p.x-1]; } 306 - 307 - bool lambda = false; 308 - for(int y=1; y<=H; ++y) 309 - for(int x=1; x<=W; ++x) 310 - lambda |= (this[y,x] == '\\'); 311 - 312 - for(int y=1; y<=H; ++y) 313 - for(int x=1; x<=W; ++x) { 314 - Pos p = new Pos(y,x); 315 - if(this[p]=='*') { 368 + sort(may_update); 369 + foreach(p; may_update) { 370 + int y = p.y, x = p.x; 371 + char rock = this[p]; 372 + if(rocky(this[p])) { 316 373 if(this[p.D]==' ') { 317 - access(p) =' '; 318 - access(p.D)='*'; 374 + writep(p, ' '); 375 + writep(p.D, (rock=='@'&&this[p.D.D]!=' ' ? '\\' : rock)); 319 376 if(robot == p.D.D) 320 377 dead=true; 321 378 } 322 - else if((this[p.D]=='*' || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { 323 - access(p)=' '; 324 - access(p.R.D)='*'; 379 + else if((rocky(this[p.D]) || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { 380 + writep(p, ' '); 381 + writep(p.R.D,(rock=='@'&&this[p.R.D.D]!=' ' ? '\\' : rock)); 325 382 if(robot == p.R.D.D) 326 383 dead=true; 327 384 } 328 - else if(this[p.D]=='*' && this[p.L]==' ' && this[p.L.D]==' ') { 329 - access(p)=' '; 330 - access(p.L.D)='*'; 385 + else if(rocky(this[p.D]) && this[p.L]==' ' && this[p.L.D]==' ') { 386 + writep(p, ' '); 387 + writep(p.L.D, (rock=='@'&&this[p.L.D.D]!=' ' ? '\\' : rock)); 331 388 if(robot == p.L.D.D) 332 389 dead=true; 333 390 } 334 391 } 335 - else if(this[p]=='L') { 336 - if(!lambda) 337 - access(p) = 'O'; 338 - } 339 392 else if(this[p]=='W') { 340 - if( hige.is_growing_turn(turn) ) 393 + if(hige_day) { 341 394 for(int dy=-1; dy<=+1; ++dy) 342 395 for(int dx=-1; dx<=+1; ++dx) 343 396 if(this[p.y+dy,p.x+dx] == ' ') 344 - access(new Pos(p.y+dy,p.x+dx)) = 'W'; 397 + write(p.y+dy,p.x+dx,'W'); 398 + } 345 399 } 346 400 } 347 - data = next; 401 + 348 402 return dead; 349 403 } 350 404 } 351 405 352 406 //////////////////////////////////////////////////////////////////////////////// 353 407 354 408 class Game 355 409 { 356 -public: 410 + mixin DeriveShow; 411 + 357 412 this(File input) 358 413 { 359 - // Read map data 360 - string[] map_data_lines; 361 - for(string line; !(line=input.readln().chomp()).empty; ) 362 - map_data_lines ~= line; 414 + string[] raw_data; 415 + string[string] params; 363 416 364 - // H*W 365 - H_ = map_data_lines.length; 366 - W_ = 0; 367 - foreach(mdl; map_data_lines) 368 - W_ = max(W_, mdl.length); 417 + // Raw map data; read until empty line. 418 + for(string line; !(line=input.readln().chomp()).empty; ) 419 + raw_data ~= line; 369 420 370 - // Copy to modifiable buffer and adjust coordinates. 371 - raw_data_ = new char[][H_+1]; 372 - foreach(i,mdl; map_data_lines) { 373 - char[] buf = new char[mdl.length+1]; 374 - buf[0] = '#'; 375 - buf[1..$] = mdl[]; 376 - raw_data_[H_-i] = buf; 377 - } 378 - 379 - // Detect objects 380 - for(int y=1; y<=H_; ++y) 381 - for(int x=1; x<raw_data_[y].length; ++x) 382 - { 383 - char c = raw_data_[y][x]; 384 - switch(c) 385 - { 386 - case '#': 387 - case '.': 388 - case ' ': 389 - break; 390 - case 'L': 391 - case 'O': 392 - lift_pos_ = new Pos(y,x); 393 - break; 394 - case 'A': .. case 'I': 395 - case '1': .. case '9': 396 - trampoline_pos_[c] = new Pos(y,x); 397 - break; 398 - case '!': 399 - razor_pos_ ~= new Pos(y,x); 400 - break; 401 - case '\\': 402 - lambda_pos_ ~= new Pos(y,x); 403 - break; 404 - 405 - // Moving objects are erased from raw_data_ 406 - case 'R': 407 - robot_pos_ = new Pos(y,x); 408 - raw_data_[y][x] = ' '; 409 - break; 410 - case '*': 411 - case 'W': 412 - dynamic_objects_[new Pos(y,x)] = c; 413 - raw_data_[y][x] = ' '; 414 - if(c=='*') 415 - may_update_[new Pos(y,x)] = true; 416 - break; 417 - default: 418 - assert(false); 419 - } 421 + // Additional commands; read until EOF. 422 + char[char] trampo; 423 + for(string line; !(line=input.readln()).empty; ) { 424 + string[] ss = line.split(); 425 + if( ss.length == 2 ) 426 + params[ss[0]] = ss[1]; 427 + if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" ) 428 + trampo[ss[1][0]] = ss[3][0]; 420 429 } 421 430 422 - // Read other parameters 423 - for(string line; !(line=input.readln()).empty; ) 424 - { 425 - string[] ss = line.split(); 426 - if( ss.length == 2 ) 427 - switch(ss[0]) 428 - { 429 - case "Water": water_base_ = ss[1].to!int(); break; 430 - case "Flooding": water_pace_ = ss[1].to!int(); break; 431 - case "Waterproof": max_air_ = ss[1].to!int(); break; 432 - case "Growth": hige_pace_ = ss[1].to!int(); break; 433 - case "Razors": num_razor_ = ss[1].to!int(); break; 434 - default: assert(false); 435 - } 436 - if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" ) 437 - { 438 - char fr=ss[1][0], to=ss[3][0]; 439 - trampoline_[fr] = to; 440 - if(to !in trampoline_rev_) trampoline_rev_[to] = []; 441 - trampoline_rev_[to] ~= fr; 442 - } 443 - } 431 + this.map = new Map(raw_data, params, trampo); 432 + this.water = Water.load(params); 433 + this.hige = Hige.load(params); 434 + this.tr = new Trampoline(this.map, trampo); 435 + } 444 436 445 - air_left_ = max_air_; 437 + Game clone() const { return new Game(this); } 438 + this(in Game g) { 439 + map = g.map.clone(); 440 + water = g.water.clone(); 441 + hige = g.hige.clone(); 442 + tr = g.tr.clone(); 443 + turn = g.turn; 444 + dead = g.dead; 445 + under_water = g.under_water; 446 446 } 447 447 448 - @property const { 449 - int H() { return H_; } 450 - int W() { return W_; } 451 - char trampoline(char c) { return (c in trampoline_ ? trampoline_[c] : 0); } 452 - const(Pos)[] trampoline_rev(char c) { 453 - const(Pos)[] pp; 454 - if(c in trampoline_rev_) { 455 - foreach(ch; trampoline_rev_[c]) 456 - pp ~= trampoline_pos_[ch]; 457 - } 458 - return pp; 459 - } 460 - int water_level() { 461 - return water_pace_ ? water_base_ + turn_/water_pace_ : water_base_; 462 - } 463 - int water_until_rise() { 464 - return water_pace_ ? water_pace_ - turn_%water_pace_ : int.max; 465 - } 466 - int hige_until_rise() { 467 - return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.max; 468 - } 469 - bool is_hige_turn() { 470 - return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : false; 471 - } 472 - int hp() { return air_left_; } 473 - int num_razor() { return num_razor_; } 474 - bool cleared() { return cleared_; } 475 - bool dead() { return dead_; } 476 - long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L : 50L) - turn_; } 477 - const(Pos) robot() { return robot_pos_; } 478 - const(Pos) lift() { return lift_pos_; } 479 - Pos[] lambdas() { 480 - Pos[] pp; 481 - foreach(p; lambda_pos_) 482 - pp ~= p.clone(); 483 - return pp; 484 - } 485 - Pos[] razors() { 486 - Pos[] pp; 487 - foreach(p; razor_pos_) 488 - pp ~= p.clone(); 489 - return pp; 490 - } 491 - const(Pos)[] higes() { 492 - const(Pos)[] pp; 493 - foreach(p,c; dynamic_objects_) 494 - if(c=='W') 495 - pp ~= p; 496 - return pp; 497 - } 498 - } 499 - const { 500 - char opIndex(in Pos p) { return opIndex(p.y, p.x); } 501 - char opIndex(int y, int x) { return map_get(y, x); } 502 - } 503 - 504 -public: 505 448 void command(char c) 506 449 { 450 + assert(c != 'A'); 507 451 if(dead || cleared) 508 452 return; 509 453 510 - if(c == 'U') command_move(+1, 0); 511 - if(c == 'D') command_move(-1, 0); 512 - if(c == 'L') command_move(0, -1); 513 - if(c == 'R') command_move(0, +1); 514 - if(c == 'S') use_razor(); 515 - if(c == 'W') {} 516 - 517 - if(!cleared) 518 - { 519 - map_update(); 520 - water_update(); 454 + // TODO: clarify the event order 455 + bool dead_now = map.command(c, turn, hige.is_growing_turn(turn), tr); 456 + if( dead_now ) 457 + dead = true; 458 + if(!map.cleared) { 459 + if( map.robot.y <= water_level ) 460 + ++under_water; 461 + else 462 + under_water = 0; 463 + if( under_water > map.waterproof ) 464 + dead = true; 521 465 } 522 - turn_ ++; 466 + turn += 1; 523 467 } 524 468 525 - void command_move(int dy, int dx) 526 - { 527 - int y = robot_pos_.y, x = robot_pos_.x; 528 - char c = this[y+dy, x+dx]; 529 - Pos p = new Pos(y+dy, x+dx); 530 - 531 - switch(c){ 532 - case 'O': 533 - cleared_ = true; 534 - move_robot_to(p); 535 - break; 536 - case '\\': 537 - take_lambda_at(p); 538 - move_robot_to(p); 539 - break; 540 - case '!': 541 - take_razor_at(p); 542 - move_robot_to(p); 543 - break; 544 - case 'A': .. case 'I': 545 - enter_trampoline_at(p, c); 546 - break; 547 - case ' ': 548 - case '.': 549 - move_robot_to(p); 550 - break; 551 - case '*': 552 - if(dy!=0 || this[y,x+dx*2]!=' ') 553 - break; 554 - move_robot_to(p); 555 - push_rock(p, new Pos(y,x+dx*2)); 556 - break; 557 - default: 558 - break; 559 - } 560 - } 561 - 562 - void use_razor() 563 - { 564 - if(num_razor_ == 0) 565 - return; 566 - num_razor_ --; 567 - 568 - for(int dy=-1; dy<=+1; ++dy) 569 - for(int dx=-1; dx<=+1; ++dx) if(dy||dx) 570 - { 571 - Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx); 572 - if(auto it = p in dynamic_objects_) 573 - if(*it == 'W') { 574 - something_gone(p); 575 - dynamic_objects_.remove(p); 576 - } 577 - } 578 - } 579 - 580 - void take_lambda_at(Pos p) 581 - { 582 - map_set_empty(p); 583 - num_lambda_ ++; 584 - lambda_pos_ = lambda_pos_.erase(p); 585 - } 586 - 587 - void take_razor_at(Pos p) 588 - { 589 - map_set_empty(p); 590 - num_razor_ ++; 591 - razor_pos_ = razor_pos_.erase(p); 592 - } 593 - 594 - void enter_trampoline_at(Pos p, char c) 595 - { 596 - char d = trampoline(c); 597 - foreach(cc; trampoline_rev_[d]) { 598 - Pos pp = trampoline_pos_[cc]; 599 - something_gone(pp); 600 - map_set_empty(pp); 601 - } 602 - move_robot_to(trampoline_pos_[d]); 603 - } 604 - 605 - void move_robot_to(Pos p) 606 - { 607 - something_gone(robot_pos_); 608 - map_set_empty(p.y, p.x); 609 - robot_pos_ = p; 610 - } 611 - 612 - void push_rock(Pos fr, Pos to) 613 - { 614 - dynamic_objects_.remove(fr); 615 - dynamic_objects_[to] = '*'; 616 - may_update_[to] = true; 617 - } 618 - 619 - void something_gone(Pos p) 620 - { 621 - for(int dy=0; dy<=+1; ++dy) 622 - for(int dx=-1; dx<=+1; ++dx) if(dy||dx) 623 - may_update_[new Pos(p.y+dy,p.x+dx)] = true; 624 - } 469 + Map map; 470 + Water water; 471 + Hige hige; 472 + Trampoline tr; 473 + int turn = 0; 474 + bool dead = false; 475 + int under_water = 0; 476 + // TODO: when adding members, take care of clone(). 477 + // TODO: fix this poor design. 625 478 626 - void map_update() 627 - { 628 - Pos[] may_update_list; 629 - foreach(p,_; may_update_) 630 - if(this[p] == '*') 631 - may_update_list ~= p; 632 - may_update_ = null; 633 - 634 - if( is_hige_turn() ) 635 - foreach(p,c; dynamic_objects_) 636 - if(c == 'W') 637 - may_update_list ~= p; 638 - 639 - sort(may_update_list); 640 - char[Pos] to_be_written; 641 - foreach(p; may_update_list) 642 - if(is_hige_turn() && this[p]=='W') 643 - { 644 - for(int dy=-1; dy<=+1; ++dy) 645 - for(int dx=-1; dx<=+1; ++dx) { 646 - Pos q = new Pos(p.y+dy,p.x+dx); 647 - if( this[q] == ' ' ) 648 - to_be_written[q] = 'W'; 649 - } 650 - } 651 - else 652 - { 653 - int y = p.y; 654 - int x = p.x; 655 - char below = this[y-1,x]; 656 - // * 657 - // _ 658 - if(below==' ') { 659 - Pos q = new Pos(y-1,x); 660 - to_be_written[p] = ' '; 661 - to_be_written[q] = '*'; 662 - may_update_[q] = true; 663 - } 664 - // *_ *_ 665 - // *_ or \_ 666 - else if((below=='*'||below=='\\')&&this[y-1,x+1]==' '&&this[y,x+1]==' ') { 667 - Pos q = new Pos(y-1,x+1); 668 - to_be_written[p] = ' '; 669 - to_be_written[q] = '*'; 670 - may_update_[q] = true; 671 - } 672 - // _* 673 - // _* 674 - else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x-1]==' ') { 675 - Pos q = new Pos(y-1,x-1); 676 - to_be_written[p] = ' '; 677 - to_be_written[q] = '*'; 678 - may_update_[q] = true; 679 - } 680 - } 681 - 682 - foreach(p,c; to_be_written) { 683 - dynamic_objects_[p] = c; 684 - if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x) 685 - dead_ = true; 686 - } 687 - 688 - if(lambda_pos_.empty) 689 - raw_data_[lift_pos_.y][lift_pos_.x] = 'O'; 690 - } 691 - 692 - void water_update() 693 - { 694 - if( robot_pos_.y <= water_level() ) 695 - air_left_ --; 696 - else 697 - air_left_ = max_air_; 698 - if( air_left_ < 0 ) 699 - dead_ = true; 700 - } 701 - 702 -private: 703 - char map_get(int y, int x) const 704 - { 705 - if( y<1 || H<y || x<1 || W<x ) return '#'; 706 - Pos p = new Pos(y,x); 707 - if(p == robot_pos_) 708 - return 'R'; 709 - if(auto it = (p in dynamic_objects_)) 710 - return *it; 711 - if( x<0 || raw_data_[y].length<=x ) return ' '; 712 - return raw_data_[y][x]; 713 - } 714 - 715 - void map_set_empty(in Pos p) 716 - { 717 - return map_set_empty(p.y, p.x); 718 - } 719 - 720 - void map_set_empty(int y, int x) 721 - { 722 - if( y<1 || H<y || x<1 || W<x ) return; 723 - if( x<0 || raw_data_[y].length<=x ) return; 724 - raw_data_[y][x] = ' '; 725 - } 726 - 727 -public: 728 - Game clone() const { return new Game(this); } 729 - this(in Game g) { 730 - H_ = g.H_; 731 - W_ = g.W_; 732 - raw_data_ = new char[][g.raw_data_.length]; 733 - foreach(i,d; g.raw_data_) raw_data_[i] = d.dup; 734 - trampoline_pos_ = cast(Pos[char]) g.trampoline_pos_; 735 - razor_pos_ = (cast(Game)g).razor_pos_.dup; 736 - lambda_pos_ = (cast(Game)g).lambda_pos_.dup; 737 - lift_pos_ = g.lift_pos_.clone(); 738 - robot_pos_ = g.robot_pos_.clone(); 739 - dynamic_objects_ = dup(g.dynamic_objects_); 740 - trampoline_ = (cast(Game)g).trampoline_; 741 - trampoline_rev_ = (cast(Game)g).trampoline_rev_; 742 - water_base_ = g.water_base_; 743 - water_pace_ = g.water_pace_; 744 - max_air_ = g.max_air_; 745 - hige_pace_ = g.hige_pace_; 746 - num_razor_ = g.num_razor_; 747 - num_lambda_ = g.num_lambda_; 748 - turn_ = g.turn_; 749 - air_left_ = g.air_left_; 750 - cleared_ = g.cleared_; 751 - dead_ = g.dead_; 752 - may_update_ = dup(g.may_update_); 753 - } 754 - 755 - V[K] dup(V,K)(in V[K] aa) { 756 - V[K] aa2; 757 - foreach(k,v; aa) aa2[k] = v; 758 - return aa2; 759 - } 760 - 761 -private: 762 - int H_; 763 - int W_; 764 - char[][] raw_data_; 765 - Pos[char] trampoline_pos_; 766 - Pos[] razor_pos_; 767 - Pos[] lambda_pos_; 768 - Pos lift_pos_; 769 - Pos robot_pos_; 770 - char[Pos] dynamic_objects_; 771 - char[char] trampoline_; 772 - char[][char] trampoline_rev_; 773 - int water_base_ = 0; 774 - int water_pace_ = 0; 775 - int max_air_ = 10; 776 - int hige_pace_ = 25; 777 - int num_razor_ = 0; 778 - int num_lambda_ = 0; 779 - 780 - int turn_ = 0; 781 - int air_left_ = 0; 782 - bool cleared_ = false; 783 - bool dead_ = false; 784 - bool[Pos] may_update_; 479 +@property const: 480 + long score() { return map.collected_lambda*(dead?25L:cleared?75L:50L)-turn; } 481 + int water_level() { return water.level(turn); } 482 + int water_until_rise() { return water.until_rise(turn); } 483 + int hige_until_rise() { return hige.until_rise(turn); } 484 + int hp() { return map.waterproof - under_water; } 485 + bool cleared() { return map.cleared; } 785 486 }

Modified src/gui.d from [e84cacd6262f93a7] to [93d9f5f261f71d2c].

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 - private void delegate(char c) fn; 17 - void set_fn(F)(F f) { this.fn = f; } 18 - 19 - void run(bool automate = false) 16 + void run(void delegate(char c) command, bool automate = true) 20 17 { 21 18 if(automate) { 22 19 Timer t = new Timer; 23 20 t.interval = 50; 24 - t.tick ~= (Timer sender, EventArgs ea){ 25 - fn(solver.single_step()); 26 - }; 21 + t.tick ~= (Timer s, EventArgs e){command(solver.single_step());}; 27 22 t.start(); 28 23 this.closing ~= (Form f,CancelEventArgs c){t.stop();}; 29 24 } else { 30 - setup_keyhandling(); 25 + setup_keyhandling(command); 31 26 } 32 27 Application.run(this); 33 28 } 34 29 35 30 override void on_game_changed(char c, in Game g, bool finished) 36 31 { 37 32 draw(g); 38 33 } 39 34 40 35 private: 41 - int cell; 42 - 43 36 void setup_size(int W, int H) 44 37 { 45 38 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; 46 39 this.maximizeBox = false; 47 40 this.minimizeBox = false; 48 41 this.cell = min(1024/W, 640/H); 49 42 this.clientSize = Size(W*cell, H*cell); 50 43 } 51 44 45 + int cell; 52 46 Font font; 53 47 Color[char] colors; 54 48 string[char] render; 55 49 Graphics graphicContext; 56 50 57 51 void setup_resources(in Game g) 58 52 { 59 53 this.graphicContext = new MemoryGraphics(this.clientSize.width, this.clientSize.height); 60 54 this.setStyle(ControlStyles.OPAQUE, true); 61 55 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 62 56 this.backColor = Color(255,255,255); 63 57 this.colors['#'] = 64 58 this.colors['.'] = Color(255,191,127); 65 - this.colors['*'] = Color(255,127,127); 59 + this.colors['*'] = 60 + this.colors['@'] = Color(255,127,127); 66 61 this.colors['R'] = Color(128,128,0); 62 + this.colors['r'] = Color(100,128,255); 67 63 this.colors['d'] = Color(255,0,0); 68 64 this.colors['\\'] = 69 65 this.colors['L'] = 70 66 this.colors['O'] = Color(127,255,127); 71 67 this.colors['w'] = Color(204,229,255); 72 68 this.colors['W'] = 73 69 this.colors['!'] = Color(159,159,159); 74 70 foreach(char c; 'A'..'J') this.colors[c] = Color(142,142,255); 75 71 foreach(char c; '1'..':') this.colors[c] = Color(255,142,255); 76 72 this.render['#'] = "■"; 77 73 this.render['*'] = "✹"; 74 + this.render['@'] = "❁"; 78 75 this.render['.'] = "♒"; 79 76 this.render['\\'] = "λ"; 80 77 this.render['R'] = "☃"; 78 + this.render['r'] = "☃"; 81 79 this.render['d'] = "☠"; 82 80 this.render['L'] = "☒"; 83 81 this.render['O'] = "☐"; 84 82 this.render['W'] = "ꔣ"; 85 83 this.render['!'] = "✄"; 86 - foreach(char c; 'A'..'J') this.render[c] = [cast(dchar)('☢'+g.trampoline(c)-'1')].to!string(); 87 - foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1')].to!string(); 84 + foreach(char c; g.tr.source_list) 85 + this.render[c] = [cast(dchar)('☢'+g.tr.target_of(c)-'1')].to!string(); 86 + foreach(char c; g.tr.target_list) 87 + this.render[c] = [cast(dchar)('☢'+c-'1')].to!string(); 88 88 this.paint ~= (Control c, PaintEventArgs ev) { 89 89 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clientSize.height)); 90 90 }; 91 91 } 92 92 93 93 void draw(in Game g) 94 94 { ................................................................................ 99 99 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH)); 100 100 101 101 // Fill water. 102 102 int w = g.water_level(); 103 103 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell*w-1, scrW, cell*w+1)); 104 104 105 105 // Paint map. 106 - for(int y=1; y<=g.H; ++y) 107 - for(int x=1; x<=g.W; ++x) { 106 + for(int y=1; y<=g.map.H; ++y) 107 + for(int x=1; x<=g.map.W; ++x) { 108 108 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 109 - char c = g[y,x]; 109 + char c = g.map[y,x]; 110 110 if( c != ' ' ) { 111 - if( c == 'R' && g.dead ) 112 - c = 'd'; 111 + if( c == 'R' ) 112 + c = (g.dead ? 'd' : g.cleared ? 'r' : 'R'); 113 113 graphicContext.drawText(this.render[c], font, this.colors[c], r); 114 114 } 115 115 } 116 116 117 117 // Update textual info. 118 118 this.text = .text( 119 119 "Score: ", g.score, 120 120 " Air: ", g.hp, 121 121 " Tide: ", g.water_until_rise, 122 122 " Wadler: ", g.hige_until_rise, 123 - " Razor: ", g.num_razor); 123 + " Razor: ", g.map.razor); 124 124 invalidate(); 125 125 } 126 126 127 127 private: 128 - void setup_keyhandling() 128 + void setup_keyhandling(void delegate(char c) command) 129 129 { 130 130 noMessageFilter(); 131 - this.keyDown ~= &my_keydown; 132 - } 133 - 134 - void do_manual_command(char c) 135 - { 136 - solver.force(c); 137 - fn(c); 138 - } 139 - 140 - void my_keydown(Control c, KeyEventArgs ev) 141 - { 142 - switch(ev.keyCode) 143 - { 144 - case Keys.DOWN: do_manual_command('D'); break; 145 - case Keys.UP: do_manual_command('U'); break; 146 - case Keys.LEFT: do_manual_command('L'); break; 147 - case Keys.RIGHT: do_manual_command('R'); break; 148 - case Keys.W: do_manual_command('W'); break; 149 - case Keys.S: do_manual_command('S'); break; 150 - case Keys.A: do_manual_command('A'); break; 151 - case Keys.G: fn(solver.single_step()); break; 152 - default: break; 153 - } 131 + this.keyDown ~= (Control c, KeyEventArgs ev) { 132 + void do_manual_command(char c) 133 + { 134 + solver.force(c); 135 + command(c); 136 + } 137 + switch(ev.keyCode) 138 + { 139 + case Keys.DOWN: do_manual_command('D'); break; 140 + case Keys.UP: do_manual_command('U'); break; 141 + case Keys.LEFT: do_manual_command('L'); break; 142 + case Keys.RIGHT: do_manual_command('R'); break; 143 + case Keys.W: do_manual_command('W'); break; 144 + case Keys.S: do_manual_command('S'); break; 145 + case Keys.A: do_manual_command('A'); break; 146 + case Keys.G: command(solver.single_step()); break; 147 + default: break; 148 + } 149 + }; 154 150 } 155 151 156 152 Solver solver; 157 153 }

Modified src/gui_main.d from [05082d0f328d756c] to [4124e840a1a49af9].

1 +import util; 1 2 import gui; 2 3 import output; 3 4 import driver; 4 5 import solver; 5 -import std.stdio; 6 6 pragma(lib, "dfl.lib"); 7 7 8 -void main(string[] args) 8 +void main(string[] argv) 9 9 { 10 - Driver d = new Driver(stdin); 10 + bool automate = (argv.length>=2 && std.string.indexOf(argv[1],"auto")>=0); 11 + 12 + auto d = new Driver(stdin); 11 13 d.addObserver!(GuardedOutput)(); 12 - auto g = d.addObserver!(GUI!MainSolver)(); 13 - g.set_fn(&d.command); 14 - g.run(); 14 + d.addObserver!(GUI!MainSolver)().run(&d.command, automate); 15 15 }

Added src/main.d version [f6cab5c23c5cba1e]

1 +import util; 2 +import game; 3 +import output; 4 +import driver; 5 +import solver; 6 + 7 +class CUI(Solver) : GameObserver 8 +{ 9 + this(in Game g) { solver = new Solver(g); } 10 + Solver solver; 11 + bool fin; 12 + override void on_game_changed(char c, in Game g, bool finished) { fin = finished; } 13 +} 14 + 15 +void main() 16 +{ 17 + auto d = new Driver(stdin); 18 + d.addObserver!(GuardedOutput)(); 19 + auto c = d.addObserver!(CUI!MainSolver)(); 20 + while(!c.fin) 21 + d.command(c.solver.single_step()); 22 +}

Modified src/output.d from [e2d0d7db868c3a44] to [95ed42a2d89e1fef].

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 + if(log.length+1==g.map.W*g.map.H) 41 + application_exit(); 40 42 } 41 43 42 44 private: 43 45 string log; 44 46 long[] score_log; 45 47 bool flushed; 46 48

Modified src/solver.d from [22c356ff1975e92f] to [4dfcc976e17caad5].

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

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 {