Check-in Differences
Not logged in

Difference From:

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

To:

[68b686ff6d] memo (user: kinaba, tags: trunk, date: 2012-07-15 13:58:47)

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

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

1 # To build, the following packages are needed. 1 # To build, the following packages are needed. 2 # wget http://ftp.digitalmars.com/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 | 3 # $ sudo apt-get install gcc gcc-multilib 4 # sudo pkg -i dmd_2.059-0_i386.deb | 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/df > 7 > 8 cui: > 9 dmd -O -release -inline -oflifter main.d driver.d game.d output.d solver > 10 > 11 gui: > 12 dmd -O -release -inline -ofgui gui_main.d gui.d driver.d game.d output.d 5 13 6 all: | 14 clean: 7 dmd -O -release -inline -oflifter cui_auto_main.d driver.d game.d output | 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/driver.d from [3d15ff20e76164b8] to [cf90fae27c74ab2c].

6 // this(in Game g); 6 // this(in Game g); 7 void on_game_changed(char c, in Game g, bool finished); 7 void on_game_changed(char c, in Game g, bool finished); 8 } 8 } 9 9 10 class Driver 10 class Driver 11 { 11 { 12 this(Game g) { this.game = g; } 12 this(Game g) { this.game = g; } 13 this(File game_data) { this(new Game(game_data)); } | 13 this(File game_data) { this(Game.load(game_data)); } 14 14 15 void command(char c) 15 void command(char c) 16 { 16 { 17 if( finished ) 17 if( finished ) 18 return; 18 return; 19 if( c == 'A' ) 19 if( c == 'A' ) 20 aborted = true; 20 aborted = true;

Modified src/game.d from [fc05481901940844] to [403db28cbc4609b7].

