Check-in Differences
Not logged in

Difference From:

[68b1c6ac49] 100x100. this is already large enough for the current routine... (user: kinaba, tags: trunk, date: 2012-07-14 15:54:47)

To:

[fc9286dad1] uum (user: kinaba, tags: redesign, date: 2012-07-15 12:11:33)

Added maps/40x40.map version [06dc362ef16f425d]

> 1 ######################################## > 2 #L\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 3 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 4 #.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*# > 5 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 6 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 7 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 8 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 9 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 10 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 11 #.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*# > 12 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 13 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 14 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 15 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 16 #.\.\.\.\.\.\.\.\.\W\.\.\.\.\.\.\.\.\.\# > 17 #.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*# > 18 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 19 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 20 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 21 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 22 #.\.\.\.\!\.\.\.\.\.\.\.\W\.\.\.\.\.\.\# > 23 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 24 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 25 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 26 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 27 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 28 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 29 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 30 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 31 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\!\.\.# > 32 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 33 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 34 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\# > 35 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\!\.\.# > 36 #.\.\.\.\.\.\.\.\W\.\.\.\.\.\.\.\.\.\.\# > 37 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.# > 38 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.R# > 39 ######################################## > 40 > 41 Flooding 80

Added maps/beard1.map version [bb6926793a51311a]

> 1 ########## > 2 #** \\\\# > 3 #.R.. # > 4 # \ ..*\# > 5 #! ..*!# > 6 #### # # > 7 #\\... # L > 8 #\\.W... # > 9 #\\. # > 10 ########## > 11 > 12 Growth 15 > 13 Razors 0

Added maps/beard2.map version [2e942009c89717d7]

> 1 ############################## > 2 #R...........................# > 3 #.........................W..# > 4 #..\\\\\\\\\\\\\\\\\\\\\\\\..# > 5 #............................# > 6 #..*****.*\...*...*...*****..# > 7 #..*\....*\....*\*..*.\\*\\..# > 8 #..*\....****..!*!......*....# > 9 #..*\....*\....*\*..*...*....# > 10 #..*\....*\...*...*.....*....# > 11 #............................# > 12 #..\\\\\\\\\\\\\\\\\\\\\\\\..# > 13 #................ ..... .....# > 14 #................ W....L# > 15 ############################## > 16 > 17 Growth 25 > 18 Razors 10 > 19 Flooding 20

Added maps/beard3.map version [1dcab340493857d0]

> 1 ################ > 2 #*****#!! 1 # > 3 #..\..# # > 4 #########\\\\ # .\\\. # > 5 #.............# * # > 6 #.. .\\\#..!..#\** # > 7 #.. LW\\#W ..##### #### > 8 #..R\\\\#.. ..*\*\*W...# > 9 #.......A.. ...\.\...\\# > 10 #.......... ** # > 11 ############....\.###### > 12 #.....!# > 13 ######## > 14 > 15 Growth 10 > 16 Trampoline A targets 1

Added maps/beard4.map version [b62967eb47a5f507]

> 1 #################### > 2 #W\\!#\\\**.\#W\\\W# > 3 ##*######..###..\\\# > 4 #.......\.R ###...\# > 5 #####.###.#.......## > 6 #.......#.#\####.### > 7 #\\##\###\#\\#...#.L > 8 #\##\.###.####.#.#.# > 9 #\W#####.....###.W.# > 10 ####\\...\\\...#.#.# > 11 #W*######.######.#.# > 12 #\\\\\\\\\.........# > 13 ############\###\### > 14 #\\.. *..........\\# > 15 #W... #.........##W# > 16 ####################

Added maps/trampoline1.map version [5af697c0003d5516]

> 1 ############ > 2 #..*.R..*..# > 3 #..A....B..###### > 4 #....2.. ..#\\\C# > 5 #......* *.#\\\1# > 6 ########L######## > 7 > 8 Trampoline A targets 1 > 9 Trampoline B targets 1 > 10 Trampoline C targets 2

Added maps/trampoline2.map version [288f9d055c2777fa]

> 1 ###### > 2 #....# > 3 #.**.# > 4 #.**.# > 5 #.**.# > 6 ######.\\.###### > 7 #**....*.......# > 8 #\\....L\\\....# > 9 #A......*****..# > 10 ######R.....########### > 11 ###.....*.....\\\# > 12 #\\\\#..1...\\\# > 13 #\\\\#......\\\# > 14 ################ > 15 > 16 Trampoline A targets 1

Added maps/trampoline3.map version [7fcf90c1ca373c41]

> 1 ####################################### > 2 #****................#..1...\\\\\\\B..# > 3 #R.......############################## > 4 #.. ..................................# > 5 #.. ........ \ ......# > 6 #.. .*. ....**.*...#....... ..........# > 7 #.. ... ....\\\\...#.A..... ..........# > 8 #.. ... ....\ .....#....... * \\..# > 9 #.. ... ....\......#....... ..........# > 10 #.. ... ....\......#....... ..........# > 11 #.. ... ...........#................**# > 12 #..\\\\\...........#................\\# > 13 ########### ############## ############ > 14 #...*.................................# > 15 #....*.................. ......# > 16 #... .*....*.............. ..... .....# > 17 #....*2*........########.. ..... .....L > 18 #...*...*.......#\\\#..... ...*.......# > 19 #.....\\\.......#\\\#....**..***......# > 20 #.... .......#\\\#*................# > 21 #...............#\\\#*...**...*.......# > 22 #...............#.....................# > 23 ###### ############## ### ####### > 24 #\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\# > 25 ####################################### > 26 > 27 Trampoline A targets 1 > 28 Trampoline B targets 2 > 29

Added score_memo.txt version [95f0626c958d6d31]

> 1 contest1 212! > 2 contest2 280? > 3 contest3 275! > 4 contest4 561? > 5 contest5 1281? > 6 contest6 737 // deadend trap > 7 contest7 867? > 8 contest8 1245 // tricky > 9 contest9 3042? > 10 contest10 2076 // * on lambda, must move * first > 11 flood1 569 // too slow, because of 1-left danger lambda > 12 flood2 280? > 13 flood3 802 // too slow, drown > 14 flood4 970 // incorrect order of digging > 15 flood5 561? > 16 trampoline1 291 // * on trampoline. must move * first > 17 trampoline2 1728? > 18 trampoline3 698 // * on trampoline target. must move * first. > 19 beard1 856? > 20 beard2 2792 // hutsu-ni muzui > 21 beard3 811 // tricky. must hurry to cut hige. > 22 beard4 677 // deadend trap

Added src/Makefile version [01a4f7a0531dae71]

> 1 # To build, the following packages are needed. > 2 # wget http://ftp.digitalmars.com/dmd_2.059-0_i386.deb > 3 # sudo apt-get install gcc gcc-multilib > 4 # sudo pkg -i dmd_2.059-0_i386.deb > 5 > 6 all: > 7 dmd -O -release -inline -oflifter cui_auto_main.d driver.d game.d output

Modified src/cui_auto_main.d from [8844bb07a00188c5] to [b38d60ea39d11e6e].

15 } 15 } 16 } 16 } 17 17 18 void main(string[] args) 18 void main(string[] args) 19 { 19 { 20 Driver d = new Driver(stdin); 20 Driver d = new Driver(stdin); 21 d.addObserver!(GuardedOutput)(); 21 d.addObserver!(GuardedOutput)(); 22 auto c = d.addObserver!(CUI!Solver_1)(); | 22 auto c = d.addObserver!(CUI!MainSolver)(); 23 while(!c.fin) 23 while(!c.fin) 24 d.command(c.solver.single_step()); 24 d.command(c.solver.single_step()); 25 } 25 }

Added src/driver.d version [3d15ff20e76164b8]

