Check-in Differences
Not logged in

Difference From:

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

To:

[30c61d0d90] trampoline.maps (user: kinaba, tags: trunk, date: 2012-07-14 16:42:10)

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

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

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

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

Deleted 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/trampoline4.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

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

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

Deleted 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 [fc05481901940844] to [3baab0ddf11cca7d].

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( 52 return new Water(params.get("Water", "0").to!int(), | 53 params.get("Water", "0").to!int(), 53 params.get("Flooding", "0").to!int()); | 54 params.get("Flooding", "0").to!int() > 55 ); 54 } 56 } 55 57 56 int level(int number_of_update) const 58 int level(int number_of_update) const 57 { 59 { 58 return pace ? base+(number_of_update/pace) : base; 60 return pace ? base+(number_of_update/pace) : base; 59 } 61 } 60 62 ................................................................................................................................................................................ 82 assert( 1 == w.level(3) ); 84 assert( 1 == w.level(3) ); 83 assert( 1 == w.level(4) ); 85 assert( 1 == w.level(4) ); 84 assert( 1 == w.level(5) ); 86 assert( 1 == w.level(5) ); 85 } 87 } 86 88 87 //////////////////////////////////////////////////////////////////////////////// 89 //////////////////////////////////////////////////////////////////////////////// 88 90 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 < 115 class Map 91 class Map 116 { 92 { 117 mixin DeriveShow; 93 mixin DeriveShow; 118 94 119 static Map load(string[] raw_data, string[string] params, char[char] tra | 95 static Map load(string[] raw_data, string[string] params) 120 { 96 { 121 // TODO: choose optimal representation. 97 // TODO: choose optimal representation. 122 return new Map(raw_data, params, trampo); | 98 return new Map(raw_data, params); 123 } 99 } 124 100 125 char[][] data; 101 char[][] data; 126 Pos robot; 102 Pos robot; 127 Pos lift; 103 Pos lift; 128 int waterproof; 104 int waterproof; 129 Pos[char] tr_target; < 130 Pos[][char] tr_source; < 131 const(Hige) hige; < 132 int razor; < 133 105 134 Map clone() const { return new Map(this); } 106 Map clone() const { return new Map(this); } 135 this(in Map m) { 107 this(in Map m) { 136 foreach(s; m.data) 108 foreach(s; m.data) 137 this.data ~= s.dup; 109 this.data ~= s.dup; 138 this.robot = m.robot.clone(); 110 this.robot = m.robot.clone(); 139 this.lift = m.lift.clone(); 111 this.lift = m.lift.clone(); 140 this.waterproof = m.waterproof; 112 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; < 145 } 113 } 146 114 147 this(string[] raw_data, string[string] params, char[char] trampo) | 115 this(string[] raw_data, string[string] params) 148 { 116 { 149 int width = 0; 117 int width = 0; 150 foreach(r; raw_data) 118 foreach(r; raw_data) 151 width = max(width, r.length); 119 width = max(width, r.length); 152 foreach(r; raw_data) { 120 foreach(r; raw_data) { 153 this.data ~= r.dup; 121 this.data ~= r.dup; 154 this.data[$-1].length = width; 122 this.data[$-1].length = width; ................................................................................................................................................................................ 159 for(int x=1; x<=W; ++x) { 127 for(int x=1; x<=W; ++x) { 160 if(this[y,x] == 'R') 128 if(this[y,x] == 'R') 161 this.robot = new Pos(y,x); 129 this.robot = new Pos(y,x); 162 if(this[y,x] == 'L' || this[y,x] == 'O') 130 if(this[y,x] == 'L' || this[y,x] == 'O') 163 this.lift = new Pos(y,x); 131 this.lift = new Pos(y,x); 164 } 132 } 165 133 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 } < 173 < 174 this.waterproof = params.get("Waterproof", "5").to!int(); 134 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(); < 183 } 135 } 184 136 185 const @property { 137 const @property { 186 int H() { return data.length; } 138 int H() { return data.length; } 187 int W() { return data[0].length; } 139 int W() { return data[0].length; } 188 } 140 } 189 141 ................................................................................................................................................................................ 213 } 165 } 214 166 215 void opIndexAssign(char c, in Pos p) 167 void opIndexAssign(char c, in Pos p) 216 { 168 { 217 this[p.y, p.x] = c; 169 this[p.y, p.x] = c; 218 } 170 } 219 171 220 Pos[] objects(char c) const { | 172 Pos[] lambdas() const { 221 Pos[] ans; 173 Pos[] ans; 222 for(int y=1; y<=H; ++y) 174 for(int y=1; y<=H; ++y) 223 for(int x=1; x<=W; ++x) 175 for(int x=1; x<=W; ++x) 224 if(this[y,x] == c) | 176 if(this[y,x] == '\\') 225 ans ~= new Pos(y,x); 177 ans ~= new Pos(y,x); 226 return ans; 178 return ans; 227 } 179 } 228 180 229 Pos[] razors() const { return objects('!'); } < 230 Pos[] lambdas() const { return objects('\\'); } < 231 < 232 bool cleared() const 181 bool cleared() const 233 { 182 { 234 for(int y=1; y<=H; ++y) 183 for(int y=1; y<=H; ++y) 235 for(int x=1; x<=W; ++x) 184 for(int x=1; x<=W; ++x) 236 if(this[y,x] == 'L' || this[y,x] == 'O') 185 if(this[y,x] == 'L' || this[y,x] == 'O') 237 return false; 186 return false; 238 return true; 187 return true; 239 } 188 } 240 189 241 Tuple!(int,bool) command(char c, int turn) | 190 Tuple!(int,bool) command(char c) 242 { 191 { 243 assert( this[robot] == 'R' ); < 244 if(c=='R') return move( 0, +1, turn); | 192 if(c=='R') return move( 0, +1); 245 if(c=='L') return move( 0, -1, turn); | 193 if(c=='L') return move( 0, -1); 246 if(c=='U') return move(+1, 0, turn); | 194 if(c=='U') return move(+1, 0); 247 if(c=='D') return move(-1, 0, turn); | 195 if(c=='D') return move(-1, 0); 248 if(c=='W') return move( 0, 0, turn); | 196 if(c=='W') return move( 0, 0); 249 if(c=='S') return use_razor(turn); < 250 assert(false); 197 assert(false); 251 } 198 } 252 199 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 < 267 Tuple!(int, bool) move(int dy, int dx, int turn) | 200 Tuple!(int, bool) move(int dy, int dx) 268 { 201 { 269 int y = robot.y; 202 int y = robot.y; 270 int x = robot.x; 203 int x = robot.x; > 204 assert( this[robot] == 'R' ); 271 int lambda = 0; 205 int lambda = 0; > 206 bool dead = false; 272 if( '\\' == this[y+dy,x+dx] ) 207 if( '\\' == this[y+dy,x+dx] ) 273 lambda++; 208 lambda++; 274 if( '!' == this[y+dy,x+dx] ) < 275 razor++; < 276 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { | 209 if( " \\.O".count(this[y+dy,x+dx])==1 ) { 277 this[y,x]=' '; 210 this[y,x]=' '; 278 this[y+dy,x+dx]='R'; 211 this[y+dy,x+dx]='R'; 279 robot = new Pos(y+dy,x+dx); 212 robot = new Pos(y+dy,x+dx); 280 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx 213 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx 281 this[y,x]=' '; 214 this[y,x]=' '; 282 this[y+dy,x+dx]='R'; 215 this[y+dy,x+dx]='R'; 283 this[y+dy*2,x+dx*2]='*'; 216 this[y+dy*2,x+dx*2]='*'; 284 robot = new Pos(y+dy,x+dx); 217 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; < 292 } 218 } 293 bool dead = update(turn); | 219 if( update() ) > 220 dead = true; 294 return tuple(lambda,dead); 221 return tuple(lambda,dead); 295 } 222 } 296 223 297 bool update(int turn) | 224 bool update() 298 { 225 { 299 bool dead = false; 226 bool dead = false; 300 227 301 char[][] next; 228 char[][] next; 302 foreach(y,s; data) 229 foreach(y,s; data) 303 next ~= s.dup; 230 next ~= s.dup; 304 231 ................................................................................................................................................................................ 332 dead=true; 259 dead=true; 333 } 260 } 334 } 261 } 335 else if(this[p]=='L') { 262 else if(this[p]=='L') { 336 if(!lambda) 263 if(!lambda) 337 access(p) = 'O'; 264 access(p) = 'O'; 338 } 265 } 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 } < 346 } 266 } 347 data = next; 267 data = next; 348 return dead; 268 return dead; 349 } 269 } 350 } 270 } 351 271 352 //////////////////////////////////////////////////////////////////////////////// 272 //////////////////////////////////////////////////////////////////////////////// 353 273 354 class Game 274 class Game 355 { 275 { 356 public: | 276 mixin DeriveShow; > 277 357 this(File input) | 278 static Game load(File input) 358 { 279 { 359 // Read map data | 280 string[] raw_data; 360 string[] map_data_lines; | 281 string[string] params; > 282 > 283 // Raw map data; read until empty line. 361 for(string line; !(line=input.readln().chomp()).empty; ) 284 for(string line; !(line=input.readln().chomp()).empty; ) 362 map_data_lines ~= line; | 285 raw_data ~= line; 363 286 364 // H*W | 287 // Additional commands; read until EOF. > 288 for(string line; !(line=input.readln()).empty; ) { > 289 string[] ss = line.split(); 365 H_ = map_data_lines.length; | 290 if( ss.length == 2 ) 366 W_ = 0; < 367 foreach(mdl; map_data_lines) < 368 W_ = max(W_, mdl.length); | 291 params[ss[0]] = ss[1]; 369 < 370 // Copy to modifiable buffer and adjust coordinates. < 371 raw_data_ = new char[][H_+1]; < 372 foreach(i,mdl; map_data_lines) { < 373 char[] buf = new char[mdl.length+1]; < 374 buf[0] = '#'; < 375 buf[1..$] = mdl[]; < 376 raw_data_[H_-i] = buf; < 377 } 292 } 378 293 379 // Detect objects | 294 return load(raw_data, params); 380 for(int y=1; y<=H_; ++y) < 381 for(int x=1; x<raw_data_[y].length; ++x) < > 295 } 382 { | 296 383 char c = raw_data_[y][x]; < > 297 static Game load(string[] raw_data, string[string] params) > 298 { 384 switch(c) | 299 return new Game(raw_data, params); > 300 } 385 { | 301 386 case '#': < 387 case '.': | 302 this(string[] raw_data, string[string] params) 388 case ' ': < > 303 { 389 break; | 304 this.map = Map.load(raw_data, params); 390 case 'L': | 305 this.water = Water.load(params); 391 case 'O': < 392 lift_pos_ = new Pos(y,x); < 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; < > 306 } 404 307 405 // Moving objects are erased from raw_data_ | 308 Game clone() const { return new Game(this); } 406 case 'R': | 309 this(in Game g) { 407 robot_pos_ = new Pos(y,x); | 310 map = g.map.clone(); 408 raw_data_[y][x] = ' '; | 311 water = g.water.clone(); 409 break; | 312 turn = g.turn; 410 case '*': | 313 dead = g.dead; 411 case 'W': | 314 lambda = g.lambda; 412 dynamic_objects_[new Pos(y,x)] = c; | 315 exit_bonus = g.exit_bonus; 413 raw_data_[y][x] = ' '; | 316 under_water = g.under_water; 414 if(c=='*') < 415 may_update_[new Pos(y,x)] = true; < 416 break; < 417 default: < 418 assert(false); < 419 } < 420 } < 421 < 422 // Read other parameters < 423 for(string line; !(line=input.readln()).empty; ) < 424 { < 425 string[] ss = line.split(); < 426 if( ss.length == 2 ) < 427 switch(ss[0]) < 428 { < 429 case "Water": water_base_ = ss[1].to!int(); < 430 case "Flooding": water_pace_ = ss[1].to!int(); < 431 case "Waterproof": max_air_ = ss[1].to!int(); < 432 case "Growth": hige_pace_ = ss[1].to!int(); < 433 case "Razors": num_razor_ = ss[1].to!int(); < 434 default: assert(false); < 435 } < 436 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar < 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; < 442 } < 443 } < 444 < 445 air_left_ = max_air_; < 446 } 317 } 447 318 448 @property const { < 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 } < 460 int water_level() { < 461 return water_pace_ ? water_base_ + turn_/water_pace_ : w < 462 } < 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_; } < 474 bool cleared() { return cleared_; } < 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) 319 void command(char c) 506 { 320 { 507 if(dead || cleared) 321 if(dead || cleared) 508 return; 322 return; 509 323 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') {} | 324 if(c == 'A') > 325 { > 326 exit_bonus = 1; > 327 return; > 328 } 516 329 > 330 // TODO: clarify the event order > 331 Tuple!(int,bool) ld = map.command(c); 517 if(!cleared) | 332 if( map.cleared() ) { 518 { < 519 map_update(); < 520 water_update(); | 333 exit_bonus = 2; > 334 } > 335 else { > 336 lambda += ld[0]; > 337 if( ld[1] ) { > 338 dead = true; > 339 } 521 } 340 } > 341 if( map.robot.y <= water_level ) > 342 ++under_water; > 343 else > 344 under_water = 0; > 345 if( under_water > map.waterproof ) > 346 dead = true; 522 turn_ ++; | 347 turn += 1; 523 } 348 } 524 349 525 void command_move(int dy, int dx) | 350 Map map; 526 { < > 351 Water water; 527 int y = robot_pos_.y, x = robot_pos_.x; | 352 int turn = 0; 528 char c = this[y+dy, x+dx]; | 353 bool dead = false; 529 Pos p = new Pos(y+dy, x+dx); | 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. 530 359 531 switch(c){ | 360 @property const { 532 case 'O': | 361 long score() { return lambda*25L*(1+exit_bonus) - turn; } 533 cleared_ = true; | 362 int water_level() { return water.level(turn); } 534 move_robot_to(p); | 363 int water_until_rise() { return water.until_rise(turn); } 535 break; | 364 bool cleared() { return exit_bonus>0; } 536 case '\\': | 365 int hp() { return map.waterproof - under_water; } 537 take_lambda_at(p); | 366 long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus 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 } 367 } > 368 } 561 369 562 void use_razor() | 370 unittest 563 { | 371 { 564 if(num_razor_ == 0) | 372 Game.load(["###","...","#RL"], ["xxx":"yyy"]); 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; < 759 } < 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; < 779 < 780 int turn_ = 0; < 781 int air_left_ = 0; < 782 bool cleared_ = false; < 783 bool dead_ = false; < 784 bool[Pos] may_update_; < 785 } 373 }