126 Pos robot; 126 Pos robot; 127 Pos lift; 127 Pos lift; 128 int waterproof; 128 int waterproof; 129 Pos[char] tr_target; 129 Pos[char] tr_target; 130 Pos[][char] tr_source; 130 Pos[][char] tr_source; 131 const(Hige) hige; 131 const(Hige) hige; 132 int razor; 132 int razor; > 133 int collected_lambda; > 134 int total_lambda; 133 135 134 Map clone() const { return new Map(this); } 136 Map clone() const { return new Map(this); } 135 this(in Map m) { 137 this(in Map m) { 136 foreach(s; m.data) 138 foreach(s; m.data) 137 this.data ~= s.dup; 139 this.data ~= s.dup; 138 this.robot = m.robot.clone(); 140 this.robot = m.robot.clone(); 139 this.lift = m.lift.clone(); 141 this.lift = m.lift.clone(); 140 this.waterproof = m.waterproof; 142 this.waterproof = m.waterproof; 141 this.tr_target = cast(Pos[char])m.tr_target; 143 this.tr_target = cast(Pos[char])m.tr_target; 142 this.tr_source = cast(Pos[][char])m.tr_source; 144 this.tr_source = cast(Pos[][char])m.tr_source; 143 this.hige = m.hige.clone(); 145 this.hige = m.hige.clone(); 144 this.razor = m.razor; 146 this.razor = m.razor; > 147 this.collected_lambda = m.collected_lambda; > 148 this.total_lambda = m.total_lambda; 145 } 149 } 146 150 147 this(string[] raw_data, string[string] params, char[char] trampo) 151 this(string[] raw_data, string[string] params, char[char] trampo) 148 { 152 { 149 int width = 0; 153 int width = 0; 150 foreach(r; raw_data) 154 foreach(r; raw_data) 151 width = max(width, r.length); 155 width = max(width, r.length); ................................................................................................................................................................................ 157 161 158 for(int y=1; y<=H; ++y) 162 for(int y=1; y<=H; ++y) 159 for(int x=1; x<=W; ++x) { 163 for(int x=1; x<=W; ++x) { 160 if(this[y,x] == 'R') 164 if(this[y,x] == 'R') 161 this.robot = new Pos(y,x); 165 this.robot = new Pos(y,x); 162 if(this[y,x] == 'L' || this[y,x] == 'O') 166 if(this[y,x] == 'L' || this[y,x] == 'O') 163 this.lift = new Pos(y,x); 167 this.lift = new Pos(y,x); > 168 if(this[y,x] == '\\' || this[y,x] == '@') > 169 total_lambda++; 164 } 170 } 165 171 166 Pos[char] tr_pos; 172 Pos[char] tr_pos; 167 for(int y=1; y<=H; ++y) 173 for(int y=1; y<=H; ++y) 168 for(int x=1; x<=W; ++x) { 174 for(int x=1; x<=W; ++x) { 169 char c = this[y,x]; 175 char c = this[y,x]; 170 if('1'<=c && c<='9' || 'A'<=c&&c<='I') 176 if('1'<=c && c<='9' || 'A'<=c&&c<='I') ................................................................................................................................................................................ 234 for(int y=1; y<=H; ++y) 240 for(int y=1; y<=H; ++y) 235 for(int x=1; x<=W; ++x) 241 for(int x=1; x<=W; ++x) 236 if(this[y,x] == 'L' || this[y,x] == 'O') 242 if(this[y,x] == 'L' || this[y,x] == 'O') 237 return false; 243 return false; 238 return true; 244 return true; 239 } 245 } 240 246 241 Tuple!(int,bool) command(char c, int turn) | 247 bool command(char c, int turn) 242 { 248 { 243 assert( this[robot] == 'R' ); 249 assert( this[robot] == 'R' ); 244 if(c=='R') return move( 0, +1, turn); 250 if(c=='R') return move( 0, +1, turn); 245 if(c=='L') return move( 0, -1, turn); 251 if(c=='L') return move( 0, -1, turn); 246 if(c=='U') return move(+1, 0, turn); 252 if(c=='U') return move(+1, 0, turn); 247 if(c=='D') return move(-1, 0, turn); 253 if(c=='D') return move(-1, 0, turn); 248 if(c=='W') return move( 0, 0, turn); 254 if(c=='W') return move( 0, 0, turn); 249 if(c=='S') return use_razor(turn); 255 if(c=='S') return use_razor(turn); 250 assert(false); 256 assert(false); 251 } 257 } 252 258 253 Tuple!(int, bool) use_razor(int turn) | 259 bool use_razor(int turn) 254 { 260 { 255 if(razor) { 261 if(razor) { 256 razor--; 262 razor--; 257 for(int dy=-1; dy<=+1; ++dy) 263 for(int dy=-1; dy<=+1; ++dy) 258 for(int dx=-1; dx<=+1; ++dx) 264 for(int dx=-1; dx<=+1; ++dx) 259 if(this[robot.y+dy,robot.x+dx] == 'W') 265 if(this[robot.y+dy,robot.x+dx] == 'W') 260 this[robot.y+dy,robot.x+dx] = ' '; 266 this[robot.y+dy,robot.x+dx] = ' '; 261 } 267 } 262 268 263 bool dead = update(turn); | 269 return update(turn); 264 return tuple(0,dead); < 265 } 270 } 266 271 > 272 bool rocky(char c) { return c=='*' || c=='@'; } > 273 267 Tuple!(int, bool) move(int dy, int dx, int turn) | 274 bool move(int dy, int dx, int turn) 268 { 275 { 269 int y = robot.y; 276 int y = robot.y; 270 int x = robot.x; 277 int x = robot.x; 271 int lambda = 0; < 272 if( '\\' == this[y+dy,x+dx] ) 278 if( '\\' == this[y+dy,x+dx] ) 273 lambda++; | 279 collected_lambda++; 274 if( '!' == this[y+dy,x+dx] ) 280 if( '!' == this[y+dy,x+dx] ) 275 razor++; 281 razor++; 276 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 282 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 277 this[y,x]=' '; 283 this[y,x]=' '; 278 this[y+dy,x+dx]='R'; 284 this[y+dy,x+dx]='R'; 279 robot = new Pos(y+dy,x+dx); 285 robot = new Pos(y+dy,x+dx); 280 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx | 286 } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+ > 287 char rock = this[y+dy,x+dx]; 281 this[y,x]=' '; 288 this[y,x]=' '; 282 this[y+dy,x+dx]='R'; 289 this[y+dy,x+dx]='R'; 283 this[y+dy*2,x+dx*2]='*'; | 290 this[y+dy*2,x+dx*2]=rock; 284 robot = new Pos(y+dy,x+dx); 291 robot = new Pos(y+dy,x+dx); 285 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { 292 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { 286 this[y,x]=' '; 293 this[y,x]=' '; 287 Pos tp = tr_target[this[y+dy,x+dx]]; 294 Pos tp = tr_target[this[y+dy,x+dx]]; 288 foreach(p; tr_source[this[tp]]) 295 foreach(p; tr_source[this[tp]]) 289 this[p] = ' '; 296 this[p] = ' '; 290 this[tp] = 'R'; 297 this[tp] = 'R'; 291 robot = tp; 298 robot = tp; 292 } 299 } 293 bool dead = update(turn); | 300 return update(turn); 294 return tuple(lambda,dead); < 295 } 301 } 296 302 297 bool update(int turn) 303 bool update(int turn) 298 { 304 { 299 bool dead = false; 305 bool dead = false; 300 306 301 char[][] next; 307 char[][] next; 302 foreach(y,s; data) 308 foreach(y,s; data) 303 next ~= s.dup; 309 next ~= s.dup; 304 310 305 ref char access(Pos p) { return next[H-p.y][p.x-1]; } 311 ref char access(Pos p) { return next[H-p.y][p.x-1]; } 306 312 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 y=1; y<=H; ++y) 313 for(int x=1; x<=W; ++x) { 314 for(int x=1; x<=W; ++x) { 314 Pos p = new Pos(y,x); 315 Pos p = new Pos(y,x); > 316 char rock = this[p]; 315 if(this[p]=='*') { | 317 if(rocky(this[p])) { 316 if(this[p.D]==' ') { 318 if(this[p.D]==' ') { 317 access(p) =' '; 319 access(p) =' '; 318 access(p.D)='*'; | 320 access(p.D)=(rock=='@'&&this[p.D.D]!=' ' 319 if(robot == p.D.D) 321 if(robot == p.D.D) 320 dead=true; 322 dead=true; 321 } 323 } 322 else if((this[p.D]=='*' || this[p.D]=='\\') && t | 324 else if((rocky(this[p.D]) || this[p.D]=='\\') && 323 access(p)=' '; 325 access(p)=' '; 324 access(p.R.D)='*'; | 326 access(p.R.D)=(rock=='@'&&this[p.R.D.D]! 325 if(robot == p.R.D.D) 327 if(robot == p.R.D.D) 326 dead=true; 328 dead=true; 327 } 329 } 328 else if(this[p.D]=='*' && this[p.L]==' ' && this | 330 else if(rocky(this[p.D]) && this[p.L]==' ' && th 329 access(p)=' '; 331 access(p)=' '; 330 access(p.L.D)='*'; | 332 access(p.L.D)=(rock=='@'&&this[p.L.D.D]! 331 if(robot == p.L.D.D) 333 if(robot == p.L.D.D) 332 dead=true; 334 dead=true; 333 } 335 } 334 } 336 } 335 else if(this[p]=='L') { 337 else if(this[p]=='L') { 336 if(!lambda) | 338 if(collected_lambda == total_lambda) 337 access(p) = 'O'; 339 access(p) = 'O'; 338 } 340 } 339 else if(this[p]=='W') { 341 else if(this[p]=='W') { 340 if( hige.is_growing_turn(turn) ) 342 if( hige.is_growing_turn(turn) ) 341 for(int dy=-1; dy<=+1; ++dy) 343 for(int dy=-1; dy<=+1; ++dy) 342 for(int dx=-1; dx<=+1; ++dx) 344 for(int dx=-1; dx<=+1; ++dx) 343 if(this[p.y+dy,p.x+dx] == ' ') 345 if(this[p.y+dy,p.x+dx] == ' ') ................................................................................................................................................................................ 349 } 351 } 350 } 352 } 351 353 352 //////////////////////////////////////////////////////////////////////////////// 354 //////////////////////////////////////////////////////////////////////////////// 353 355 354 class Game 356 class Game 355 { 357 { 356 public: | 358 mixin DeriveShow; > 359 357 this(File input) | 360 static Game load(File input) 358 { 361 { 359 // Read map data | 362 string[] raw_data; 360 string[] map_data_lines; | 363 string[string] params; > 364 > 365 // Raw map data; read until empty line. 361 for(string line; !(line=input.readln().chomp()).empty; ) 366 for(string line; !(line=input.readln().chomp()).empty; ) 362 map_data_lines ~= line; | 367 raw_data ~= line; 363 368 364 // H*W | 369 // Additional commands; read until EOF. 365 H_ = map_data_lines.length; | 370 char[char] trampo; 366 W_ = 0; | 371 for(string line; !(line=input.readln()).empty; ) { 367 foreach(mdl; map_data_lines) | 372 string[] ss = line.split(); 368 W_ = max(W_, mdl.length); | 373 if( ss.length == 2 ) 369 < > 374 params[ss[0]] = ss[1]; 370 // Copy to modifiable buffer and adjust coordinates. | 375 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar 371 raw_data_ = new char[][H_+1]; | 376 trampo[ss[1][0]] = ss[3][0]; 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 } 377 } 378 378 379 // Detect objects | 379 return load(raw_data, params, trampo); 380 for(int y=1; y<=H_; ++y) < 381 for(int x=1; x<raw_data_[y].length; ++x) < > 380 } 382 { | 381 383 char c = raw_data_[y][x]; < > 382 static Game load(string[] raw_data, string[string] params, char[char] tr > 383 { 384 switch(c) | 384 return new Game(raw_data, params, trampo); > 385 } 385 { | 386 386 case '#': < 387 case '.': | 387 this(string[] raw_data, string[string] params, char[char] trampo) 388 case ' ': < > 388 { 389 break; | 389 this.map = Map.load(raw_data, params, trampo); 390 case 'L': | 390 this.water = Water.load(params); 391 case 'O': < 392 lift_pos_ = new Pos(y,x); < > 391 } > 392 393 break; | 393 Game clone() const { return new Game(this); } 394 case 'A': .. case 'I': | 394 this(in Game g) { 395 case '1': .. case '9': | 395 map = g.map.clone(); 396 trampoline_pos_[c] = new Pos(y,x); | 396 water = g.water.clone(); 397 break; | 397 turn = g.turn; 398 case '!': | 398 dead = g.dead; 399 razor_pos_ ~= new Pos(y,x); | 399 cleared = g.cleared; 400 break; | 400 under_water = g.under_water; 401 case '\\': < 402 lambda_pos_ ~= new Pos(y,x); < > 401 } > 402 403 break; | 403 void command(char c) > 404 { > 405 assert(c != 'A'); > 406 if(dead || cleared) > 407 return; 404 408 405 // Moving objects are erased from raw_data_ | 409 // TODO: clarify the event order 406 case 'R': | 410 bool dead_now = map.command(c, turn); 407 robot_pos_ = new Pos(y,x); | 411 if( map.cleared() ) { 408 raw_data_[y][x] = ' '; | 412 cleared = true; 409 break; < > 413 } 410 case '*': | 414 else { 411 case 'W': | 415 if( dead_now ) 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 dead = true; 416 break; < 417 default: < 418 assert(false); < 419 } | 417 } > 418 if(!cleared) { > 419 if( map.robot.y <= water_level ) > 420 ++under_water; > 421 else > 422 under_water = 0; > 423 if( under_water > map.waterproof ) > 424 dead = true; 420 } 425 } > 426 turn += 1; > 427 } 421 428 422 // Read other parameters | 429 Map map; 423 for(string line; !(line=input.readln()).empty; ) | 430 Water water; 424 { < > 431 int turn = 0; 425 string[] ss = line.split(); | 432 bool dead = false; 426 if( ss.length == 2 ) | 433 int under_water = 0; 427 switch(ss[0]) | 434 bool cleared = false; 428 { < > 435 // TODO: when adding members, take care of clone(). 429 case "Water": water_base_ = ss[1].to!int(); | 436 // TODO: fix this poor design. 430 case "Flooding": water_pace_ = ss[1].to!int(); < 431 case "Waterproof": max_air_ = ss[1].to!int(); < 432 case "Growth": hige_pace_ = ss[1].to!int(); < 433 case "Razors": num_razor_ = ss[1].to!int(); < 434 default: assert(false); < 435 } < 436 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar < 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 437 448 @property const { 438 @property const { 449 int H() { return H_; } | 439 long score() { return map.collected_lambda*(dead ? 25L : cleared 450 int W() { return W_; } < 451 char trampoline(char c) { return (c in trampoline_ ? trampoline_ < 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() { | 440 int water_level() { return water.level(turn); } 461 return water_pace_ ? water_base_ + turn_/water_pace_ : w < 462 } < 463 int water_until_rise() { | 441 int water_until_rise() { return water.until_rise(turn); } 464 return water_pace_ ? water_pace_ - turn_%water_pace_ : i < 465 } < 466 int hige_until_rise() { | 442 int hige_until_rise() { return map.hige.until_rise(turn); } 467 return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int. < 468 } < 469 bool is_hige_turn() { < 470 return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : f < 471 } < 472 int hp() { return air_left_; } | 443 int hp() { return map.waterproof - under_water; } 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 < 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 } | 444 } 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 void command(char c) < 506 { < 507 if(dead || cleared) < 508 return; < 509 < 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 } < 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] < 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 < 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_; < 785 } 445 }

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

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

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

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

31 override void on_game_changed(char c, in Game g, bool finished) 31 override void on_game_changed(char c, in Game g, bool finished) 32 { 32 { 33 if(flushed) 33 if(flushed) 34 return; 34 return; 35 35 36 log ~= c; 36 log ~= c; 37 score_log ~= g.score; 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 flush(); 39 flush(); 40 } 40 } 41 41 42 private: 42 private: 43 string log; 43 string log; 44 long[] score_log; 44 long[] score_log; 45 bool flushed; 45 bool flushed;

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

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

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

4 public import std.range; 4 public import std.range; 5 public import std.stdio; 5 public import std.stdio; 6 public import std.string; 6 public import std.string; 7 public import std.typecons; 7 public import std.typecons; 8 public import std.math; 8 public import std.math; 9 import std.c.stdlib; 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 // To avoide the following ICE: 11 // To avoide the following ICE: 20 // src\phobos\std\algorithm.d(4552): 12 // src\phobos\std\algorithm.d(4552): 21 // Error: function std.algorithm.count!("a == b",string,char).count 13 // Error: function std.algorithm.count!("a == b",string,char).count 22 // compiler error, parameter 'value', bugzilla 2962? 14 // compiler error, parameter 'value', bugzilla 2962? 23 // Assertion failure: '0' on line 717 in file 'glue.c' 15 // Assertion failure: '0' on line 717 in file 'glue.c' 24 int count(T,V)(T[] a, V v) 16 int count(T,V)(T[] a, V v) 25 { 17 {