Check-in [bee0596f0f]
Not logged in
Overview
SHA1 Hash:bee0596f0fcfe8d8ac2135382c34fb134c8abc40
Date: 2012-07-14 20:24:30
User: kinaba
Comment:Refactoring.
Timelines: family | ancestors | descendants | both | trunk
Diffs: redesign
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified src/game.d from [7c15481493257083] to [cde4121762ca0c01].

1 import util; 1 import util; 2 import output; < 3 2 4 //////////////////////////////////////////////////////////////////////////////// 3 //////////////////////////////////////////////////////////////////////////////// 5 4 6 class Pos 5 class Pos 7 { 6 { 8 public immutable int y, x; 7 public immutable int y, x; 9 mixin DeriveCreate; 8 mixin DeriveCreate; 10 mixin DeriveCompare; 9 mixin DeriveCompare; 11 mixin DeriveShow; 10 mixin DeriveShow; 12 Pos clone() { return this; } | 11 Pos clone() const { return new Pos(y, x); } 13 12 14 @property: 13 @property: 15 Pos wait() { return this; } | 14 Pos wait() { return this.clone(); } 16 Pos up() { return new Pos(y+1, x); } 15 Pos up() { return new Pos(y+1, x); } 17 Pos down() { return new Pos(y-1, x); } 16 Pos down() { return new Pos(y-1, x); } 18 Pos left() { return new Pos(y, x-1); } 17 Pos left() { return new Pos(y, x-1); } 19 Pos right() { return new Pos(y, x+1); } 18 Pos right() { return new Pos(y, x+1); } 20 alias wait W,w; 19 alias wait W,w; 21 alias up U,u; 20 alias up U,u; 22 alias down D,d; 21 alias down D,d; ................................................................................................................................................................................ 42 41 43 class Water 42 class Water 44 { 43 { 45 public immutable int base, pace; 44 public immutable int base, pace; 46 mixin DeriveCreate; 45 mixin DeriveCreate; 47 mixin DeriveCompare; 46 mixin DeriveCompare; 48 mixin DeriveShow; 47 mixin DeriveShow; 49 Water clone() { return this; } | 48 Water clone() const { return new Water(base, pace); } 50 49 51 static load(string[string] params) 50 static load(string[string] params) 52 { 51 { 53 return new Water( 52 return new Water( 54 params.get("Water", "0").to!int(), 53 params.get("Water", "0").to!int(), 55 params.get("Flooding", "0").to!int() 54 params.get("Flooding", "0").to!int() 56 ); 55 ); 57 } 56 } 58 57 59 int level(int number_of_update) | 58 int level(int number_of_update) const 60 { 59 { 61 return pace ? base+(number_of_update/pace) : base; 60 return pace ? base+(number_of_update/pace) : base; 62 } 61 } 63 62 64 int until_rise(int number_of_update) | 63 int until_rise(int number_of_update) const 65 { 64 { 66 return pace ? pace-number_of_update%pace : int.max; 65 return pace ? pace-number_of_update%pace : int.max; 67 } 66 } 68 } 67 } 69 68 70 unittest 69 unittest 71 { 70 { ................................................................................................................................................................................ 100 } 99 } 101 100 102 char[][] data; 101 char[][] data; 103 Pos robot; 102 Pos robot; 104 Pos lift; 103 Pos lift; 105 int waterproof; 104 int waterproof; 106 105 107 Map clone() { return new Map(this); } | 106 Map clone() const { return new Map(this); } 108 this(Map m) { | 107 this(const(Map) m) { 109 foreach(s; m.data) 108 foreach(s; m.data) 110 this.data ~= s.dup; 109 this.data ~= s.dup; 111 this.robot = m.robot.clone(); 110 this.robot = m.robot.clone(); 112 this.lift = m.lift.clone(); 111 this.lift = m.lift.clone(); 113 this.waterproof = m.waterproof; 112 this.waterproof = m.waterproof; 114 } 113 } 115 114 ................................................................................................................................................................................ 136 } 135 } 137 136 138 const @property { 137 const @property { 139 int H() { return data.length; } 138 int H() { return data.length; } 140 int W() { return data[0].length; } 139 int W() { return data[0].length; } 141 } 140 } 142 141 > 142 const { 143 char opIndex(int y, int x) | 143 char opIndex(int y, int x) 144 { | 144 { 145 // Adjust coordinate to the spec. bottom-left is (1,1). | 145 // Adjust coordinate to the spec. bottom-left is (1,1). 146 --y, --x; | 146 --y, --x; 147 if(y<0||H<=y||x<0||W<=x) | 147 if(y<0||H<=y||x<0||W<=x) 148 return '#'; | 148 return '#'; 149 return data[H-1-y][x]; | 149 return data[H-1-y][x]; 150 } | 150 } 151 151 152 char opIndex(Pos p) | 152 char opIndex(Pos p) 153 { | 153 { 154 return this[p.y, p.x]; | 154 return this[p.y, p.x]; > 155 } 155 } 156 } 156 157 157 void opIndexAssign(char c, int y, int x) 158 void opIndexAssign(char c, int y, int x) 158 { 159 { 159 // Adjust coordinate to the spec. bottom-left is (1,1). 160 // Adjust coordinate to the spec. bottom-left is (1,1). 160 --y, --x; 161 --y, --x; 161 if(y<0||H<=y||x<0||W<=x) 162 if(y<0||H<=y||x<0||W<=x) ................................................................................................................................................................................ 298 return new Game(raw_data, params); 299 return new Game(raw_data, params); 299 } 300 } 300 301 301 this(string[] raw_data, string[string] params) 302 this(string[] raw_data, string[string] params) 302 { 303 { 303 this.map = Map.load(raw_data, params); 304 this.map = Map.load(raw_data, params); 304 this.water = Water.load(params); 305 this.water = Water.load(params); 305 this.output = new NilOutput; < 306 } 306 } 307 307 308 Game clone() { return new Game(this); } | 308 Game clone() const { return new Game(this); } 309 this(Game g) { | 309 this(const(Game) g) { 310 map = g.map.clone(); 310 map = g.map.clone(); 311 water = g.water.clone(); 311 water = g.water.clone(); 312 output = new NilOutput; < 313 turn = g.turn; 312 turn = g.turn; 314 dead = g.dead; 313 dead = g.dead; 315 lambda = g.lambda; 314 lambda = g.lambda; 316 exit_bonus = g.exit_bonus; 315 exit_bonus = g.exit_bonus; 317 under_water = g.under_water; 316 under_water = g.under_water; 318 } 317 } 319 318 320 void set_output(Output o) { this.output = (o is null ? new NilOutput : o < 321 < 322 void command(char c) 319 void command(char c) 323 { 320 { 324 if(dead || cleared) 321 if(dead || cleared) 325 return; 322 return; 326 scope(exit) { < 327 if(dead || cleared) < 328 output.flush(); < 329 } < 330 this.output.command(c); < 331 323 332 if(c == 'A') 324 if(c == 'A') 333 { 325 { 334 exit_bonus = 1; 326 exit_bonus = 1; 335 return; 327 return; 336 } 328 } 337 329 ................................................................................................................................................................................ 353 if( under_water > map.waterproof ) 345 if( under_water > map.waterproof ) 354 dead = true; 346 dead = true; 355 turn += 1; 347 turn += 1; 356 } 348 } 357 349 358 Map map; 350 Map map; 359 Water water; 351 Water water; 360 Output output; < 361 int turn = 0; 352 int turn = 0; 362 bool dead = false; 353 bool dead = false; 363 int lambda = 0; 354 int lambda = 0; 364 int exit_bonus = 0; 355 int exit_bonus = 0; 365 int under_water = 0; 356 int under_water = 0; 366 // TODO: when adding members, take care of clone(). 357 // TODO: when adding members, take care of clone(). 367 // TODO: fix this poor design. 358 // TODO: fix this poor design. 368 359 369 @property { | 360 @property const { 370 long score() { return lambda*25L*(1+exit_bonus) - turn; } 361 long score() { return lambda*25L*(1+exit_bonus) - turn; } 371 int water_level() { return water.level(turn); } 362 int water_level() { return water.level(turn); } 372 int water_until_rise() { return water.until_rise(turn); } 363 int water_until_rise() { return water.until_rise(turn); } 373 bool cleared() { return exit_bonus>0; } 364 bool cleared() { return exit_bonus>0; } 374 int hp() { return map.waterproof - under_water; } 365 int hp() { return map.waterproof - under_water; } 375 long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus 366 long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus 376 } 367 } 377 } 368 } 378 369 379 unittest 370 unittest 380 { 371 { 381 Game.load(["###","...","#RL"], ["xxx":"yyy"]); 372 Game.load(["###","...","#RL"], ["xxx":"yyy"]); 382 } 373 }