Modified src/gui.d from [e84cacd6262f93a7] to [6f9d0f82c55a2152].

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

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

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 score_log ~= g.score; | 27 ideal_log ~= g.score_if_abort_now; 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; 38 if(finished || log.length+1==g.W*g.H) | 39 if(finished || log.length+1==g.map.W*g.map.H) 39 flush(); 40 flush(); 40 } 41 } 41 42 42 private: 43 private: 43 string log; 44 string log; 44 long[] score_log; 45 long[] score_log; > 46 long[] ideal_log; 45 bool flushed; 47 bool flushed; 46 48 47 void flush() 49 void flush() 48 { 50 { 49 if(flushed) < 50 return; < 51 < 52 Tuple!(long, int) cand; | 51 Tuple!(long, int, int) cand; 53 cand[0] = long.min; 52 cand[0] = long.min; 54 53 55 for(int i=0; i<score_log.length; ++i) 54 for(int i=0; i<score_log.length; ++i) 56 if(cand[0] < score_log[i]) 55 if(cand[0] < score_log[i]) 57 cand = tuple(score_log[i],i); | 56 cand = tuple(score_log[i],i,0); > 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); 58 60 > 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]]; 59 std.c.stdio.printf("%.*sA\n", cand[1], log.ptr); | 66 std.c.stdio.printf("%.*sA\n", str.length, str.ptr); > 67 } 60 std.c.stdio.fflush(std.c.stdio.stdout); 68 std.c.stdio.fflush(std.c.stdio.stdout); 61 flushed = true; 69 flushed = true; 62 } 70 } 63 71 64 private: 72 private: 65 static __gshared GuardedOutput g_output; 73 static __gshared GuardedOutput g_output; 66 74

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

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(in Game g) {} | 6 this(const(Game) g) {} 7 char single_step() { return 'W'; } 7 char single_step() { return 'W'; } 8 void force(char c) {} < 9 } 8 } 10 9 11 class Solver_1 10 class Solver_1 12 { 11 { 13 int wait_count = 0; 12 int wait_count = 0; 14 int choke_count = 0; < 15 13 16 Game g; 14 Game g; 17 this(in Game g) | 15 this(const(Game) g) 18 { 16 { 19 this.g = g.clone(); 17 this.g = g.clone(); 20 forbidden_cell = new bool[][](g.H+2, g.W+2); | 18 forbidden_cell = new bool[][](g.map.H+2, g.map.W+2); 21 } 19 } 22 20 23 char single_step() 21 char single_step() 24 { 22 { 25 Tuple!(string,int) de = death_move(g); 23 Tuple!(string,int) de = death_move(g); 26 char c = act(g, de[0], de[1]); 24 char c = act(g, de[0], de[1]); 27 force(c); | 25 g.command(c); 28 return c; 26 return c; 29 } 27 } 30 28 31 void force(char c) < 32 { < 33 if(c != 'A') < 34 g.command(c); < 35 } < 36 < 37 Tuple!(string,int) death_move(const(Game) g) 29 Tuple!(string,int) death_move(const(Game) g) 38 { 30 { 39 string death; 31 string death; 40 int choice = 0; 32 int choice = 0; 41 foreach(char c; "UDLRW") { 33 foreach(char c; "UDLRW") { 42 Game gg = g.clone(); 34 Game gg = g.clone(); 43 gg.command(c); 35 gg.command(c); 44 if( !gg.cleared && gg.dead ) 36 if( !gg.cleared && gg.dead ) 45 death ~= c; 37 death ~= c; 46 else if( gg.robot != g.robot ) | 38 else if( gg.map.robot != g.map.robot ) 47 choice++; 39 choice++; 48 else if( c != 'W' ) // meaningless move < 49 death ~= c; < 50 } 40 } 51 return tuple(death, choice); 41 return tuple(death, choice); 52 } 42 } 53 43 54 Tuple!(Pos, int)[] log; 44 Tuple!(Pos, int)[] log; 55 bool[][] forbidden_cell; 45 bool[][] forbidden_cell; 56 46 57 char act(const(Game) g, string death, int breath) 47 char act(const(Game) g, string death, int breath) 58 { 48 { 59 const Pos ro = g.robot; | 49 const Pos ro = g.map.robot; 60 const Pos li = g.lift; | 50 const Pos[] la = g.map.lambdas(); 61 Pos[] la = g.lambdas(); | 51 const Pos li = g.map.lift; 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(); < 69 52 70 Tuple!(char,int)[] cand; 53 Tuple!(char,int)[] cand; 71 char c = 'W'; 54 char c = 'W'; 72 if( la.empty ) { 55 if( la.empty ) { 73 cand = search(g, ro, [li], death); 56 cand = search(g, ro, [li], death); 74 } else { 57 } else { 75 cand ~= search(g, ro, la~ra, death); | 58 cand ~= search(g, ro, la, death); 76 } 59 } 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 } < 103 } < 104 < 105 // 'dig' mode < 106 if(cand.empty) { 60 if(cand.empty) { 107 const(Pos)[] tgt; 61 const(Pos)[] tgt; 108 for(int y=1; y<=g.H; ++y) | 62 for(int y=1; y<=g.map.H; ++y) 109 for(int x=1; x<=g.W; ++x) | 63 for(int x=1; x<=g.map.W; ++x) 110 if(g[y,x]=='.') | 64 if(g.map[y,x]=='.') 111 if(g[y+1,x]=='*'||g[y+1,x-1]=='*'||g[y+1 | 65 if(g.map[y+1,x]=='*'||g.map[y+1,x-1]=='* 112 ||g[y,x+1]=='*'||g[y,x-1]=='*') | 66 ||g.map[y,x+1]=='*'||g.map[y,x-1]=='*') 113 tgt ~= new Pos(y,x); 67 tgt ~= new Pos(y,x); 114 cand ~= search(g, ro, tgt, death, true); 68 cand ~= search(g, ro, tgt, death, true); 115 } 69 } 116 70 117 if(cand.empty) { | 71 if(cand.empty) 118 choke_count++; < 119 cand ~= tuple('W',int.max); 72 cand ~= tuple('W',int.max); 120 } < 121 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ 73 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ 122 if(c1[1] != c2[1]) 74 if(c1[1] != c2[1]) 123 return c1[1] < c2[1]; 75 return c1[1] < c2[1]; 124 return c1[0] < c2[0]; 76 return c1[0] < c2[0]; 125 })(cand); 77 })(cand); 126 c = cand[0][0]; 78 c = cand[0][0]; 127 79 128 if(death.count(c) || wait_count>=2) { | 80 if(death.count(c)) { 129 foreach(char live; "UDLRW") | 81 foreach(char live; "UDLRWA") 130 if(death.count(live)==0) { 82 if(death.count(live)==0) { 131 c=live; 83 c=live; 132 break; 84 break; 133 } 85 } 134 } 86 } 135 87 136 if(c == 'W') | 88 if(c=='W') { 137 wait_count++; 89 wait_count++; > 90 if(wait_count > g.map.H) > 91 c = 'A'; > 92 } 138 else 93 else 139 wait_count = 0; 94 wait_count = 0; 140 if(choke_count >= g.H) < 141 c = 'A'; < 142 95 143 bool[char] choice; 96 bool[char] choice; 144 foreach(t; cand) 97 foreach(t; cand) 145 choice[t[0]] = true; 98 choice[t[0]] = true; 146 log ~= tuple(ro.clone(), cast(int)choice.length); 99 log ~= tuple(ro.clone(), cast(int)choice.length); 147 if(log.length > 5) 100 if(log.length > 5) 148 log = log[$-5..$]; 101 log = log[$-5..$]; ................................................................................................................................................................................ 157 return c; 110 return c; 158 } 111 } 159 112 160 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death 113 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death 161 { 114 { 162 bool danger(int y, int x) 115 bool danger(int y, int x) 163 { 116 { 164 if(g[y,x] == ' ' || g[y,x] == 'R') | 117 if(g.map[y,x] == ' ' || g.map[y,x] == 'R') 165 return false; 118 return false; 166 if(g[y+1,x] == '*') | 119 if(g.map[y+1,x] == '*') > 120 return true; > 121 if(g.map[y+1,x-1]=='*' && (g.map[y,x-1]=='\\'||g.map[y,x 167 return true; 122 return true; 168 if(g[y+1,x-1]=='*' && (g[y,x-1]=='\\'||g[y,x-1]=='*') && | 123 if(g.map[y+1,x+1]=='*' && (g.map[y,x+1]=='*') && (g.map[ 169 return true; 124 return true; 170 if(g[y+1,x+1]=='*' && (g[y,x+1]=='*') && (g[y+1,x]==' '| | 125 if(g.map[y,x-1]=='*' && (g.map[y-1,x-1]=='\\'||g.map[y-1 171 return true; 126 return true; 172 if(g[y,x-1]=='*' && (g[y-1,x-1]=='\\'||g[y-1,x-1]=='*') | 127 if(g.map[y,x+1]=='*' && (g.map[y-1,x+1]=='*') && (g.map[ 173 return true; < 174 if(g[y,x+1]=='*' && (g[y-1,x+1]=='*') && (g[y-1,x]==' '| < 175 return true; 128 return true; 176 return false; 129 return false; 177 } 130 } 178 131 179 // avoid directly below '*' 132 // avoid directly below '*' 180 Tuple!(char,int)[] tryA() { 133 Tuple!(char,int)[] tryA() { 181 const(Pos)[] q; 134 const(Pos)[] q; 182 foreach(p; gs) 135 foreach(p; gs) 183 if(!danger(p.y,p.x)) 136 if(!danger(p.y,p.x)) 184 q ~= p; 137 q ~= p; 185 bool[][] v = new bool[][](g.H+2, g.W+2); | 138 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 186 foreach(p; q) v[p.y][p.x]=true; 139 foreach(p; q) v[p.y][p.x]=true; 187 for(int step=1; q.length; ++step) { 140 for(int step=1; q.length; ++step) { 188 Pos[] q2; 141 Pos[] q2; 189 foreach(p; q) { 142 foreach(p; q) { 190 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; | 143 int[] dy=[-1,+1,0,0]; 191 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; | 144 int[] dx=[0,0,-1,+1]; 192 for(int i=0; i<yyy.length; ++i) { | 145 for(int i=0; i<4; ++i) { 193 int y = yyy[i]; | 146 int y = p.y+dy[i]; 194 int x = xxx[i]; | 147 int x = p.x+dx[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 } < 202 if(v[y][x]) continue; 148 if(v[y][x]) continue; 203 if(y==s.y && x==s.x && i<4) { | 149 if(y==s.y && x==s.x) { 204 char c = "UDRL"[i]; 150 char c = "UDRL"[i]; 205 if( death.count(c) == 0 151 if( death.count(c) == 0 206 return [tuple(c, 152 return [tuple(c, 207 } else if(forbidden_cell[y][x]){ 153 } else if(forbidden_cell[y][x]){ 208 } else if(g[y,x]==' '||g[y,x]==' | 154 } else if(g.map[y,x]==' '||g.map 209 if(danger(y,x)) 155 if(danger(y,x)) 210 continue; 156 continue; 211 q2 ~= new Pos(y,x); 157 q2 ~= new Pos(y,x); 212 v[y][x]=true; 158 v[y][x]=true; 213 } 159 } 214 } 160 } 215 } 161 } ................................................................................................................................................................................ 218 return []; 164 return []; 219 } 165 } 220 166 221 // any empty space is my ground 167 // any empty space is my ground 222 Tuple!(char,int)[] tryB() { 168 Tuple!(char,int)[] tryB() { 223 const(Pos)[] q; 169 const(Pos)[] q; 224 foreach(p; gs) q ~= p; 170 foreach(p; gs) q ~= p; 225 bool[][] v = new bool[][](g.H+2, g.W+2); | 171 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 226 foreach(p; q) v[p.y][p.x]=true; 172 foreach(p; q) v[p.y][p.x]=true; 227 for(int step=10; q.length; ++step) { 173 for(int step=10; q.length; ++step) { 228 Pos[] q2; 174 Pos[] q2; 229 foreach(p; q) { 175 foreach(p; q) { 230 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; | 176 int[] dy=[-1,+1,0,0]; 231 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; | 177 int[] dx=[0,0,-1,+1]; 232 for(int i=0; i<yyy.length; ++i) { | 178 for(int i=0; i<4; ++i) { 233 int y = yyy[i]; | 179 int y = p.y+dy[i]; 234 int x = xxx[i]; | 180 int x = p.x+dx[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 } < 242 if(v[y][x]) continue; 181 if(v[y][x]) continue; 243 if(y==s.y && x==s.x && i<4) { | 182 if(y==s.y && x==s.x) { 244 char c = "UDRL"[i]; 183 char c = "UDRL"[i]; 245 if( death.count(c) == 0 184 if( death.count(c) == 0 246 return [tuple(c, 185 return [tuple(c, 247 } else if(forbidden_cell[y][x]){ 186 } else if(forbidden_cell[y][x]){ 248 } else if(g[y,x]==' '||g[y,x]==' | 187 } else if(g.map[y,x]==' '||g.map 249 q2 ~= new Pos(y,x); 188 q2 ~= new Pos(y,x); 250 v[y][x]=true; 189 v[y][x]=true; 251 } 190 } 252 } 191 } 253 } 192 } 254 q = q2; 193 q = q2; 255 } 194 } ................................................................................................................................................................................ 256 return []; 195 return []; 257 } 196 } 258 197 259 // push rocks! 198 // push rocks! 260 Tuple!(char,int)[] tryC() { 199 Tuple!(char,int)[] tryC() { 261 const(Pos)[] q; 200 const(Pos)[] q; 262 foreach(p; gs) q ~= p; 201 foreach(p; gs) q ~= p; 263 bool[][] v = new bool[][](g.H+2, g.W+2); | 202 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); 264 foreach(p; q) v[p.y][p.x]=true; 203 foreach(p; q) v[p.y][p.x]=true; 265 for(int step=20; q.length; ++step) { 204 for(int step=20; q.length; ++step) { 266 Pos[] q2; 205 Pos[] q2; 267 foreach(p; q) { 206 foreach(p; q) { 268 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; | 207 int[] dy=[-1,+1,0,0]; 269 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; | 208 int[] dx=[0,0,-1,+1]; 270 for(int i=0; i<yyy.length; ++i) { | 209 for(int i=0; i<4; ++i) { 271 int y = yyy[i]; | 210 int y = p.y+dy[i]; 272 int x = xxx[i]; | 211 int x = p.x+dx[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 } < 285 if(v[y][x]) continue; 212 if(v[y][x]) continue; 286 if(y==s.y && x==s.x && i<4) { | 213 if(y==s.y && x==s.x) { 287 char c = "UDRL"[i]; 214 char c = "UDRL"[i]; 288 if( death.count(c) == 0 215 if( death.count(c) == 0 289 return [tuple(c, 216 return [tuple(c, 290 } else if(forbidden_cell[y][x]){ 217 } else if(forbidden_cell[y][x]){ 291 } else if(g[y,x]==' '||g[y,x]==' | 218 } else if(g.map[y,x]==' '||g.map > 219 q2 ~= new Pos(y,x); > 220 v[y][x]=true; > 221 } else if(dy[i]==0 && g.map[p]== 292 q2 ~= new Pos(y,x); 222 q2 ~= new Pos(y,x); 293 v[y][x]=true; 223 v[y][x]=true; 294 } 224 } 295 } 225 } 296 } 226 } 297 q = q2; 227 q = q2; 298 } 228 } 299 return []; 229 return []; 300 } 230 } 301 return (danger_ok ? [] : tryA()) ~ tryB() ~ tryC(); 231 return (danger_ok ? [] : tryA()) ~ tryB() ~ tryC(); 302 } 232 } 303 } 233 } 304 234 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..$]; < 387 } < 388 } < 389 < 390 alias Solver_2!(Solver_1) MainSolver; < 391 //alias Solver_1 MainSolver; | 235 alias Solver_1 MainSolver;

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

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; < 9 import std.c.stdlib; 8 import std.c.stdlib; 10 9 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 } < 32 < 33 void application_exit() 10 void application_exit() 34 { 11 { 35 std.c.stdlib.exit(0); 12 std.c.stdlib.exit(0); 36 } 13 } 37 14 38 template DeriveCreate() 15 template DeriveCreate() 39 { 16 { ................................................................................................................................................................................ 42 this.tupleof = params; 19 this.tupleof = params; 43 } 20 } 44 } 21 } 45 22 46 template DeriveCompare() 23 template DeriveCompare() 47 { 24 { 48 override: 25 override: 49 bool opEquals(Object rhs) const | 26 bool opEquals(Object rhs) 50 { 27 { 51 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl 28 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl 52 } 29 } 53 30 54 int opCmp(Object rhs) const | 31 int opCmp(Object rhs) 55 { 32 { 56 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t 33 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t 57 } 34 } 58 35 59 hash_t toHash() const | 36 hash_t toHash() 60 { 37 { 61 hash_t v = 0; 38 hash_t v = 0; 62 foreach(mem; this.tupleof) { 39 foreach(mem; this.tupleof) { 63 v *= 11; 40 v *= 11; 64 static if(__traits(compiles, v^=mem)) 41 static if(__traits(compiles, v^=mem)) 65 v ^= mem; 42 v ^= mem; 66 else 43 else ................................................................................................................................................................................ 69 return v; 46 return v; 70 } 47 } 71 } 48 } 72 49 73 template DeriveShow() 50 template DeriveShow() 74 { 51 { 75 override: 52 override: 76 string toString() const | 53 string toString() 77 { 54 { 78 string str = text(typeof(this).stringof, "("); 55 string str = text(typeof(this).stringof, "("); 79 foreach(i,mem; this.tupleof) { 56 foreach(i,mem; this.tupleof) { 80 if(i) str ~= ", "; 57 if(i) str ~= ", "; 81 str = text(str, this.tupleof[i].stringof[5..$], ":", me 58 str = text(str, this.tupleof[i].stringof[5..$], ":", me 82 } 59 } 83 return str ~ ")"; 60 return str ~ ")"; 84 } 61 } 85 } 62 }