Difference From:
[69105bf94a] Stand alone solver. (user: kinaba, tags: trunk, date: 2012-07-14 08:55:55)
To:
[fc9286dad1] uum (user: kinaba, tags: redesign, date: 2012-07-15 12:11:33)
Deleted game.d version [7c15481493257083]
1 import util; < 2 import output; < 3 < 4 //////////////////////////////////////////////////////////////////////////////// < 5 < 6 class Pos < 7 { < 8 public immutable int y, x; < 9 mixin DeriveCreate; < 10 mixin DeriveCompare; < 11 mixin DeriveShow; < 12 Pos clone() { return this; } < 13 < 14 @property: < 15 Pos wait() { return this; } < 16 Pos up() { return new Pos(y+1, x); } < 17 Pos down() { return new Pos(y-1, x); } < 18 Pos left() { return new Pos(y, x-1); } < 19 Pos right() { return new Pos(y, x+1); } < 20 alias wait W,w; < 21 alias up U,u; < 22 alias down D,d; < 23 alias left L,l; < 24 alias right R,r; < 25 } < 26 < 27 unittest < 28 { < 29 assert( (new Pos(2,1)).U == new Pos(3,1) ); < 30 assert( (new Pos(0,1)).D == new Pos(-1,1) ); < 31 assert( (new Pos(2,1)).L == new Pos(2,0) ); < 32 assert( (new Pos(2,1)).R == new Pos(2,2) ); < 33 int[Pos] aa; < 34 aa[new Pos(1,2)] = 1; < 35 aa[new Pos(1,2)] = 2; < 36 aa[new Pos(2,1)] = 3; < 37 assert( aa.length==2 ); < 38 assert( aa[new Pos(1,2)]==2 ); < 39 } < 40 < 41 //////////////////////////////////////////////////////////////////////////////// < 42 < 43 class Water < 44 { < 45 public immutable int base, pace; < 46 mixin DeriveCreate; < 47 mixin DeriveCompare; < 48 mixin DeriveShow; < 49 Water clone() { return this; } < 50 < 51 static load(string[string] params) < 52 { < 53 return new Water( < 54 params.get("Water", "0").to!int(), < 55 params.get("Flooding", "0").to!int() < 56 ); < 57 } < 58 < 59 int level(int number_of_update) < 60 { < 61 return pace ? base+(number_of_update/pace) : base; < 62 } < 63 < 64 int until_rise(int number_of_update) < 65 { < 66 return pace ? pace-number_of_update%pace : int.max; < 67 } < 68 } < 69 < 70 unittest < 71 { < 72 Water w = new Water(1, 3); < 73 assert( 1 == w.level(0) ); < 74 assert( 1 == w.level(1) ); < 75 assert( 1 == w.level(2) ); < 76 assert( 2 == w.level(3) ); < 77 assert( 2 == w.level(4) ); < 78 assert( 2 == w.level(5) ); < 79 assert( 3 == w.level(6) ); < 80 < 81 w = new Water(1, 0); < 82 assert( 1 == w.level(0) ); < 83 assert( 1 == w.level(1) ); < 84 assert( 1 == w.level(2) ); < 85 assert( 1 == w.level(3) ); < 86 assert( 1 == w.level(4) ); < 87 assert( 1 == w.level(5) ); < 88 } < 89 < 90 //////////////////////////////////////////////////////////////////////////////// < 91 < 92 class Map < 93 { < 94 mixin DeriveShow; < 95 < 96 static Map load(string[] raw_data, string[string] params) < 97 { < 98 // TODO: choose optimal representation. < 99 return new Map(raw_data, params); < 100 } < 101 < 102 char[][] data; < 103 Pos robot; < 104 Pos lift; < 105 int waterproof; < 106 < 107 Map clone() { return new Map(this); } < 108 this(Map m) { < 109 foreach(s; m.data) < 110 this.data ~= s.dup; < 111 this.robot = m.robot.clone(); < 112 this.lift = m.lift.clone(); < 113 this.waterproof = m.waterproof; < 114 } < 115 < 116 this(string[] raw_data, string[string] params) < 117 { < 118 int width = 0; < 119 foreach(r; raw_data) < 120 width = max(width, r.length); < 121 foreach(r; raw_data) { < 122 this.data ~= r.dup; < 123 this.data[$-1].length = width; < 124 this.data[$-1][r.length..$] = ' '; < 125 } < 126 < 127 for(int y=1; y<=H; ++y) < 128 for(int x=1; x<=W; ++x) { < 129 if(this[y,x] == 'R') < 130 this.robot = new Pos(y,x); < 131 if(this[y,x] == 'L' || this[y,x] == 'O') < 132 this.lift = new Pos(y,x); < 133 } < 134 < 135 this.waterproof = params.get("Waterproof", "5").to!int(); < 136 } < 137 < 138 const @property { < 139 int H() { return data.length; } < 140 int W() { return data[0].length; } < 141 } < 142 < 143 char opIndex(int y, int x) < 144 { < 145 // Adjust coordinate to the spec. bottom-left is (1,1). < 146 --y, --x; < 147 if(y<0||H<=y||x<0||W<=x) < 148 return '#'; < 149 return data[H-1-y][x]; < 150 } < 151 < 152 char opIndex(Pos p) < 153 { < 154 return this[p.y, p.x]; < 155 } < 156 < 157 void opIndexAssign(char c, int y, int x) < 158 { < 159 // Adjust coordinate to the spec. bottom-left is (1,1). < 160 --y, --x; < 161 if(y<0||H<=y||x<0||W<=x) < 162 return; < 163 data[H-1-y][x] = c; < 164 } < 165 < 166 void opIndexAssign(char c, Pos p) < 167 { < 168 this[p.y, p.x] = c; < 169 } < 170 < 171 Pos[] lambdas() { < 172 Pos[] ans; < 173 for(int y=1; y<=H; ++y) < 174 for(int x=1; x<=W; ++x) < 175 if(this[y,x] == '\\') < 176 ans ~= new Pos(y,x); < 177 return ans; < 178 } < 179 < 180 bool cleared() < 181 { < 182 for(int y=1; y<=H; ++y) < 183 for(int x=1; x<=W; ++x) < 184 if(this[y,x] == 'L' || this[y,x] == 'O') < 185 return false; < 186 return true; < 187 } < 188 < 189 Tuple!(int,bool) command(char c) < 190 { < 191 if(c=='R') return move( 0, +1); < 192 if(c=='L') return move( 0, -1); < 193 if(c=='U') return move(+1, 0); < 194 if(c=='D') return move(-1, 0); < 195 if(c=='W') return move( 0, 0); < 196 assert(false); < 197 } < 198 < 199 Tuple!(int, bool) move(int dy, int dx) < 200 { < 201 int y = robot.y; < 202 int x = robot.x; < 203 assert( this[robot] == 'R' ); < 204 int lambda = 0; < 205 bool dead = false; < 206 if( '\\' == this[y+dy,x+dx] ) < 207 lambda++; < 208 if( " \\.O".count(this[y+dy,x+dx])==1 ) { < 209 this[y,x]=' '; < 210 this[y+dy,x+dx]='R'; < 211 robot = new Pos(y+dy,x+dx); < 212 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx < 213 this[y,x]=' '; < 214 this[y+dy,x+dx]='R'; < 215 this[y+dy*2,x+dx*2]='*'; < 216 robot = new Pos(y+dy,x+dx); < 217 } < 218 if( update() ) < 219 dead = true; < 220 return tuple(lambda,dead); < 221 } < 222 < 223 bool update() < 224 { < 225 bool dead = false; < 226 < 227 char[][] next; < 228 foreach(y,s; data) < 229 next ~= s.dup; < 230 < 231 ref char access(Pos p) { return next[H-p.y][p.x-1]; } < 232 < 233 bool lambda = false; < 234 for(int y=1; y<=H; ++y) < 235 for(int x=1; x<=W; ++x) < 236 lambda |= (this[y,x] == '\\'); < 237 < 238 for(int y=1; y<=H; ++y) < 239 for(int x=1; x<=W; ++x) { < 240 Pos p = new Pos(y,x); < 241 if(this[p]=='*') { < 242 if(this[p.D]==' ') { < 243 access(p) =' '; < 244 access(p.D)='*'; < 245 if(robot == p.D.D) < 246 dead=true; < 247 } < 248 else if((this[p.D]=='*' || this[p.D]=='\\') && t < 249 access(p)=' '; < 250 access(p.R.D)='*'; < 251 if(robot == p.R.D.D) < 252 dead=true; < 253 } < 254 else if(this[p.D]=='*' && this[p.L]==' ' && this < 255 access(p)=' '; < 256 access(p.L.D)='*'; < 257 if(robot == p.L.D.D) < 258 dead=true; < 259 } < 260 } < 261 else if(this[p]=='L') { < 262 if(!lambda) < 263 access(p) = 'O'; < 264 } < 265 } < 266 data = next; < 267 return dead; < 268 } < 269 } < 270 < 271 //////////////////////////////////////////////////////////////////////////////// < 272 < 273 class Game < 274 { < 275 mixin DeriveShow; < 276 < 277 static Game load(File input) < 278 { < 279 string[] raw_data; < 280 string[string] params; < 281 < 282 // Raw map data; read until empty line. < 283 for(string line; !(line=input.readln().chomp()).empty; ) < 284 raw_data ~= line; < 285 < 286 // Additional commands; read until EOF. < 287 for(string line; !(line=input.readln()).empty; ) { < 288 string[] ss = line.split(); < 289 if( ss.length == 2 ) < 290 params[ss[0]] = ss[1]; < 291 } < 292 < 293 return load(raw_data, params); < 294 } < 295 < 296 static Game load(string[] raw_data, string[string] params) < 297 { < 298 return new Game(raw_data, params); < 299 } < 300 < 301 this(string[] raw_data, string[string] params) < 302 { < 303 this.map = Map.load(raw_data, params); < 304 this.water = Water.load(params); < 305 this.output = new NilOutput; < 306 } < 307 < 308 Game clone() { return new Game(this); } < 309 this(Game g) { < 310 map = g.map.clone(); < 311 water = g.water.clone(); < 312 output = new NilOutput; < 313 turn = g.turn; < 314 dead = g.dead; < 315 lambda = g.lambda; < 316 exit_bonus = g.exit_bonus; < 317 under_water = g.under_water; < 318 } < 319 < 320 void set_output(Output o) { this.output = (o is null ? new NilOutput : o < 321 < 322 void command(char c) < 323 { < 324 if(dead || cleared) < 325 return; < 326 scope(exit) { < 327 if(dead || cleared) < 328 output.flush(); < 329 } < 330 this.output.command(c); < 331 < 332 if(c == 'A') < 333 { < 334 exit_bonus = 1; < 335 return; < 336 } < 337 < 338 // TODO: clarify the event order < 339 Tuple!(int,bool) ld = map.command(c); < 340 if( map.cleared() ) { < 341 exit_bonus = 2; < 342 } < 343 else { < 344 lambda += ld[0]; < 345 if( ld[1] ) { < 346 dead = true; < 347 } < 348 } < 349 if( map.robot.y <= water_level ) < 350 ++under_water; < 351 else < 352 under_water = 0; < 353 if( under_water > map.waterproof ) < 354 dead = true; < 355 turn += 1; < 356 } < 357 < 358 Map map; < 359 Water water; < 360 Output output; < 361 int turn = 0; < 362 bool dead = false; < 363 int lambda = 0; < 364 int exit_bonus = 0; < 365 int under_water = 0; < 366 // TODO: when adding members, take care of clone(). < 367 // TODO: fix this poor design. < 368 < 369 @property { < 370 long score() { return lambda*25L*(1+exit_bonus) - turn; } < 371 int water_level() { return water.level(turn); } < 372 int water_until_rise() { return water.until_rise(turn); } < 373 bool cleared() { return exit_bonus>0; } < 374 int hp() { return map.waterproof - under_water; } < 375 long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus < 376 } < 377 } < 378 < 379 unittest < 380 { < 381 Game.load(["###","...","#RL"], ["xxx":"yyy"]); < 382 } <
Deleted gui.d version [8bca70d55515c665]
1 import dfl.all; < 2 import util; < 3 import game; < 4 import output; < 5 //import solver; < 6 < 7 class GUI : Form < 8 { < 9 private { < 10 Game g; < 11 int cell; < 12 int turn = 0; < 13 < 14 Font font; < 15 Color[char] colors; < 16 string[char] render; < 17 } < 18 < 19 this(Game g) < 20 { < 21 noMessageFilter(); < 22 this.setStyle(ControlStyles.OPAQUE, true); < 23 this.g = g; < 24 < 25 this.paint ~= &my_paint; < 26 this.keyDown ~= &my_keydown; < 27 < 28 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; < 29 this.maximizeBox = false; < 30 this.minimizeBox = false; < 31 this.cell = min(1024/g.map.W, 640/g.map.H); < 32 this.clientSize = Size(g.map.W*cell, g.map.H*cell); < 33 set_text(); < 34 < 35 // Resources < 36 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); < 37 this.backColor = Color(255,255,255); < 38 this.colors['#'] = < 39 this.colors['.'] = Color(255,191,127); < 40 this.colors['*'] = Color(255,127,127); < 41 this.colors['R'] = Color(128,128,0); < 42 this.colors['D'] = Color(255,0,0); // Dead < 43 this.colors['\\'] = < 44 this.colors['L'] = < 45 this.colors['O'] = Color(127,255,127); < 46 this.colors['W'] = Color(204,229,255); // water < 47 < 48 this.render['#'] = "■"; < 49 this.render['*'] = "✹"; < 50 this.render['.'] = "♒"; < 51 this.render['\\'] = "λ"; < 52 this.render['R'] = "☃"; < 53 this.render['D'] = "☠"; < 54 this.render['L'] = "☒"; < 55 this.render['O'] = "☐"; < 56 } < 57 < 58 private: < 59 void my_paint(Control, PaintEventArgs ev) < 60 { < 61 const scrH = this.clientSize.height; < 62 const scrW = this.clientSize.width; < 63 Graphics gr = new MemoryGraphics(scrW, scrH, ev.graphics); < 64 scope(exit) { < 65 gr.copyTo(ev.graphics, Rect(0,0,scrW,scrH)); < 66 gr.dispose(); < 67 } < 68 < 69 // Fill bg. < 70 gr.fillRectangle(this.backColor, Rect(0,0,scrW,scrH)); < 71 < 72 // Fill water. < 73 int w = g.water_level(); < 74 gr.fillRectangle(this.colors['W'], Rect(0, scrH-cell*w-1, scrW, < 75 < 76 // Paint map. < 77 for(int y=1; y<=g.map.H; ++y) < 78 for(int x=1; x<=g.map.W; ++x) { < 79 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); < 80 char c = g.map[y,x]; < 81 if( c != ' ' ) { < 82 if( c == 'R' && g.dead ) < 83 c = 'D'; < 84 gr.drawText(this.render[c], font, this.colors[c] < 85 } < 86 } < 87 } < 88 < 89 void my_keydown(Control c, KeyEventArgs ev) < 90 { < 91 switch(ev.keyCode) < 92 { < 93 case Keys.DOWN: g.command('D'); break; < 94 case Keys.UP: g.command('U'); break; < 95 case Keys.LEFT: g.command('L'); break; < 96 case Keys.RIGHT: g.command('R'); break; < 97 case Keys.W: g.command('W'); break; < 98 case Keys.A: g.command('A'); break; < 99 // case Keys.G: solver.act(g); break; < 100 default: break; < 101 } < 102 if(g.cleared) < 103 Application.exit(); < 104 invalidate(); < 105 set_text(); < 106 } < 107 < 108 void set_text() { < 109 this.text = .text("Score: ", g.score, " Air: ", g.hp, " Tide: ", < 110 } < 111 } < 112 < 113 void main(string[] args) < 114 { < 115 auto g = Game.load(File(args[1])); < 116 g.set_output(new GuardedOutput(g)); < 117 auto myForm = new GUI(g); < 118 Application.run(myForm); < 119 } <
Added icfp-96533632.tgz version [943329c30072989f]
cannot compute difference between binary files
Added make-submission version [bd7a911c141ae544]
Added maps/100x100.map version [5beaf6fad4143830]
> 1 ################################################################################ > 2 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 3 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 4 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 5 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 6 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\L\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 7 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 8 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 9 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 10 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 11 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 12 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 13 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 14 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 15 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 16 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 17 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 18 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 19 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 20 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 21 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 22 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 23 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 24 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 25 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 26 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 27 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 28 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 29 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 30 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 31 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 32 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 33 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 34 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 35 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 36 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 37 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 38 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 39 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 40 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 41 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 42 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 43 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 44 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 45 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 46 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 47 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 48 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 49 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 50 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 51 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 52 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 53 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 54 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 55 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 56 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 57 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 58 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 59 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 60 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 61 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 62 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\R\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 63 #************************\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 64 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.********************************\.\.\.\.\.\.\.\.\. > 65 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.************* > 66 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 67 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 68 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 69 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 70 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 71 #************************\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 72 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.********************************\.\.\.\.\.\.\.\.\. > 73 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.************* > 74 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 75 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 76 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 77 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 78 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 79 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 80 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 81 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 82 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 83 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 84 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 85 #************************\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 86 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.********************************\.\.\.\.\.\.\.\.\. > 87 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.************* > 88 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 89 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 90 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 91 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 92 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 93 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 94 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 95 #************************\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 96 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.********************************\.\.\.\.\.\.\.\.\. > 97 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.************* > 98 #.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. > 99 #\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\ > 100 ################################################################################
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]
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/fun1.map version [2f7f87a4d02c6448]
Added maps/trampoline1.map version [5af697c0003d5516]
Added maps/trampoline2.map version [288f9d055c2777fa]
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
Deleted output.d version [1b458d7cd25e92dc]
1 import util; < 2 import game; < 3 import core.stdc.signal; < 4 import std.c.stdlib; < 5 < 6 abstract class Output < 7 { < 8 void command(char c); < 9 void flush(); < 10 } < 11 < 12 class NilOutput : Output < 13 { < 14 override void command(char c) {} < 15 override void flush() {} < 16 } < 17 < 18 class StdOutput : Output < 19 { < 20 override void command(char c) < 21 { < 22 write(c); < 23 stdout.flush(); < 24 } < 25 override void flush() {} < 26 } < 27 < 28 // TODO: clean it up. < 29 __gshared Output g_output; < 30 < 31 class GuardedOutput : StdOutput < 32 { < 33 // Handle SIGINT: force abort and exit. < 34 static this() < 35 { < 36 signal(SIGINT, &sigint); < 37 } < 38 < 39 extern(C) static void sigint(int) < 40 { < 41 if(g_output !is null) < 42 g_output.flush(); < 43 else { < 44 write("A"); < 45 stdout.flush(); < 46 } < 47 exit(0); < 48 } < 49 < 50 Game g; < 51 this(Game ini) { this.g = ini.clone(); ideal_log ~= g.score_if_abort_now < 52 < 53 string log; < 54 long[] score_log; < 55 long[] ideal_log; < 56 < 57 override void command(char c) < 58 { < 59 g.command(c); < 60 log ~= c; < 61 score_log ~= g.score; < 62 ideal_log ~= g.score_if_abort_now; < 63 } < 64 override void flush() < 65 { < 66 Tuple!(long, int, int) cand; < 67 cand[0] = long.min; < 68 foreach(int i, long s; score_log) < 69 if(cand[0] < s) < 70 cand = tuple(s,i,0); < 71 foreach(int i, long s; ideal_log) < 72 if(cand[0] < s) < 73 cand = tuple(s,i,1); < 74 if(cand[2]==0) < 75 writeln(log[0..cand[1]+1]); < 76 else < 77 writeln(log[0..cand[1]]~"A"); < 78 stdout.flush(); < 79 } < 80 } <
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]
Added src/cui_auto_main.d version [b38d60ea39d11e6e]
> 1 import util; > 2 import game; > 3 import output; > 4 import driver; > 5 import solver; > 6 > 7 class CUI(Solver) : GameObserver > 8 { > 9 this(in Game g) { solver = new Solver(g); } > 10 Solver solver; > 11 bool fin; > 12 override void on_game_changed(char c, in Game g, bool finished) > 13 { > 14 fin = finished; > 15 } > 16 } > 17 > 18 void main(string[] args) > 19 { > 20 Driver d = new Driver(stdin); > 21 d.addObserver!(GuardedOutput)(); > 22 auto c = d.addObserver!(CUI!MainSolver)(); > 23 while(!c.fin) > 24 d.command(c.solver.single_step()); > 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 }
Added src/game.d version [fc05481901940844]
> 1 import util; > 2 > 3 //////////////////////////////////////////////////////////////////////////////// > 4 > 5 class Pos > 6 { > 7 public immutable int y, x; > 8 mixin DeriveCreate; > 9 mixin DeriveCompare; > 10 mixin DeriveShow; > 11 Pos clone() const { return cast(Pos) this; } > 12 > 13 @property: > 14 Pos wait() { return this.clone(); } > 15 Pos up() { return new Pos(y+1, x); } > 16 Pos down() { return new Pos(y-1, x); } > 17 Pos left() { return new Pos(y, x-1); } > 18 Pos right() { return new Pos(y, x+1); } > 19 alias wait W,w; > 20 alias up U,u; > 21 alias down D,d; > 22 alias left L,l; > 23 alias right R,r; > 24 } > 25 > 26 unittest > 27 { > 28 assert( (new Pos(2,1)).U == new Pos(3,1) ); > 29 assert( (new Pos(0,1)).D == new Pos(-1,1) ); > 30 assert( (new Pos(2,1)).L == new Pos(2,0) ); > 31 assert( (new Pos(2,1)).R == new Pos(2,2) ); > 32 int[Pos] aa; > 33 aa[new Pos(1,2)] = 1; > 34 aa[new Pos(1,2)] = 2; > 35 aa[new Pos(2,1)] = 3; > 36 assert( aa.length==2 ); > 37 assert( aa[new Pos(1,2)]==2 ); > 38 } > 39 > 40 //////////////////////////////////////////////////////////////////////////////// > 41 > 42 class Water > 43 { > 44 public immutable int base, pace; > 45 mixin DeriveCreate; > 46 mixin DeriveCompare; > 47 mixin DeriveShow; > 48 Water clone() const { return cast(Water)this; } > 49 > 50 static load(string[string] params) > 51 { > 52 return new Water(params.get("Water", "0").to!int(), > 53 params.get("Flooding", "0").to!int()); > 54 } > 55 > 56 int level(int number_of_update) const > 57 { > 58 return pace ? base+(number_of_update/pace) : base; > 59 } > 60 > 61 int until_rise(int number_of_update) const > 62 { > 63 return pace ? pace-number_of_update%pace : int.max; > 64 } > 65 } > 66 > 67 unittest > 68 { > 69 Water w = new Water(1, 3); > 70 assert( 1 == w.level(0) ); > 71 assert( 1 == w.level(1) ); > 72 assert( 1 == w.level(2) ); > 73 assert( 2 == w.level(3) ); > 74 assert( 2 == w.level(4) ); > 75 assert( 2 == w.level(5) ); > 76 assert( 3 == w.level(6) ); > 77 > 78 w = new Water(1, 0); > 79 assert( 1 == w.level(0) ); > 80 assert( 1 == w.level(1) ); > 81 assert( 1 == w.level(2) ); > 82 assert( 1 == w.level(3) ); > 83 assert( 1 == w.level(4) ); > 84 assert( 1 == w.level(5) ); > 85 } > 86 > 87 //////////////////////////////////////////////////////////////////////////////// > 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 > 115 class Map > 116 { > 117 mixin DeriveShow; > 118 > 119 static Map load(string[] raw_data, string[string] params, char[char] tra > 120 { > 121 // TODO: choose optimal representation. > 122 return new Map(raw_data, params, trampo); > 123 } > 124 > 125 char[][] data; > 126 Pos robot; > 127 Pos lift; > 128 int waterproof; > 129 Pos[char] tr_target; > 130 Pos[][char] tr_source; > 131 const(Hige) hige; > 132 int razor; > 133 > 134 Map clone() const { return new Map(this); } > 135 this(in Map m) { > 136 foreach(s; m.data) > 137 this.data ~= s.dup; > 138 this.robot = m.robot.clone(); > 139 this.lift = m.lift.clone(); > 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; > 145 } > 146 > 147 this(string[] raw_data, string[string] params, char[char] trampo) > 148 { > 149 int width = 0; > 150 foreach(r; raw_data) > 151 width = max(width, r.length); > 152 foreach(r; raw_data) { > 153 this.data ~= r.dup; > 154 this.data[$-1].length = width; > 155 this.data[$-1][r.length..$] = ' '; > 156 } > 157 > 158 for(int y=1; y<=H; ++y) > 159 for(int x=1; x<=W; ++x) { > 160 if(this[y,x] == 'R') > 161 this.robot = new Pos(y,x); > 162 if(this[y,x] == 'L' || this[y,x] == 'O') > 163 this.lift = new Pos(y,x); > 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 } > 173 > 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(); > 183 } > 184 > 185 const @property { > 186 int H() { return data.length; } > 187 int W() { return data[0].length; } > 188 } > 189 > 190 const { > 191 char opIndex(int y, int x) > 192 { > 193 // Adjust coordinate to the spec. bottom-left is (1,1). > 194 --y, --x; > 195 if(y<0||H<=y||x<0||W<=x) > 196 return '#'; > 197 return data[H-1-y][x]; > 198 } > 199 > 200 char opIndex(in Pos p) > 201 { > 202 return this[p.y, p.x]; > 203 } > 204 } > 205 > 206 void opIndexAssign(char c, int y, int x) > 207 { > 208 // Adjust coordinate to the spec. bottom-left is (1,1). > 209 --y, --x; > 210 if(y<0||H<=y||x<0||W<=x) > 211 return; > 212 data[H-1-y][x] = c; > 213 } > 214 > 215 void opIndexAssign(char c, in Pos p) > 216 { > 217 this[p.y, p.x] = c; > 218 } > 219 > 220 Pos[] objects(char c) const { > 221 Pos[] ans; > 222 for(int y=1; y<=H; ++y) > 223 for(int x=1; x<=W; ++x) > 224 if(this[y,x] == c) > 225 ans ~= new Pos(y,x); > 226 return ans; > 227 } > 228 > 229 Pos[] razors() const { return objects('!'); } > 230 Pos[] lambdas() const { return objects('\\'); } > 231 > 232 bool cleared() const > 233 { > 234 for(int y=1; y<=H; ++y) > 235 for(int x=1; x<=W; ++x) > 236 if(this[y,x] == 'L' || this[y,x] == 'O') > 237 return false; > 238 return true; > 239 } > 240 > 241 Tuple!(int,bool) command(char c, int turn) > 242 { > 243 assert( this[robot] == 'R' ); > 244 if(c=='R') return move( 0, +1, turn); > 245 if(c=='L') return move( 0, -1, turn); > 246 if(c=='U') return move(+1, 0, turn); > 247 if(c=='D') return move(-1, 0, turn); > 248 if(c=='W') return move( 0, 0, turn); > 249 if(c=='S') return use_razor(turn); > 250 assert(false); > 251 } > 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 > 267 Tuple!(int, bool) move(int dy, int dx, int turn) > 268 { > 269 int y = robot.y; > 270 int x = robot.x; > 271 int lambda = 0; > 272 if( '\\' == this[y+dy,x+dx] ) > 273 lambda++; > 274 if( '!' == this[y+dy,x+dx] ) > 275 razor++; > 276 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { > 277 this[y,x]=' '; > 278 this[y+dy,x+dx]='R'; > 279 robot = new Pos(y+dy,x+dx); > 280 } else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx > 281 this[y,x]=' '; > 282 this[y+dy,x+dx]='R'; > 283 this[y+dy*2,x+dx*2]='*'; > 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; > 292 } > 293 bool dead = update(turn); > 294 return tuple(lambda,dead); > 295 } > 296 > 297 bool update(int turn) > 298 { > 299 bool dead = false; > 300 > 301 char[][] next; > 302 foreach(y,s; data) > 303 next ~= s.dup; > 304 > 305 ref char access(Pos p) { return next[H-p.y][p.x-1]; } > 306 > 307 bool lambda = false; > 308 for(int y=1; y<=H; ++y) > 309 for(int x=1; x<=W; ++x) > 310 lambda |= (this[y,x] == '\\'); > 311 > 312 for(int y=1; y<=H; ++y) > 313 for(int x=1; x<=W; ++x) { > 314 Pos p = new Pos(y,x); > 315 if(this[p]=='*') { > 316 if(this[p.D]==' ') { > 317 access(p) =' '; > 318 access(p.D)='*'; > 319 if(robot == p.D.D) > 320 dead=true; > 321 } > 322 else if((this[p.D]=='*' || this[p.D]=='\\') && t > 323 access(p)=' '; > 324 access(p.R.D)='*'; > 325 if(robot == p.R.D.D) > 326 dead=true; > 327 } > 328 else if(this[p.D]=='*' && this[p.L]==' ' && this > 329 access(p)=' '; > 330 access(p.L.D)='*'; > 331 if(robot == p.L.D.D) > 332 dead=true; > 333 } > 334 } > 335 else if(this[p]=='L') { > 336 if(!lambda) > 337 access(p) = 'O'; > 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 } > 346 } > 347 data = next; > 348 return dead; > 349 } > 350 } > 351 > 352 //////////////////////////////////////////////////////////////////////////////// > 353 > 354 class Game > 355 { > 356 public: > 357 this(File input) > 358 { > 359 // Read map data > 360 string[] map_data_lines; > 361 for(string line; !(line=input.readln().chomp()).empty; ) > 362 map_data_lines ~= line; > 363 > 364 // H*W > 365 H_ = map_data_lines.length; > 366 W_ = 0; > 367 foreach(mdl; map_data_lines) > 368 W_ = max(W_, mdl.length); > 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 } > 378 > 379 // Detect objects > 380 for(int y=1; y<=H_; ++y) > 381 for(int x=1; x<raw_data_[y].length; ++x) > 382 { > 383 char c = raw_data_[y][x]; > 384 switch(c) > 385 { > 386 case '#': > 387 case '.': > 388 case ' ': > 389 break; > 390 case 'L': > 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; > 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); > 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 } > 447 > 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) > 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; > 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 }
Added src/gui.d version [e84cacd6262f93a7]
> 1 import dfl.all; > 2 import util; > 3 import game; > 4 import driver; > 5 > 6 class GUI(Solver) : Form, GameObserver > 7 { > 8 this(in Game g) > 9 { > 10 this.solver = new Solver(g); > 11 setup_size(g.W, g.H); > 12 setup_resources(g); > 13 draw(g); > 14 } > 15 > 16 private void delegate(char c) fn; > 17 void set_fn(F)(F f) { this.fn = f; } > 18 > 19 void run(bool automate = false) > 20 { > 21 if(automate) { > 22 Timer t = new Timer; > 23 t.interval = 50; > 24 t.tick ~= (Timer sender, EventArgs ea){ > 25 fn(solver.single_step()); > 26 }; > 27 t.start(); > 28 this.closing ~= (Form f,CancelEventArgs c){t.stop();}; > 29 } else { > 30 setup_keyhandling(); > 31 } > 32 Application.run(this); > 33 } > 34 > 35 override void on_game_changed(char c, in Game g, bool finished) > 36 { > 37 draw(g); > 38 } > 39 > 40 private: > 41 int cell; > 42 > 43 void setup_size(int W, int H) > 44 { > 45 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; > 46 this.maximizeBox = false; > 47 this.minimizeBox = false; > 48 this.cell = min(1024/W, 640/H); > 49 this.clientSize = Size(W*cell, H*cell); > 50 } > 51 > 52 Font font; > 53 Color[char] colors; > 54 string[char] render; > 55 Graphics graphicContext; > 56 > 57 void setup_resources(in Game g) > 58 { > 59 this.graphicContext = new MemoryGraphics(this.clientSize.width, > 60 this.setStyle(ControlStyles.OPAQUE, true); > 61 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); > 62 this.backColor = Color(255,255,255); > 63 this.colors['#'] = > 64 this.colors['.'] = Color(255,191,127); > 65 this.colors['*'] = Color(255,127,127); > 66 this.colors['R'] = Color(128,128,0); > 67 this.colors['d'] = Color(255,0,0); > 68 this.colors['\\'] = > 69 this.colors['L'] = > 70 this.colors['O'] = Color(127,255,127); > 71 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); > 76 this.render['#'] = "■"; > 77 this.render['*'] = "✹"; > 78 this.render['.'] = "♒"; > 79 this.render['\\'] = "λ"; > 80 this.render['R'] = "☃"; > 81 this.render['d'] = "☠"; > 82 this.render['L'] = "☒"; > 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 > 88 this.paint ~= (Control c, PaintEventArgs ev) { > 89 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientS > 90 }; > 91 } > 92 > 93 void draw(in Game g) > 94 { > 95 int scrW = this.clientSize.width; > 96 int scrH = this.clientSize.height; > 97 > 98 // Fill bg. > 99 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH) > 100 > 101 // Fill water. > 102 int w = g.water_level(); > 103 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell > 104 > 105 // Paint map. > 106 for(int y=1; y<=g.H; ++y) > 107 for(int x=1; x<=g.W; ++x) { > 108 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); > 109 char c = g[y,x]; > 110 if( c != ' ' ) { > 111 if( c == 'R' && g.dead ) > 112 c = 'd'; > 113 graphicContext.drawText(this.render[c], font, th > 114 } > 115 } > 116 > 117 // Update textual info. > 118 this.text = .text( > 119 "Score: ", g.score, > 120 " Air: ", g.hp, > 121 " Tide: ", g.water_until_rise, > 122 " Wadler: ", g.hige_until_rise, > 123 " Razor: ", g.num_razor); > 124 invalidate(); > 125 } > 126 > 127 private: > 128 void setup_keyhandling() > 129 { > 130 noMessageFilter(); > 131 this.keyDown ~= &my_keydown; > 132 } > 133 > 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) > 141 { > 142 switch(ev.keyCode) > 143 { > 144 case Keys.DOWN: do_manual_command('D'); break; > 145 case Keys.UP: do_manual_command('U'); break; > 146 case Keys.LEFT: do_manual_command('L'); break; > 147 case Keys.RIGHT: do_manual_command('R'); break; > 148 case Keys.W: do_manual_command('W'); break; > 149 case Keys.S: do_manual_command('S'); break; > 150 case Keys.A: do_manual_command('A'); break; > 151 case Keys.G: fn(solver.single_step()); break; > 152 default: break; > 153 } > 154 } > 155 > 156 Solver solver; > 157 }
Added src/gui_main.d version [05082d0f328d756c]
> 1 import gui; > 2 import output; > 3 import driver; > 4 import solver; > 5 import std.stdio; > 6 pragma(lib, "dfl.lib"); > 7 > 8 void main(string[] args) > 9 { > 10 Driver d = new Driver(stdin); > 11 d.addObserver!(GuardedOutput)(); > 12 auto g = d.addObserver!(GUI!MainSolver)(); > 13 g.set_fn(&d.command); > 14 g.run(); > 15 }
Added src/output.d version [e2d0d7db868c3a44]
> 1 import util; > 2 import game; > 3 import driver; > 4 import core.stdc.signal; > 5 > 6 class NilOutput : GameObserver > 7 { > 8 this(in Game g) {} > 9 override void on_game_changed(char c, in Game g, bool finished) {} > 10 } > 11 > 12 class StdOutput : GameObserver > 13 { > 14 this(in Game g) {} > 15 override void on_game_changed(char c, in Game g, bool finished) > 16 { > 17 stdout.write(c); > 18 stdout.flush(); > 19 } > 20 } > 21 > 22 class GuardedOutput : GameObserver > 23 { > 24 this(in Game g) > 25 { > 26 setup_sigint_handling(); > 27 score_log ~= g.score; > 28 flushed = false; > 29 } > 30 > 31 override void on_game_changed(char c, in Game g, bool finished) > 32 { > 33 if(flushed) > 34 return; > 35 > 36 log ~= c; > 37 score_log ~= g.score; > 38 if(finished || log.length+1==g.W*g.H) > 39 flush(); > 40 } > 41 > 42 private: > 43 string log; > 44 long[] score_log; > 45 bool flushed; > 46 > 47 void flush() > 48 { > 49 if(flushed) > 50 return; > 51 > 52 Tuple!(long, int) cand; > 53 cand[0] = long.min; > 54 > 55 for(int i=0; i<score_log.length; ++i) > 56 if(cand[0] < score_log[i]) > 57 cand = tuple(score_log[i],i); > 58 > 59 std.c.stdio.printf("%.*sA\n", cand[1], log.ptr); > 60 std.c.stdio.fflush(std.c.stdio.stdout); > 61 flushed = true; > 62 } > 63 > 64 private: > 65 static __gshared GuardedOutput g_output; > 66 > 67 void setup_sigint_handling() > 68 { > 69 assert(g_output is null); > 70 g_output = this; > 71 extern(C) static void catch_sigint(int) { g_output.flush(); appl > 72 core.stdc.signal.signal(SIGINT, &catch_sigint); > 73 } > 74 }
Added src/solver.d version [22c356ff1975e92f]
> 1 import util; > 2 import game; > 3 > 4 class Solver_0 > 5 { > 6 this(in Game g) {} > 7 char single_step() { return 'W'; } > 8 void force(char c) {} > 9 } > 10 > 11 class Solver_1 > 12 { > 13 int wait_count = 0; > 14 int choke_count = 0; > 15 > 16 Game g; > 17 this(in Game g) > 18 { > 19 this.g = g.clone(); > 20 forbidden_cell = new bool[][](g.H+2, g.W+2); > 21 } > 22 > 23 char single_step() > 24 { > 25 Tuple!(string,int) de = death_move(g); > 26 char c = act(g, de[0], de[1]); > 27 force(c); > 28 return c; > 29 } > 30 > 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) > 38 { > 39 string death; > 40 int choice = 0; > 41 foreach(char c; "UDLRW") { > 42 Game gg = g.clone(); > 43 gg.command(c); > 44 if( !gg.cleared && gg.dead ) > 45 death ~= c; > 46 else if( gg.robot != g.robot ) > 47 choice++; > 48 else if( c != 'W' ) // meaningless move > 49 death ~= c; > 50 } > 51 return tuple(death, choice); > 52 } > 53 > 54 Tuple!(Pos, int)[] log; > 55 bool[][] forbidden_cell; > 56 > 57 char act(const(Game) g, string death, int breath) > 58 { > 59 const Pos ro = g.robot; > 60 const Pos li = g.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(); > 69 > 70 Tuple!(char,int)[] cand; > 71 char c = 'W'; > 72 if( la.empty ) { > 73 cand = search(g, ro, [li], death); > 74 } else { > 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 } > 103 } > 104 > 105 // 'dig' mode > 106 if(cand.empty) { > 107 const(Pos)[] tgt; > 108 for(int y=1; y<=g.H; ++y) > 109 for(int x=1; x<=g.W; ++x) > 110 if(g[y,x]=='.') > 111 if(g[y+1,x]=='*'||g[y+1,x-1]=='*'||g[y+1 > 112 ||g[y,x+1]=='*'||g[y,x-1]=='*') > 113 tgt ~= new Pos(y,x); > 114 cand ~= search(g, ro, tgt, death, true); > 115 } > 116 > 117 if(cand.empty) { > 118 choke_count++; > 119 cand ~= tuple('W',int.max); > 120 } > 121 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ > 122 if(c1[1] != c2[1]) > 123 return c1[1] < c2[1]; > 124 return c1[0] < c2[0]; > 125 })(cand); > 126 c = cand[0][0]; > 127 > 128 if(death.count(c) || wait_count>=2) { > 129 foreach(char live; "UDLRW") > 130 if(death.count(live)==0) { > 131 c=live; > 132 break; > 133 } > 134 } > 135 > 136 if(c == 'W') > 137 wait_count++; > 138 else > 139 wait_count = 0; > 140 if(choke_count >= g.H) > 141 c = 'A'; > 142 > 143 bool[char] choice; > 144 foreach(t; cand) > 145 choice[t[0]] = true; > 146 log ~= tuple(ro.clone(), cast(int)choice.length); > 147 if(log.length > 5) > 148 log = log[$-5..$]; > 149 int cnt = 0; > 150 foreach(l; log) > 151 if(l[0] == log[$-1][0]) > 152 ++cnt; > 153 if( cnt >= 3 && breath==1 ) { > 154 forbidden_cell[ro.y][ro.x] = true; > 155 } > 156 > 157 return c; > 158 } > 159 > 160 Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death > 161 { > 162 bool danger(int y, int x) > 163 { > 164 if(g[y,x] == ' ' || g[y,x] == 'R') > 165 return false; > 166 if(g[y+1,x] == '*') > 167 return true; > 168 if(g[y+1,x-1]=='*' && (g[y,x-1]=='\\'||g[y,x-1]=='*') && > 169 return true; > 170 if(g[y+1,x+1]=='*' && (g[y,x+1]=='*') && (g[y+1,x]==' '| > 171 return true; > 172 if(g[y,x-1]=='*' && (g[y-1,x-1]=='\\'||g[y-1,x-1]=='*') > 173 return true; > 174 if(g[y,x+1]=='*' && (g[y-1,x+1]=='*') && (g[y-1,x]==' '| > 175 return true; > 176 return false; > 177 } > 178 > 179 // avoid directly below '*' > 180 Tuple!(char,int)[] tryA() { > 181 const(Pos)[] q; > 182 foreach(p; gs) > 183 if(!danger(p.y,p.x)) > 184 q ~= p; > 185 bool[][] v = new bool[][](g.H+2, g.W+2); > 186 foreach(p; q) v[p.y][p.x]=true; > 187 for(int step=1; q.length; ++step) { > 188 Pos[] q2; > 189 foreach(p; q) { > 190 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; > 191 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; > 192 for(int i=0; i<yyy.length; ++i) { > 193 int y = yyy[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 } > 202 if(v[y][x]) continue; > 203 if(y==s.y && x==s.x && i<4) { > 204 char c = "UDRL"[i]; > 205 if( death.count(c) == 0 > 206 return [tuple(c, > 207 } else if(forbidden_cell[y][x]){ > 208 } else if(g[y,x]==' '||g[y,x]==' > 209 if(danger(y,x)) > 210 continue; > 211 q2 ~= new Pos(y,x); > 212 v[y][x]=true; > 213 } > 214 } > 215 } > 216 q = q2; > 217 } > 218 return []; > 219 } > 220 > 221 // any empty space is my ground > 222 Tuple!(char,int)[] tryB() { > 223 const(Pos)[] q; > 224 foreach(p; gs) q ~= p; > 225 bool[][] v = new bool[][](g.H+2, g.W+2); > 226 foreach(p; q) v[p.y][p.x]=true; > 227 for(int step=10; q.length; ++step) { > 228 Pos[] q2; > 229 foreach(p; q) { > 230 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; > 231 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; > 232 for(int i=0; i<yyy.length; ++i) { > 233 int y = yyy[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 } > 242 if(v[y][x]) continue; > 243 if(y==s.y && x==s.x && i<4) { > 244 char c = "UDRL"[i]; > 245 if( death.count(c) == 0 > 246 return [tuple(c, > 247 } else if(forbidden_cell[y][x]){ > 248 } else if(g[y,x]==' '||g[y,x]==' > 249 q2 ~= new Pos(y,x); > 250 v[y][x]=true; > 251 } > 252 } > 253 } > 254 q = q2; > 255 } > 256 return []; > 257 } > 258 > 259 // push rocks! > 260 Tuple!(char,int)[] tryC() { > 261 const(Pos)[] q; > 262 foreach(p; gs) q ~= p; > 263 bool[][] v = new bool[][](g.H+2, g.W+2); > 264 foreach(p; q) v[p.y][p.x]=true; > 265 for(int step=20; q.length; ++step) { > 266 Pos[] q2; > 267 foreach(p; q) { > 268 int[] yyy=[p.y-1,p.y+1,p.y,p.y]; > 269 int[] xxx=[p.x,p.x,p.x-1,p.x+1]; > 270 for(int i=0; i<yyy.length; ++i) { > 271 int y = yyy[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 } > 285 if(v[y][x]) continue; > 286 if(y==s.y && x==s.x && i<4) { > 287 char c = "UDRL"[i]; > 288 if( death.count(c) == 0 > 289 return [tuple(c, > 290 } else if(forbidden_cell[y][x]){ > 291 } else if(g[y,x]==' '||g[y,x]==' > 292 q2 ~= new Pos(y,x); > 293 v[y][x]=true; > 294 } > 295 } > 296 } > 297 q = q2; > 298 } > 299 return []; > 300 } > 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..$]; > 387 } > 388 } > 389 > 390 alias Solver_2!(Solver_1) MainSolver; > 391 //alias Solver_1 MainSolver;
Added src/util.d version [b76be1f6ad977d56]
> 1 public import std.algorithm; > 2 public import std.array; > 3 public import std.conv; > 4 public import std.range; > 5 public import std.stdio; > 6 public import std.string; > 7 public import std.typecons; > 8 public import std.math; > 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 } > 32 > 33 void application_exit() > 34 { > 35 std.c.stdlib.exit(0); > 36 } > 37 > 38 template DeriveCreate() > 39 { > 40 this(TS...)(TS params) > 41 { > 42 this.tupleof = params; > 43 } > 44 } > 45 > 46 template DeriveCompare() > 47 { > 48 override: > 49 bool opEquals(Object rhs) const > 50 { > 51 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl > 52 } > 53 > 54 int opCmp(Object rhs) const > 55 { > 56 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t > 57 } > 58 > 59 hash_t toHash() const > 60 { > 61 hash_t v = 0; > 62 foreach(mem; this.tupleof) { > 63 v *= 11; > 64 static if(__traits(compiles, v^=mem)) > 65 v ^= mem; > 66 else > 67 v ^= typeid(mem).getHash(&mem); > 68 } > 69 return v; > 70 } > 71 } > 72 > 73 template DeriveShow() > 74 { > 75 override: > 76 string toString() const > 77 { > 78 string str = text(typeof(this).stringof, "("); > 79 foreach(i,mem; this.tupleof) { > 80 if(i) str ~= ", "; > 81 str = text(str, this.tupleof[i].stringof[5..$], ":", me > 82 } > 83 return str ~ ")"; > 84 } > 85 }
Added submission/PACKAGES version [da39a3ee5e6b4b0d]
Added submission/README version [9ce063855f41ff05]
> 1 Team: > 2 Dark Integers > 3 Member: > 4 Kazuhiro Inaba (www.kmonos.net / kiki@kmonos.net) > 5 Language: > 6 D Programming Language (dlang.org) > 7 > 8 This submission for lightning division is not particulary interseting. > 9 > 10 - Robot rushes to the nearest lambda (or the open lift) by breadth first search. > 11 - Not at all taking into account the dynamics (falling rocks, floods). > 12 - To mitigate the staticness, the robot avoids the '.' below '*' as much as > 13 possible, so that it won't fall new rocks. > 14 > 15 - Output routine is 'guarded' by a 'sudden death' or 'stray sheep' detector. > 16 That is, if the above search routine was hit by a rock or a water, or it > 17 couldn't find a way to the next target and walked in vain, the output guards > 18 trims the command history and inserts the 'A'bort at the optimal timing. > 19 This is also used for SIGINT handling. > 20 > 21 - gui.d is a windows GUI for the game, using DFL (http://github.com/Rayerd/dfl) > 22 it is not compiled into the submitted routine. This is just a helper. > 23 > 24 Stay tuned for the full submission, judges!
Added submission/install version [be776bcfbc13fcbf]
Added submission/lifter version [5103f55f5323fb3f]
cannot compute difference between binary files
Deleted test.d version [d9955daaabe58d54]
1 import std.algorithm; < 2 import std.array; < 3 import std.conv; < 4 import std.stdio; < 5 import std.string; < 6 import std.typecons; < 7 import core.stdc.signal; < 8 import core.stdc.stdlib; < 9 import dfl.all; < 10 < 11 class Map < 12 { < 13 private char[][] data; < 14 bool dead = false; < 15 bool cleared = false; < 16 int water = 0; < 17 int flooding = 0; < 18 int water_proof = 10; < 19 int underwater = 0; < 20 int flooding_counter = 0; < 21 < 22 this(File input) < 23 { < 24 string line; < 25 while( (line=input.readln().chomp()).length ) < 26 data ~= line.dup; < 27 < 28 int width = 0; < 29 foreach(s; data) < 30 width = max(width, s.length); < 31 < 32 // space padding and sentinels < 33 foreach(ref s; data) { < 34 int p = s.length; < 35 s.length = width; < 36 s[p..$] = ' '; < 37 s = '#' ~ s ~ '#'; < 38 } < 39 < 40 // vertical sentinel < 41 char[] sen = new char[width+2]; < 42 sen[] = '#'; < 43 data = sen.dup ~ data ~ sen; < 44 < 45 // flooding < 46 water = H-1; < 47 while( (line=input.readln()).length ) { < 48 string[] ss = line.split(); < 49 if(ss.length==2 && ss[0]=="Water") < 50 water = H-1 - ss[1].to!int(); < 51 else if(ss.length==2 && ss[0]=="Flooding") < 52 flooding = ss[1].to!int(); < 53 else if(ss.length==2 && ss[0]=="Waterproof") < 54 water_proof = ss[1].to!int(); < 55 } < 56 } < 57 < 58 @property const < 59 { < 60 int W() { return data[0].length; } < 61 int H() { return data.length; } < 62 string toString() { < 63 string result; < 64 foreach(i,s; data) { < 65 if(i) result ~= '\n'; < 66 result ~= s.idup; < 67 } < 68 return result; < 69 } < 70 } < 71 < 72 int command_R() { if(dead)return 0; write("R"); return move(0, +1); } < 73 int command_L() { if(dead)return 0; write("L"); return move(0, -1); } < 74 int command_U() { if(dead)return 0; write("U"); return move(-1, 0); } < 75 int command_D() { if(dead)return 0; write("D"); return move(+1, 0); } < 76 int wait() { if(dead)return 0; update(); write("W"); return -1; } < 77 int abort() { if(dead)return 0; cleared=true; write("A"); return gained* < 78 < 79 int move(int dy, int dx) { < 80 foreach(y,s; data) < 81 foreach(x,c; s) < 82 if(c == 'R') < 83 return move(dy, dx, y, x); < 84 assert(false); < 85 } < 86 < 87 int gained = 0; // TODO: atode naosu < 88 int move(int dy, int dx, int y, int x) { < 89 if(dead) < 90 return 0; < 91 int score = 0; < 92 if(data[y+dy][x+dx]=='\\') { < 93 score += 25; < 94 ++gained; < 95 } < 96 if(data[y+dy][x+dx]=='O') { < 97 score += gained*50; < 98 cleared = true; < 99 } < 100 < 101 if(data[y+dy][x+dx]==' ' || data[y+dy][x+dx]=='.' < 102 || data[y+dy][x+dx]=='\\' || data[y+dy][x+dx]=='O') { < 103 data[y][x]=' '; < 104 data[y+dy][x+dx]='R'; < 105 } else if(dy==0 && data[y+dy][x+dx]=='*' && data[y+2*dy][x+2*dx] < 106 data[y][x]=' '; < 107 data[y+dy][x+dx]='R'; < 108 data[y+2*dy][x+2*dx]='*'; < 109 } < 110 update(); < 111 return score-1; < 112 } < 113 < 114 void update() { < 115 char[][] next; < 116 foreach(y,s; data) < 117 next ~= s.dup; < 118 < 119 bool lambda = false; < 120 for(int y=1; y+1<H; ++y) < 121 for(int x=1; x+1<W; ++x) < 122 lambda |= (data[y][x] == '\\'); < 123 < 124 for(int y=H-2; y>=1; --y) < 125 for(int x=1; x+1<W; ++x) { < 126 if(data[y][x]=='*') { < 127 if(data[y+1][x]==' ') { < 128 next[y][x]=' '; < 129 next[y+1][x]='*'; < 130 if(next[y+2][x]=='R') < 131 dead=true; < 132 } < 133 else if(data[y+1][x]=='*' && data[y][x+1]==' ' & < 134 next[y][x]=' '; < 135 next[y+1][x+1]='*'; < 136 if(next[y+2][x+1]=='R') < 137 dead=true; < 138 } < 139 else if(data[y+1][x]=='*' && data[y][x-1]==' ' & < 140 next[y][x]=' '; < 141 next[y+1][x-1]='*'; < 142 if(next[y+2][x-1]=='R') < 143 dead=true; < 144 } < 145 else if(data[y+1][x]=='\\' && data[y][x+1]==' ' < 146 next[y][x]=' '; < 147 next[y+1][x+1]='*'; < 148 if(next[y+2][x+1]=='R') < 149 dead=true; < 150 } < 151 } < 152 else if(data[y][x]=='L') { < 153 if(!lambda) < 154 next[y][x] = 'O'; < 155 } < 156 } < 157 data = next; < 158 < 159 if(flooding) { < 160 bool wa = false; < 161 for(int y=water; y+1<H; ++y) < 162 for(int x=1; x+1<W; ++x) < 163 if(data[y][x]=='R') { < 164 wa = true; < 165 underwater++; < 166 if(underwater > water_proof) < 167 dead = true; < 168 } < 169 flooding_counter ++; < 170 if(flooding_counter == flooding) { < 171 flooding_counter = 0; < 172 water --; < 173 } < 174 } < 175 } < 176 < 177 int clever() < 178 { < 179 if(dead) < 180 return 0; < 181 int sy,sx; < 182 int[] ly,lx; < 183 int oy,ox; < 184 for(int y=0; y<H; ++y) < 185 for(int x=0; x<W; ++x) < 186 if(data[y][x]=='R') < 187 sy=y, sx=x; < 188 else if(data[y][x]=='\\') < 189 ly~=y, lx~=x; < 190 else if(data[y][x]=='O') < 191 oy=y, ox=x; < 192 if(ly.length==0) { < 193 auto r = search(sy,sx,oy,ox); < 194 switch(r[0]) { < 195 case 'D': return command_D(); < 196 case 'U': return command_U(); < 197 case 'L': return command_L(); < 198 case 'R': return command_R(); < 199 case 'A': return abort(); < 200 default: return wait(); < 201 } < 202 } else { < 203 Tuple!(char,int)[] cand; < 204 for(int i=0; i<ly.length; ++i) { < 205 auto r = search(sy,sx,ly[i],lx[i]); < 206 cand ~= r; < 207 } < 208 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ < 209 if(c1[1] != c2[1]) < 210 return c1[1] < c2[1]; < 211 return c1[0] < c2[0]; < 212 })(cand); < 213 switch(cand[0][0]) { < 214 case 'D': return command_D(); < 215 case 'U': return command_U(); < 216 case 'L': return command_L(); < 217 case 'R': return command_R(); < 218 case 'A': return abort(); < 219 default: return wait(); < 220 } < 221 } < 222 return wait(); < 223 } < 224 Tuple!(char,int) search(int sy, int sx, int oy, int ox) < 225 { < 226 alias Tuple!(int,"y",int,"x") Pt; < 227 Pt[] q = [Pt(oy,ox)]; < 228 bool[][] v = new bool[][](H,W); < 229 for(int step=1; q.length; ++step) { < 230 Pt[] q2; < 231 foreach(p; q) { < 232 int[] dy=[-1,+1,0,0]; < 233 int[] dx=[0,0,-1,+1]; < 234 for(int i=0; i<4; ++i) { < 235 int y = p.y+dy[i]; < 236 int x = p.x+dx[i]; < 237 if(v[y][x]) continue; < 238 if(y==sy && x==sx) { < 239 if(i==0) return tuple('D',step); < 240 if(i==1) return tuple('U',step); < 241 if(i==2) return tuple('R',step); < 242 if(i==3) return tuple('L',step); < 243 } else if(data[y][x]==' '||data[y][x]==' < 244 q2 ~= Pt(y,x); < 245 v[y][x]=true; < 246 } else if(data[y][x]=='.' && data[y-1][x < 247 q2 ~= Pt(y,x); < 248 v[y][x]=true; < 249 } < 250 } < 251 } < 252 q = q2; < 253 } < 254 q = [Pt(oy,ox)]; < 255 v = new bool[][](H,W); < 256 for(int step=1<<10; q.length; ++step) { < 257 Pt[] q2; < 258 foreach(p; q) { < 259 < 260 int[] dy=[-1,+1,0,0]; < 261 int[] dx=[0,0,-1,+1]; < 262 for(int i=0; i<4; ++i) { < 263 int y = p.y+dy[i]; < 264 int x = p.x+dx[i]; < 265 if(v[y][x]) continue; < 266 if(y==sy && x==sx) { < 267 if(i==0) return tuple('D',step); < 268 if(i==1) return tuple('U',step); < 269 if(i==2) return tuple('R',step); < 270 if(i==3) return tuple('L',step); < 271 } else if(data[y][x]==' '||data[y][x]==' < 272 q2 ~= Pt(y,x); < 273 v[y][x]=true; < 274 } else if(data[y][x]=='.'/* && data[y-1] < 275 q2 ~= Pt(y,x); < 276 v[y][x]=true; < 277 } < 278 } < 279 } < 280 q = q2; < 281 } < 282 return tuple('A',int.max); < 283 } < 284 } < 285 < 286 class MyForm : Form < 287 { < 288 Map m; < 289 int score; < 290 < 291 this(Map m) < 292 { < 293 noMessageFilter(); < 294 this.m = m; < 295 this.text = .text("Score: ", score, " air[",m.water_proof-m.und < 296 this.keyDown ~= &myKey; < 297 this.score = 0; < 298 } < 299 override void onResize(EventArgs ev) { < 300 invalidate(); < 301 } < 302 override void onPaint(PaintEventArgs ev) < 303 { < 304 int Z = min(this.clientSize.width/(m.W-2), this.clientSize.heigh < 305 Font font = new Font("MS Gothic", Z-4); < 306 Graphics g = ev.graphics; < 307 g.fillRectangle(Color(0,233,255), Rect(0,Z*(m.water-1),this.clie < 308 for(int y=1; y+1<m.H; ++y) < 309 for(int x=1; x+1<m.W; ++x) { < 310 if(m.data[y][x]=='*') { < 311 g.drawText("岩", font, Color(0,0,0), Rect((x-1)*Z < 312 } < 313 if(m.data[y][x]=='\\') { < 314 g.drawText("λ", font, Color(0,255,0), Rect((x-1) < 315 } < 316 if(m.data[y][x]=='R') { < 317 if(m.dead) < 318 g.drawText("Я", font, Color(255,0,0), Re < 319 else < 320 g.drawText("R", font, Color(128,128,0), < 321 } < 322 if(m.data[y][x]=='L') { < 323 g.drawText("扉", font, Color(255,255,0), Rect((x- < 324 } < 325 if(m.data[y][x]=='O') { < 326 g.drawText("外", font, Color(255,255,0), Rect((x- < 327 } < 328 if(m.data[y][x]=='#') { < 329 g.drawText("#", font, Color(0,0,0), Rect((x-1)*Z < 330 } < 331 if(m.data[y][x]=='.') { < 332 g.drawText("・", font, Color(128,40,0), Rect((x-1 < 333 } < 334 } < 335 } < 336 void myKey(Control c, KeyEventArgs ev) < 337 { < 338 switch(ev.keyCode) < 339 { < 340 case Keys.DOWN: < 341 score += m.command_D(); < 342 stdout.flush(); < 343 break; < 344 case Keys.UP: < 345 score += m.command_U(); < 346 stdout.flush(); < 347 break; < 348 case Keys.LEFT: < 349 score += m.command_L(); < 350 stdout.flush(); < 351 break; < 352 case Keys.RIGHT: < 353 score += m.command_R(); < 354 stdout.flush(); < 355 break; < 356 case Keys.W: < 357 score += m.wait(); < 358 stdout.flush(); < 359 break; < 360 case Keys.A: < 361 score += m.abort(); < 362 stdout.flush(); < 363 break; < 364 case Keys.G: < 365 score += m.clever(); < 366 stdout.flush(); < 367 break; < 368 default: < 369 break; < 370 } < 371 if(m.cleared) { < 372 writeln(); < 373 writeln("Score: ", score); < 374 Application.exit(); < 375 } < 376 this.text = .text("Score: ", score, " air[",m.water_proof-m.und < 377 invalidate(); < 378 } < 379 } < 380 < 381 extern(C) { < 382 void sigint(int) { < 383 write("A"); < 384 stdout.flush(); < 385 exit(0); < 386 } < 387 } < 388 < 389 void main(string[] args) < 390 { < 391 signal(SIGINT, &sigint); < 392 < 393 Form myForm = new MyForm(new Map(File(args[1]))); < 394 Application.run(myForm); < 395 } <
Deleted util.d version [8d98b81c5616ea88]
1 public import std.algorithm; < 2 public import std.array; < 3 public import std.conv; < 4 public import std.range; < 5 public import std.stdio; < 6 public import std.string; < 7 public import std.typecons; < 8 < 9 template DeriveCreate() < 10 { < 11 this(TS...)(TS params) < 12 { < 13 this.tupleof = params; < 14 } < 15 } < 16 < 17 template DeriveCompare() < 18 { < 19 override: < 20 bool opEquals(Object rhs) < 21 { < 22 return tuple(this.tupleof) == tuple((cast(typeof(this))rhs).tupl < 23 } < 24 < 25 int opCmp(Object rhs) < 26 { < 27 return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).t < 28 } < 29 < 30 hash_t toHash() < 31 { < 32 hash_t v = 0; < 33 foreach(mem; this.tupleof) { < 34 v *= 11; < 35 static if(__traits(compiles, v^=mem)) < 36 v ^= mem; < 37 else < 38 v ^= typeid(mem).getHash(&mem); < 39 } < 40 return v; < 41 } < 42 } < 43 < 44 template DeriveShow() < 45 { < 46 override: < 47 string toString() < 48 { < 49 string str = text(typeof(this).stringof, "("); < 50 foreach(i,mem; this.tupleof) { < 51 if(i) str ~= ", "; < 52 str = text(str, this.tupleof[i].stringof[5..$], ":", me < 53 } < 54 return str ~ ")"; < 55 } < 56 } <