Index: score_memo.txt ================================================================== --- score_memo.txt +++ score_memo.txt @@ -1,22 +1,22 @@ contest1 212! contest2 280? contest3 275! contest4 561? contest5 1281? -contest6 737 // deadend trap +contest6 737 contest7 867? -contest8 1245 // tricky +contest8 1245 contest9 3042? -contest10 2076 // * on lambda, must move * first -flood1 569 // too slow, because of 1-left danger lambda +contest10 2076 +flood1 569 flood2 280? -flood3 802 // too slow, drown -flood4 970 // incorrect order of digging +flood3 802 +flood4 970 flood5 561? -trampoline1 291 // * on trampoline. must move * first +trampoline1 291 trampoline2 1728? -trampoline3 698 // * on trampoline target. must move * first. +trampoline3 698 beard1 856? -beard2 2792 // hutsu-ni muzui -beard3 811 // tricky. must hurry to cut hige. -beard4 677 // deadend trap +beard2 2792 +beard3 811 +beard4 677 DELETED src/driver.d Index: src/driver.d ================================================================== --- src/driver.d +++ src/driver.d @@ -1,65 +0,0 @@ -import game; -import util; - -interface GameObserver -{ - // this(in Game g); - void on_game_changed(char c, in Game g, bool finished); -} - -class Driver -{ - this(Game g) { this.game = g; } - this(File game_data) { this(new Game(game_data)); } - - void command(char c) - { - if( finished ) - return; - if( c == 'A' ) - aborted = true; - else - game.command(c); - foreach(ob; observers) - ob.on_game_changed(c, game, finished); - } - - T addObserver(T)() - { - T t = new T(game); - observers ~= t; - return t; - } - - @property bool finished() - { - return game.cleared || game.dead || aborted; - } - -private: - Game game; - GameObserver[] observers; - bool aborted = false; -} - -unittest -{ - static class MockGame : Game { - this() { super(null,null,null); } - string log; - void command(char c) { log ~= c; } - } - static class MockObserver : GameObserver { - string log; - this(in Game g) {} - void on_game_changed(char c, in Game g, bool fin) { log~=c; if(fin)log~="$"; } - } - - auto g = new MockGame; - auto d = new Driver(g); - auto o = d.addObserver!MockObserver(); - foreach(char c; "UDLRSAUDLRSA") - d.command(c); - assert(g.log == "UDLRS"); - assert(o.log == "UDLRSA$"); -} Index: src/game.d ================================================================== --- src/game.d +++ src/game.d @@ -235,11 +235,11 @@ for(int x=1; x<=W; ++x) if(this[y,x] == 'L' || this[y,x] == 'O') return false; return true; } - + Tuple!(int,bool) command(char c, int turn) { assert( this[robot] == 'R' ); if(c=='R') return move( 0, +1, turn); if(c=='L') return move( 0, -1, turn); @@ -348,11 +348,11 @@ return dead; } } //////////////////////////////////////////////////////////////////////////////// -/* + class Game { mixin DeriveShow; static Game load(File input) @@ -442,441 +442,5 @@ int water_until_rise() { return water.until_rise(turn); } int hige_until_rise() { return map.hige.until_rise(turn); } int hp() { return map.waterproof - under_water; } } } -*/ - -//////////////////////////////////////////////////////////////////////////////// - -class Game -{ -public: - this(File input) - { - // Read map data - string[] map_data_lines; - for(string line; !(line=input.readln().chomp()).empty; ) - map_data_lines ~= line; - - // H*W - H_ = map_data_lines.length; - W_ = 0; - foreach(mdl; map_data_lines) - W_ = max(W_, mdl.length); - - // Copy to modifiable buffer and adjust coordinates. - raw_data_ = new char[][H_+1]; - foreach(i,mdl; map_data_lines) { - char[] buf = new char[mdl.length+1]; - buf[0] = '#'; - buf[1..$] = mdl[]; - raw_data_[H_-i] = buf; - } - - // Detect objects - for(int y=1; y<=H_; ++y) - for(int x=1; xbd;; })(la); - Pos[] ra = g.razors(); - const(Pos)[] hi = g.higes(); + Pos[] ra = g.map.razors(); + const(Pos)[] hi = g.map.objects('W'); Tuple!(char,int)[] cand; char c = 'W'; if( la.empty ) { cand = search(g, ro, [li], death); @@ -74,28 +74,28 @@ } else { cand ~= search(g, ro, la~ra, death); } // 'higesori' mode - if( !hi.empty && g.num_razor>0 ) { + if( !hi.empty && g.map.razor>0 ) { int his = 0; for(int dy=-1; dy<=+1; ++dy) for(int dx=-1; dx<=+1; ++dx) - if(g[ro.y+dy,ro.x+dx] == 'W') + if(g.map[ro.y+dy,ro.x+dx] == 'W') his++; if(his>=2 || his==hi.length) cand = [tuple('S',int.max)]; if(cand.empty) { const(Pos)[] tgt; - for(int y=1; y<=g.H; ++y) - for(int x=1; x<=g.W; ++x) - if(g[y,x]=='.'||g[y,x]==' ') { + for(int y=1; y<=g.map.H; ++y) + for(int x=1; x<=g.map.W; ++x) + if(g.map[y,x]=='.'||g.map[y,x]==' ') { his = 0; for(int dy=-1; dy<=+1; ++dy) for(int dx=-1; dx<=+1; ++dx) - if(g[y+dy,x+dx] == 'W') + if(g.map[y+dy,x+dx] == 'W') his++; if(his>=2) tgt ~= new Pos(y,x); } cand ~= search(g, ro, tgt, death, true); @@ -103,15 +103,15 @@ } // 'dig' mode if(cand.empty) { const(Pos)[] tgt; - for(int y=1; y<=g.H; ++y) - for(int x=1; x<=g.W; ++x) - if(g[y,x]=='.') - if(g[y+1,x]=='*'||g[y+1,x-1]=='*'||g[y+1,x+1]=='*' - ||g[y,x+1]=='*'||g[y,x-1]=='*') + for(int y=1; y<=g.map.H; ++y) + for(int x=1; x<=g.map.W; ++x) + if(g.map[y,x]=='.') + if(g.map[y+1,x]=='*'||g.map[y+1,x-1]=='*'||g.map[y+1,x+1]=='*' + ||g.map[y,x+1]=='*'||g.map[y,x-1]=='*') tgt ~= new Pos(y,x); cand ~= search(g, ro, tgt, death, true); } if(cand.empty) { @@ -135,11 +135,11 @@ if(c == 'W') wait_count++; else wait_count = 0; - if(choke_count >= g.H) + if(choke_count >= g.map.H) c = 'A'; bool[char] choice; foreach(t; cand) choice[t[0]] = true; @@ -159,21 +159,21 @@ Tuple!(char,int)[] search(in Game g, in Pos s, in Pos[] gs, string death, bool danger_ok=false) { bool danger(int y, int x) { - if(g[y,x] == ' ' || g[y,x] == 'R') + if(g.map[y,x] == ' ' || g.map[y,x] == 'R') return false; - if(g[y+1,x] == '*') + if(g.map[y+1,x] == '*') + return true; + if(g.map[y+1,x-1]=='*' && (g.map[y,x-1]=='\\'||g.map[y,x-1]=='*') && (g.map[y+1,x]==' '||g.map[y+1,x]=='R')) return true; - if(g[y+1,x-1]=='*' && (g[y,x-1]=='\\'||g[y,x-1]=='*') && (g[y+1,x]==' '||g[y+1,x]=='R')) + if(g.map[y+1,x+1]=='*' && (g.map[y,x+1]=='*') && (g.map[y+1,x]==' '||g.map[y+1,x]=='R')) return true; - if(g[y+1,x+1]=='*' && (g[y,x+1]=='*') && (g[y+1,x]==' '||g[y+1,x]=='R')) + if(g.map[y,x-1]=='*' && (g.map[y-1,x-1]=='\\'||g.map[y-1,x-1]=='*') && (g.map[y-1,x]==' '||g.map[y-1,x]=='R')) return true; - if(g[y,x-1]=='*' && (g[y-1,x-1]=='\\'||g[y-1,x-1]=='*') && (g[y-1,x]==' '||g[y-1,x]=='R')) - return true; - if(g[y,x+1]=='*' && (g[y-1,x+1]=='*') && (g[y-1,x]==' '||g[y-1,x]=='R')) + if(g.map[y,x+1]=='*' && (g.map[y-1,x+1]=='*') && (g.map[y-1,x]==' '||g.map[y-1,x]=='R')) return true; return false; } // avoid directly below '*' @@ -180,22 +180,22 @@ Tuple!(char,int)[] tryA() { const(Pos)[] q; foreach(p; gs) if(!danger(p.y,p.x)) q ~= p; - bool[][] v = new bool[][](g.H+2, g.W+2); + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); foreach(p; q) v[p.y][p.x]=true; for(int step=1; q.length; ++step) { Pos[] q2; foreach(p; q) { int[] yyy=[p.y-1,p.y+1,p.y,p.y]; int[] xxx=[p.x,p.x,p.x-1,p.x+1]; for(int i=0; i=4) { + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='!'||i>=4) { if(danger(y,x)) continue; q2 ~= new Pos(y,x); v[y][x]=true; } @@ -220,22 +220,22 @@ // any empty space is my ground Tuple!(char,int)[] tryB() { const(Pos)[] q; foreach(p; gs) q ~= p; - bool[][] v = new bool[][](g.H+2, g.W+2); + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); foreach(p; q) v[p.y][p.x]=true; for(int step=10; q.length; ++step) { Pos[] q2; foreach(p; q) { int[] yyy=[p.y-1,p.y+1,p.y,p.y]; int[] xxx=[p.x,p.x,p.x-1,p.x+1]; for(int i=0; i=4) { + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='!'||i>=4) { q2 ~= new Pos(y,x); v[y][x]=true; } } } @@ -258,27 +258,27 @@ // push rocks! Tuple!(char,int)[] tryC() { const(Pos)[] q; foreach(p; gs) q ~= p; - bool[][] v = new bool[][](g.H+2, g.W+2); + bool[][] v = new bool[][](g.map.H+2, g.map.W+2); foreach(p; q) v[p.y][p.x]=true; for(int step=20; q.length; ++step) { Pos[] q2; foreach(p; q) { int[] yyy=[p.y-1,p.y+1,p.y,p.y]; int[] xxx=[p.x,p.x,p.x-1,p.x+1]; for(int i=0; i=4)continue; if(y!=p.y)continue; - if(g[y,p.x+(p.x-x)]!=' '&&g[y,p.x+(p.x-x)]!='R')continue; + if(g.map[y,p.x+(p.x-x)]!=' '&&g.map[y,p.x+(p.x-x)]!='R')continue; } - if('1'<=g[y,x]&&g[y,x]<='9') { - foreach(ppp; g.trampoline_rev(g[y,x])) { + if('1'<=g.map[y,x]&&g.map[y,x]<='9') { + foreach(ppp; g.map.tr_source[g.map[y,x]]) { yyy ~= ppp.y; xxx ~= ppp.x; } continue; } @@ -286,11 +286,11 @@ if(y==s.y && x==s.x && i<4) { char c = "UDRL"[i]; if( death.count(c) == 0 ) return [tuple(c,step)]; } else if(forbidden_cell[y][x]){ - } else if(g[y,x]==' '||g[y,x]=='\\'||g[y,x]=='.'||g[y,x]=='*'||g[y,x]=='!'||i>=4) { + } else if(g.map[y,x]==' '||g.map[y,x]=='\\'||g.map[y,x]=='.'||g.map[y,x]=='*'||g.map[y,x]=='!'||i>=4) { q2 ~= new Pos(y,x); v[y][x]=true; } } } @@ -316,11 +316,11 @@ Tuple!(Solver,string) run_sub_solver(in Game g) { string log; auto s = new Solver(g); - while(!g.cleared && !g.dead && plan.length<=g.H*g.W) { + while(!g.cleared && !g.dead && plan.length<=g.map.H*g.map.W) { char c = s.single_step(); if( c == 'A' ) break; log ~= c; } Index: src/util.d ================================================================== --- src/util.d +++ src/util.d @@ -6,18 +6,10 @@ public import std.string; public import std.typecons; public import std.math; import std.c.stdlib; -T[] erase(T,V)(T[] xs, V y) -{ - foreach(i,x; xs) - if(x == y) - return xs[0..i]~xs[i+1..$]; - return xs; -} - // To avoide the following ICE: // src\phobos\std\algorithm.d(4552): // Error: function std.algorithm.count!("a == b",string,char).count // compiler error, parameter 'value', bugzilla 2962? // Assertion failure: '0' on line 717 in file 'glue.c'