Check-in [6293256fec]
Not logged in
Overview
SHA1 Hash:6293256fec3cefab3c48efbd34428ec0b7b24870
Date: 2012-07-14 18:16:47
User: kinaba
Comment:Preparing for submission...
Timelines: family | ancestors | descendants | both | trunk
Diffs: redesign
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

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

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

Deleted solver.d version [2d4705e7ff103283]

1 import util; < 2 import game; < 3 import output; < 4 < 5 int g_wc = 0; < 6 < 7 void act(Game g) < 8 { < 9 Pos ro = g.map.robot; < 10 Pos[] la = g.map.lambdas(); < 11 Pos li = g.map.lift; < 12 < 13 char c = 'W'; < 14 if( la.empty ) { < 15 auto r = search(g, ro, li); < 16 c = r[0]; < 17 } else { < 18 Tuple!(char,int)[] cand; < 19 foreach(lam; la) < 20 cand ~= search(g, ro, lam); < 21 sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){ < 22 if(c1[1] != c2[1]) < 23 return c1[1] < c2[1]; < 24 return c1[0] < c2[0]; < 25 })(cand); < 26 c = cand[0][0]; < 27 } < 28 if(c=='W') { < 29 g_wc++; < 30 if(g_wc > 10) < 31 c = 'A'; < 32 } < 33 else < 34 g_wc = 0; < 35 g.command(c); < 36 } < 37 < 38 Tuple!(char,int) search(Game g, Pos s, Pos o) < 39 { < 40 Pos[] q = [o]; < 41 bool[][] v = new bool[][](g.map.H+2, g.map.W+2); < 42 for(int step=1; q.length; ++step) { < 43 Pos[] q2; < 44 foreach(p; q) { < 45 int[] dy=[-1,+1,0,0]; < 46 int[] dx=[0,0,-1,+1]; < 47 for(int i=0; i<4; ++i) { < 48 int y = p.y+dy[i]; < 49 int x = p.x+dx[i]; < 50 if(v[y][x]) continue; < 51 if(y==s.y && x==s.x) { < 52 if(i==0) return tuple('U',step); < 53 if(i==1) return tuple('D',step); < 54 if(i==2) return tuple('R',step); < 55 if(i==3) return tuple('L',step); < 56 } else if(g.map[y,x]==' '||g.map[y,x]=='\\') { < 57 q2 ~= new Pos(y,x); < 58 v[y][x]=true; < 59 } else if(g.map[y,x]=='.' && g.map[y-1,x]!='*') < 60 q2 ~= new Pos(y,x); < 61 v[y][x]=true; < 62 } < 63 } < 64 } < 65 q = q2; < 66 } < 67 q = [o]; < 68 v = new bool[][](g.map.H+2, g.map.W+2); < 69 for(int step=1000; q.length; ++step) { < 70 Pos[] q2; < 71 foreach(p; q) { < 72 int[] dy=[-1,+1,0,0]; < 73 int[] dx=[0,0,-1,+1]; < 74 for(int i=0; i<4; ++i) { < 75 int y = p.y+dy[i]; < 76 int x = p.x+dx[i]; < 77 if(v[y][x]) continue; < 78 if(y==s.y && x==s.x) { < 79 if(i==0) return tuple('U',step); < 80 if(i==1) return tuple('D',step); < 81 if(i==2) return tuple('R',step); < 82 if(i==3) return tuple('L',step); < 83 } else if(g.map[y,x]==' '||g.map[y,x]=='\\') { < 84 q2 ~= new Pos(y,x); < 85 v[y][x]=true; < 86 } else if(g.map[y,x]=='.'/* && g[y-1,x]!='*'*/) < 87 q2 ~= new Pos(y,x); < 88 v[y][x]=true; < 89 } < 90 } < 91 } < 92 q = q2; < 93 } < 94 return tuple('W', int.max); < 95 } < 96 < 97 void main(string[] args) < 98 { < 99 auto g = Game.load(File(args[1])); < 100 g.set_output(new GuardedOutput(g)); < 101 < 102 while(!g.dead && !g.cleared) < 103 act(g); < 104 } <

Name change from from game.d to src/game.d.

Name change from from gui.d to src/gui.d.

Name change from from output.d to src/output.d.

Modified src/solver.d from [2d4705e7ff103283] to [42db89cb5c63a7bd].

92 q = q2; 92 q = q2; 93 } 93 } 94 return tuple('W', int.max); 94 return tuple('W', int.max); 95 } 95 } 96 96 97 void main(string[] args) 97 void main(string[] args) 98 { 98 { 99 auto g = Game.load(File(args[1])); | 99 auto g = Game.load(stdin); 100 g.set_output(new GuardedOutput(g)); 100 g.set_output(new GuardedOutput(g)); 101 101 102 while(!g.dead && !g.cleared) 102 while(!g.dead && !g.cleared) 103 act(g); 103 act(g); 104 } 104 }

Name change from from test.d to src/test.d.

Name change from from util.d to src/util.d.

Added submission/PACKAGES version [da39a3ee5e6b4b0d]

Added submission/README version [e299f78be5d1c45f]

> 1 Team "Dark Integers". > 2 > 3 Member: > 4 Kazuhiro Inaba (www.kmonos.net) > 5 Language: > 6 D Programming Language (http://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! > 25

Added submission/install version [be776bcfbc13fcbf]

> 1 #!/bin/sh > 2 echo "Hello, world"

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