6293256fec 2012-07-14 kinaba: import util; bee0596f0f 2012-07-14 kinaba: bee0596f0f 2012-07-14 kinaba: //////////////////////////////////////////////////////////////////////////////// bee0596f0f 2012-07-14 kinaba: b96971b0b6 2012-07-16 kinaba: bool is_spacy(char c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O'; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: bool is_rocky(char c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: return c=='*' || c=='@'; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: bool is_true_space(char c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: return c==' '; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: bool is_trampoline_source(char c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: return 'A'<=c && c<='I'; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: bool is_rocklambda(char c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: return is_rocky(c) || c=='\\'; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: //////////////////////////////////////////////////////////////////////////////// b96971b0b6 2012-07-16 kinaba: 6293256fec 2012-07-14 kinaba: class Pos 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: public immutable int y, x; 6293256fec 2012-07-14 kinaba: mixin DeriveCreate; 6293256fec 2012-07-14 kinaba: mixin DeriveCompare; 6293256fec 2012-07-14 kinaba: mixin DeriveShow; a0c3529225 2012-07-14 kinaba: Pos clone() const { return cast(Pos) this; } 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: const @property: bee0596f0f 2012-07-14 kinaba: Pos wait() { return this.clone(); } 6293256fec 2012-07-14 kinaba: Pos up() { return new Pos(y+1, x); } 6293256fec 2012-07-14 kinaba: Pos down() { return new Pos(y-1, x); } 6293256fec 2012-07-14 kinaba: Pos left() { return new Pos(y, x-1); } 6293256fec 2012-07-14 kinaba: Pos right() { return new Pos(y, x+1); } 6293256fec 2012-07-14 kinaba: alias wait W,w; 6293256fec 2012-07-14 kinaba: alias up U,u; 6293256fec 2012-07-14 kinaba: alias down D,d; 6293256fec 2012-07-14 kinaba: alias left L,l; 6293256fec 2012-07-14 kinaba: alias right R,r; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: unittest 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: assert( (new Pos(2,1)).U == new Pos(3,1) ); 6293256fec 2012-07-14 kinaba: assert( (new Pos(0,1)).D == new Pos(-1,1) ); 6293256fec 2012-07-14 kinaba: assert( (new Pos(2,1)).L == new Pos(2,0) ); 6293256fec 2012-07-14 kinaba: assert( (new Pos(2,1)).R == new Pos(2,2) ); 6293256fec 2012-07-14 kinaba: int[Pos] aa; 6293256fec 2012-07-14 kinaba: aa[new Pos(1,2)] = 1; 6293256fec 2012-07-14 kinaba: aa[new Pos(1,2)] = 2; 6293256fec 2012-07-14 kinaba: aa[new Pos(2,1)] = 3; 6293256fec 2012-07-14 kinaba: assert( aa.length==2 ); 6293256fec 2012-07-14 kinaba: assert( aa[new Pos(1,2)]==2 ); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: //////////////////////////////////////////////////////////////////////////////// 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: class Water 6293256fec 2012-07-14 kinaba: { 64f5c73b88 2012-07-15 kinaba: mixin DeriveShow; b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: private: b96971b0b6 2012-07-16 kinaba: immutable int base, pace; b96971b0b6 2012-07-16 kinaba: mixin DeriveCreate; 64f5c73b88 2012-07-15 kinaba: Water clone() const { return cast(Water) this; } b1ce0206cd 2012-07-14 kinaba: b1ce0206cd 2012-07-14 kinaba: static load(string[string] params) 6293256fec 2012-07-14 kinaba: { 4aa9d7f484 2012-07-15 kinaba: return new Water(params.get("Water", "0").to!int(), 4aa9d7f484 2012-07-15 kinaba: params.get("Flooding", "0").to!int()); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: int level(int turn) const 6293256fec 2012-07-14 kinaba: { 64f5c73b88 2012-07-15 kinaba: return pace ? base+(turn/pace) : base; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: int until_rise(int turn) const 6293256fec 2012-07-14 kinaba: { 64f5c73b88 2012-07-15 kinaba: return pace ? pace-turn%pace : int.max; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: unittest 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: Water w = new Water(1, 3); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(0) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(1) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(2) ); 6293256fec 2012-07-14 kinaba: assert( 2 == w.level(3) ); 6293256fec 2012-07-14 kinaba: assert( 2 == w.level(4) ); 6293256fec 2012-07-14 kinaba: assert( 2 == w.level(5) ); 6293256fec 2012-07-14 kinaba: assert( 3 == w.level(6) ); 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: w = new Water(1, 0); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(0) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(1) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(2) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(3) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(4) ); 6293256fec 2012-07-14 kinaba: assert( 1 == w.level(5) ); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: //////////////////////////////////////////////////////////////////////////////// 6293256fec 2012-07-14 kinaba: 9d983af88c 2012-07-15 kinaba: class Hige 9d983af88c 2012-07-15 kinaba: { 9d983af88c 2012-07-15 kinaba: mixin DeriveShow; b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: private: b96971b0b6 2012-07-16 kinaba: immutable int pace; b96971b0b6 2012-07-16 kinaba: mixin DeriveCreate; 9d983af88c 2012-07-15 kinaba: Hige clone() const { return cast(Hige)this; } 9d983af88c 2012-07-15 kinaba: 9d983af88c 2012-07-15 kinaba: static load(string[string] params) 9d983af88c 2012-07-15 kinaba: { 9d983af88c 2012-07-15 kinaba: return new Hige(params.get("Growth", "25").to!int()); 9d983af88c 2012-07-15 kinaba: } 9d983af88c 2012-07-15 kinaba: 9d983af88c 2012-07-15 kinaba: bool is_growing_turn(int turn) const 9d983af88c 2012-07-15 kinaba: { 9d983af88c 2012-07-15 kinaba: return pace ? turn%pace == pace-1 : false; 9d983af88c 2012-07-15 kinaba: } 9d983af88c 2012-07-15 kinaba: 9d983af88c 2012-07-15 kinaba: int until_rise(int turn) const 9d983af88c 2012-07-15 kinaba: { 9d983af88c 2012-07-15 kinaba: return pace ? pace-turn%pace : int.max; 9d983af88c 2012-07-15 kinaba: } 9d983af88c 2012-07-15 kinaba: } 9d983af88c 2012-07-15 kinaba: 9d983af88c 2012-07-15 kinaba: //////////////////////////////////////////////////////////////////////////////// 9d983af88c 2012-07-15 kinaba: d40deaae5a 2012-07-15 kinaba: class Trampoline d40deaae5a 2012-07-15 kinaba: { d40deaae5a 2012-07-15 kinaba: mixin DeriveShow; b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: private: b96971b0b6 2012-07-16 kinaba: immutable char[] target_of_; b96971b0b6 2012-07-16 kinaba: immutable char[][] source_of_; b96971b0b6 2012-07-16 kinaba: immutable Pos[] position_of_; b96971b0b6 2012-07-16 kinaba: immutable char[] source_list_; b96971b0b6 2012-07-16 kinaba: immutable char[] target_list_; d40deaae5a 2012-07-15 kinaba: Trampoline clone() const { return cast(Trampoline) this; } b96971b0b6 2012-07-16 kinaba: d40deaae5a 2012-07-15 kinaba: this(Map m, char[char] tramparam) d40deaae5a 2012-07-15 kinaba: { d40deaae5a 2012-07-15 kinaba: auto ta = new char['I'+1]; d40deaae5a 2012-07-15 kinaba: auto sr = new char[]['9'+1]; d40deaae5a 2012-07-15 kinaba: auto po = new Pos[max('I','9')+1]; d40deaae5a 2012-07-15 kinaba: char[] sl, tl; d40deaae5a 2012-07-15 kinaba: foreach(fr,to; tramparam) { d40deaae5a 2012-07-15 kinaba: ta[fr] = to; d40deaae5a 2012-07-15 kinaba: sr[to] ~= fr; d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: for(int y=1; y<=m.H; ++y) d40deaae5a 2012-07-15 kinaba: for(int x=1; x<=m.W; ++x) { d40deaae5a 2012-07-15 kinaba: char c = m[y,x]; d40deaae5a 2012-07-15 kinaba: if('A'<=c && c<='I') { d40deaae5a 2012-07-15 kinaba: sl ~= c; d40deaae5a 2012-07-15 kinaba: po[c] = new Pos(y,x); d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: if('1'<=c && c<='9') { d40deaae5a 2012-07-15 kinaba: tl ~= c; d40deaae5a 2012-07-15 kinaba: po[c] = new Pos(y,x); d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: target_of_ = cast(immutable) ta; d40deaae5a 2012-07-15 kinaba: source_of_ = cast(immutable) sr; d40deaae5a 2012-07-15 kinaba: position_of_ = cast(immutable) po; d40deaae5a 2012-07-15 kinaba: source_list_ = cast(immutable) sl; d40deaae5a 2012-07-15 kinaba: target_list_ = cast(immutable) tl; d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: b96971b0b6 2012-07-16 kinaba: public @property const: d40deaae5a 2012-07-15 kinaba: const(char[]) source_list() { return source_list_; } d40deaae5a 2012-07-15 kinaba: const(char[]) target_list() { return target_list_; } d40deaae5a 2012-07-15 kinaba: const(char[]) source_of(char c) { return source_of_[c]; } d40deaae5a 2012-07-15 kinaba: char target_of(char c) { return target_of_[c]; } d40deaae5a 2012-07-15 kinaba: Pos[] source_pos(char c) { d40deaae5a 2012-07-15 kinaba: Pos[] ps; d40deaae5a 2012-07-15 kinaba: foreach(s; source_of(c)) d40deaae5a 2012-07-15 kinaba: ps ~= position_of_[s].clone(); d40deaae5a 2012-07-15 kinaba: return ps; d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: Pos target_pos(char c) { return position_of_[target_of_[c]].clone(); } d40deaae5a 2012-07-15 kinaba: } d40deaae5a 2012-07-15 kinaba: d40deaae5a 2012-07-15 kinaba: //////////////////////////////////////////////////////////////////////////////// d40deaae5a 2012-07-15 kinaba: 6293256fec 2012-07-14 kinaba: class Map 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: mixin DeriveShow; 6293256fec 2012-07-14 kinaba: b96971b0b6 2012-07-16 kinaba: private char[][] data; 6293256fec 2012-07-14 kinaba: Pos robot; 6293256fec 2012-07-14 kinaba: Pos lift; b96971b0b6 2012-07-16 kinaba: private int waterproof; b96971b0b6 2012-07-16 kinaba: private int collected_razor; de416b884b 2012-07-15 kinaba: int collected_lambda; de416b884b 2012-07-15 kinaba: int total_lambda; b96971b0b6 2012-07-16 kinaba: private bool cleared; b96971b0b6 2012-07-16 kinaba: private Pos[] may_update; 6293256fec 2012-07-14 kinaba: b96971b0b6 2012-07-16 kinaba: private Map clone() const { return new Map(this); } b96971b0b6 2012-07-16 kinaba: private this(in Map m) { 6293256fec 2012-07-14 kinaba: foreach(s; m.data) 6293256fec 2012-07-14 kinaba: this.data ~= s.dup; b96971b0b6 2012-07-16 kinaba: this.robot = m.robot.clone(); b96971b0b6 2012-07-16 kinaba: this.lift = m.lift.clone(); 6293256fec 2012-07-14 kinaba: this.waterproof = m.waterproof; b96971b0b6 2012-07-16 kinaba: this.collected_razor = m.collected_razor; de416b884b 2012-07-15 kinaba: this.collected_lambda = m.collected_lambda; b96971b0b6 2012-07-16 kinaba: this.total_lambda = m.total_lambda; b96971b0b6 2012-07-16 kinaba: this.cleared = m.cleared; b83558c1a5 2012-07-15 kinaba: this.may_update = (cast(Map)m).may_update.dup; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: const { b96971b0b6 2012-07-16 kinaba: @property { b96971b0b6 2012-07-16 kinaba: int H() { return data.length; } b96971b0b6 2012-07-16 kinaba: int W() { return data[0].length; } b96971b0b6 2012-07-16 kinaba: int num_razor() { return collected_razor; } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: Pos[] razors() { return objects('!'); } b96971b0b6 2012-07-16 kinaba: Pos[] lambdas() { return objects('\\'); } b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: Pos[] objects(char c) { b96971b0b6 2012-07-16 kinaba: Pos[] ans; b96971b0b6 2012-07-16 kinaba: for(int y=1; y<=H; ++y) b96971b0b6 2012-07-16 kinaba: for(int x=1; x<=W; ++x) b96971b0b6 2012-07-16 kinaba: if(this[y,x] == c) b96971b0b6 2012-07-16 kinaba: ans ~= new Pos(y,x); b96971b0b6 2012-07-16 kinaba: return ans; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: char opIndex(int y, int x) { b96971b0b6 2012-07-16 kinaba: --y, --x; b96971b0b6 2012-07-16 kinaba: if(y<0||H<=y||x<0||W<=x) b96971b0b6 2012-07-16 kinaba: return '#'; b96971b0b6 2012-07-16 kinaba: return data[H-1-y][x]; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: char opIndex(in Pos p) { b96971b0b6 2012-07-16 kinaba: return this[p.y, p.x]; b96971b0b6 2012-07-16 kinaba: } 64f5c73b88 2012-07-15 kinaba: } 64f5c73b88 2012-07-15 kinaba: b96971b0b6 2012-07-16 kinaba: private: b8acb5f918 2012-07-14 kinaba: this(string[] raw_data, string[string] params, char[char] trampo) 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: int width = 0; 6293256fec 2012-07-14 kinaba: foreach(r; raw_data) 6293256fec 2012-07-14 kinaba: width = max(width, r.length); 6293256fec 2012-07-14 kinaba: foreach(r; raw_data) { 6293256fec 2012-07-14 kinaba: this.data ~= r.dup; 6293256fec 2012-07-14 kinaba: this.data[$-1].length = width; 6293256fec 2012-07-14 kinaba: this.data[$-1][r.length..$] = ' '; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: for(int y=1; y<=H; ++y) 6293256fec 2012-07-14 kinaba: for(int x=1; x<=W; ++x) { 6293256fec 2012-07-14 kinaba: if(this[y,x] == 'R') 6293256fec 2012-07-14 kinaba: this.robot = new Pos(y,x); 6293256fec 2012-07-14 kinaba: if(this[y,x] == 'L' || this[y,x] == 'O') 6293256fec 2012-07-14 kinaba: this.lift = new Pos(y,x); de416b884b 2012-07-15 kinaba: if(this[y,x] == '\\' || this[y,x] == '@') de416b884b 2012-07-15 kinaba: total_lambda++; b96971b0b6 2012-07-16 kinaba: if(is_rocky(this[y,x])) b83558c1a5 2012-07-15 kinaba: may_update ~= new Pos(y,x); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: b96971b0b6 2012-07-16 kinaba: this.waterproof = params.get("Waterproof", "5").to!int(); b96971b0b6 2012-07-16 kinaba: this.collected_razor = params.get("Razors", "0").to!int(); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: void opIndexAssign(char c, int y, int x) 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: --y, --x; 6293256fec 2012-07-14 kinaba: if(y<0||H<=y||x<0||W<=x) 6293256fec 2012-07-14 kinaba: return; 6293256fec 2012-07-14 kinaba: data[H-1-y][x] = c; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 62a5c6c47f 2012-07-14 kinaba: void opIndexAssign(char c, in Pos p) 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: this[p.y, p.x] = c; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: d40deaae5a 2012-07-15 kinaba: bool command(char c, int turn, bool hige_day, in Trampoline tr) 5491fa544d 2012-07-15 kinaba: { b96971b0b6 2012-07-16 kinaba: switch(c) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: case 'R': return move( 0, +1, hige_day, tr); b96971b0b6 2012-07-16 kinaba: case 'L': return move( 0, -1, hige_day, tr); b96971b0b6 2012-07-16 kinaba: case 'U': return move(+1, 0, hige_day, tr); b96971b0b6 2012-07-16 kinaba: case 'D': return move(-1, 0, hige_day, tr); b96971b0b6 2012-07-16 kinaba: case 'W': return move( 0, 0, hige_day, tr); b96971b0b6 2012-07-16 kinaba: case 'S': return use_razor(hige_day); b96971b0b6 2012-07-16 kinaba: default: assert(false); b96971b0b6 2012-07-16 kinaba: } 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 5491fa544d 2012-07-15 kinaba: bool use_razor(bool hige_day) 6293256fec 2012-07-14 kinaba: { b96971b0b6 2012-07-16 kinaba: if(collected_razor > 0) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: collected_razor--; 3a08e528e7 2012-07-15 kinaba: for(int dy=-1; dy<=+1; ++dy) 3a08e528e7 2012-07-15 kinaba: for(int dx=-1; dx<=+1; ++dx) 03b7073abc 2012-07-16 kinaba: if(this[robot.y+dy,robot.x+dx] == 'W') 03b7073abc 2012-07-16 kinaba: emptify(new Pos(robot.y+dy,robot.x+dx)); 3a08e528e7 2012-07-15 kinaba: } 5491fa544d 2012-07-15 kinaba: return update(hige_day); 5491fa544d 2012-07-15 kinaba: } 6293256fec 2012-07-14 kinaba: b96971b0b6 2012-07-16 kinaba: // Register a position that may become empty in the last turn. 03b7073abc 2012-07-16 kinaba: void emptify(Pos p) b96971b0b6 2012-07-16 kinaba: { 03b7073abc 2012-07-16 kinaba: this[p] = ' '; b96971b0b6 2012-07-16 kinaba: for(int dy=0; dy<=+1; ++dy) b96971b0b6 2012-07-16 kinaba: for(int dx=-1; dx<=+1; ++dx) b96971b0b6 2012-07-16 kinaba: may_update ~= new Pos(p.y+dy, p.x+dx); b96971b0b6 2012-07-16 kinaba: } 6293256fec 2012-07-14 kinaba: d40deaae5a 2012-07-15 kinaba: bool move(int dy, int dx, bool hige_day, in Trampoline tr) 6293256fec 2012-07-14 kinaba: { b96971b0b6 2012-07-16 kinaba: Pos next = new Pos(robot.y+dy, robot.x+dx); b96971b0b6 2012-07-16 kinaba: int y=robot.y, x=robot.x; b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: if( '\\' == this[next] ) collected_lambda++; b96971b0b6 2012-07-16 kinaba: if( '!' == this[next] ) collected_razor++; b96971b0b6 2012-07-16 kinaba: if( 'O' == this[next] ) cleared = true; b96971b0b6 2012-07-16 kinaba: b96971b0b6 2012-07-16 kinaba: if( is_spacy(this[next]) ) b96971b0b6 2012-07-16 kinaba: { 03b7073abc 2012-07-16 kinaba: emptify(robot); b96971b0b6 2012-07-16 kinaba: robot = next; 03b7073abc 2012-07-16 kinaba: this[next] = 'R'; b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: else if(dy==0 && is_rocky(this[next]) && ' '==this[y+dy*2,x+dx*2]) b96971b0b6 2012-07-16 kinaba: { b96971b0b6 2012-07-16 kinaba: char rock = this[next]; 03b7073abc 2012-07-16 kinaba: emptify(robot); 03b7073abc 2012-07-16 kinaba: robot = next; b96971b0b6 2012-07-16 kinaba: this[next] = 'R'; b96971b0b6 2012-07-16 kinaba: this[y+dy*2,x+dx*2] = rock; bf626def96 2012-07-15 kinaba: may_update ~= new Pos(y+dy*2,x+dx*2); b96971b0b6 2012-07-16 kinaba: } b96971b0b6 2012-07-16 kinaba: else if(is_trampoline_source(this[next])) b96971b0b6 2012-07-16 kinaba: { 03b7073abc 2012-07-16 kinaba: emptify(robot); b96971b0b6 2012-07-16 kinaba: Pos tp = tr.target_pos(this[next]); b96971b0b6 2012-07-16 kinaba: foreach(p; tr.source_pos(this[tp])) 03b7073abc 2012-07-16 kinaba: emptify(p); deca17f61a 2012-07-14 kinaba: this[tp] = 'R'; b96971b0b6 2012-07-16 kinaba: robot = tp; 6293256fec 2012-07-14 kinaba: } 5491fa544d 2012-07-15 kinaba: return update(hige_day); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 5491fa544d 2012-07-15 kinaba: bool update(bool hige_day) 6293256fec 2012-07-14 kinaba: { b83558c1a5 2012-07-15 kinaba: // Write after all the updates are processed. b83558c1a5 2012-07-15 kinaba: Tuple!(int,int,char)[] write_buffer; b83558c1a5 2012-07-15 kinaba: void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); } b83558c1a5 2012-07-15 kinaba: void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c); } b83558c1a5 2012-07-15 kinaba: scope(exit) { b83558c1a5 2012-07-15 kinaba: may_update.length = 0; b83558c1a5 2012-07-15 kinaba: foreach(wr; write_buffer) { b83558c1a5 2012-07-15 kinaba: this[wr[0],wr[1]] = wr[2]; b96971b0b6 2012-07-16 kinaba: if(is_rocky(wr[2])) b83558c1a5 2012-07-15 kinaba: may_update ~= new Pos(wr[0],wr[1]); b83558c1a5 2012-07-15 kinaba: if(wr[2]==' ') 03b7073abc 2012-07-16 kinaba: emptify(new Pos(wr[0], wr[1])); b83558c1a5 2012-07-15 kinaba: } b83558c1a5 2012-07-15 kinaba: } b83558c1a5 2012-07-15 kinaba: b83558c1a5 2012-07-15 kinaba: if(collected_lambda == total_lambda) b83558c1a5 2012-07-15 kinaba: if(this[lift]=='L') b83558c1a5 2012-07-15 kinaba: this[lift] = 'O'; b83558c1a5 2012-07-15 kinaba: 6293256fec 2012-07-14 kinaba: bool dead = false; 5491fa544d 2012-07-15 kinaba: if( hige_day ) { 5491fa544d 2012-07-15 kinaba: for(int y=1; y<=H; ++y) 5491fa544d 2012-07-15 kinaba: for(int x=1; x<=W; ++x) 5491fa544d 2012-07-15 kinaba: if(this[y,x]=='W') 5491fa544d 2012-07-15 kinaba: may_update ~= new Pos(y,x); 5491fa544d 2012-07-15 kinaba: } 5491fa544d 2012-07-15 kinaba: b83558c1a5 2012-07-15 kinaba: sort(may_update); b83558c1a5 2012-07-15 kinaba: foreach(p; may_update) { b83558c1a5 2012-07-15 kinaba: int y = p.y, x = p.x; de416b884b 2012-07-15 kinaba: char rock = this[p]; b96971b0b6 2012-07-16 kinaba: if(is_rocky(this[p])) { 6293256fec 2012-07-14 kinaba: if(this[p.D]==' ') { b83558c1a5 2012-07-15 kinaba: writep(p, ' '); b83558c1a5 2012-07-15 kinaba: writep(p.D, (rock=='@'&&this[p.D.D]!=' ' ? '\\' : rock)); 6293256fec 2012-07-14 kinaba: if(robot == p.D.D) 6293256fec 2012-07-14 kinaba: dead=true; 6293256fec 2012-07-14 kinaba: } b96971b0b6 2012-07-16 kinaba: else if((is_rocky(this[p.D]) || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { b83558c1a5 2012-07-15 kinaba: writep(p, ' '); b83558c1a5 2012-07-15 kinaba: writep(p.R.D,(rock=='@'&&this[p.R.D.D]!=' ' ? '\\' : rock)); 6293256fec 2012-07-14 kinaba: if(robot == p.R.D.D) 6293256fec 2012-07-14 kinaba: dead=true; 6293256fec 2012-07-14 kinaba: } b96971b0b6 2012-07-16 kinaba: else if(is_rocky(this[p.D]) && this[p.L]==' ' && this[p.L.D]==' ') { b83558c1a5 2012-07-15 kinaba: writep(p, ' '); b83558c1a5 2012-07-15 kinaba: writep(p.L.D, (rock=='@'&&this[p.L.D.D]!=' ' ? '\\' : rock)); 6293256fec 2012-07-14 kinaba: if(robot == p.L.D.D) 6293256fec 2012-07-14 kinaba: dead=true; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: } 5491fa544d 2012-07-15 kinaba: else if(this[p]=='W') { 5491fa544d 2012-07-15 kinaba: if(hige_day) { 2b4f8bba2d 2012-07-15 kinaba: for(int dy=-1; dy<=+1; ++dy) 2b4f8bba2d 2012-07-15 kinaba: for(int dx=-1; dx<=+1; ++dx) 971863e35a 2012-07-16 kinaba: if(this[p.y+dy,p.x+dx] == ' ') { b83558c1a5 2012-07-15 kinaba: write(p.y+dy,p.x+dx,'W'); 971863e35a 2012-07-16 kinaba: if(robot.y==p.y+dy-1 && robot.x==p.x+dx) 971863e35a 2012-07-16 kinaba: dead = false; // guarded by hige! 971863e35a 2012-07-16 kinaba: } 5491fa544d 2012-07-15 kinaba: } 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: } 64f5c73b88 2012-07-15 kinaba: 6293256fec 2012-07-14 kinaba: return dead; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: //////////////////////////////////////////////////////////////////////////////// e02668367d 2012-07-15 kinaba: 6293256fec 2012-07-14 kinaba: class Game 6293256fec 2012-07-14 kinaba: { 6293256fec 2012-07-14 kinaba: mixin DeriveShow; 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: this(File input) 6293256fec 2012-07-14 kinaba: { b1ce0206cd 2012-07-14 kinaba: string[] raw_data; b1ce0206cd 2012-07-14 kinaba: string[string] params; 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: // Raw map data; read until empty line. 6293256fec 2012-07-14 kinaba: for(string line; !(line=input.readln().chomp()).empty; ) 6293256fec 2012-07-14 kinaba: raw_data ~= line; 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: // Additional commands; read until EOF. b8acb5f918 2012-07-14 kinaba: char[char] trampo; 6293256fec 2012-07-14 kinaba: for(string line; !(line=input.readln()).empty; ) { 6293256fec 2012-07-14 kinaba: string[] ss = line.split(); b1ce0206cd 2012-07-14 kinaba: if( ss.length == 2 ) b1ce0206cd 2012-07-14 kinaba: params[ss[0]] = ss[1]; b8acb5f918 2012-07-14 kinaba: if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" ) b8acb5f918 2012-07-14 kinaba: trampo[ss[1][0]] = ss[3][0]; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: this.map = new Map(raw_data, params, trampo); bee0596f0f 2012-07-14 kinaba: this.water = Water.load(params); 5491fa544d 2012-07-15 kinaba: this.hige = Hige.load(params); d40deaae5a 2012-07-15 kinaba: this.tr = new Trampoline(this.map, trampo); 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: bee0596f0f 2012-07-14 kinaba: Game clone() const { return new Game(this); } a0c3529225 2012-07-14 kinaba: this(in Game g) { 64f5c73b88 2012-07-15 kinaba: map = g.map.clone(); 6293256fec 2012-07-14 kinaba: water = g.water.clone(); 5491fa544d 2012-07-15 kinaba: hige = g.hige.clone(); d40deaae5a 2012-07-15 kinaba: tr = g.tr.clone(); 64f5c73b88 2012-07-15 kinaba: turn = g.turn; 64f5c73b88 2012-07-15 kinaba: dead = g.dead; 6293256fec 2012-07-14 kinaba: under_water = g.under_water; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: void command(char c) 6293256fec 2012-07-14 kinaba: { 879099f815 2012-07-15 kinaba: assert(c != 'A'); 6293256fec 2012-07-14 kinaba: if(dead || cleared) 6293256fec 2012-07-14 kinaba: return; 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: // TODO: clarify the event order d40deaae5a 2012-07-15 kinaba: bool dead_now = map.command(c, turn, hige.is_growing_turn(turn), tr); 64f5c73b88 2012-07-15 kinaba: if( dead_now ) 64f5c73b88 2012-07-15 kinaba: dead = true; 64f5c73b88 2012-07-15 kinaba: if(!map.cleared) { 6d497011d6 2012-07-15 kinaba: if( map.robot.y <= water_level ) 6d497011d6 2012-07-15 kinaba: ++under_water; 6d497011d6 2012-07-15 kinaba: else 6d497011d6 2012-07-15 kinaba: under_water = 0; 6d497011d6 2012-07-15 kinaba: if( under_water > map.waterproof ) 6293256fec 2012-07-14 kinaba: dead = true; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: turn += 1; 6293256fec 2012-07-14 kinaba: } 6293256fec 2012-07-14 kinaba: 6293256fec 2012-07-14 kinaba: Map map; 6293256fec 2012-07-14 kinaba: Water water; 5491fa544d 2012-07-15 kinaba: Hige hige; d40deaae5a 2012-07-15 kinaba: Trampoline tr; 6293256fec 2012-07-14 kinaba: int turn = 0; 6293256fec 2012-07-14 kinaba: bool dead = false; 6293256fec 2012-07-14 kinaba: int under_water = 0; 6293256fec 2012-07-14 kinaba: // TODO: when adding members, take care of clone(). 6293256fec 2012-07-14 kinaba: // TODO: fix this poor design. 6293256fec 2012-07-14 kinaba: 64f5c73b88 2012-07-15 kinaba: @property const: 64f5c73b88 2012-07-15 kinaba: long score() { return map.collected_lambda*(dead?25L:cleared?75L:50L)-turn; } 64f5c73b88 2012-07-15 kinaba: int water_level() { return water.level(turn); } 64f5c73b88 2012-07-15 kinaba: int water_until_rise() { return water.until_rise(turn); } 5491fa544d 2012-07-15 kinaba: int hige_until_rise() { return hige.until_rise(turn); } 64f5c73b88 2012-07-15 kinaba: int hp() { return map.waterproof - under_water; } 64f5c73b88 2012-07-15 kinaba: bool cleared() { return map.cleared; } 6293256fec 2012-07-14 kinaba: }