> 1 import game; > 2 import util; > 3 > 4 interface GameObserver > 5 { > 6 // this(in Game g); > 7 void on_game_changed(char c, in Game g, bool finished); > 8 } > 9 > 10 class Driver > 11 { > 12 this(Game g) { this.game = g; } > 13 this(File game_data) { this(new Game(game_data)); } > 14 > 15 void command(char c) > 16 { > 17 if( finished ) > 18 return; > 19 if( c == 'A' ) > 20 aborted = true; > 21 else > 22 game.command(c); > 23 foreach(ob; observers) > 24 ob.on_game_changed(c, game, finished); > 25 } > 26 > 27 T addObserver(T)() > 28 { > 29 T t = new T(game); > 30 observers ~= t; > 31 return t; > 32 } > 33 > 34 @property bool finished() > 35 { > 36 return game.cleared || game.dead || aborted; > 37 } > 38 > 39 private: > 40 Game game; > 41 GameObserver[] observers; > 42 bool aborted = false; > 43 } > 44 > 45 unittest > 46 { > 47 static class MockGame : Game { > 48 this() { super(null,null,null); } > 49 string log; > 50 void command(char c) { log ~= c; } > 51 } > 52 static class MockObserver : GameObserver { > 53 string log; > 54 this(in Game g) {} > 55 void on_game_changed(char c, in Game g, bool fin) { log~=c; if(f > 56 } > 57 > 58 auto g = new MockGame; > 59 auto d = new Driver(g); > 60 auto o = d.addObserver!MockObserver(); > 61 foreach(char c; "UDLRSAUDLRSA") > 62 d.command(c); > 63 assert(g.log == "UDLRS"); > 64 assert(o.log == "UDLRSA$"); > 65 }

Modified src/game.d from [3baab0ddf11cca7d] to [fc05481901940844].

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( < 53 params.get("Water", "0").to!int(), | 52 return new Water(params.get("Water", "0").to!int(), 54 params.get("Flooding", "0").to!int() | 53 params.get("Flooding", "0").to!int()); 55 ); < 56 } 54 } 57 55 58 int level(int number_of_update) const 56 int level(int number_of_update) const 59 { 57 { 60 return pace ? base+(number_of_update/pace) : base; 58 return pace ? base+(number_of_update/pace) : base; 61 } 59 } 62 60 ................................................................................................................................................................................ 84 assert( 1 == w.level(3) ); 82 assert( 1 == w.level(3) ); 85 assert( 1 == w.level(4) ); 83 assert( 1 == w.level(4) ); 86 assert( 1 == w.level(5) ); 84 assert( 1 == w.level(5) ); 87 } 85 } 88 86 89 //////////////////////////////////////////////////////////////////////////////// 87 //////////////////////////////////////////////////////////////////////////////// 90 88 > 89 class Hige > 90 { > 91 public immutable int pace; > 92 mixin DeriveCreate; > 93 mixin DeriveCompare; > 94 mixin DeriveShow; > 95 Hige clone() const { return cast(Hige)this; } > 96 > 97 static load(string[string] params) > 98 { > 99 return new Hige(params.get("Growth", "25").to!int()); > 100 } > 101 > 102 bool is_growing_turn(int turn) const > 103 { > 104 return pace ? turn%pace == pace-1 : false; > 105 } > 106 > 107 int until_rise(int turn) const > 108 { > 109 return pace ? pace-turn%pace : int.max; > 110 } > 111 } > 112 > 113 //////////////////////////////////////////////////////////////////////////////// > 114 91 class Map 115 class Map 92 { 116 { 93 mixin DeriveShow; 117 mixin DeriveShow; 94 118 95 static Map load(string[] raw_data, string[string] params) | 119 static Map load(string[] raw_data, string[string] params, char[char] tra 96 { 120 { 97 // TODO: choose optimal representation. 121 // TODO: choose optimal representation. 98 return new Map(raw_data, params); | 122 return new Map(raw_data, params, trampo); 99 } 123 } 100 124 101 char[][] data; 125 char[][] data; 102 Pos robot; 126 Pos robot; 103 Pos lift; 127 Pos lift; 104 int waterproof; 128 int waterproof; > 129 Pos[char] tr_target; > 130 Pos[][char] tr_source; > 131 const(Hige) hige; > 132 int razor; 105 133 106 Map clone() const { return new Map(this); } 134 Map clone() const { return new Map(this); } 107 this(in Map m) { 135 this(in Map m) { 108 foreach(s; m.data) 136 foreach(s; m.data) 109 this.data ~= s.dup; 137 this.data ~= s.dup; 110 this.robot = m.robot.clone(); 138 this.robot = m.robot.clone(); 111 this.lift = m.lift.clone(); 139 this.lift = m.lift.clone(); 112 this.waterproof = m.waterproof; 140 this.waterproof = m.waterproof; > 141 this.tr_target = cast(Pos[char])m.tr_target; > 142 this.tr_source = cast(Pos[][char])m.tr_source; > 143 this.hige = m.hige.clone(); > 144 this.razor = m.razor; 113 } 145 } 114 146 115 this(string[] raw_data, string[string] params) | 147 this(string[] raw_data, string[string] params, char[char] trampo) 116 { 148 { 117 int width = 0; 149 int width = 0; 118 foreach(r; raw_data) 150 foreach(r; raw_data) 119 width = max(width, r.length); 151 width = max(width, r.length); 120 foreach(r; raw_data) { 152 foreach(r; raw_data) { 121 this.data ~= r.dup; 153 this.data ~= r.dup; 122 this.data[$-1].length = width; 154 this.data[$-1].length = width; ................................................................................................................................................................................ 126 for(int y=1; y<=H; ++y) 158 for(int y=1; y<=H; ++y) 127 for(int x=1; x<=W; ++x) { 159 for(int x=1; x<=W; ++x) { 128 if(this[y,x] == 'R') 160 if(this[y,x] == 'R') 129 this.robot = new Pos(y,x); 161 this.robot = new Pos(y,x); 130 if(this[y,x] == 'L' || this[y,x] == 'O') 162 if(this[y,x] == 'L' || this[y,x] == 'O') 131 this.lift = new Pos(y,x); 163 this.lift = new Pos(y,x); 132 } 164 } > 165 > 166 Pos[char] tr_pos; > 167 for(int y=1; y<=H; ++y) > 168 for(int x=1; x<=W; ++x) { > 169 char c = this[y,x]; > 170 if('1'<=c && c<='9' || 'A'<=c&&c<='I') > 171 tr_pos[c] = new Pos(y,x); > 172 } 133 173 134 this.waterproof = params.get("Waterproof", "5").to!int(); 174 this.waterproof = params.get("Waterproof", "5").to!int(); > 175 foreach(fr,to; trampo) { > 176 tr_target[fr] = tr_pos[to]; > 177 if(to !in tr_source) tr_source[to] = []; > 178 tr_source[to] ~= tr_pos[fr]; > 179 } > 180 > 181 this.hige = Hige.load(params); > 182 this.razor = params.get("Razors", "0").to!int(); 135 } 183 } 136 184 137 const @property { 185 const @property { 138 int H() { return data.length; } 186 int H() { return data.length; } 139 int W() { return data[0].length; } 187 int W() { return data[0].length; } 140 } 188 } 141 189 ................................................................................................................................................................................ 165 } 213 } 166 214 167 void opIndexAssign(char c, in Pos p) 215 void opIndexAssign(char c, in Pos p) 168 { 216 { 169 this[p.y, p.x] = c; 217 this[p.y, p.x] = c; 170 } 218 } 171 219 172 Pos[] lambdas() const { | 220 Pos[] objects(char c) const { 173 Pos[] ans; 221 Pos[] ans; 174 for(int y=1; y<=H; ++y) 222 for(int y=1; y<=H; ++y) 175 for(int x=1; x<=W; ++x) 223 for(int x=1; x<=W; ++x) 176 if(this[y,x] == '\\') | 224 if(this[y,x] == c) 177 ans ~= new Pos(y,x); 225 ans ~= new Pos(y,x); 178 return ans; 226 return ans; 179 } 227 } 180 228 > 229 Pos[] razors() const { return objects('!'); } > 230 Pos[] lambdas() const { return objects('\\'); } > 231 181 bool cleared() const 232 bool cleared() const 182 { 233 { 183 for(int y=1; y<=H; ++y) 234 for(int y=1; y<=H; ++y) 184 for(int x=1; x<=W; ++x) 235 for(int x=1; x<=W; ++x) 185 if(this[y,x] == 'L' || this[y,x] == 'O') 236 if(this[y,x] == 'L' || this[y,x] == 'O') 186 return false; 237 return false; 187 return true; 238 return true; 188 } 239 } 189 240 190 Tuple!(int,bool) command(char c) | 241 Tuple!(int,bool) command(char c, int turn) 191 { 242 { > 243 assert( this[robot] == 'R' ); 192 if(c=='R') return move( 0, +1); | 244 if(c=='R') return move( 0, +1, turn); 193 if(c=='L') return move( 0, -1); | 245 if(c=='L') return move( 0, -1, turn); 194 if(c=='U') return move(+1, 0); | 246 if(c=='U') return move(+1, 0, turn); 195 if(c=='D') return move(-1, 0); | 247 if(c=='D') return move(-1, 0, turn); 196 if(c=='W') return move( 0, 0); | 248 if(c=='W') return move( 0, 0, turn); > 249 if(c=='S') return use_razor(turn); 197 assert(false); 250 assert(false); 198 } 251 } 199 252 > 253 Tuple!(int, bool) use_razor(int turn) > 254 { > 255 if(razor) { > 256 razor--; > 257 for(int dy=-1; dy<=+1; ++dy) > 258 for(int dx=-1; dx<=+1; ++dx) > 259 if(this[robot.y+dy,robot.x+dx] == 'W') > 260 this[robot.y+dy,robot.x+dx] = ' '; > 261 } > 262 > 263 bool dead = update(turn); > 264 return tuple(0,dead); > 265 } > 266 200 Tuple!(int, bool) move(int dy, int dx) | 267 Tuple!(int, bool) move(int dy, int dx, int turn) 201 { 268 { 202 int y = robot.y; 269 int y = robot.y; 203 int x = robot.x; 270 int x = robot.x; 204 assert( this[robot] == 'R' ); < 205 int lambda = 0; 271 int lambda = 0; 206 bool dead = false; < 207 if( '\\' == this[y+dy,x+dx] ) 272 if( '\\' == this[y+dy,x+dx] ) 208 lambda++; 273 lambda++; > 274 if( '!' == this[y+dy,x+dx] ) > 275 razor++; 209 if( " \\.O".count(this[y+dy,x+dx])==1 ) { | 276 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { 210 this[y,x]=' '; 277 this[y,x]=' '; 211 this[y+dy,x+dx]='R'; 278 this[y+dy,x+dx]='R'; 212 robot = new Pos(y+dy,x+dx); 279 robot = new Pos(y+dy,x+dx); 213 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx 280 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx 214 this[y,x]=' '; 281 this[y,x]=' '; 215 this[y+dy,x+dx]='R'; 282 this[y+dy,x+dx]='R'; 216 this[y+dy*2,x+dx*2]='*'; 283 this[y+dy*2,x+dx*2]='*'; 217 robot = new Pos(y+dy,x+dx); 284 robot = new Pos(y+dy,x+dx); > 285 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { > 286 this[y,x]=' '; > 287 Pos tp = tr_target[this[y+dy,x+dx]]; > 288 foreach(p; tr_source[this[tp]]) > 289 this[p] = ' '; > 290 this[tp] = 'R'; > 291 robot = tp; 218 } 292 } 219 if( update() ) | 293 bool dead = update(turn); 220 dead = true; < 221 return tuple(lambda,dead); 294 return tuple(lambda,dead); 222 } 295 } 223 296 224 bool update() | 297 bool update(int turn) 225 { 298 { 226 bool dead = false; 299 bool dead = false; 227 300 228 char[][] next; 301 char[][] next; 229 foreach(y,s; data) 302 foreach(y,s; data) 230 next ~= s.dup; 303 next ~= s.dup; 231 304 ................................................................................................................................................................................ 259 dead=true; 332 dead=true; 260 } 333 } 261 } 334 } 262 else if(this[p]=='L') { 335 else if(this[p]=='L') { 263 if(!lambda) 336 if(!lambda) 264 access(p) = 'O'; 337 access(p) = 'O'; 265 } 338 } > 339 else if(this[p]=='W') { > 340 if( hige.is_growing_turn(turn) ) > 341 for(int dy=-1; dy<=+1; ++dy) > 342 for(int dx=-1; dx<=+1; ++dx) > 343 if(this[p.y+dy,p.x+dx] == ' ') > 344 access(new Pos(p.y+dy,p. > 345 } 266 } 346 } 267 data = next; 347 data = next; 268 return dead; 348 return dead; 269 } 349 } 270 } 350 } 271 351 272 //////////////////////////////////////////////////////////////////////////////// 352 //////////////////////////////////////////////////////////////////////////////// 273 353 274 class Game 354 class Game 275 { 355 { 276 mixin DeriveShow; | 356 public: 277 < 278 static Game load(File input) | 357 this(File input) 279 { 358 { 280 string[] raw_data; | 359 // Read map data 281 string[string] params; | 360 string[] map_data_lines; 282 < 283 // Raw map data; read until empty line. < 284 for(string line; !(line=input.readln().chomp()).empty; ) 361 for(string line; !(line=input.readln().chomp()).empty; ) 285 raw_data ~= line; | 362 map_data_lines ~= line; 286 | 363 287 // Additional commands; read until EOF. | 364 // H*W 288 for(string line; !(line=input.readln()).empty; ) { < 289 string[] ss = line.split(); < 290 if( ss.length == 2 ) | 365 H_ = map_data_lines.length; > 366 W_ = 0; > 367 foreach(mdl; map_data_lines) 291 params[ss[0]] = ss[1]; | 368 W_ = max(W_, mdl.length); 292 } | 369 293 < > 370 // Copy to modifiable buffer and adjust coordinates. 294 return load(raw_data, params); | 371 raw_data_ = new char[][H_+1]; 295 } < 296 < > 372 foreach(i,mdl; map_data_lines) { > 373 char[] buf = new char[mdl.length+1]; 297 static Game load(string[] raw_data, string[string] params) | 374 buf[0] = '#'; 298 { < > 375 buf[1..$] = mdl[]; 299 return new Game(raw_data, params); | 376 raw_data_[H_-i] = buf; 300 } | 377 } 301 | 378 302 this(string[] raw_data, string[string] params) | 379 // Detect objects > 380 for(int y=1; y<=H_; ++y) > 381 for(int x=1; x<raw_data_[y].length; ++x) 303 { | 382 { 304 this.map = Map.load(raw_data, params); < 305 this.water = Water.load(params); < 306 } < > 383 char c = raw_data_[y][x]; > 384 switch(c) 307 | 385 { 308 Game clone() const { return new Game(this); } < 309 this(in Game g) { | 386 case '#': 310 map = g.map.clone(); | 387 case '.': 311 water = g.water.clone(); | 388 case ' ': 312 turn = g.turn; | 389 break; 313 dead = g.dead; | 390 case 'L': 314 lambda = g.lambda; | 391 case 'O': 315 exit_bonus = g.exit_bonus; | 392 lift_pos_ = new Pos(y,x); 316 under_water = g.under_water; | 393 break; > 394 case 'A': .. case 'I': > 395 case '1': .. case '9': > 396 trampoline_pos_[c] = new Pos(y,x); > 397 break; > 398 case '!': > 399 razor_pos_ ~= new Pos(y,x); > 400 break; > 401 case '\\': > 402 lambda_pos_ ~= new Pos(y,x); > 403 break; 317 } | 404 > 405 // Moving objects are erased from raw_data_ > 406 case 'R': > 407 robot_pos_ = new Pos(y,x); > 408 raw_data_[y][x] = ' '; > 409 break; > 410 case '*': > 411 case 'W': > 412 dynamic_objects_[new Pos(y,x)] = c; > 413 raw_data_[y][x] = ' '; > 414 if(c=='*') > 415 may_update_[new Pos(y,x)] = true; > 416 break; > 417 default: > 418 assert(false); 318 | 419 } 319 void command(char c) < 320 { < 321 if(dead || cleared) < 322 return; < 323 | 420 } 324 if(c == 'A') < > 421 > 422 // Read other parameters > 423 for(string line; !(line=input.readln()).empty; ) 325 { 424 { 326 exit_bonus = 1; | 425 string[] ss = line.split(); 327 return; | 426 if( ss.length == 2 ) 328 } < > 427 switch(ss[0]) 329 | 428 { 330 // TODO: clarify the event order | 429 case "Water": water_base_ = ss[1].to!int(); 331 Tuple!(int,bool) ld = map.command(c); | 430 case "Flooding": water_pace_ = ss[1].to!int(); 332 if( map.cleared() ) { | 431 case "Waterproof": max_air_ = ss[1].to!int(); 333 exit_bonus = 2; | 432 case "Growth": hige_pace_ = ss[1].to!int(); > 433 case "Razors": num_razor_ = ss[1].to!int(); > 434 default: assert(false); 334 } | 435 } 335 else { < 336 lambda += ld[0]; < 337 if( ld[1] ) { | 436 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar 338 dead = true; < > 437 { > 438 char fr=ss[1][0], to=ss[3][0]; > 439 trampoline_[fr] = to; > 440 if(to !in trampoline_rev_) trampoline_rev_[to] = > 441 trampoline_rev_[to] ~= fr; 339 } 442 } 340 } 443 } 341 if( map.robot.y <= water_level ) < > 444 342 ++under_water; | 445 air_left_ = max_air_; 343 else < 344 under_water = 0; < 345 if( under_water > map.waterproof ) < 346 dead = true; < 347 turn += 1; < 348 } 446 } 349 447 350 Map map; < 351 Water water; < 352 int turn = 0; < 353 bool dead = false; < 354 int lambda = 0; < 355 int exit_bonus = 0; < 356 int under_water = 0; < 357 // TODO: when adding members, take care of clone(). < 358 // TODO: fix this poor design. < 359 < 360 @property const { 448 @property const { 361 long score() { return lambda*25L*(1+exit_bonus) - turn; } | 449 int H() { return H_; } > 450 int W() { return W_; } > 451 char trampoline(char c) { return (c in trampoline_ ? trampoline_ > 452 const(Pos)[] trampoline_rev(char c) { > 453 const(Pos)[] pp; > 454 if(c in trampoline_rev_) { > 455 foreach(ch; trampoline_rev_[c]) > 456 pp ~= trampoline_pos_[ch]; > 457 } > 458 return pp; > 459 } 362 int water_level() { return water.level(turn); } | 460 int water_level() { > 461 return water_pace_ ? water_base_ + turn_/water_pace_ : w > 462 } 363 int water_until_rise() { return water.until_rise(turn); } | 463 int water_until_rise() { > 464 return water_pace_ ? water_pace_ - turn_%water_pace_ : i > 465 } > 466 int hige_until_rise() { > 467 return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int. > 468 } > 469 bool is_hige_turn() { > 470 return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : f > 471 } > 472 int hp() { return air_left_; } > 473 int num_razor() { return num_razor_; } 364 bool cleared() { return exit_bonus>0; } | 474 bool cleared() { return cleared_; } 365 int hp() { return map.waterproof - under_water; } < 366 long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus < > 475 bool dead() { return dead_; } > 476 long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L > 477 const(Pos) robot() { return robot_pos_; } > 478 const(Pos) lift() { return lift_pos_; } > 479 Pos[] lambdas() { > 480 Pos[] pp; > 481 foreach(p; lambda_pos_) > 482 pp ~= p.clone(); > 483 return pp; > 484 } > 485 Pos[] razors() { > 486 Pos[] pp; > 487 foreach(p; razor_pos_) > 488 pp ~= p.clone(); > 489 return pp; > 490 } > 491 const(Pos)[] higes() { > 492 const(Pos)[] pp; > 493 foreach(p,c; dynamic_objects_) > 494 if(c=='W') > 495 pp ~= p; > 496 return pp; > 497 } > 498 } > 499 const { > 500 char opIndex(in Pos p) { return opIndex(p.y, p.x); } > 501 char opIndex(int y, int x) { return map_get(y, x); } > 502 } > 503 > 504 public: > 505 void command(char c) > 506 { > 507 if(dead || cleared) > 508 return; > 509 > 510 if(c == 'U') command_move(+1, 0); > 511 if(c == 'D') command_move(-1, 0); > 512 if(c == 'L') command_move(0, -1); > 513 if(c == 'R') command_move(0, +1); > 514 if(c == 'S') use_razor(); > 515 if(c == 'W') {} > 516 > 517 if(!cleared) > 518 { > 519 map_update(); > 520 water_update(); > 521 } > 522 turn_ ++; > 523 } > 524 > 525 void command_move(int dy, int dx) > 526 { > 527 int y = robot_pos_.y, x = robot_pos_.x; > 528 char c = this[y+dy, x+dx]; > 529 Pos p = new Pos(y+dy, x+dx); > 530 > 531 switch(c){ > 532 case 'O': > 533 cleared_ = true; > 534 move_robot_to(p); > 535 break; > 536 case '\\': > 537 take_lambda_at(p); > 538 move_robot_to(p); > 539 break; > 540 case '!': > 541 take_razor_at(p); > 542 move_robot_to(p); > 543 break; > 544 case 'A': .. case 'I': > 545 enter_trampoline_at(p, c); > 546 break; > 547 case ' ': > 548 case '.': > 549 move_robot_to(p); > 550 break; > 551 case '*': > 552 if(dy!=0 || this[y,x+dx*2]!=' ') > 553 break; > 554 move_robot_to(p); > 555 push_rock(p, new Pos(y,x+dx*2)); > 556 break; > 557 default: > 558 break; > 559 } > 560 } > 561 > 562 void use_razor() > 563 { > 564 if(num_razor_ == 0) > 565 return; > 566 num_razor_ --; > 567 > 568 for(int dy=-1; dy<=+1; ++dy) > 569 for(int dx=-1; dx<=+1; ++dx) if(dy||dx) > 570 { > 571 Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx); > 572 if(auto it = p in dynamic_objects_) > 573 if(*it == 'W') { > 574 something_gone(p); > 575 dynamic_objects_.remove(p); > 576 } > 577 } > 578 } > 579 > 580 void take_lambda_at(Pos p) > 581 { > 582 map_set_empty(p); > 583 num_lambda_ ++; > 584 lambda_pos_ = lambda_pos_.erase(p); > 585 } > 586 > 587 void take_razor_at(Pos p) > 588 { > 589 map_set_empty(p); > 590 num_razor_ ++; > 591 razor_pos_ = razor_pos_.erase(p); > 592 } > 593 > 594 void enter_trampoline_at(Pos p, char c) > 595 { > 596 char d = trampoline(c); > 597 foreach(cc; trampoline_rev_[d]) { > 598 Pos pp = trampoline_pos_[cc]; > 599 something_gone(pp); > 600 map_set_empty(pp); > 601 } > 602 move_robot_to(trampoline_pos_[d]); > 603 } > 604 > 605 void move_robot_to(Pos p) > 606 { > 607 something_gone(robot_pos_); > 608 map_set_empty(p.y, p.x); > 609 robot_pos_ = p; > 610 } > 611 > 612 void push_rock(Pos fr, Pos to) > 613 { > 614 dynamic_objects_.remove(fr); > 615 dynamic_objects_[to] = '*'; > 616 may_update_[to] = true; > 617 } > 618 > 619 void something_gone(Pos p) > 620 { > 621 for(int dy=0; dy<=+1; ++dy) > 622 for(int dx=-1; dx<=+1; ++dx) if(dy||dx) > 623 may_update_[new Pos(p.y+dy,p.x+dx)] = true; > 624 } > 625 > 626 void map_update() > 627 { > 628 Pos[] may_update_list; > 629 foreach(p,_; may_update_) > 630 if(this[p] == '*') > 631 may_update_list ~= p; > 632 may_update_ = null; > 633 > 634 if( is_hige_turn() ) > 635 foreach(p,c; dynamic_objects_) > 636 if(c == 'W') > 637 may_update_list ~= p; > 638 > 639 sort(may_update_list); > 640 char[Pos] to_be_written; > 641 foreach(p; may_update_list) > 642 if(is_hige_turn() && this[p]=='W') > 643 { > 644 for(int dy=-1; dy<=+1; ++dy) > 645 for(int dx=-1; dx<=+1; ++dx) { > 646 Pos q = new Pos(p.y+dy,p.x+dx); > 647 if( this[q] == ' ' ) > 648 to_be_written[q] = 'W'; > 649 } > 650 } > 651 else > 652 { > 653 int y = p.y; > 654 int x = p.x; > 655 char below = this[y-1,x]; > 656 // * > 657 // _ > 658 if(below==' ') { > 659 Pos q = new Pos(y-1,x); > 660 to_be_written[p] = ' '; > 661 to_be_written[q] = '*'; > 662 may_update_[q] = true; > 663 } > 664 // *_ *_ > 665 // *_ or \_ > 666 else if((below=='*'||below=='\\')&&this[y-1,x+1] > 667 Pos q = new Pos(y-1,x+1); > 668 to_be_written[p] = ' '; > 669 to_be_written[q] = '*'; > 670 may_update_[q] = true; > 671 } > 672 // _* > 673 // _* > 674 else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x > 675 Pos q = new Pos(y-1,x-1); > 676 to_be_written[p] = ' '; > 677 to_be_written[q] = '*'; > 678 may_update_[q] = true; > 679 } > 680 } > 681 > 682 foreach(p,c; to_be_written) { > 683 dynamic_objects_[p] = c; > 684 if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x) > 685 dead_ = true; > 686 } > 687 > 688 if(lambda_pos_.empty) > 689 raw_data_[lift_pos_.y][lift_pos_.x] = 'O'; > 690 } > 691 > 692 void water_update() > 693 { > 694 if( robot_pos_.y <= water_level() ) > 695 air_left_ --; > 696 else > 697 air_left_ = max_air_; > 698 if( air_left_ < 0 ) > 699 dead_ = true; > 700 } > 701 > 702 private: > 703 char map_get(int y, int x) const > 704 { > 705 if( y<1 || H<y || x<1 || W<x ) return '#'; > 706 Pos p = new Pos(y,x); > 707 if(p == robot_pos_) > 708 return 'R'; > 709 if(auto it = (p in dynamic_objects_)) > 710 return *it; > 711 if( x<0 || raw_data_[y].length<=x ) return ' '; > 712 return raw_data_[y][x]; > 713 } > 714 > 715 void map_set_empty(in Pos p) > 716 { > 717 return map_set_empty(p.y, p.x); > 718 } > 719 > 720 void map_set_empty(int y, int x) > 721 { > 722 if( y<1 || H<y || x<1 || W<x ) return; > 723 if( x<0 || raw_data_[y].length<=x ) return; > 724 raw_data_[y][x] = ' '; > 725 } > 726 > 727 public: > 728 Game clone() const { return new Game(this); } > 729 this(in Game g) { > 730 H_ = g.H_; > 731 W_ = g.W_; > 732 raw_data_ = new char[][g.raw_data_.length]; > 733 foreach(i,d; g.raw_data_) raw_data_[i] = d.dup; > 734 trampoline_pos_ = cast(Pos[char]) g.trampoline_pos_; > 735 razor_pos_ = (cast(Game)g).razor_pos_.dup; > 736 lambda_pos_ = (cast(Game)g).lambda_pos_.dup; > 737 lift_pos_ = g.lift_pos_.clone(); > 738 robot_pos_ = g.robot_pos_.clone(); > 739 dynamic_objects_ = dup(g.dynamic_objects_); > 740 trampoline_ = (cast(Game)g).trampoline_; > 741 trampoline_rev_ = (cast(Game)g).trampoline_rev_; > 742 water_base_ = g.water_base_; > 743 water_pace_ = g.water_pace_; > 744 max_air_ = g.max_air_; > 745 hige_pace_ = g.hige_pace_; > 746 num_razor_ = g.num_razor_; > 747 num_lambda_ = g.num_lambda_; > 748 turn_ = g.turn_; > 749 air_left_ = g.air_left_; > 750 cleared_ = g.cleared_; > 751 dead_ = g.dead_; > 752 may_update_ = dup(g.may_update_); > 753 } > 754 > 755 V[K] dup(V,K)(in V[K] aa) { > 756 V[K] aa2; > 757 foreach(k,v; aa) aa2[k] = v; > 758 return aa2; 367 } 759 } 368 } | 760 > 761 private: > 762 int H_; > 763 int W_; > 764 char[][] raw_data_; > 765 Pos[char] trampoline_pos_; > 766 Pos[] razor_pos_; > 767 Pos[] lambda_pos_; > 768 Pos lift_pos_; > 769 Pos robot_pos_; > 770 char[Pos] dynamic_objects_; > 771 char[char] trampoline_; > 772 char[][char] trampoline_rev_; > 773 int water_base_ = 0; > 774 int water_pace_ = 0; > 775 int max_air_ = 10; > 776 int hige_pace_ = 25; > 777 int num_razor_ = 0; > 778 int num_lambda_ = 0; 369 779 370 unittest | 780 int turn_ = 0; 371 { < > 781 int air_left_ = 0; 372 Game.load(["###","...","#RL"], ["xxx":"yyy"]); | 782 bool cleared_ = false; > 783 bool dead_ = false; > 784 bool[Pos] may_update_; 373 } 785 }

