Diff
Not logged in

Differences From Artifact [074b8ae4c20c37c4]:

To Artifact [189f5a19c7160df3]:


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