Check-in Differences
Not logged in

Difference From:

[d40deaae5a] Trampoline factored out. (user: kinaba, tags: trunk, date: 2012-07-15 15:38:46)

To:

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

Deleted 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

Deleted 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

Deleted 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

Deleted 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

Deleted 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 [0e695941ab7be6d2] to [95f0626c958d6d31].

1 1 contest1 212! 2 2 contest2 280? 3 3 contest3 275! 4 4 contest4 561? 5 5 contest5 1281? 6 -contest6 737 // 一度通り過ぎるとふさがってしまう曲がり道 6 +contest6 737 // deadend trap 7 7 contest7 867? 8 -contest8 1245 // 無理ゲー 8 +contest8 1245 // tricky 9 9 contest9 3042? 10 -contest10 2076 // "λの上に岩" トラップが複数 11 -flood1 569 // 崩すの怖がりすぎ & 一直線に並んでるのに真ん中から取るのはどうなの 10 +contest10 2076 // * on lambda, must move * first 11 +flood1 569 // too slow, because of 1-left danger lambda 12 12 flood2 280? 13 -flood3 802 // 溺死 14 -flood4 970 // むずかしい岩崩し 13 +flood3 802 // too slow, drown 14 +flood4 970 // incorrect order of digging 15 15 flood5 561? 16 -trampoline1 291 // むずかしい岩崩し 16 +trampoline1 291 // * on trampoline. must move * first 17 17 trampoline2 1728? 18 -trampoline3 698 // "上に岩" ワープゾーン版 18 +trampoline3 698 // * on trampoline target. must move * first. 19 19 beard1 856? 20 -beard2 2792 // 崩すの怖がりすぎて間に合わなくなって溺死 21 -beard3 811 // 無理ゲー:速攻で髭刈らないといけない 22 -beard4 677 // 岩が落ちてきてデッドエンド 23 -beard5 665 // これクリアできるの 24 -horock1 333 25 -horock2 235 26 -horock3 1542 20 +beard2 2792 // hutsu-ni muzui 21 +beard3 811 // tricky. must hurry to cut hige. 22 +beard4 677 // deadend trap

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

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 5 -# 6 -# Optional GUI is Windows only. Need to install DFL (http://github.com/Rayerd/dfl). 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 7 5 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 13 - 14 -clean: 15 - rm *.obj *.o *.exe *.deps 6 +all: 7 + dmd -O -release -inline -oflifter cui_auto_main.d driver.d game.d output.d solver.d util.d

