Index: game.d
==================================================================
--- game.d
+++ game.d
@@ -7,10 +7,11 @@
 {
 	public immutable int y, x;
 	mixin DeriveCreate;
 	mixin DeriveCompare;
 	mixin DeriveShow;
+	Pos clone() { return this; }
 
 @property:
 	Pos wait()  { return this; }
 	Pos up()    { return new Pos(y+1, x); }
 	Pos down()  { return new Pos(y-1, x); }
@@ -43,10 +44,11 @@
 {
 	public immutable int base, pace;
 	mixin DeriveCreate;
 	mixin DeriveCompare;
 	mixin DeriveShow;
+	Water clone() { return this; }
 
 	static load(string[string] params)
 	{
 		return new Water(
 			params.get("Water",    "0").to!int(),
@@ -100,10 +102,18 @@
 	private {
 		char[][] data;
 		Pos robot;
 		Pos lift;
 		int waterproof;
+	}
+	Map clone() { return new Map(this); }
+	this(Map m) {
+		foreach(s; m.data)
+			this.data ~= s.dup;
+		this.robot = m.robot.clone();
+		this.lift = m.lift.clone();
+		this.waterproof = m.waterproof;
 	}
 
 	this(string[] raw_data, string[string] params)
 	{
 		int width = 0;
@@ -284,17 +294,33 @@
 	{
 		this.map = Map.load(raw_data, params);
 		this.water = Water.load(params);
 		this.output = new NilOutput;
 	}
+
+	Game clone() { return new Game(this); }
+	this(Game g) {
+		map = g.map.clone();
+		water = g.water.clone();
+		output = new NilOutput;
+		turn = g.turn;
+		dead = g.dead;
+		lambda = g.lambda;
+		exit_bonus = g.exit_bonus;
+		under_water = g.under_water;
+	}
 
 	void set_output(Output o) { this.output = (o is null ? new NilOutput : o); }
 
 	void command(char c)
 	{
 		if(dead || cleared)
 			return;
+		scope(exit) {
+			if(dead || cleared)
+				output.flush();
+		}
 		this.output.command(c);
 
 		if(c == 'A')
 		{
 			exit_bonus = 1;
@@ -311,36 +337,38 @@
 			if( ld[1] ) {
 				dead = true;
 			}
 		}
 		if( map.robot.y <= water_level )
-			++under_warter;
+			++under_water;
 		else
-			under_warter = 0;
-		if( under_warter > map.waterproof )
+			under_water = 0;
+		if( under_water > map.waterproof )
 			dead = true;
 		turn += 1;
 	}
 
 	Map map;
 	Water water;
 	Output output;
-
 	int  turn = 0;
 	bool dead = false;
 	int  lambda = 0;
 	int  exit_bonus = 0;
-	int  under_warter = 0;
+	int  under_water = 0;
+	// TODO: when adding members, take care of clone().
+	// TODO: fix this poor design.
+
 	@property {
 		long score() { return lambda*25L*(1+exit_bonus) - turn; }
 		int water_level() { return water.level(turn); }
 		int water_until_rise() { return water.until_rise(turn); }
 		bool cleared() { return exit_bonus>0; }
-		int hp() { return map.waterproof - under_warter; }
+		int hp() { return map.waterproof - under_water; }
 		long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus)) - turn; }
 	}
 }
 
 unittest
 {
 	Game.load(["###","...","#RL"], ["xxx":"yyy"]);
 }

Index: gui.d
==================================================================
--- gui.d
+++ gui.d
@@ -110,9 +110,9 @@
 }
 
 void main(string[] args)
 {
 	auto g = Game.load(File(args[1]));
-	g.set_output(new StdOutput);
+	g.set_output(new GuardedOutput(g));
 	auto myForm = new GUI(g);
 	Application.run(myForm);
 }

Index: output.d
==================================================================
--- output.d
+++ output.d
@@ -4,32 +4,77 @@
 import std.c.stdlib;
 
 abstract class Output
 {
 	void command(char c);
+	void flush();
 }
 
 class NilOutput : Output
 {
 	override void command(char c) {}
+	override void flush() {}
 }
 
 class StdOutput : Output
 {
+	override void command(char c)
+	{
+		write(c);
+		stdout.flush();
+	}
+	override void flush() {}
+}
+
+// TODO: clean it up.
+__gshared Output g_output;
+
+class GuardedOutput : StdOutput
+{
 	// Handle SIGINT: force abort and exit.
 	static this()
 	{
 		signal(SIGINT, &sigint);
 	}
-	extern(C) static void sigint(int) {
-		write("A");
-		stdout.flush();
+
+	extern(C) static void sigint(int)
+	{
+		if(g_output !is null)
+			g_output.flush();
+		else {
+			write("A");
+			stdout.flush();
+		}
 		exit(0);
 	}
 
+	Game g;
+	this(Game ini) { this.g = ini.clone(); ideal_log ~= g.score_if_abort_now; g_output = this; }
+
+	string log;
+	long[] score_log;
+	long[] ideal_log;
+
 	override void command(char c)
 	{
-		// TODO: optimize redundancy.
-		write(c);
+		g.command(c);
+		log ~= c;
+		score_log ~= g.score;
+		ideal_log ~= g.score_if_abort_now;
+	}
+	override void flush()
+	{
+		Tuple!(long, int, int) cand;
+		cand[0] = long.min;
+		foreach(int i, long s; score_log)
+			if(cand[0] < s)	
+				cand = tuple(s,i,0);
+		foreach(int i, long s; ideal_log)
+			if(cand[0] < s)	
+				cand = tuple(s,i,1);
+		if(cand[2]==0)
+			writeln(log[0..cand[1]+1]);
+		else
+			writeln(log[0..cand[1]]~"A");
 		stdout.flush();
 	}
 }