Diff
Not logged in

Differences From Artifact [074b8ae4c20c37c4]:

To Artifact [189f5a19c7160df3]:


6 { 6 { 7 public immutable int y, x; 7 public immutable int y, x; 8 mixin DeriveCreate; 8 mixin DeriveCreate; 9 mixin DeriveCompare; 9 mixin DeriveCompare; 10 mixin DeriveShow; 10 mixin DeriveShow; 11 Pos clone() const { return cast(Pos) this; } 11 Pos clone() const { return cast(Pos) this; } 12 12 13 @property: | 13 const @property: 14 Pos wait() { return this.clone(); } 14 Pos wait() { return this.clone(); } 15 Pos up() { return new Pos(y+1, x); } 15 Pos up() { return new Pos(y+1, x); } 16 Pos down() { return new Pos(y-1, x); } 16 Pos down() { return new Pos(y-1, x); } 17 Pos left() { return new Pos(y, x-1); } 17 Pos left() { return new Pos(y, x-1); } 18 Pos right() { return new Pos(y, x+1); } 18 Pos right() { return new Pos(y, x+1); } 19 alias wait W,w; 19 alias wait W,w; 20 alias up U,u; 20 alias up U,u; ................................................................................................................................................................................ 41 41 42 class Water 42 class Water 43 { 43 { 44 public immutable int base, pace; 44 public immutable int base, pace; 45 mixin DeriveCreate; 45 mixin DeriveCreate; 46 mixin DeriveCompare; 46 mixin DeriveCompare; 47 mixin DeriveShow; 47 mixin DeriveShow; 48 Water clone() const { return cast(Water)this; } | 48 Water clone() const { return cast(Water) this; } 49 49 50 static load(string[string] params) 50 static load(string[string] params) 51 { 51 { 52 return new Water(params.get("Water", "0").to!int(), 52 return new Water(params.get("Water", "0").to!int(), 53 params.get("Flooding", "0").to!int()); 53 params.get("Flooding", "0").to!int()); 54 } 54 } 55 55 56 int level(int number_of_update) const | 56 int level(int turn) const 57 { 57 { 58 return pace ? base+(number_of_update/pace) : base; | 58 return pace ? base+(turn/pace) : base; 59 } 59 } 60 60 61 int until_rise(int number_of_update) const | 61 int until_rise(int turn) const 62 { 62 { 63 return pace ? pace-number_of_update%pace : int.max; | 63 return pace ? pace-turn%pace : int.max; 64 } 64 } 65 } 65 } 66 66 67 unittest 67 unittest 68 { 68 { 69 Water w = new Water(1, 3); 69 Water w = new Water(1, 3); 70 assert( 1 == w.level(0) ); 70 assert( 1 == w.level(0) ); ................................................................................................................................................................................ 112 112 113 //////////////////////////////////////////////////////////////////////////////// 113 //////////////////////////////////////////////////////////////////////////////// 114 114 115 class Map 115 class Map 116 { 116 { 117 mixin DeriveShow; 117 mixin DeriveShow; 118 118 119 static Map load(string[] raw_data, string[string] params, char[char] tra < 120 { < 121 // TODO: choose optimal representation. < 122 return new Map(raw_data, params, trampo); < 123 } < 124 < 125 char[][] data; 119 char[][] data; 126 Pos robot; 120 Pos robot; 127 Pos lift; 121 Pos lift; 128 int waterproof; 122 int waterproof; 129 Pos[char] tr_target; 123 Pos[char] tr_target; 130 Pos[][char] tr_source; 124 Pos[][char] tr_source; 131 const(Hige) hige; 125 const(Hige) hige; 132 int razor; 126 int razor; 133 int collected_lambda; 127 int collected_lambda; 134 int total_lambda; 128 int total_lambda; > 129 bool cleared; > 130 Pos[] may_update; 135 131 136 Map clone() const { return new Map(this); } 132 Map clone() const { return new Map(this); } 137 this(in Map m) { 133 this(in Map m) { 138 foreach(s; m.data) 134 foreach(s; m.data) 139 this.data ~= s.dup; 135 this.data ~= s.dup; 140 this.robot = m.robot.clone(); 136 this.robot = m.robot.clone(); 141 this.lift = m.lift.clone(); 137 this.lift = m.lift.clone(); ................................................................................................................................................................................ 143 this.tr_target = cast(Pos[char])m.tr_target; 139 this.tr_target = cast(Pos[char])m.tr_target; 144 this.tr_source = cast(Pos[][char])m.tr_source; 140 this.tr_source = cast(Pos[][char])m.tr_source; 145 this.hige = m.hige.clone(); 141 this.hige = m.hige.clone(); 146 this.razor = m.razor; 142 this.razor = m.razor; 147 this.collected_lambda = m.collected_lambda; 143 this.collected_lambda = m.collected_lambda; 148 this.total_lambda = m.total_lambda; 144 this.total_lambda = m.total_lambda; 149 this.may_update = (cast(Map)m).may_update.dup; 145 this.may_update = (cast(Map)m).may_update.dup; > 146 this.cleared = m.cleared; 150 } 147 } 151 148 152 this(string[] raw_data, string[string] params, char[char] trampo) 149 this(string[] raw_data, string[string] params, char[char] trampo) 153 { 150 { 154 int width = 0; 151 int width = 0; 155 foreach(r; raw_data) 152 foreach(r; raw_data) 156 width = max(width, r.length); 153 width = max(width, r.length); ................................................................................................................................................................................ 234 ans ~= new Pos(y,x); 231 ans ~= new Pos(y,x); 235 return ans; 232 return ans; 236 } 233 } 237 234 238 Pos[] razors() const { return objects('!'); } 235 Pos[] razors() const { return objects('!'); } 239 Pos[] lambdas() const { return objects('\\'); } 236 Pos[] lambdas() const { return objects('\\'); } 240 237 241 bool cleared() const < 242 { < 243 for(int y=1; y<=H; ++y) < 244 for(int x=1; x<=W; ++x) < 245 if(this[y,x] == 'L' || this[y,x] == 'O') < 246 return false; < 247 return true; < 248 } < 249 < 250 bool command(char c, int turn) | 238 bool command(char c, int turn, bool hige_day) 251 { 239 { 252 assert( this[robot] == 'R' ); 240 assert( this[robot] == 'R' ); 253 if(c=='R') return move( 0, +1, turn); | 241 if(c=='R') return move( 0, +1, turn, hige_day); 254 if(c=='L') return move( 0, -1, turn); | 242 if(c=='L') return move( 0, -1, turn, hige_day); 255 if(c=='U') return move(+1, 0, turn); | 243 if(c=='U') return move(+1, 0, turn, hige_day); 256 if(c=='D') return move(-1, 0, turn); | 244 if(c=='D') return move(-1, 0, turn, hige_day); 257 if(c=='W') return move( 0, 0, turn); | 245 if(c=='W') return move( 0, 0, turn, hige_day); 258 if(c=='S') return use_razor(turn); | 246 if(c=='S') return use_razor(turn, hige_day); 259 assert(false); 247 assert(false); 260 } 248 } 261 249 262 bool use_razor(int turn) | 250 bool use_razor(int turn, bool hige_day) 263 { 251 { 264 if(razor) { 252 if(razor) { 265 razor--; 253 razor--; 266 for(int dy=-1; dy<=+1; ++dy) 254 for(int dy=-1; dy<=+1; ++dy) 267 for(int dx=-1; dx<=+1; ++dx) 255 for(int dx=-1; dx<=+1; ++dx) 268 if(this[robot.y+dy,robot.x+dx] == 'W') | 256 if(this[robot.y+dy,robot.x+dx] == 'W') { > 257 emptified(new Pos(robot.y+dy,robot.x+dx) 269 this[robot.y+dy,robot.x+dx] = ' '; 258 this[robot.y+dy,robot.x+dx] = ' '; > 259 } 270 } 260 } 271 261 272 return update(turn); | 262 return update(turn, hige_day); 273 } 263 } 274 264 275 bool rocky(char c) { return c=='*' || c=='@'; } 265 bool rocky(char c) { return c=='*' || c=='@'; } 276 Pos[] may_update; < > 266 277 void emptified(Pos p) { 267 void emptified(Pos p) { 278 for(int dy=0; dy<=+1; ++dy) 268 for(int dy=0; dy<=+1; ++dy) 279 for(int dx=-1; dx<=+1; ++dx) 269 for(int dx=-1; dx<=+1; ++dx) 280 may_update ~= new Pos(p.y+dy, p.x+dx); 270 may_update ~= new Pos(p.y+dy, p.x+dx); 281 } 271 } 282 272 283 bool move(int dy, int dx, int turn) | 273 bool move(int dy, int dx, int turn, bool hige_day) 284 { 274 { 285 275 286 emptified(robot); 276 emptified(robot); 287 277 288 int y = robot.y; 278 int y = robot.y; 289 int x = robot.x; 279 int x = robot.x; 290 if( '\\' == this[y+dy,x+dx] ) 280 if( '\\' == this[y+dy,x+dx] ) 291 collected_lambda++; 281 collected_lambda++; 292 if( '!' == this[y+dy,x+dx] ) 282 if( '!' == this[y+dy,x+dx] ) 293 razor++; 283 razor++; > 284 if( 'O' == this[y+dy,x+dx] ) > 285 cleared = true; 294 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 286 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 295 this[y,x]=' '; 287 this[y,x]=' '; 296 this[y+dy,x+dx]='R'; 288 this[y+dy,x+dx]='R'; 297 robot = new Pos(y+dy,x+dx); 289 robot = new Pos(y+dy,x+dx); 298 } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+ 290 } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+ 299 char rock = this[y+dy,x+dx]; 291 char rock = this[y+dy,x+dx]; 300 this[y,x]=' '; 292 this[y,x]=' '; ................................................................................................................................................................................ 307 foreach(p; tr_source[this[tp]]) { 299 foreach(p; tr_source[this[tp]]) { 308 emptified(p); 300 emptified(p); 309 this[p] = ' '; 301 this[p] = ' '; 310 } 302 } 311 this[tp] = 'R'; 303 this[tp] = 'R'; 312 robot = tp; 304 robot = tp; 313 } 305 } 314 return update(turn); | 306 return update(turn, hige_day); 315 } 307 } 316 308 317 bool update(int turn) | 309 bool update(int turn, bool hige_day) 318 { 310 { 319 // Write after all the updates are processed. 311 // Write after all the updates are processed. 320 Tuple!(int,int,char)[] write_buffer; 312 Tuple!(int,int,char)[] write_buffer; 321 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); 313 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); 322 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c 314 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c 323 scope(exit) { 315 scope(exit) { 324 may_update.length = 0; 316 may_update.length = 0; ................................................................................................................................................................................ 356 else if(rocky(this[p.D]) && this[p.L]==' ' && th 348 else if(rocky(this[p.D]) && this[p.L]==' ' && th 357 writep(p, ' '); 349 writep(p, ' '); 358 writep(p.L.D, (rock=='@'&&this[p.L.D.D]! 350 writep(p.L.D, (rock=='@'&&this[p.L.D.D]! 359 if(robot == p.L.D.D) 351 if(robot == p.L.D.D) 360 dead=true; 352 dead=true; 361 } 353 } 362 } 354 } > 355 } > 356 > 357 if( hige_day ) > 358 for(int y=1; y<=H; ++y) > 359 for(int x=1; x<=W; ++x) { > 360 Pos p = new Pos(y,x); 363 else if(this[p]=='W') { | 361 if(this[p]=='W') { 364 if( hige.is_growing_turn(turn) ) < 365 for(int dy=-1; dy<=+1; ++dy) 362 for(int dy=-1; dy<=+1; ++dy) 366 for(int dx=-1; dx<=+1; ++dx) 363 for(int dx=-1; dx<=+1; ++dx) 367 if(this[p.y+dy,p.x+dx] == ' ') 364 if(this[p.y+dy,p.x+dx] == ' ') 368 write(p.y+dy,p.x+dx,'W') 365 write(p.y+dy,p.x+dx,'W') 369 } 366 } 370 } 367 } > 368 371 return dead; 369 return dead; 372 } 370 } 373 } 371 } 374 372 375 //////////////////////////////////////////////////////////////////////////////// 373 //////////////////////////////////////////////////////////////////////////////// 376 374 377 class Game 375 class Game 378 { 376 { 379 mixin DeriveShow; 377 mixin DeriveShow; 380 378 381 static Game load(File input) | 379 this(File input) 382 { 380 { 383 string[] raw_data; 381 string[] raw_data; 384 string[string] params; 382 string[string] params; 385 383 386 // Raw map data; read until empty line. 384 // Raw map data; read until empty line. 387 for(string line; !(line=input.readln().chomp()).empty; ) 385 for(string line; !(line=input.readln().chomp()).empty; ) 388 raw_data ~= line; 386 raw_data ~= line; ................................................................................................................................................................................ 393 string[] ss = line.split(); 391 string[] ss = line.split(); 394 if( ss.length == 2 ) 392 if( ss.length == 2 ) 395 params[ss[0]] = ss[1]; 393 params[ss[0]] = ss[1]; 396 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar 394 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar 397 trampo[ss[1][0]] = ss[3][0]; 395 trampo[ss[1][0]] = ss[3][0]; 398 } 396 } 399 397 400 return load(raw_data, params, trampo); | 398 this.map = new Map(raw_data, params, trampo); 401 } < 402 < 403 static Game load(string[] raw_data, string[string] params, char[char] tr < 404 { < 405 return new Game(raw_data, params, trampo); < 406 } < 407 < 408 this(string[] raw_data, string[string] params, char[char] trampo) < 409 { < 410 this.map = Map.load(raw_data, params, trampo); < 411 this.water = Water.load(params); 399 this.water = Water.load(params); 412 } 400 } 413 401 414 Game clone() const { return new Game(this); } 402 Game clone() const { return new Game(this); } 415 this(in Game g) { 403 this(in Game g) { 416 map = g.map.clone(); | 404 map = g.map.clone(); 417 water = g.water.clone(); 405 water = g.water.clone(); 418 turn = g.turn; | 406 turn = g.turn; 419 dead = g.dead; | 407 dead = g.dead; 420 cleared = g.cleared; < 421 under_water = g.under_water; 408 under_water = g.under_water; 422 } 409 } 423 410 424 void command(char c) 411 void command(char c) 425 { 412 { 426 assert(c != 'A'); 413 assert(c != 'A'); 427 if(dead || cleared) 414 if(dead || cleared) 428 return; 415 return; 429 416 430 // TODO: clarify the event order 417 // TODO: clarify the event order 431 bool dead_now = map.command(c, turn); | 418 bool dead_now = map.command(c, turn, map.hige.is_growing_turn(tu 432 if( map.cleared() ) { < 433 cleared = true; < 434 } < 435 else { < 436 if( dead_now ) | 419 if( dead_now ) 437 dead = true; | 420 dead = true; 438 } < 439 if(!cleared) { | 421 if(!map.cleared) { 440 if( map.robot.y <= water_level ) 422 if( map.robot.y <= water_level ) 441 ++under_water; 423 ++under_water; 442 else 424 else 443 under_water = 0; 425 under_water = 0; 444 if( under_water > map.waterproof ) 426 if( under_water > map.waterproof ) 445 dead = true; 427 dead = true; 446 } 428 } ................................................................................................................................................................................ 448 } 430 } 449 431 450 Map map; 432 Map map; 451 Water water; 433 Water water; 452 int turn = 0; 434 int turn = 0; 453 bool dead = false; 435 bool dead = false; 454 int under_water = 0; 436 int under_water = 0; 455 bool cleared = false; < 456 // TODO: when adding members, take care of clone(). 437 // TODO: when adding members, take care of clone(). 457 // TODO: fix this poor design. 438 // TODO: fix this poor design. 458 439 459 @property const { | 440 @property const: 460 long score() { return map.collected_lambda*(dead ? 25L : cleared | 441 long score() { return map.collected_lambda*(dead?25L:cleared?7 461 int water_level() { return water.level(turn); } | 442 int water_level() { return water.level(turn); } 462 int water_until_rise() { return water.until_rise(turn); } | 443 int water_until_rise() { return water.until_rise(turn); } 463 int hige_until_rise() { return map.hige.until_rise(turn); } | 444 int hige_until_rise() { return map.hige.until_rise(turn); } 464 int hp() { return map.waterproof - under_water; } | 445 int hp() { return map.waterproof - under_water; } 465 } < > 446 bool cleared() { return map.cleared; } 466 } 447 }