Modified src/gui.d from [8bca70d55515c665] to [e76b6b97ba56256b].

1 import dfl.all; 1 import dfl.all; 2 import util; 2 import util; 3 import game; 3 import game; 4 import output; 4 import output; > 5 import driver; 5 //import solver; 6 //import solver; > 7 pragma(lib, "dfl.lib"); 6 8 7 class GUI : Form | 9 class GUI : Form, GameObserver 8 { 10 { > 11 bool on_game_changed(char c, const(Game) g, bool finished) { > 12 draw(gr, g); > 13 invalidate(); > 14 return false; > 15 } > 16 9 private { 17 private { 10 Game g; < 11 int cell; 18 int cell; 12 int turn = 0; 19 int turn = 0; 13 20 14 Font font; 21 Font font; 15 Color[char] colors; 22 Color[char] colors; 16 string[char] render; 23 string[char] render; > 24 void delegate(char c) fn; 17 } 25 } 18 26 19 this(Game g) | 27 this(const(Game) g) 20 { 28 { 21 noMessageFilter(); 29 noMessageFilter(); 22 this.setStyle(ControlStyles.OPAQUE, true); 30 this.setStyle(ControlStyles.OPAQUE, true); 23 this.g = g; | 31 this.fn = fn; 24 32 25 this.paint ~= &my_paint; 33 this.paint ~= &my_paint; 26 this.keyDown ~= &my_keydown; 34 this.keyDown ~= &my_keydown; 27 35 28 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; 36 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG; 29 this.maximizeBox = false; 37 this.maximizeBox = false; 30 this.minimizeBox = false; 38 this.minimizeBox = false; 31 this.cell = min(1024/g.map.W, 640/g.map.H); 39 this.cell = min(1024/g.map.W, 640/g.map.H); 32 this.clientSize = Size(g.map.W*cell, g.map.H*cell); 40 this.clientSize = Size(g.map.W*cell, g.map.H*cell); 33 set_text(); < > 41 > 42 const scrH = this.clientSize.height; > 43 const scrW = this.clientSize.width; > 44 this.gr = new MemoryGraphics(scrW, scrH); 34 45 35 // Resources 46 // Resources 36 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 47 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL); 37 this.backColor = Color(255,255,255); 48 this.backColor = Color(255,255,255); 38 this.colors['#'] = 49 this.colors['#'] = 39 this.colors['.'] = Color(255,191,127); 50 this.colors['.'] = Color(255,191,127); 40 this.colors['*'] = Color(255,127,127); 51 this.colors['*'] = Color(255,127,127); ................................................................................................................................................................................ 49 this.render['*'] = "✹"; 60 this.render['*'] = "✹"; 50 this.render['.'] = "♒"; 61 this.render['.'] = "♒"; 51 this.render['\\'] = "λ"; 62 this.render['\\'] = "λ"; 52 this.render['R'] = "☃"; 63 this.render['R'] = "☃"; 53 this.render['D'] = "☠"; 64 this.render['D'] = "☠"; 54 this.render['L'] = "☒"; 65 this.render['L'] = "☒"; 55 this.render['O'] = "☐"; 66 this.render['O'] = "☐"; > 67 draw(gr, g); > 68 } > 69 > 70 void set_fn(F)(F f) { this.fn = f; } > 71 > 72 void run() { > 73 Application.run(this); 56 } 74 } 57 75 58 private: 76 private: > 77 Graphics gr; > 78 59 void my_paint(Control, PaintEventArgs ev) 79 void my_paint(Control, PaintEventArgs ev) 60 { 80 { 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)); | 81 gr.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clien 66 gr.dispose(); < 67 } | 82 } 68 83 > 84 void draw(Graphics gr, const(Game) g) > 85 { > 86 int scrW = this.clientSize.width; > 87 int scrH = this.clientSize.height; 69 // Fill bg. 88 // Fill bg. 70 gr.fillRectangle(this.backColor, Rect(0,0,scrW,scrH)); 89 gr.fillRectangle(this.backColor, Rect(0,0,scrW,scrH)); 71 90 72 // Fill water. 91 // Fill water. 73 int w = g.water_level(); 92 int w = g.water_level(); 74 gr.fillRectangle(this.colors['W'], Rect(0, scrH-cell*w-1, scrW, 93 gr.fillRectangle(this.colors['W'], Rect(0, scrH-cell*w-1, scrW, 75 94 ................................................................................................................................................................................ 80 char c = g.map[y,x]; 99 char c = g.map[y,x]; 81 if( c != ' ' ) { 100 if( c != ' ' ) { 82 if( c == 'R' && g.dead ) 101 if( c == 'R' && g.dead ) 83 c = 'D'; 102 c = 'D'; 84 gr.drawText(this.render[c], font, this.colors[c] 103 gr.drawText(this.render[c], font, this.colors[c] 85 } 104 } 86 } 105 } > 106 > 107 set_text(g); 87 } 108 } 88 109 89 void my_keydown(Control c, KeyEventArgs ev) 110 void my_keydown(Control c, KeyEventArgs ev) 90 { 111 { 91 switch(ev.keyCode) 112 switch(ev.keyCode) 92 { 113 { 93 case Keys.DOWN: g.command('D'); break; | 114 case Keys.DOWN: fn('D'); break; 94 case Keys.UP: g.command('U'); break; | 115 case Keys.UP: fn('U'); break; 95 case Keys.LEFT: g.command('L'); break; | 116 case Keys.LEFT: fn('L'); break; 96 case Keys.RIGHT: g.command('R'); break; | 117 case Keys.RIGHT: fn('R'); break; 97 case Keys.W: g.command('W'); break; | 118 case Keys.W: fn('W'); break; 98 case Keys.A: g.command('A'); break; | 119 case Keys.A: fn('A'); break; 99 // case Keys.G: solver.act(g); break; < 100 default: break; 120 default: break; 101 } 121 } 102 if(g.cleared) < 103 Application.exit(); < 104 invalidate(); < 105 set_text(); < 106 } 122 } 107 123 108 void set_text() { | 124 void set_text(const(Game) g) { 109 this.text = .text("Score: ", g.score, " Air: ", g.hp, " Tide: ", 125 this.text = .text("Score: ", g.score, " Air: ", g.hp, " Tide: ", 110 } 126 } 111 } 127 } 112 128 113 void main(string[] args) 129 void main(string[] args) 114 { 130 { 115 auto g = Game.load(File(args[1])); | 131 auto d = new Driver(File(args[1])); 116 g.set_output(new GuardedOutput(g)); | 132 d.addObserver!(GuardedOutput)(); 117 auto myForm = new GUI(g); | 133 GUI g = d.addObserver!(GUI)(); 118 Application.run(myForm); | 134 g.set_fn(&d.command); > 135 g.run(); 119 } 136 }