Added 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 [b141e39ade797d94] to [fc05481901940844].

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 -const @property: 13 +@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; 46 47 mixin DeriveShow; 47 - Water clone() const { return cast(Water) this; } 48 + Water clone() const { return cast(Water)this; } 48 49 49 50 static load(string[string] params) 50 51 { 51 52 return new Water(params.get("Water", "0").to!int(), 52 53 params.get("Flooding", "0").to!int()); 53 54 } 54 55 55 - int level(int turn) const 56 + int level(int number_of_update) const 56 57 { 57 - return pace ? base+(turn/pace) : base; 58 + return pace ? base+(number_of_update/pace) : base; 58 59 } 59 60 60 - int until_rise(int turn) const 61 + int until_rise(int number_of_update) const 61 62 { 62 - return pace ? pace-turn%pace : int.max; 63 + return pace ? pace-number_of_update%pace : int.max; 63 64 } 64 65 } 65 66 66 67 unittest 67 68 { 68 69 Water w = new Water(1, 3); 69 70 assert( 1 == w.level(0) ); ................................................................................ 85 86 86 87 //////////////////////////////////////////////////////////////////////////////// 87 88 88 89 class Hige 89 90 { 90 91 public immutable int pace; 91 92 mixin DeriveCreate; 93 + mixin DeriveCompare; 92 94 mixin DeriveShow; 93 95 Hige clone() const { return cast(Hige)this; } 94 96 95 97 static load(string[string] params) 96 98 { 97 99 return new Hige(params.get("Growth", "25").to!int()); 98 100 } ................................................................................ 106 108 { 107 109 return pace ? pace-turn%pace : int.max; 108 110 } 109 111 } 110 112 111 113 //////////////////////////////////////////////////////////////////////////////// 112 114 113 -class Trampoline 115 +class Map 114 116 { 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_; 120 117 mixin DeriveShow; 121 - Trampoline clone() const { return cast(Trampoline) this; } 122 - this(Map m, char[char] tramparam) 118 + 119 + static Map load(string[] raw_data, string[string] params, char[char] trampo) 123 120 { 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; 121 + // TODO: choose optimal representation. 122 + return new Map(raw_data, params, trampo); 149 123 } 150 124 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 - 171 125 char[][] data; 172 126 Pos robot; 173 127 Pos lift; 174 128 int waterproof; 129 + Pos[char] tr_target; 130 + Pos[][char] tr_source; 131 + const(Hige) hige; 175 132 int razor; 176 - int collected_lambda; 177 - int total_lambda; 178 - bool cleared; 179 - Pos[] may_update; 180 133 181 134 Map clone() const { return new Map(this); } 182 135 this(in Map m) { 183 136 foreach(s; m.data) 184 137 this.data ~= s.dup; 185 138 this.robot = m.robot.clone(); 186 139 this.lift = m.lift.clone(); 187 140 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(); 188 144 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; 193 145 } 194 146 195 147 this(string[] raw_data, string[string] params, char[char] trampo) 196 148 { 197 149 int width = 0; 198 150 foreach(r; raw_data) 199 151 width = max(width, r.length); ................................................................................ 205 157 206 158 for(int y=1; y<=H; ++y) 207 159 for(int x=1; x<=W; ++x) { 208 160 if(this[y,x] == 'R') 209 161 this.robot = new Pos(y,x); 210 162 if(this[y,x] == 'L' || this[y,x] == 'O') 211 163 this.lift = 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); 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); 216 172 } 217 173 218 174 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); 219 182 this.razor = params.get("Razors", "0").to!int(); 220 183 } 221 184 222 185 const @property { 223 186 int H() { return data.length; } 224 187 int W() { return data[0].length; } 225 188 } ................................................................................ 262 225 ans ~= new Pos(y,x); 263 226 return ans; 264 227 } 265 228 266 229 Pos[] razors() const { return objects('!'); } 267 230 Pos[] lambdas() const { return objects('\\'); } 268 231 269 - bool command(char c, int turn, bool hige_day, in Trampoline tr) 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) 270 242 { 271 243 assert( this[robot] == 'R' ); 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); 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); 278 250 assert(false); 279 251 } 280 252 281 - bool use_razor(bool hige_day) 253 + Tuple!(int, bool) use_razor(int turn) 282 254 { 283 255 if(razor) { 284 256 razor--; 285 257 for(int dy=-1; dy<=+1; ++dy) 286 258 for(int dx=-1; dx<=+1; ++dx) 287 - if(this[robot.y+dy,robot.x+dx] == 'W') { 288 - emptified(new Pos(robot.y+dy,robot.x+dx)); 259 + if(this[robot.y+dy,robot.x+dx] == 'W') 289 260 this[robot.y+dy,robot.x+dx] = ' '; 290 - } 291 261 } 292 262 293 - return update(hige_day); 263 + bool dead = update(turn); 264 + return tuple(0,dead); 294 265 } 295 266 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) 267 + Tuple!(int, bool) move(int dy, int dx, int turn) 305 268 { 306 - emptified(robot); 307 - 308 269 int y = robot.y; 309 270 int x = robot.x; 271 + int lambda = 0; 310 272 if( '\\' == this[y+dy,x+dx] ) 311 - collected_lambda++; 273 + lambda++; 312 274 if( '!' == this[y+dy,x+dx] ) 313 275 razor++; 314 - if( 'O' == this[y+dy,x+dx] ) 315 - cleared = true; 316 276 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 317 277 this[y,x]=' '; 318 278 this[y+dy,x+dx]='R'; 319 279 robot = new Pos(y+dy,x+dx); 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]; 280 + } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx*2]) { 322 281 this[y,x]=' '; 323 282 this[y+dy,x+dx]='R'; 324 - this[y+dy*2,x+dx*2]=rock; 283 + this[y+dy*2,x+dx*2]='*'; 325 284 robot = new Pos(y+dy,x+dx); 326 285 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { 327 286 this[y,x]=' '; 328 - Pos tp = tr.target_pos(this[y+dy,x+dx]); 329 - foreach(p; tr.source_pos(this[tp])) { 330 - emptified(p); 287 + Pos tp = tr_target[this[y+dy,x+dx]]; 288 + foreach(p; tr_source[this[tp]]) 331 289 this[p] = ' '; 332 - } 333 290 this[tp] = 'R'; 334 291 robot = tp; 335 292 } 336 - return update(hige_day); 293 + bool dead = update(turn); 294 + return tuple(lambda,dead); 337 295 } 338 296 339 - bool update(bool hige_day) 297 + bool update(int turn) 340 298 { 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 - 360 299 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 - } 367 300 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])) { 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]=='*') { 373 316 if(this[p.D]==' ') { 374 - writep(p, ' '); 375 - writep(p.D, (rock=='@'&&this[p.D.D]!=' ' ? '\\' : rock)); 317 + access(p) =' '; 318 + access(p.D)='*'; 376 319 if(robot == p.D.D) 377 320 dead=true; 378 321 } 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)); 322 + else if((this[p.D]=='*' || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { 323 + access(p)=' '; 324 + access(p.R.D)='*'; 382 325 if(robot == p.R.D.D) 383 326 dead=true; 384 327 } 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)); 328 + else if(this[p.D]=='*' && this[p.L]==' ' && this[p.L.D]==' ') { 329 + access(p)=' '; 330 + access(p.L.D)='*'; 388 331 if(robot == p.L.D.D) 389 332 dead=true; 390 333 } 334 + } 335 + else if(this[p]=='L') { 336 + if(!lambda) 337 + access(p) = 'O'; 391 338 } 392 339 else if(this[p]=='W') { 393 - if(hige_day) { 340 + if( hige.is_growing_turn(turn) ) 394 341 for(int dy=-1; dy<=+1; ++dy) 395 342 for(int dx=-1; dx<=+1; ++dx) 396 343 if(this[p.y+dy,p.x+dx] == ' ') 397 - write(p.y+dy,p.x+dx,'W'); 398 - } 344 + access(new Pos(p.y+dy,p.x+dx)) = 'W'; 399 345 } 400 346 } 401 - 347 + data = next; 402 348 return dead; 403 349 } 404 350 } 405 351 406 352 //////////////////////////////////////////////////////////////////////////////// 407 353 408 354 class Game 409 355 { 410 - mixin DeriveShow; 411 - 356 +public: 412 357 this(File input) 413 358 { 414 - string[] raw_data; 415 - string[string] params; 416 - 417 - // Raw map data; read until empty line. 359 + // Read map data 360 + string[] map_data_lines; 418 361 for(string line; !(line=input.readln().chomp()).empty; ) 419 - raw_data ~= line; 362 + map_data_lines ~= line; 420 363 421 - // Additional commands; read until EOF. 422 - char[char] trampo; 423 - for(string line; !(line=input.readln()).empty; ) { 364 + // H*W 365 + H_ = map_data_lines.length; 366 + W_ = 0; 367 + foreach(mdl; map_data_lines) 368 + W_ = max(W_, mdl.length); 369 + 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 + } 420 + } 421 + 422 + // Read other parameters 423 + for(string line; !(line=input.readln()).empty; ) 424 + { 424 425 string[] ss = line.split(); 425 426 if( ss.length == 2 ) 426 - params[ss[0]] = ss[1]; 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 + } 427 436 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" ) 428 - trampo[ss[1][0]] = ss[3][0]; 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 + } 444 + 445 + air_left_ = max_air_; 446 + } 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; 429 497 } 430 - 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); 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); } 435 502 } 436 503 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 - } 447 - 504 +public: 448 505 void command(char c) 449 506 { 450 - assert(c != 'A'); 451 507 if(dead || cleared) 452 508 return; 453 509 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; 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(); 521 + } 522 + turn_ ++; 523 + } 524 + 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 + } 625 + 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 + } 461 651 else 462 - under_water = 0; 463 - if( under_water > map.waterproof ) 464 - dead = true; 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; 465 686 } 466 - turn += 1; 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; 467 759 } 468 760 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. 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; 478 779 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; } 780 + int turn_ = 0; 781 + int air_left_ = 0; 782 + bool cleared_ = false; 783 + bool dead_ = false; 784 + bool[Pos] may_update_; 486 785 }

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

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.map.W, g.map.H); 11 + setup_size(g.W, g.H); 12 12 setup_resources(g); 13 13 draw(g); 14 14 } 15 15 16 - void run(void delegate(char c) command, bool automate = true) 16 + private void delegate(char c) fn; 17 + void set_fn(F)(F f) { this.fn = f; } 18 + 19 + void run(bool automate = false) 17 20 { 18 21 if(automate) { 19 22 Timer t = new Timer; 20 23 t.interval = 50; 21 - t.tick ~= (Timer s, EventArgs e){command(solver.single_step());}; 24 + t.tick ~= (Timer sender, EventArgs ea){ 25 + fn(solver.single_step()); 26 + }; 22 27 t.start(); 23 28 this.closing ~= (Form f,CancelEventArgs c){t.stop();}; 24 29 } else { 25 - setup_keyhandling(command); 30 + setup_keyhandling(); 26 31 } 27 32 Application.run(this); 28 33 } 29 34 30 35 override void on_game_changed(char c, in Game g, bool finished) 31 36 { 32 37 draw(g); 33 38 } 34 39 35 40 private: 41 + int cell; 42 + 36 43 void setup_size(int W, int H) 37 44 { 38 45 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; 39 46 this.maximizeBox = false; 40 47 this.minimizeBox = false; 41 48 this.cell = min(1024/W, 640/H); 42 49 this.clientSize = Size(W*cell, H*cell); 43 50 } 44 51 45 - int cell; 46 52 Font font; 47 53 Color[char] colors; 48 54 string[char] render; 49 55 Graphics graphicContext; 50 56 51 57 void setup_resources(in Game g) 52 58 { 53 59 this.graphicContext = new MemoryGraphics(this.clientSize.width, this.clientSize.height); 54 60 this.setStyle(ControlStyles.OPAQUE, true); 55 61 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 56 62 this.backColor = Color(255,255,255); 57 63 this.colors['#'] = 58 64 this.colors['.'] = Color(255,191,127); 59 - this.colors['*'] = 60 - this.colors['@'] = Color(255,127,127); 65 + this.colors['*'] = Color(255,127,127); 61 66 this.colors['R'] = Color(128,128,0); 62 - this.colors['r'] = Color(100,128,255); 63 67 this.colors['d'] = Color(255,0,0); 64 68 this.colors['\\'] = 65 69 this.colors['L'] = 66 70 this.colors['O'] = Color(127,255,127); 67 71 this.colors['w'] = Color(204,229,255); 68 72 this.colors['W'] = 69 73 this.colors['!'] = Color(159,159,159); 70 74 foreach(char c; 'A'..'J') this.colors[c] = Color(142,142,255); 71 75 foreach(char c; '1'..':') this.colors[c] = Color(255,142,255); 72 76 this.render['#'] = "■"; 73 77 this.render['*'] = "✹"; 74 - this.render['@'] = "❁"; 75 78 this.render['.'] = "♒"; 76 79 this.render['\\'] = "λ"; 77 80 this.render['R'] = "☃"; 78 - this.render['r'] = "☃"; 79 81 this.render['d'] = "☠"; 80 82 this.render['L'] = "☒"; 81 83 this.render['O'] = "☐"; 82 84 this.render['W'] = "ꔣ"; 83 85 this.render['!'] = "✄"; 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(); 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(); 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.map.H; ++y) 107 - for(int x=1; x<=g.map.W; ++x) { 106 + for(int y=1; y<=g.H; ++y) 107 + for(int x=1; x<=g.W; ++x) { 108 108 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 109 - char c = g.map[y,x]; 109 + char c = g[y,x]; 110 110 if( c != ' ' ) { 111 - if( c == 'R' ) 112 - c = (g.dead ? 'd' : g.cleared ? 'r' : 'R'); 111 + if( c == 'R' && g.dead ) 112 + c = 'd'; 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.map.razor); 123 + " Razor: ", g.num_razor); 124 124 invalidate(); 125 125 } 126 126 127 127 private: 128 - void setup_keyhandling(void delegate(char c) command) 128 + void setup_keyhandling() 129 129 { 130 130 noMessageFilter(); 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 - }; 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 + } 150 154 } 151 155 152 156 Solver solver; 153 157 }

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

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

Deleted 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 [95ed42a2d89e1fef] to [e2d0d7db868c3a44].

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

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

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

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

3 3 public import std.conv; 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 + 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 +} 10 18 11 19 // To avoide the following ICE: 12 20 // src\phobos\std\algorithm.d(4552): 13 21 // Error: function std.algorithm.count!("a == b",string,char).count 14 22 // compiler error, parameter 'value', bugzilla 2962? 15 23 // Assertion failure: '0' on line 717 in file 'glue.c' 16 24 int count(T,V)(T[] a, V v)