Index: src/game.d ================================================================== --- src/game.d +++ src/game.d @@ -41,11 +41,10 @@ class Water { public immutable int base, pace; mixin DeriveCreate; - mixin DeriveCompare; mixin DeriveShow; Water clone() const { return cast(Water) this; } static load(string[string] params) { @@ -88,11 +87,10 @@ class Hige { public immutable int pace; mixin DeriveCreate; - mixin DeriveCompare; mixin DeriveShow; Hige clone() const { return cast(Hige)this; } static load(string[string] params) { @@ -110,20 +108,72 @@ } } //////////////////////////////////////////////////////////////////////////////// +class Trampoline +{ + private immutable char[] target_of_; + private immutable char[][] source_of_; + private immutable Pos[] position_of_; + private immutable char[] source_list_; + private immutable char[] target_list_; + mixin DeriveShow; + Trampoline clone() const { return cast(Trampoline) this; } + this(Map m, char[char] tramparam) + { + auto ta = new char['I'+1]; + auto sr = new char[]['9'+1]; + auto po = new Pos[max('I','9')+1]; + char[] sl, tl; + foreach(fr,to; tramparam) { + ta[fr] = to; + sr[to] ~= fr; + } + for(int y=1; y<=m.H; ++y) + for(int x=1; x<=m.W; ++x) { + char c = m[y,x]; + if('A'<=c && c<='I') { + sl ~= c; + po[c] = new Pos(y,x); + } + if('1'<=c && c<='9') { + tl ~= c; + po[c] = new Pos(y,x); + } + } + target_of_ = cast(immutable) ta; + source_of_ = cast(immutable) sr; + position_of_ = cast(immutable) po; + source_list_ = cast(immutable) sl; + target_list_ = cast(immutable) tl; + } + +@property const: + const(char[]) source_list() { return source_list_; } + const(char[]) target_list() { return target_list_; } + const(char[]) source_of(char c) { return source_of_[c]; } + char target_of(char c) { return target_of_[c]; } + Pos[] source_pos(char c) { + Pos[] ps; + foreach(s; source_of(c)) + ps ~= position_of_[s].clone(); + return ps; + } + Pos target_pos(char c) { return position_of_[target_of_[c]].clone(); } +} + +//////////////////////////////////////////////////////////////////////////////// + class Map { mixin DeriveShow; char[][] data; Pos robot; Pos lift; int waterproof; - Pos[char] tr_target; - Pos[][char] tr_source; int razor; int collected_lambda; int total_lambda; bool cleared; Pos[] may_update; @@ -133,12 +183,10 @@ foreach(s; m.data) this.data ~= s.dup; this.robot = m.robot.clone(); this.lift = m.lift.clone(); this.waterproof = m.waterproof; - this.tr_target = cast(Pos[char])m.tr_target; - this.tr_source = cast(Pos[][char])m.tr_source; this.razor = m.razor; this.collected_lambda = m.collected_lambda; this.total_lambda = m.total_lambda; this.may_update = (cast(Map)m).may_update.dup; this.cleared = m.cleared; @@ -165,25 +213,11 @@ total_lambda++; if(this[y,x] == '*' || this[y,x] == '@') may_update ~= new Pos(y,x); } - Pos[char] tr_pos; - for(int y=1; y<=H; ++y) - for(int x=1; x<=W; ++x) { - char c = this[y,x]; - if('1'<=c && c<='9' || 'A'<=c&&c<='I') - tr_pos[c] = new Pos(y,x); - } - this.waterproof = params.get("Waterproof", "5").to!int(); - foreach(fr,to; trampo) { - tr_target[fr] = tr_pos[to]; - if(to !in tr_source) tr_source[to] = []; - tr_source[to] ~= tr_pos[fr]; - } - this.razor = params.get("Razors", "0").to!int(); } const @property { int H() { return data.length; } @@ -230,18 +264,18 @@ } Pos[] razors() const { return objects('!'); } Pos[] lambdas() const { return objects('\\'); } - bool command(char c, int turn, bool hige_day) + bool command(char c, int turn, bool hige_day, in Trampoline tr) { assert( this[robot] == 'R' ); - if(c=='R') return move( 0, +1, hige_day); - if(c=='L') return move( 0, -1, hige_day); - if(c=='U') return move(+1, 0, hige_day); - if(c=='D') return move(-1, 0, hige_day); - if(c=='W') return move( 0, 0, hige_day); + if(c=='R') return move( 0, +1, hige_day, tr); + if(c=='L') return move( 0, -1, hige_day, tr); + if(c=='U') return move(+1, 0, hige_day, tr); + if(c=='D') return move(-1, 0, hige_day, tr); + if(c=='W') return move( 0, 0, hige_day, tr); if(c=='S') return use_razor(hige_day); assert(false); } bool use_razor(bool hige_day) @@ -265,11 +299,11 @@ for(int dy=0; dy<=+1; ++dy) for(int dx=-1; dx<=+1; ++dx) may_update ~= new Pos(p.y+dy, p.x+dx); } - bool move(int dy, int dx, bool hige_day) + bool move(int dy, int dx, bool hige_day, in Trampoline tr) { emptified(robot); int y = robot.y; int x = robot.x; @@ -289,12 +323,12 @@ this[y+dy,x+dx]='R'; 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]]) { + Pos tp = tr.target_pos(this[y+dy,x+dx]); + foreach(p; tr.source_pos(this[tp])) { emptified(p); this[p] = ' '; } this[tp] = 'R'; robot = tp; @@ -395,17 +429,19 @@ } this.map = new Map(raw_data, params, trampo); this.water = Water.load(params); this.hige = Hige.load(params); + this.tr = new Trampoline(this.map, trampo); } Game clone() const { return new Game(this); } this(in Game g) { map = g.map.clone(); water = g.water.clone(); hige = g.hige.clone(); + tr = g.tr.clone(); turn = g.turn; dead = g.dead; under_water = g.under_water; } @@ -414,11 +450,11 @@ assert(c != 'A'); if(dead || cleared) return; // TODO: clarify the event order - bool dead_now = map.command(c, turn, hige.is_growing_turn(turn)); + bool dead_now = map.command(c, turn, hige.is_growing_turn(turn), tr); if( dead_now ) dead = true; if(!map.cleared) { if( map.robot.y <= water_level ) ++under_water; @@ -431,10 +467,11 @@ } Map map; Water water; Hige hige; + Trampoline tr; int turn = 0; bool dead = false; int under_water = 0; // TODO: when adding members, take care of clone(). // TODO: fix this poor design. Index: src/gui.d ================================================================== --- src/gui.d +++ src/gui.d @@ -79,12 +79,14 @@ this.render['d'] = "☠"; this.render['L'] = "☒"; this.render['O'] = "☐"; this.render['W'] = "ꔣ"; this.render['!'] = "✄"; - foreach(c,tp; g.map.tr_target) this.render[c] = [cast(dchar)('☢'+g.map[tp]-'1')].to!string(); - foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1')].to!string(); + foreach(char c; g.tr.source_list) + this.render[c] = [cast(dchar)('☢'+g.tr.target_of(c)-'1')].to!string(); + foreach(char c; g.tr.target_list) + this.render[c] = [cast(dchar)('☢'+c-'1')].to!string(); this.paint ~= (Control c, PaintEventArgs ev) { graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clientSize.height)); }; } Index: src/solver.d ================================================================== --- src/solver.d +++ src/solver.d @@ -193,11 +193,11 @@ int[] xxx=[p.x,p.x,p.x-1,p.x+1]; for(int i=0; i=4)continue; if(y!=p.y)continue; if(g.map[y,p.x+(p.x-x)]!=' '&&g.map[y,p.x+(p.x-x)]!='R')continue; } if('1'<=g.map[y,x]&&g.map[y,x]<='9') { - foreach(ppp; g.map.tr_source[g.map[y,x]]) { + foreach(ppp; g.tr.source_pos(g.map[y,x])) { yyy ~= ppp.y; xxx ~= ppp.x; } continue; }