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*2]) { 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]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') { 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[p.L.D]==' ') { 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)) - turn; } 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, cell*w+1)); 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], r); 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: ", g.water_until_rise); 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; g_output = this; } 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 92 q = q2; 93 93 } 94 94 return tuple('W', int.max); 95 95 } 96 96 97 97 void main(string[] args) 98 98 { 99 - auto g = Game.load(File(args[1])); 99 + auto g = Game.load(stdin); 100 100 g.set_output(new GuardedOutput(g)); 101 101 102 102 while(!g.dead && !g.cleared) 103 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*25; } 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]==' ' && data[y+1][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]==' ' && data[y+1][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]==' ' && data[y+1][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][x]!='*'*/) { 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.underwater,"]"); 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.height/(m.H-2)); 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.clientSize.width,this.clientSize.height-(Z*(m.water-1)))); 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, (y-1)*Z, Z, Z)); 312 - } 313 - if(m.data[y][x]=='\\') { 314 - g.drawText("λ", font, Color(0,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 315 - } 316 - if(m.data[y][x]=='R') { 317 - if(m.dead) 318 - g.drawText("Я", font, Color(255,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 319 - else 320 - g.drawText("R", font, Color(128,128,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 321 - } 322 - if(m.data[y][x]=='L') { 323 - g.drawText("扉", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 324 - } 325 - if(m.data[y][x]=='O') { 326 - g.drawText("外", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 327 - } 328 - if(m.data[y][x]=='#') { 329 - g.drawText("#", font, Color(0,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 330 - } 331 - if(m.data[y][x]=='.') { 332 - g.drawText("・", font, Color(128,40,0), Rect((x-1)*Z, (y-1)*Z, Z, Z)); 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.underwater,"]"); 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).tupleof); 23 - } 24 - 25 - int opCmp(Object rhs) 26 - { 27 - return tuple(this.tupleof).opCmp(tuple((cast(typeof(this))rhs).tupleof)); 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..$], ":", mem); 53 - } 54 - return str ~ ")"; 55 - } 56 -}