Modified src/output.d from [1b458d7cd25e92dc] to [2ca374354297c908].

1 import util; 1 import util; 2 import game; 2 import game; 3 import core.stdc.signal; | 3 import driver; 4 import std.c.stdlib; 4 import std.c.stdlib; > 5 import core.stdc.signal; 5 6 6 abstract class Output | 7 class NilOutput : GameObserver 7 { 8 { 8 void command(char c); | 9 this(const(Game) g) {} 9 void flush(); | 10 override bool on_game_changed(char c, const(Game) g, bool finished) {ret 10 } 11 } 11 12 12 class NilOutput : Output | 13 class StdOutput : GameObserver 13 { 14 { 14 override void command(char c) {} | 15 this(const(Game) g) {} 15 override void flush() {} | 16 override bool on_game_changed(char c, const(Game) g, bool finished) 16 } < 17 < 18 class StdOutput : Output < 19 { < 20 override void command(char c) < 21 { 17 { 22 write(c); | 18 stdout.write(c); 23 stdout.flush(); 19 stdout.flush(); > 20 return false; 24 } 21 } 25 override void flush() {} < 26 } 22 } 27 23 28 // TODO: clean it up. < 29 __gshared Output g_output; < 30 < 31 class GuardedOutput : StdOutput | 24 class GuardedOutput : GameObserver 32 { 25 { 33 // Handle SIGINT: force abort and exit. | 26 this(const(Game) g) 34 static this() < > 27 { > 28 setup_sigint_handling(); > 29 ideal_log ~= g.score_if_abort_now; > 30 } > 31 > 32 override bool on_game_changed(char c, const(Game) g, bool finished) 35 { 33 { 36 signal(SIGINT, &sigint); | 34 log ~= c; > 35 score_log ~= g.score; > 36 ideal_log ~= g.score_if_abort_now; > 37 if(finished) > 38 flush(); > 39 return false; 37 } 40 } 38 41 39 extern(C) static void sigint(int) | 42 private: 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; 43 string log; 54 long[] score_log; 44 long[] score_log; 55 long[] ideal_log; 45 long[] ideal_log; 56 46 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() | 47 void flush() 65 { 48 { 66 Tuple!(long, int, int) cand; 49 Tuple!(long, int, int) cand; 67 cand[0] = long.min; 50 cand[0] = long.min; 68 foreach(int i, long s; score_log) < > 51 > 52 for(int i=0; i<score_log.length; ++i) 69 if(cand[0] < s) | 53 if(cand[0] < score_log[i]) 70 cand = tuple(s,i,0); | 54 cand = tuple(score_log[i],i,0); 71 foreach(int i, long s; ideal_log) < > 55 for(int i=0; i<ideal_log.length; ++i) 72 if(cand[0] < s) | 56 if(cand[0] < ideal_log[i]) 73 cand = tuple(s,i,1); | 57 cand = tuple(ideal_log[i],i,1); > 58 74 if(cand[2]==0) | 59 if(cand[2]==0) { 75 writeln(log[0..cand[1]+1]); | 60 string str = log[0..cand[1]+1]; > 61 std.c.stdio.printf("%.*s\n", str.length, str.ptr); 76 else | 62 } else { 77 writeln(log[0..cand[1]]~"A"); | 63 string str = log[0..cand[1]]; 78 stdout.flush(); < > 64 std.c.stdio.printf("%.*sA\n", str.length, str.ptr); > 65 } > 66 std.c.stdio.fflush(std.c.stdio.stdout); > 67 } > 68 > 69 private: > 70 static __gshared GuardedOutput g_output; > 71 > 72 void setup_sigint_handling() > 73 { > 74 assert(g_output is null); > 75 g_output = this; > 76 extern(C) static void catch_sigint(int) { g_output.flush(); appl > 77 core.stdc.signal.signal(SIGINT, &catch_sigint); 79 } 78 } 80 } 79 }

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

1 public import std.algorithm; 1 public import std.algorithm; 2 public import std.array; 2 public import std.array; 3 public import std.conv; 3 public import std.conv; 4 public import std.range; 4 public import std.range; 5 public import std.stdio; 5 public import std.stdio; 6 public import std.string; 6 public import std.string; 7 public import std.typecons; 7 public import std.typecons; > 8 import std.c.stdlib; > 9 > 10 void application_exit() > 11 { > 12 std.c.stdlib.exit(0); > 13 } 8 14 9 template DeriveCreate() 15 template DeriveCreate() 10 { 16 { 11 this(TS...)(TS params) 17 this(TS...)(TS params) 12 { 18 { 13 this.tupleof = params; 19 this.tupleof = params; 14 } 20 }