Index: src/game.d ================================================================== --- src/game.d +++ src/game.d @@ -128,10 +128,12 @@ int waterproof; Pos[char] tr_target; Pos[][char] tr_source; const(Hige) hige; int razor; + int collected_lambda; + int total_lambda; Map clone() const { return new Map(this); } this(in Map m) { foreach(s; m.data) this.data ~= s.dup; @@ -140,10 +142,12 @@ this.waterproof = m.waterproof; this.tr_target = cast(Pos[char])m.tr_target; this.tr_source = cast(Pos[][char])m.tr_source; this.hige = m.hige.clone(); this.razor = m.razor; + this.collected_lambda = m.collected_lambda; + this.total_lambda = m.total_lambda; } this(string[] raw_data, string[string] params, char[char] trampo) { int width = 0; @@ -159,10 +163,12 @@ for(int x=1; x<=W; ++x) { if(this[y,x] == 'R') this.robot = new Pos(y,x); if(this[y,x] == 'L' || this[y,x] == 'O') this.lift = new Pos(y,x); + if(this[y,x] == '\\' || this[y,x] == '@') + total_lambda++; } Pos[char] tr_pos; for(int y=1; y<=H; ++y) for(int x=1; x<=W; ++x) { @@ -236,11 +242,11 @@ if(this[y,x] == 'L' || this[y,x] == 'O') return false; return true; } - Tuple!(int,bool) command(char c, int turn) + bool command(char c, int turn) { assert( this[robot] == 'R' ); if(c=='R') return move( 0, +1, turn); if(c=='L') return move( 0, -1, turn); if(c=='U') return move(+1, 0, turn); @@ -248,52 +254,52 @@ if(c=='W') return move( 0, 0, turn); if(c=='S') return use_razor(turn); assert(false); } - Tuple!(int, bool) use_razor(int turn) + bool use_razor(int turn) { if(razor) { razor--; for(int dy=-1; dy<=+1; ++dy) for(int dx=-1; dx<=+1; ++dx) if(this[robot.y+dy,robot.x+dx] == 'W') this[robot.y+dy,robot.x+dx] = ' '; } - bool dead = update(turn); - return tuple(0,dead); + return update(turn); } - Tuple!(int, bool) move(int dy, int dx, int turn) + bool rocky(char c) { return c=='*' || c=='@'; } + + bool move(int dy, int dx, int turn) { int y = robot.y; int x = robot.x; - int lambda = 0; if( '\\' == this[y+dy,x+dx] ) - lambda++; + collected_lambda++; if( '!' == this[y+dy,x+dx] ) razor++; if( " \\!.O".count(this[y+dy,x+dx])==1 ) { this[y,x]=' '; this[y+dy,x+dx]='R'; robot = new Pos(y+dy,x+dx); - } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx*2]) { + } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+dx*2]) { + char rock = this[y+dy,x+dx]; this[y,x]=' '; this[y+dy,x+dx]='R'; - this[y+dy*2,x+dx*2]='*'; + this[y+dy*2,x+dx*2]=rock; robot = new Pos(y+dy,x+dx); } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { this[y,x]=' '; Pos tp = tr_target[this[y+dy,x+dx]]; foreach(p; tr_source[this[tp]]) this[p] = ' '; this[tp] = 'R'; robot = tp; } - bool dead = update(turn); - return tuple(lambda,dead); + return update(turn); } bool update(int turn) { bool dead = false; @@ -302,40 +308,36 @@ foreach(y,s; data) next ~= s.dup; ref char access(Pos p) { return next[H-p.y][p.x-1]; } - bool lambda = false; - for(int y=1; y<=H; ++y) - for(int x=1; x<=W; ++x) - lambda |= (this[y,x] == '\\'); - for(int y=1; y<=H; ++y) for(int x=1; x<=W; ++x) { Pos p = new Pos(y,x); - if(this[p]=='*') { + char rock = this[p]; + if(rocky(this[p])) { if(this[p.D]==' ') { access(p) =' '; - access(p.D)='*'; + access(p.D)=(rock=='@'&&this[p.D.D]!=' ' ? '\\' : rock); if(robot == p.D.D) dead=true; } - else if((this[p.D]=='*' || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { + else if((rocky(this[p.D]) || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { access(p)=' '; - access(p.R.D)='*'; + access(p.R.D)=(rock=='@'&&this[p.R.D.D]!=' ' ? '\\' : rock); if(robot == p.R.D.D) dead=true; } - else if(this[p.D]=='*' && this[p.L]==' ' && this[p.L.D]==' ') { + else if(rocky(this[p.D]) && this[p.L]==' ' && this[p.L.D]==' ') { access(p)=' '; - access(p.L.D)='*'; + access(p.L.D)=(rock=='@'&&this[p.L.D.D]!=' ' ? '\\' : rock); if(robot == p.L.D.D) dead=true; } } else if(this[p]=='L') { - if(!lambda) + if(collected_lambda == total_lambda) access(p) = 'O'; } else if(this[p]=='W') { if( hige.is_growing_turn(turn) ) for(int dy=-1; dy<=+1; ++dy) @@ -392,11 +394,10 @@ this(in Game g) { map = g.map.clone(); water = g.water.clone(); turn = g.turn; dead = g.dead; - lambda = g.lambda; cleared = g.cleared; under_water = g.under_water; } void command(char c) @@ -404,17 +405,16 @@ assert(c != 'A'); if(dead || cleared) return; // TODO: clarify the event order - Tuple!(int,bool) ld = map.command(c, turn); + bool dead_now = map.command(c, turn); if( map.cleared() ) { cleared = true; } else { - lambda += ld[0]; - if( ld[1] ) + if( dead_now ) dead = true; } if(!cleared) { if( map.robot.y <= water_level ) ++under_water; @@ -428,19 +428,18 @@ Map map; Water water; int turn = 0; bool dead = false; - int lambda = 0; int under_water = 0; bool cleared = false; // TODO: when adding members, take care of clone(). // TODO: fix this poor design. @property const { - long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L) - turn; } + long score() { return map.collected_lambda*(dead ? 25L : cleared ? 75L : 50L) - turn; } int water_level() { return water.level(turn); } int water_until_rise() { return water.until_rise(turn); } int hige_until_rise() { return map.hige.until_rise(turn); } int hp() { return map.waterproof - under_water; } } }