Differences From Artifact [074b8ae4c20c37c4]:
- File
src/game.d
- 2012-07-15 14:36:04 - part of checkin [b83558c1a5] on branch trunk - Speed up update(). (user: kinaba) [annotate]
To Artifact [189f5a19c7160df3]:
- File
src/game.d
- 2012-07-15 14:55:18 - part of checkin [64f5c73b88] on branch trunk - hige moving tochu. (user: kinaba) [annotate]
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 }