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 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 }