File Annotation
Not logged in
b6daa1efa1 2012-07-14        kinaba: import util;
b6daa1efa1 2012-07-14        kinaba: import output;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: class Pos
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	public immutable int y, x;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveCreate;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveCompare;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveShow;
a5e6c99b3d 2012-07-14        kinaba: 	Pos clone() { return this; }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: @property:
b6daa1efa1 2012-07-14        kinaba: 	Pos wait()  { return this; }
b6daa1efa1 2012-07-14        kinaba: 	Pos up()    { return new Pos(y+1, x); }
b6daa1efa1 2012-07-14        kinaba: 	Pos down()  { return new Pos(y-1, x); }
b6daa1efa1 2012-07-14        kinaba: 	Pos left()  { return new Pos(y, x-1); }
b6daa1efa1 2012-07-14        kinaba: 	Pos right() { return new Pos(y, x+1); }
b6daa1efa1 2012-07-14        kinaba: 	alias wait  W,w;
b6daa1efa1 2012-07-14        kinaba: 	alias up    U,u;
b6daa1efa1 2012-07-14        kinaba: 	alias down  D,d;
b6daa1efa1 2012-07-14        kinaba: 	alias left  L,l;
b6daa1efa1 2012-07-14        kinaba: 	alias right R,r;
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: unittest
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	assert( (new Pos(2,1)).U == new Pos(3,1) );
b6daa1efa1 2012-07-14        kinaba: 	assert( (new Pos(0,1)).D == new Pos(-1,1) );
b6daa1efa1 2012-07-14        kinaba: 	assert( (new Pos(2,1)).L == new Pos(2,0) );
b6daa1efa1 2012-07-14        kinaba: 	assert( (new Pos(2,1)).R == new Pos(2,2) );
b6daa1efa1 2012-07-14        kinaba: 	int[Pos] aa;
b6daa1efa1 2012-07-14        kinaba: 	aa[new Pos(1,2)] = 1;
b6daa1efa1 2012-07-14        kinaba: 	aa[new Pos(1,2)] = 2;
b6daa1efa1 2012-07-14        kinaba: 	aa[new Pos(2,1)] = 3;
b6daa1efa1 2012-07-14        kinaba: 	assert( aa.length==2 );
b6daa1efa1 2012-07-14        kinaba: 	assert( aa[new Pos(1,2)]==2 );
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: class Water
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	public immutable int base, pace;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveCreate;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveCompare;
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveShow;
a5e6c99b3d 2012-07-14        kinaba: 	Water clone() { return this; }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	static load(string[string] params)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		return new Water(
b6daa1efa1 2012-07-14        kinaba: 			params.get("Water",    "0").to!int(),
b6daa1efa1 2012-07-14        kinaba: 			params.get("Flooding", "0").to!int()
b6daa1efa1 2012-07-14        kinaba: 		);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	int level(int number_of_update)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		return pace ? base+(number_of_update/pace) : base;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	int until_rise(int number_of_update)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		return pace ? pace-number_of_update%pace : int.max;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: unittest
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	Water w = new Water(1, 3);
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(0) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(1) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(2) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 2 == w.level(3) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 2 == w.level(4) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 2 == w.level(5) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 3 == w.level(6) );
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	w = new Water(1, 0);
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(0) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(1) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(2) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(3) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(4) );
b6daa1efa1 2012-07-14        kinaba: 	assert( 1 == w.level(5) );
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: class Map
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveShow;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	static Map load(string[] raw_data, string[string] params)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		// TODO: choose optimal representation.
b6daa1efa1 2012-07-14        kinaba: 		return new Map(raw_data, params);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	private {
b6daa1efa1 2012-07-14        kinaba: 		char[][] data;
b6daa1efa1 2012-07-14        kinaba: 		Pos robot;
b6daa1efa1 2012-07-14        kinaba: 		Pos lift;
b6daa1efa1 2012-07-14        kinaba: 		int waterproof;
a5e6c99b3d 2012-07-14        kinaba: 	}
a5e6c99b3d 2012-07-14        kinaba: 	Map clone() { return new Map(this); }
a5e6c99b3d 2012-07-14        kinaba: 	this(Map m) {
a5e6c99b3d 2012-07-14        kinaba: 		foreach(s; m.data)
a5e6c99b3d 2012-07-14        kinaba: 			this.data ~= s.dup;
a5e6c99b3d 2012-07-14        kinaba: 		this.robot = m.robot.clone();
a5e6c99b3d 2012-07-14        kinaba: 		this.lift = m.lift.clone();
a5e6c99b3d 2012-07-14        kinaba: 		this.waterproof = m.waterproof;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	this(string[] raw_data, string[string] params)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		int width = 0;
b6daa1efa1 2012-07-14        kinaba: 		foreach(r; raw_data)
b6daa1efa1 2012-07-14        kinaba: 			width = max(width, r.length);
b6daa1efa1 2012-07-14        kinaba: 		foreach(r; raw_data) {
b6daa1efa1 2012-07-14        kinaba: 			this.data ~= r.dup;
b6daa1efa1 2012-07-14        kinaba: 			this.data[$-1].length = width;
b6daa1efa1 2012-07-14        kinaba: 			this.data[$-1][r.length..$] = ' ';
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
b6daa1efa1 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x) {
b6daa1efa1 2012-07-14        kinaba: 			if(this[y,x] == 'R')
b6daa1efa1 2012-07-14        kinaba: 				this.robot = new Pos(y,x);
b6daa1efa1 2012-07-14        kinaba: 			if(this[y,x] == 'L')
b6daa1efa1 2012-07-14        kinaba: 				this.lift = new Pos(y,x);
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		this.waterproof = params.get("Waterproof", "5").to!int();
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	const @property {
b6daa1efa1 2012-07-14        kinaba: 		int H() { return data.length; }
b6daa1efa1 2012-07-14        kinaba: 		int W() { return data[0].length; }
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	char opIndex(int y, int x)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		// Adjust coordinate to the spec. bottom-left is (1,1).
b6daa1efa1 2012-07-14        kinaba: 		--y, --x;
b6daa1efa1 2012-07-14        kinaba: 		if(y<0||H<=y||x<0||W<=x)
b6daa1efa1 2012-07-14        kinaba: 			return '#';
b6daa1efa1 2012-07-14        kinaba: 		return data[H-1-y][x];
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	char opIndex(Pos p)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		return this[p.y, p.x];
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	void opIndexAssign(char c, int y, int x)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		// Adjust coordinate to the spec. bottom-left is (1,1).
b6daa1efa1 2012-07-14        kinaba: 		--y, --x;
b6daa1efa1 2012-07-14        kinaba: 		if(y<0||H<=y||x<0||W<=x)
b6daa1efa1 2012-07-14        kinaba: 			return;
b6daa1efa1 2012-07-14        kinaba: 		data[H-1-y][x] = c;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	void opIndexAssign(char c, Pos p)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		this[p.y, p.x] = c;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	bool cleared()
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
b6daa1efa1 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x)
b6daa1efa1 2012-07-14        kinaba: 			if(this[y,x] == 'L' || this[y,x] == 'O')
b6daa1efa1 2012-07-14        kinaba: 				return false;
b6daa1efa1 2012-07-14        kinaba: 		return true;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	Tuple!(int,bool) command(char c)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		if(c=='R') return move( 0, +1);
b6daa1efa1 2012-07-14        kinaba: 		if(c=='L') return move( 0, -1);
b6daa1efa1 2012-07-14        kinaba: 		if(c=='U') return move(+1,  0);
b6daa1efa1 2012-07-14        kinaba: 		if(c=='D') return move(-1,  0);
b6daa1efa1 2012-07-14        kinaba: 		if(c=='W') return move( 0,  0);
b6daa1efa1 2012-07-14        kinaba: 		assert(false);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	Tuple!(int, bool) move(int dy, int dx)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		int y = robot.y;
b6daa1efa1 2012-07-14        kinaba: 		int x = robot.x;
b6daa1efa1 2012-07-14        kinaba: 		assert( this[robot] == 'R' );
b6daa1efa1 2012-07-14        kinaba: 		int lambda = 0;
b6daa1efa1 2012-07-14        kinaba: 		bool dead = false;
b6daa1efa1 2012-07-14        kinaba: 		if( '\\' == this[y+dy,x+dx] )
b6daa1efa1 2012-07-14        kinaba: 			lambda++;
b6daa1efa1 2012-07-14        kinaba: 		if( " \\.O".count(this[y+dy,x+dx])==1 ) {
b6daa1efa1 2012-07-14        kinaba: 			this[y,x]=' ';
b6daa1efa1 2012-07-14        kinaba: 			this[y+dy,x+dx]='R';
b6daa1efa1 2012-07-14        kinaba: 			robot = new Pos(y+dy,x+dx);
b6daa1efa1 2012-07-14        kinaba: 		} else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx*2]) {
b6daa1efa1 2012-07-14        kinaba: 			this[y,x]=' ';
b6daa1efa1 2012-07-14        kinaba: 			this[y+dy,x+dx]='R';
b6daa1efa1 2012-07-14        kinaba: 			this[y+dy*2,x+dx*2]='*';
b6daa1efa1 2012-07-14        kinaba: 			robot = new Pos(y+dy,x+dx);
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 		if( update() )
b6daa1efa1 2012-07-14        kinaba: 			dead = true;
b6daa1efa1 2012-07-14        kinaba: 		return tuple(lambda,dead);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	bool update()
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		bool dead = false;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		char[][] next;
b6daa1efa1 2012-07-14        kinaba: 		foreach(y,s; data)
b6daa1efa1 2012-07-14        kinaba: 			next ~= s.dup;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		ref char access(Pos p) { return next[H-p.y][p.x-1]; }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		bool lambda = false;
b6daa1efa1 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
b6daa1efa1 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x)
b6daa1efa1 2012-07-14        kinaba: 			lambda |= (this[y,x] == '\\');
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
b6daa1efa1 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x) {
b6daa1efa1 2012-07-14        kinaba: 			Pos p = new Pos(y,x);
b6daa1efa1 2012-07-14        kinaba: 			if(this[p]=='*') {
b6daa1efa1 2012-07-14        kinaba: 				if(this[p.D]==' ') {
b6daa1efa1 2012-07-14        kinaba: 					access(p)  =' ';
b6daa1efa1 2012-07-14        kinaba: 					access(p.D)='*';
b6daa1efa1 2012-07-14        kinaba: 					if(robot == p.D.D)
b6daa1efa1 2012-07-14        kinaba: 						dead=true;
b6daa1efa1 2012-07-14        kinaba: 				}
b6daa1efa1 2012-07-14        kinaba: 				else if((this[p.D]=='*' || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') {
b6daa1efa1 2012-07-14        kinaba: 					access(p)=' ';
b6daa1efa1 2012-07-14        kinaba: 					access(p.R.D)='*';
b6daa1efa1 2012-07-14        kinaba: 					if(robot == p.R.D.D)
b6daa1efa1 2012-07-14        kinaba: 						dead=true;
b6daa1efa1 2012-07-14        kinaba: 				}
b6daa1efa1 2012-07-14        kinaba: 				else if(this[p.D]=='*' && this[p.L]==' ' && this[p.L.D]==' ') {
b6daa1efa1 2012-07-14        kinaba: 					access(p)=' ';
b6daa1efa1 2012-07-14        kinaba: 					access(p.L.D)='*';
b6daa1efa1 2012-07-14        kinaba: 					if(robot == p.L.D.D)
b6daa1efa1 2012-07-14        kinaba: 						dead=true;
b6daa1efa1 2012-07-14        kinaba: 				}
b6daa1efa1 2012-07-14        kinaba: 			}
b6daa1efa1 2012-07-14        kinaba: 			else if(this[p]=='L') {
b6daa1efa1 2012-07-14        kinaba: 				if(!lambda)
b6daa1efa1 2012-07-14        kinaba: 					access(p) = 'O';
b6daa1efa1 2012-07-14        kinaba: 			}
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 		data = next;
b6daa1efa1 2012-07-14        kinaba: 		return dead;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: class Game
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	mixin DeriveShow;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	static Game load(File input)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		string[]       raw_data;
b6daa1efa1 2012-07-14        kinaba: 		string[string] params;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		// Raw map data; read until empty line.
b6daa1efa1 2012-07-14        kinaba: 		for(string line; !(line=input.readln().chomp()).empty; )
b6daa1efa1 2012-07-14        kinaba: 			raw_data ~= line;
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		// Additional commands; read until EOF.
b6daa1efa1 2012-07-14        kinaba: 		for(string line; !(line=input.readln()).empty; ) {
b6daa1efa1 2012-07-14        kinaba: 			string[] ss = line.split();
b6daa1efa1 2012-07-14        kinaba: 			if( ss.length == 2 )
b6daa1efa1 2012-07-14        kinaba: 				params[ss[0]] = ss[1];
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		return load(raw_data, params);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	static Game load(string[] raw_data, string[string] params)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		return new Game(raw_data, params);
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	this(string[] raw_data, string[string] params)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		this.map = Map.load(raw_data, params);
b6daa1efa1 2012-07-14        kinaba: 		this.water = Water.load(params);
b6daa1efa1 2012-07-14        kinaba: 		this.output = new NilOutput;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
a5e6c99b3d 2012-07-14        kinaba: 	Game clone() { return new Game(this); }
a5e6c99b3d 2012-07-14        kinaba: 	this(Game g) {
a5e6c99b3d 2012-07-14        kinaba: 		map = g.map.clone();
a5e6c99b3d 2012-07-14        kinaba: 		water = g.water.clone();
a5e6c99b3d 2012-07-14        kinaba: 		output = new NilOutput;
a5e6c99b3d 2012-07-14        kinaba: 		turn = g.turn;
a5e6c99b3d 2012-07-14        kinaba: 		dead = g.dead;
a5e6c99b3d 2012-07-14        kinaba: 		lambda = g.lambda;
a5e6c99b3d 2012-07-14        kinaba: 		exit_bonus = g.exit_bonus;
a5e6c99b3d 2012-07-14        kinaba: 		under_water = g.under_water;
a5e6c99b3d 2012-07-14        kinaba: 	}
a5e6c99b3d 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	void set_output(Output o) { this.output = (o is null ? new NilOutput : o); }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	void command(char c)
b6daa1efa1 2012-07-14        kinaba: 	{
b6daa1efa1 2012-07-14        kinaba: 		if(dead || cleared)
b6daa1efa1 2012-07-14        kinaba: 			return;
a5e6c99b3d 2012-07-14        kinaba: 		scope(exit) {
a5e6c99b3d 2012-07-14        kinaba: 			if(dead || cleared)
a5e6c99b3d 2012-07-14        kinaba: 				output.flush();
a5e6c99b3d 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 		this.output.command(c);
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		if(c == 'A')
b6daa1efa1 2012-07-14        kinaba: 		{
b6daa1efa1 2012-07-14        kinaba: 			exit_bonus = 1;
b6daa1efa1 2012-07-14        kinaba: 			return;
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 		// TODO: clarify the event order
b6daa1efa1 2012-07-14        kinaba: 		Tuple!(int,bool) ld = map.command(c);
b6daa1efa1 2012-07-14        kinaba: 		if( map.cleared() ) {
b6daa1efa1 2012-07-14        kinaba: 			exit_bonus = 2;
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 		else {
b6daa1efa1 2012-07-14        kinaba: 			lambda += ld[0];
b6daa1efa1 2012-07-14        kinaba: 			if( ld[1] ) {
b6daa1efa1 2012-07-14        kinaba: 				dead = true;
b6daa1efa1 2012-07-14        kinaba: 			}
b6daa1efa1 2012-07-14        kinaba: 		}
b6daa1efa1 2012-07-14        kinaba: 		if( map.robot.y <= water_level )
a5e6c99b3d 2012-07-14        kinaba: 			++under_water;
b6daa1efa1 2012-07-14        kinaba: 		else
a5e6c99b3d 2012-07-14        kinaba: 			under_water = 0;
a5e6c99b3d 2012-07-14        kinaba: 		if( under_water > map.waterproof )
b6daa1efa1 2012-07-14        kinaba: 			dead = true;
b6daa1efa1 2012-07-14        kinaba: 		turn += 1;
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	Map map;
b6daa1efa1 2012-07-14        kinaba: 	Water water;
b6daa1efa1 2012-07-14        kinaba: 	Output output;
b6daa1efa1 2012-07-14        kinaba: 	int  turn = 0;
b6daa1efa1 2012-07-14        kinaba: 	bool dead = false;
b6daa1efa1 2012-07-14        kinaba: 	int  lambda = 0;
b6daa1efa1 2012-07-14        kinaba: 	int  exit_bonus = 0;
a5e6c99b3d 2012-07-14        kinaba: 	int  under_water = 0;
a5e6c99b3d 2012-07-14        kinaba: 	// TODO: when adding members, take care of clone().
a5e6c99b3d 2012-07-14        kinaba: 	// TODO: fix this poor design.
a5e6c99b3d 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: 	@property {
3e342af26c 2012-07-14        kinaba: 		long score() { return lambda*25L*(1+exit_bonus) - turn; }
b6daa1efa1 2012-07-14        kinaba: 		int water_level() { return water.level(turn); }
b6daa1efa1 2012-07-14        kinaba: 		int water_until_rise() { return water.until_rise(turn); }
b6daa1efa1 2012-07-14        kinaba: 		bool cleared() { return exit_bonus>0; }
a5e6c99b3d 2012-07-14        kinaba: 		int hp() { return map.waterproof - under_water; }
3e342af26c 2012-07-14        kinaba: 		long score_if_abort_now() { return lambda*25*(1+max(1,exit_bonus)) - turn; }
b6daa1efa1 2012-07-14        kinaba: 	}
b6daa1efa1 2012-07-14        kinaba: }
b6daa1efa1 2012-07-14        kinaba: 
b6daa1efa1 2012-07-14        kinaba: unittest
b6daa1efa1 2012-07-14        kinaba: {
b6daa1efa1 2012-07-14        kinaba: 	Game.load(["###","...","#RL"], ["xxx":"yyy"]);
b6daa1efa1 2012-07-14        kinaba: }