Modified src/gui.d from [e185ff3281d95738] to [e84cacd6262f93a7].

4 import driver; 4 import driver; 5 5 6 class GUI(Solver) : Form, GameObserver 6 class GUI(Solver) : Form, GameObserver 7 { 7 { 8 this(in Game g) 8 this(in Game g) 9 { 9 { 10 this.solver = new Solver(g); 10 this.solver = new Solver(g); 11 setup_size(g.map.W, g.map.H); | 11 setup_size(g.W, g.H); 12 setup_resources(); | 12 setup_resources(g); 13 setup_keyhandling(); < 14 draw(g); 13 draw(g); 15 } 14 } 16 15 17 private void delegate(char c) fn; 16 private void delegate(char c) fn; 18 void set_fn(F)(F f) { this.fn = f; } 17 void set_fn(F)(F f) { this.fn = f; } 19 18 20 void run(bool automate = false) 19 void run(bool automate = false) 21 { 20 { 22 if(automate) { 21 if(automate) { 23 Timer t = new Timer; 22 Timer t = new Timer; 24 t.interval = 100; | 23 t.interval = 50; 25 t.tick ~= (Timer sender, EventArgs ea){ 24 t.tick ~= (Timer sender, EventArgs ea){ 26 fn(solver.single_step()); 25 fn(solver.single_step()); 27 }; 26 }; 28 t.start(); 27 t.start(); 29 this.closing ~= (Form f,CancelEventArgs c){t.stop();}; 28 this.closing ~= (Form f,CancelEventArgs c){t.stop();}; > 29 } else { > 30 setup_keyhandling(); 30 } 31 } 31 Application.run(this); 32 Application.run(this); 32 } 33 } 33 34 34 override void on_game_changed(char c, in Game g, bool finished) 35 override void on_game_changed(char c, in Game g, bool finished) 35 { 36 { 36 draw(g); 37 draw(g); ................................................................................................................................................................................ 49 } 50 } 50 51 51 Font font; 52 Font font; 52 Color[char] colors; 53 Color[char] colors; 53 string[char] render; 54 string[char] render; 54 Graphics graphicContext; 55 Graphics graphicContext; 55 56 56 void setup_resources() | 57 void setup_resources(in Game g) 57 { 58 { 58 this.graphicContext = new MemoryGraphics(this.clientSize.width, 59 this.graphicContext = new MemoryGraphics(this.clientSize.width, 59 this.setStyle(ControlStyles.OPAQUE, true); 60 this.setStyle(ControlStyles.OPAQUE, true); 60 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 61 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 61 this.backColor = Color(255,255,255); 62 this.backColor = Color(255,255,255); 62 this.colors['#'] = 63 this.colors['#'] = 63 this.colors['.'] = Color(255,191,127); 64 this.colors['.'] = Color(255,191,127); 64 this.colors['*'] = Color(255,127,127); 65 this.colors['*'] = Color(255,127,127); 65 this.colors['R'] = Color(128,128,0); 66 this.colors['R'] = Color(128,128,0); 66 this.colors['D'] = Color(255,0,0); | 67 this.colors['d'] = Color(255,0,0); 67 this.colors['\\'] = 68 this.colors['\\'] = 68 this.colors['L'] = 69 this.colors['L'] = 69 this.colors['O'] = Color(127,255,127); 70 this.colors['O'] = Color(127,255,127); > 71 this.colors['w'] = Color(204,229,255); 70 this.colors['W'] = Color(204,229,255); | 72 this.colors['W'] = > 73 this.colors['!'] = Color(159,159,159); > 74 foreach(char c; 'A'..'J') this.colors[c] = Color(142,142,255); > 75 foreach(char c; '1'..':') this.colors[c] = Color(255,142,255); 71 this.render['#'] = "■"; 76 this.render['#'] = "■"; 72 this.render['*'] = "✹"; 77 this.render['*'] = "✹"; 73 this.render['.'] = "♒"; 78 this.render['.'] = "♒"; 74 this.render['\\'] = "λ"; 79 this.render['\\'] = "λ"; 75 this.render['R'] = "☃"; 80 this.render['R'] = "☃"; 76 this.render['D'] = "☠"; | 81 this.render['d'] = "☠"; 77 this.render['L'] = "☒"; 82 this.render['L'] = "☒"; 78 this.render['O'] = "☐"; 83 this.render['O'] = "☐"; > 84 this.render['W'] = "ꔣ"; > 85 this.render['!'] = "✄"; > 86 foreach(char c; 'A'..'J') this.render[c] = [cast(dchar)('☢'+g.tr > 87 foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1 79 this.paint ~= (Control c, PaintEventArgs ev) { 88 this.paint ~= (Control c, PaintEventArgs ev) { 80 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientS 89 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientS 81 }; 90 }; 82 } 91 } 83 92 84 void draw(in Game g) 93 void draw(in Game g) 85 { 94 { ................................................................................................................................................................................ 87 int scrH = this.clientSize.height; 96 int scrH = this.clientSize.height; 88 97 89 // Fill bg. 98 // Fill bg. 90 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH) 99 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH) 91 100 92 // Fill water. 101 // Fill water. 93 int w = g.water_level(); 102 int w = g.water_level(); 94 graphicContext.fillRectangle(this.colors['W'], Rect(0, scrH-cell | 103 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell 95 104 96 // Paint map. 105 // Paint map. 97 for(int y=1; y<=g.map.H; ++y) | 106 for(int y=1; y<=g.H; ++y) 98 for(int x=1; x<=g.map.W; ++x) { | 107 for(int x=1; x<=g.W; ++x) { 99 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 108 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 100 char c = g.map[y,x]; | 109 char c = g[y,x]; 101 if( c != ' ' ) { 110 if( c != ' ' ) { 102 if( c == 'R' && g.dead ) 111 if( c == 'R' && g.dead ) 103 c = 'D'; | 112 c = 'd'; 104 graphicContext.drawText(this.render[c], font, th 113 graphicContext.drawText(this.render[c], font, th 105 } 114 } 106 } 115 } 107 116 108 // Update textual info. 117 // Update textual info. > 118 this.text = .text( > 119 "Score: ", g.score, > 120 " Air: ", g.hp, 109 this.text = .text("Score: ", g.score, " Air: ", g.hp, " Tide: ", | 121 " Tide: ", g.water_until_rise, > 122 " Wadler: ", g.hige_until_rise, > 123 " Razor: ", g.num_razor); 110 invalidate(); 124 invalidate(); 111 } 125 } 112 126 113 private: 127 private: 114 void setup_keyhandling() 128 void setup_keyhandling() 115 { 129 { 116 noMessageFilter(); 130 noMessageFilter(); 117 this.keyDown ~= &my_keydown; 131 this.keyDown ~= &my_keydown; 118 } 132 } > 133 > 134 void do_manual_command(char c) > 135 { > 136 solver.force(c); > 137 fn(c); > 138 } 119 139 120 void my_keydown(Control c, KeyEventArgs ev) 140 void my_keydown(Control c, KeyEventArgs ev) 121 { 141 { 122 switch(ev.keyCode) 142 switch(ev.keyCode) 123 { 143 { 124 case Keys.DOWN: fn('D'); break; | 144 case Keys.DOWN: do_manual_command('D'); break; 125 case Keys.UP: fn('U'); break; | 145 case Keys.UP: do_manual_command('U'); break; 126 case Keys.LEFT: fn('L'); break; | 146 case Keys.LEFT: do_manual_command('L'); break; 127 case Keys.RIGHT: fn('R'); break; | 147 case Keys.RIGHT: do_manual_command('R'); break; 128 case Keys.W: fn('W'); break; | 148 case Keys.W: do_manual_command('W'); break; > 149 case Keys.S: do_manual_command('S'); break; 129 case Keys.A: fn('A'); break; | 150 case Keys.A: do_manual_command('A'); break; 130 case Keys.G: fn(solver.single_step()); break; 151 case Keys.G: fn(solver.single_step()); break; 131 default: break; 152 default: break; 132 } 153 } 133 } 154 } 134 155 135 Solver solver; 156 Solver solver; 136 } 157 }

Modified src/gui_main.d from [49f16753320613b8] to [05082d0f328d756c].

5 import std.stdio; 5 import std.stdio; 6 pragma(lib, "dfl.lib"); 6 pragma(lib, "dfl.lib"); 7 7 8 void main(string[] args) 8 void main(string[] args) 9 { 9 { 10 Driver d = new Driver(stdin); 10 Driver d = new Driver(stdin); 11 d.addObserver!(GuardedOutput)(); 11 d.addObserver!(GuardedOutput)(); 12 auto g = d.addObserver!(GUI!Solver_1)(); | 12 auto g = d.addObserver!(GUI!MainSolver)(); 13 g.set_fn(&d.command); 13 g.set_fn(&d.command); 14 g.run(); 14 g.run(); 15 } 15 }

Modified src/output.d from [62e6040714438eff] to [e2d0d7db868c3a44].

20 } 20 } 21 21 22 class GuardedOutput : GameObserver 22 class GuardedOutput : GameObserver 23 { 23 { 24 this(in Game g) 24 this(in Game g) 25 { 25 { 26 setup_sigint_handling(); 26 setup_sigint_handling(); 27 ideal_log ~= g.score_if_abort_now; | 27 score_log ~= g.score; 28 flushed = false; 28 flushed = false; 29 } 29 } 30 30 31 override void on_game_changed(char c, in Game g, bool finished) 31 override void on_game_changed(char c, in Game g, bool finished) 32 { 32 { 33 if(flushed) 33 if(flushed) 34 return; 34 return; 35 35 36 log ~= c; 36 log ~= c; 37 score_log ~= g.score; 37 score_log ~= g.score; 38 ideal_log ~= g.score_if_abort_now; < 39 if(finished || log.length+1==g.map.W*g.map.H) | 38 if(finished || log.length+1==g.W*g.H) 40 flush(); 39 flush(); 41 } 40 } 42 41 43 private: 42 private: 44 string log; 43 string log; 45 long[] score_log; 44 long[] score_log; 46 long[] ideal_log; < 47 bool flushed; 45 bool flushed; 48 46 49 void flush() 47 void flush() 50 { 48 { > 49 if(flushed) > 50 return; > 51 51 Tuple!(long, int, int) cand; | 52 Tuple!(long, int) cand; 52 cand[0] = long.min; 53 cand[0] = long.min; 53 54 54 for(int i=0; i<score_log.length; ++i) 55 for(int i=0; i<score_log.length; ++i) 55 if(cand[0] < score_log[i]) 56 if(cand[0] < score_log[i]) 56 cand = tuple(score_log[i],i,0); | 57 cand = tuple(score_log[i],i); 57 for(int i=0; i<ideal_log.length; ++i) < 58 if(cand[0] < ideal_log[i]) < 59 cand = tuple(ideal_log[i],i,1); < 60 58 61 if(cand[2]==0) { < 62 string str = log[0..cand[1]+1]; < 63 std.c.stdio.printf("%.*s\n", str.length, str.ptr); < 64 } else { < 65 string str = log[0..cand[1]]; < 66 std.c.stdio.printf("%.*sA\n", str.length, str.ptr); | 59 std.c.stdio.printf("%.*sA\n", cand[1], log.ptr); 67 } < 68 std.c.stdio.fflush(std.c.stdio.stdout); 60 std.c.stdio.fflush(std.c.stdio.stdout); 69 flushed = true; 61 flushed = true; 70 } 62 } 71 63 72 private: 64 private: 73 static __gshared GuardedOutput g_output; 65 static __gshared GuardedOutput g_output; 74 66

Modified src/solver.d from [dca756d0b000be21] to [22c356ff1975e92f].

1 import util; 1 import util; 2 import game; 2 import game; 3 3 4 class Solver_0 4 class Solver_0 5 { 5 { 6 this(const(Game) g) {} | 6 this(in Game g) {} 7 char single_step() { return 'W'; } 7 char single_step() { return 'W'; } > 8 void force(char c) {} 8 } 9 } 9 10 10 class Solver_1 11 class Solver_1 11 { 12 { 12 int wait_count = 0; 13 int wait_count = 0; > 14 int choke_count = 0; 13 15 14 Game g; 16 Game g; 15 this(const(Game) g) | 17 this(in Game g) 16 { 18 { 17 this.g = g.clone(); 19 this.g = g.clone(); 18 forbidden_cell = new bool[][](g.map.H+2, g.map.W+2); | 20 forbidden_cell = new bool[][](g.H+2, g.W+2); 19 } 21 } 20 22 21 char single_step() 23 char single_step() 22 { 24 { 23 Tuple!(string,int) de = death_move(g); 25 Tuple!(string,int) de = death_move(g); 24 char c = act(g, de[0], de[1]); 26 char c = act(g, de[0], de[1]); 25 g.command(c); | 27 force(c); 26 return c; 28 return c; 27 } 29 } > 30 > 31 void force(char c) > 32 { > 33 if(c != 'A') > 34 g.command(c); > 35 } 28 36 29 Tuple!(string,int) death_move(const(Game) g) 37 Tuple!(string,int) death_move(const(Game) g) 30 { 38 { 31 string death; 39 string death; 32 int choice = 0; 40 int choice = 0; 33 foreach(char c; "UDLRW") { 41 foreach(char c; "UDLRW") { 34 Game gg = g.clone(); 42 Game gg = g.clone(); 35 gg.command(c); 43 gg.command(c); 36 if( !gg.cleared && gg.dead ) 44 if( !gg.cleared && gg.dead ) 37 death ~= c; 45 death ~= c; 38 else if( gg.map.robot != g.map.robot ) | 46 else if( gg.robot != g.robot ) 39 choice++; 47 choice++; > 48 else if( c != 'W' ) // meaningless move > 49 death ~= c; 40 } 50 } 41 return tuple(death, choice); 51 return tuple(death, choice); 42 } 52 } 43 53 44 Tuple!(Pos, int)[] log; 54 Tuple!(Pos, int)[] log; 45 bool[][] forbidden_cell; 55 bool[][] forbidden_cell; 46 56 47 char act(const(Game) g, string death, int breath) 57 char act(const(Game) g, string death, int breath) 48 { 58 { 49 const Pos ro = g.map.robot; | 59 const Pos ro = g.robot; 50 const Pos[] la = g.map.lambdas(); | 60 const Pos li = g.lift; 51 const Pos li = g.map.lift; | 61 Pos[] la = g.lambdas(); > 62 sort!((Pos a,Pos b){ > 63 int ad=abs(a.y-li.y)+abs(a.x-li.x); > 64 int bd=abs(b.y-li.y)+abs(b.x-li.x); > 65 return ad>bd;; > 66 })(la); > 67 Pos[] ra = g.razors(); > 68 const(Pos)[] hi = g.higes(); 52 69 53 Tuple!(char,int)[] cand; 70 Tuple!(char,int)[] cand; 54 char c = 'W'; 71 char c = 'W'; 55 if( la.empty ) { 72 if( la.empty ) { 56 cand = search(g, ro, [li], death); 73 cand = search(g, ro, [li], death); 57 } else { 74 } else { 58 cand ~= search(g, ro, la, death); | 75 cand ~= search(g, ro, la~ra, death); > 76 } > 77 > 78 // 'higesori' mode > 79 if( !hi.empty && g.num_razor>0 ) { > 80 int his = 0; > 81 for(int dy=-1; dy<=+1; ++dy) > 82 for(int dx=-1; dx<=+1; ++dx) > 83 if(g[ro.y+dy,ro.x+dx] == 'W') > 84 his++; > 85 > 86 if(his>=2 || his==hi.length) > 87 cand = [tuple('S',int.max)]; > 88 if(cand.empty) { > 89 const(Pos)[] tgt; > 90 for(int y=1; y<=g.H; ++y) > 91 for(int x=1; x<=g.W; ++x) > 92 if(g[y,x]=='.'||g[y,x]==' ') { > 93 his = 0; > 94 for(int dy=-1; dy<=+1; ++dy) > 95 for(int dx=-1; dx<=+1; ++dx) > 96 if(g[y+dy,x+dx] == 'W') > 97 his++; > 98 if(his>=2) > 99 tgt ~= new Pos(y,x); > 100 } > 101 cand ~= search(g, ro, tgt, death, true); > 102 } 59 } 103 } > 104 > 105 // 'dig' mode 60 if(cand.empty) { 106 if(cand.empty) { 61 const(Pos)[] tgt; 107 const(Pos)[] tgt; 62 for(int y=1; y<=g.map.H; ++y) | 108 for(int y=1; y<=g.H; ++y) 63 for(int x=1; x<=g.map.W; ++x) | 109 for(int x=1; x<=g.W; ++x) 64 if(g.map[y,x]=='.') | 110 if(g[y,x]=='.') 65 if(g.map[y+1,x]=='*'||g.map[y+1,x-1]=='* | 111 if(g[y+1,x]=='*'||g[y+1,x-1]=='*'||g[y+1 66 ||g.map[y,x+1]=='*'||g.map[y,x-1]=='*') | 112 ||g[y,x+1]=='*'||g[y,x-1]=='*') 67 tgt ~= new Pos(y,x); 113 tgt ~= new Pos(y,x); 68 cand ~= search(g, ro, tgt, death); | 114 cand ~= search(g, ro, tgt, death, true); 69 } 115 } 70 116 71 if(cand.empty) | 117 if(cand.empty) { > 118 choke_count++; 72 cand ~= tuple('W',int.max); 119 cand ~= tuple('W',int.max); > 120 } 73 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ 121 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ 74 if(c1[1] != c2[1]) 122 if(c1[1] != c2[1]) 75 return c1[1] < c2[1]; 123 return c1[1] < c2[1]; 76 return c1[0] < c2[0]; 124 return c1[0] < c2[0]; 77 })(cand); 125 })(cand); 78 c = cand[0][0]; 126 c = cand[0][0]; 79 127 80 if(death.count(c)) { | 128 if(death.count(c) || wait_count>=2) { 81 foreach(char live; "UDLRWA") | 129 foreach(char live; "UDLRW") 82 if(death.count(live)==0) { 130 if(death.count(live)==0) { 83 c=live; 131 c=live; 84 break; 132 break; 85 } 133 } 86 } 134 } 87 135 88 if(c=='W') { | 136 if(c == 'W') 89 wait_count++; 137 wait_count++; 90 if(wait_count > g.map.H) < 91 c = 'A'; < 92 } < 93 else 138 else 94 wait_count = 0; 139 wait_count = 0; > 140 if(choke_count >= g.H) > 141 c = 'A'; 95 142 96 bool[char] choice; 143 bool[char] choice; 97 foreach(t; cand) 144 foreach(t; cand) 98 choice[t[0]] = true; 145 choice[t[0]] = true; 99 log ~= tuple(ro.clone(), cast(int)choice.length); 146 log ~= tuple(ro.clone(), cast(int)choice.length); 100 if(log.length > 5) 147 if(log.length > 5) 101 log = log[$-5..$]; 148 log = log[$-5..$]; ................................................................................................................................................................................ 106 if( cnt >= 3 && breath==1 ) { 153 if( cnt >= 3 && breath==1 ) { 107 forbidden_cell[ro.y][ro.x] = true; 154 forbidden_cell[ro.y][ro.x] = true; 108 } 155 } 109 156 110 return c; 157 return c; 111 } 158 } 112 159 113 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death | 160 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death 114 { 161 { 115 bool danger(int y, int x) 162 bool danger(int y, int x) 116 { 163 { > 164 if(g[y,x] == ' ' || g[y,x] == 'R') > 165 return false; 117 if(g.map[y+1,x] == '*') | 166 if(g[y+1,x] == '*') > 167 return true; > 168 if(g[y+1,x-1]=='*' && (g[y,x-1]=='\\'||g[y,x-1]=='*') && 118 return true; 169 return true; 119 if(g.map[y+1,x-1]=='*' && (g.map[y,x-1]=='\\'||g.map[y,x | 170 if(g[y+1,x+1]=='*' && (g[y,x+1]=='*') && (g[y+1,x]==' '| 120 return true; 171 return true; 121 if(g.map[y+1,x+1]=='*' && (g.map[y,x+1]=='*') && (g.map[ | 172 if(g[y,x-1]=='*' && (g[y-1,x-1]=='\\'||g[y-1,x-1]=='*') 122 return true; 173 return true; 123 if(g.map[y,x-1]=='*' && (g.map[y-1,x-1]=='\\'||g.map[y-1 | 174 if(g[y,x+1]=='*' && (g[y-1,x+1]=='*') && (g[y-1,x]==' '| 124 return true; < 125 if(g.map[y,x+1]=='*' && (g.map[y-1,x+1]=='*') && (g.map[ < 126 return true; 175 return true; 127 return false; 176 return false; 128 } 177 } 129 178 130 // avoid directly below '*' 179 // avoid directly below '*' 131 Tuple!(char,int)[] tryA() { 180 Tuple!(char,int)[] tryA() { 132 const(Pos)[] q; 181 const(Pos)[] q; 133 foreach(p; gs) 182 foreach(p; gs) 134 if(!danger(p.y,p.x)) 183 if(!danger(p.y,p.x)) 135 q ~= p; 184 q ~= p; 136 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); | 185 bool[][] v = new bool[][](g.H+2, g.W+2); 137 foreach(p; q) v[p.y][p.x]=true; 186 foreach(p; q) v[p.y][p.x]=true; 138 for(int step=1; q.length; ++step) { 187 for(int step=1; q.length; ++step) { 139 Pos[] q2; 188 Pos[] q2; 140 foreach(p; q) { 189 foreach(p; q) { 141 int[] dy=[-1,+1,0,0]; | 190 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 142 int[] dx=[0,0,-1,+1]; | 191 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 143 for(int i=0; i<4; ++i) { | 192 for(int i=0; i<yyy.length; ++i) { 144 int y = p.y+dy[i]; | 193 int y = yyy[i]; 145 int x = p.x+dx[i]; | 194 int x = xxx[i]; > 195 if('1'<=g[y,x]&&g[y,x]<='9') { > 196 foreach(ppp; g.trampolin > 197 yyy ~= ppp.y; > 198 xxx ~= ppp.x; > 199 } > 200 continue; > 201 } 146 if(v[y][x]) continue; 202 if(v[y][x]) continue; 147 if(y==s.y && x==s.x) { | 203 if(y==s.y && x==s.x && i<4) { 148 char c = "UDRL"[i]; 204 char c = "UDRL"[i]; 149 if( death.count(c) == 0 205 if( death.count(c) == 0 150 return [tuple(c, 206 return [tuple(c, 151 } else if(forbidden_cell[y][x]){ 207 } else if(forbidden_cell[y][x]){ 152 } else if(g.map[y,x]==' '||g.map | 208 } else if(g[y,x]==' '||g[y,x]==' 153 if(danger(y,x)) 209 if(danger(y,x)) 154 continue; 210 continue; 155 q2 ~= new Pos(y,x); 211 q2 ~= new Pos(y,x); 156 v[y][x]=true; 212 v[y][x]=true; 157 } 213 } 158 } 214 } 159 } 215 } ................................................................................................................................................................................ 162 return []; 218 return []; 163 } 219 } 164 220 165 // any empty space is my ground 221 // any empty space is my ground 166 Tuple!(char,int)[] tryB() { 222 Tuple!(char,int)[] tryB() { 167 const(Pos)[] q; 223 const(Pos)[] q; 168 foreach(p; gs) q ~= p; 224 foreach(p; gs) q ~= p; 169 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); | 225 bool[][] v = new bool[][](g.H+2, g.W+2); 170 foreach(p; q) v[p.y][p.x]=true; 226 foreach(p; q) v[p.y][p.x]=true; 171 for(int step=10; q.length; ++step) { 227 for(int step=10; q.length; ++step) { 172 Pos[] q2; 228 Pos[] q2; 173 foreach(p; q) { 229 foreach(p; q) { 174 int[] dy=[-1,+1,0,0]; | 230 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 175 int[] dx=[0,0,-1,+1]; | 231 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 176 for(int i=0; i<4; ++i) { | 232 for(int i=0; i<yyy.length; ++i) { 177 int y = p.y+dy[i]; | 233 int y = yyy[i]; 178 int x = p.x+dx[i]; | 234 int x = xxx[i]; > 235 if('1'<=g[y,x]&&g[y,x]<='9') { > 236 foreach(ppp; g.trampolin > 237 yyy ~= ppp.y; > 238 xxx ~= ppp.x; > 239 } > 240 continue; > 241 } 179 if(v[y][x]) continue; 242 if(v[y][x]) continue; 180 if(y==s.y && x==s.x) { | 243 if(y==s.y && x==s.x && i<4) { 181 char c = "UDRL"[i]; 244 char c = "UDRL"[i]; 182 if( death.count(c) == 0 245 if( death.count(c) == 0 183 return [tuple(c, 246 return [tuple(c, 184 } else if(forbidden_cell[y][x]){ 247 } else if(forbidden_cell[y][x]){ 185 } else if(g.map[y,x]==' '||g.map | 248 } else if(g[y,x]==' '||g[y,x]==' 186 q2 ~= new Pos(y,x); 249 q2 ~= new Pos(y,x); 187 v[y][x]=true; 250 v[y][x]=true; 188 } 251 } 189 } 252 } 190 } 253 } 191 q = q2; 254 q = q2; 192 } 255 } ................................................................................................................................................................................ 193 return []; 256 return []; 194 } 257 } 195 258 196 // push rocks! 259 // push rocks! 197 Tuple!(char,int)[] tryC() { 260 Tuple!(char,int)[] tryC() { 198 const(Pos)[] q; 261 const(Pos)[] q; 199 foreach(p; gs) q ~= p; 262 foreach(p; gs) q ~= p; 200 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); | 263 bool[][] v = new bool[][](g.H+2, g.W+2); 201 foreach(p; q) v[p.y][p.x]=true; 264 foreach(p; q) v[p.y][p.x]=true; 202 for(int step=20; q.length; ++step) { 265 for(int step=20; q.length; ++step) { 203 Pos[] q2; 266 Pos[] q2; 204 foreach(p; q) { 267 foreach(p; q) { 205 int[] dy=[-1,+1,0,0]; | 268 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; 206 int[] dx=[0,0,-1,+1]; | 269 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; 207 for(int i=0; i<4; ++i) { | 270 for(int i=0; i<yyy.length; ++i) { 208 int y = p.y+dy[i]; | 271 int y = yyy[i]; 209 int x = p.x+dx[i]; | 272 int x = xxx[i]; > 273 if(g[p] == '*') { > 274 if(i>=4)continue; > 275 if(y!=p.y)continue; > 276 if(g[y,p.x+(p.x-x)]!=' ' > 277 } > 278 if('1'<=g[y,x]&&g[y,x]<='9') { > 279 foreach(ppp; g.trampolin > 280 yyy ~= ppp.y; > 281 xxx ~= ppp.x; > 282 } > 283 continue; > 284 } 210 if(v[y][x]) continue; 285 if(v[y][x]) continue; 211 if(y==s.y && x==s.x) { | 286 if(y==s.y && x==s.x && i<4) { 212 char c = "UDRL"[i]; 287 char c = "UDRL"[i]; 213 if( death.count(c) == 0 288 if( death.count(c) == 0 214 return [tuple(c, 289 return [tuple(c, 215 } else if(forbidden_cell[y][x]){ 290 } else if(forbidden_cell[y][x]){ 216 } else if(g.map[y,x]==' '||g.map | 291 } else if(g[y,x]==' '||g[y,x]==' 217 q2 ~= new Pos(y,x); < 218 v[y][x]=true; < 219 } else if(dy[i]==0 && g.map[p]== < 220 q2 ~= new Pos(y,x); 292 q2 ~= new Pos(y,x); 221 v[y][x]=true; 293 v[y][x]=true; 222 } 294 } 223 } 295 } 224 } 296 } 225 q = q2; 297 q = q2; 226 } 298 } 227 return []; 299 return []; 228 } 300 } 229 return tryA() ~ tryB() ~ tryC(); | 301 return (danger_ok ? [] : tryA()) ~ tryB() ~ tryC(); > 302 } > 303 } > 304 > 305 class Solver_2(Solver) > 306 { > 307 string plan; > 308 bool plan_broken = true; > 309 > 310 Game g; > 311 this(in Game g) > 312 { > 313 this.g = g.clone(); > 314 make_plan(g); > 315 } > 316 > 317 Tuple!(Solver,string) run_sub_solver(in Game g) > 318 { > 319 string log; > 320 auto s = new Solver(g); > 321 while(!g.cleared && !g.dead && plan.length<=g.H*g.W) { > 322 char c = s.single_step(); > 323 if( c == 'A' ) > 324 break; > 325 log ~= c; > 326 } > 327 while(log.length>0 && log[$-1]=='W') > 328 log.length--; > 329 return tuple(s, log); > 330 } > 331 > 332 void make_plan(in Game g) { > 333 plan_broken = false; > 334 Tuple!(Solver,string) x = run_sub_solver(g); > 335 plan = x[1]; > 336 if(x[0].g.cleared) > 337 return; > 338 modify_plan(g, x[0].g.score); > 339 } > 340 > 341 void modify_plan(in Game ini, long unmod) > 342 { > 343 int bp = max(0, (cast(int)plan.length)-10); > 344 Game g = ini.clone(); > 345 for(int i=0; i<bp; ++i) g.command(plan[i]); > 346 > 347 Tuple!(string,long) cand = tuple(plan, unmod); > 348 for(int i=bp; i<plan.length; ++i) { > 349 foreach(string c; ["U","D","L","R","UD","DU","LR","RL"]) > 350 if(c[0] != plan[i]) { > 351 Tuple!(string,long) zz = try_plan(c, g); > 352 if(cand[1]<zz[1]) > 353 cand = tuple(plan[0..i]~c~zz[0], > 354 } > 355 g.command(plan[i]); > 356 } > 357 plan = cand[0]; > 358 } > 359 > 360 Tuple!(string,long) try_plan(string c, in Game g) > 361 { > 362 Game gg = g.clone(); > 363 foreach(cc;c)gg.command(cc); > 364 Tuple!(Solver, string) x = run_sub_solver(gg); > 365 return tuple(x[1], x[0].g.score); > 366 } > 367 > 368 char single_step() { > 369 if(plan_broken) > 370 make_plan(g); > 371 if(plan.empty) > 372 return 'A'; > 373 char c = plan[0]; > 374 plan = plan[1..$]; > 375 g.command(c); > 376 return c; > 377 } > 378 > 379 void force(char c) { > 380 g.command(c); > 381 if(plan.length==0 || plan[0]!=c) { > 382 plan = ""; > 383 plan_broken = true; > 384 } > 385 else > 386 plan = plan[1..$]; 230 } 387 } 231 } 388 } > 389 > 390 alias Solver_2!(Solver_1) MainSolver; > 391 //alias Solver_1 MainSolver;

Modified src/util.d from [783554bf667412ed] to [b76be1f6ad977d56].

1 public import std.algorithm; 1 public import std.algorithm; 2 public import std.array; 2 public import std.array; 3 public import std.conv; 3 public import std.conv; 4 public import std.range; 4 public import std.range; 5 public import std.stdio; 5 public import std.stdio; 6 public import std.string; 6 public import std.string; 7 public import std.typecons; 7 public import std.typecons; > 8 public import std.math; 8 import std.c.stdlib; 9 import std.c.stdlib; > 10 > 11 T[] erase(T,V)(T[] xs, V y) > 12 { > 13 foreach(i,x; xs) > 14 if(x == y) > 15 return xs[0..i]~xs[i+1..$]; > 16 return xs; > 17 } > 18 > 19 // To avoide the following ICE: > 20 // src\phobos\std\algorithm.d(4552): > 21 // Error: function std.algorithm.count!("a == b",string,char).count > 22 // compiler error, parameter 'value', bugzilla 2962? > 23 // Assertion failure: '0' on line 717 in file 'glue.c' > 24 int count(T,V)(T[] a, V v) > 25 { > 26 int cnt = 0; > 27 foreach(e; a) > 28 if(e == v) > 29 ++cnt; > 30 return cnt; > 31 } 9 32 10 void application_exit() 33 void application_exit() 11 { 34 { 12 std.c.stdlib.exit(0); 35 std.c.stdlib.exit(0); 13 } 36 } 14 37 15 template DeriveCreate() 38 template DeriveCreate() ................................................................................................................................................................................ 19 this.tupleof = params; 42 this.tupleof = params; 20 } 43 } 21 } 44 } 22 45 23 template DeriveCompare() 46 template DeriveCompare() 24 { 47 { 25 override: 48 override: 26 bool opEquals(Object rhs) | 49 bool opEquals(Object rhs) const 27 { 50 { 28 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl 51 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl 29 } 52 } 30 53 31 int opCmp(Object rhs) | 54 int opCmp(Object rhs) const 32 { 55 { 33 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t 56 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t 34 } 57 } 35 58 36 hash_t toHash() | 59 hash_t toHash() const 37 { 60 { 38 hash_t v = 0; 61 hash_t v = 0; 39 foreach(mem; this.tupleof) { 62 foreach(mem; this.tupleof) { 40 v *= 11; 63 v *= 11; 41 static if(__traits(compiles, v^=mem)) 64 static if(__traits(compiles, v^=mem)) 42 v ^= mem; 65 v ^= mem; 43 else 66 else ................................................................................................................................................................................ 46 return v; 69 return v; 47 } 70 } 48 } 71 } 49 72 50 template DeriveShow() 73 template DeriveShow() 51 { 74 { 52 override: 75 override: 53 string toString() | 76 string toString() const 54 { 77 { 55 string str = text(typeof(this).stringof, "("); 78 string str = text(typeof(this).stringof, "("); 56 foreach(i,mem; this.tupleof) { 79 foreach(i,mem; this.tupleof) { 57 if(i) str ~= ", "; 80 if(i) str ~= ", "; 58 str = text(str, this.tupleof[i].stringof[5..$], ":", me 81 str = text(str, this.tupleof[i].stringof[5..$], ":", me 59 } 82 } 60 return str ~ ")"; 83 return str ~ ")"; 61 } 84 } 62 } 85 }