File Annotation
Not logged in
6293256fec 2012-07-14        kinaba: import util;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: class Pos
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	public immutable int y, x;
6293256fec 2012-07-14        kinaba: 	mixin DeriveCreate;
6293256fec 2012-07-14        kinaba: 	mixin DeriveCompare;
6293256fec 2012-07-14        kinaba: 	mixin DeriveShow;
a0c3529225 2012-07-14        kinaba: 	Pos clone() const { return cast(Pos) this; }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: @property:
bee0596f0f 2012-07-14        kinaba: 	Pos wait()  { return this.clone(); }
6293256fec 2012-07-14        kinaba: 	Pos up()    { return new Pos(y+1, x); }
6293256fec 2012-07-14        kinaba: 	Pos down()  { return new Pos(y-1, x); }
6293256fec 2012-07-14        kinaba: 	Pos left()  { return new Pos(y, x-1); }
6293256fec 2012-07-14        kinaba: 	Pos right() { return new Pos(y, x+1); }
6293256fec 2012-07-14        kinaba: 	alias wait  W,w;
6293256fec 2012-07-14        kinaba: 	alias up    U,u;
6293256fec 2012-07-14        kinaba: 	alias down  D,d;
6293256fec 2012-07-14        kinaba: 	alias left  L,l;
6293256fec 2012-07-14        kinaba: 	alias right R,r;
6293256fec 2012-07-14        kinaba: }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: unittest
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	assert( (new Pos(2,1)).U == new Pos(3,1) );
6293256fec 2012-07-14        kinaba: 	assert( (new Pos(0,1)).D == new Pos(-1,1) );
6293256fec 2012-07-14        kinaba: 	assert( (new Pos(2,1)).L == new Pos(2,0) );
6293256fec 2012-07-14        kinaba: 	assert( (new Pos(2,1)).R == new Pos(2,2) );
6293256fec 2012-07-14        kinaba: 	int[Pos] aa;
6293256fec 2012-07-14        kinaba: 	aa[new Pos(1,2)] = 1;
6293256fec 2012-07-14        kinaba: 	aa[new Pos(1,2)] = 2;
6293256fec 2012-07-14        kinaba: 	aa[new Pos(2,1)] = 3;
6293256fec 2012-07-14        kinaba: 	assert( aa.length==2 );
6293256fec 2012-07-14        kinaba: 	assert( aa[new Pos(1,2)]==2 );
6293256fec 2012-07-14        kinaba: }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: class Water
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	public immutable int base, pace;
6293256fec 2012-07-14        kinaba: 	mixin DeriveCreate;
6293256fec 2012-07-14        kinaba: 	mixin DeriveCompare;
6293256fec 2012-07-14        kinaba: 	mixin DeriveShow;
a0c3529225 2012-07-14        kinaba: 	Water clone() const { return cast(Water)this; }
6293256fec 2012-07-14        kinaba: 
b1ce0206cd 2012-07-14        kinaba: 	static load(string[string] params)
6293256fec 2012-07-14        kinaba: 	{
4aa9d7f484 2012-07-15        kinaba: 		return new Water(params.get("Water",    "0").to!int(),
4aa9d7f484 2012-07-15        kinaba: 		                 params.get("Flooding", "0").to!int());
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	int level(int number_of_update) const
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		return pace ? base+(number_of_update/pace) : base;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	int until_rise(int number_of_update) const
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		return pace ? pace-number_of_update%pace : int.max;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: unittest
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	Water w = new Water(1, 3);
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(0) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(1) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(2) );
6293256fec 2012-07-14        kinaba: 	assert( 2 == w.level(3) );
6293256fec 2012-07-14        kinaba: 	assert( 2 == w.level(4) );
6293256fec 2012-07-14        kinaba: 	assert( 2 == w.level(5) );
6293256fec 2012-07-14        kinaba: 	assert( 3 == w.level(6) );
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	w = new Water(1, 0);
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(0) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(1) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(2) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(3) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(4) );
6293256fec 2012-07-14        kinaba: 	assert( 1 == w.level(5) );
6293256fec 2012-07-14        kinaba: }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
6293256fec 2012-07-14        kinaba: 
9d983af88c 2012-07-15        kinaba: class Hige
9d983af88c 2012-07-15        kinaba: {
9d983af88c 2012-07-15        kinaba: 	public immutable int pace;
9d983af88c 2012-07-15        kinaba: 	mixin DeriveCreate;
9d983af88c 2012-07-15        kinaba: 	mixin DeriveCompare;
9d983af88c 2012-07-15        kinaba: 	mixin DeriveShow;
9d983af88c 2012-07-15        kinaba: 	Hige clone() const { return cast(Hige)this; }
9d983af88c 2012-07-15        kinaba: 
9d983af88c 2012-07-15        kinaba: 	static load(string[string] params)
9d983af88c 2012-07-15        kinaba: 	{
9d983af88c 2012-07-15        kinaba: 		return new Hige(params.get("Growth", "25").to!int());
9d983af88c 2012-07-15        kinaba: 	}
9d983af88c 2012-07-15        kinaba: 
9d983af88c 2012-07-15        kinaba: 	bool is_growing_turn(int turn) const
9d983af88c 2012-07-15        kinaba: 	{
9d983af88c 2012-07-15        kinaba: 		return pace ? turn%pace == pace-1 : false;
9d983af88c 2012-07-15        kinaba: 	}
9d983af88c 2012-07-15        kinaba: 
9d983af88c 2012-07-15        kinaba: 	int until_rise(int turn) const
9d983af88c 2012-07-15        kinaba: 	{
9d983af88c 2012-07-15        kinaba: 		return pace ? pace-turn%pace : int.max;
9d983af88c 2012-07-15        kinaba: 	}
9d983af88c 2012-07-15        kinaba: }
9d983af88c 2012-07-15        kinaba: 
9d983af88c 2012-07-15        kinaba: ////////////////////////////////////////////////////////////////////////////////
9d983af88c 2012-07-15        kinaba: 
6293256fec 2012-07-14        kinaba: class Map
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	mixin DeriveShow;
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 	static Map load(string[] raw_data, string[string] params, char[char] trampo)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		// TODO: choose optimal representation.
b8acb5f918 2012-07-14        kinaba: 		return new Map(raw_data, params, trampo);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	char[][] data;
6293256fec 2012-07-14        kinaba: 	Pos robot;
6293256fec 2012-07-14        kinaba: 	Pos lift;
6293256fec 2012-07-14        kinaba: 	int waterproof;
b8acb5f918 2012-07-14        kinaba: 	Pos[char] tr_target;
b8acb5f918 2012-07-14        kinaba: 	Pos[][char] tr_source;
9d983af88c 2012-07-15        kinaba: 	const(Hige) hige;
9d983af88c 2012-07-15        kinaba: 	int razor;
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	Map clone() const { return new Map(this); }
a0c3529225 2012-07-14        kinaba: 	this(in Map m) {
6293256fec 2012-07-14        kinaba: 		foreach(s; m.data)
6293256fec 2012-07-14        kinaba: 			this.data ~= s.dup;
6293256fec 2012-07-14        kinaba: 		this.robot = m.robot.clone();
6293256fec 2012-07-14        kinaba: 		this.lift = m.lift.clone();
6293256fec 2012-07-14        kinaba: 		this.waterproof = m.waterproof;
deca17f61a 2012-07-14        kinaba: 		this.tr_target = cast(Pos[char])m.tr_target;
deca17f61a 2012-07-14        kinaba: 		this.tr_source = cast(Pos[][char])m.tr_source;
9d983af88c 2012-07-15        kinaba: 		this.hige = m.hige.clone();
9d983af88c 2012-07-15        kinaba: 		this.razor = m.razor;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 	this(string[] raw_data, string[string] params, char[char] trampo)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		int width = 0;
6293256fec 2012-07-14        kinaba: 		foreach(r; raw_data)
6293256fec 2012-07-14        kinaba: 			width = max(width, r.length);
6293256fec 2012-07-14        kinaba: 		foreach(r; raw_data) {
6293256fec 2012-07-14        kinaba: 			this.data ~= r.dup;
6293256fec 2012-07-14        kinaba: 			this.data[$-1].length = width;
6293256fec 2012-07-14        kinaba: 			this.data[$-1][r.length..$] = ' ';
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
6293256fec 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x) {
6293256fec 2012-07-14        kinaba: 			if(this[y,x] == 'R')
6293256fec 2012-07-14        kinaba: 				this.robot = new Pos(y,x);
6293256fec 2012-07-14        kinaba: 			if(this[y,x] == 'L' || this[y,x] == 'O')
6293256fec 2012-07-14        kinaba: 				this.lift = new Pos(y,x);
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 		Pos[char] tr_pos;
b8acb5f918 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
b8acb5f918 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x) {
b8acb5f918 2012-07-14        kinaba: 			char c = this[y,x];
b8acb5f918 2012-07-14        kinaba: 			if('1'<=c && c<='9' || 'A'<=c&&c<='I')
b8acb5f918 2012-07-14        kinaba: 				tr_pos[c] = new Pos(y,x);
b8acb5f918 2012-07-14        kinaba: 		}
b8acb5f918 2012-07-14        kinaba: 
b1ce0206cd 2012-07-14        kinaba: 		this.waterproof = params.get("Waterproof", "5").to!int();
b8acb5f918 2012-07-14        kinaba: 		foreach(fr,to; trampo) {
b8acb5f918 2012-07-14        kinaba: 			tr_target[fr] = tr_pos[to];
b8acb5f918 2012-07-14        kinaba: 			if(to !in tr_source) tr_source[to] = [];
deca17f61a 2012-07-14        kinaba: 			tr_source[to] ~= tr_pos[fr];
b8acb5f918 2012-07-14        kinaba: 		}
9d983af88c 2012-07-15        kinaba: 
9d983af88c 2012-07-15        kinaba: 		this.hige = Hige.load(params);
9d983af88c 2012-07-15        kinaba: 		this.razor = params.get("Razors", "0").to!int();
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	const @property {
6293256fec 2012-07-14        kinaba: 		int H() { return data.length; }
6293256fec 2012-07-14        kinaba: 		int W() { return data[0].length; }
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	const {
bee0596f0f 2012-07-14        kinaba: 		char opIndex(int y, int x)
bee0596f0f 2012-07-14        kinaba: 		{
bee0596f0f 2012-07-14        kinaba: 			// Adjust coordinate to the spec. bottom-left is (1,1).
bee0596f0f 2012-07-14        kinaba: 			--y, --x;
bee0596f0f 2012-07-14        kinaba: 			if(y<0||H<=y||x<0||W<=x)
bee0596f0f 2012-07-14        kinaba: 				return '#';
bee0596f0f 2012-07-14        kinaba: 			return data[H-1-y][x];
bee0596f0f 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
62a5c6c47f 2012-07-14        kinaba: 		char opIndex(in Pos p)
bee0596f0f 2012-07-14        kinaba: 		{
bee0596f0f 2012-07-14        kinaba: 			return this[p.y, p.x];
bee0596f0f 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	void opIndexAssign(char c, int y, int x)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		// Adjust coordinate to the spec. bottom-left is (1,1).
6293256fec 2012-07-14        kinaba: 		--y, --x;
6293256fec 2012-07-14        kinaba: 		if(y<0||H<=y||x<0||W<=x)
6293256fec 2012-07-14        kinaba: 			return;
6293256fec 2012-07-14        kinaba: 		data[H-1-y][x] = c;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
62a5c6c47f 2012-07-14        kinaba: 	void opIndexAssign(char c, in Pos p)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		this[p.y, p.x] = c;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
34bbd14c1a 2012-07-15        kinaba: 	Pos[] objects(char c) const {
6293256fec 2012-07-14        kinaba: 		Pos[] ans;
6293256fec 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
6293256fec 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x)
34bbd14c1a 2012-07-15        kinaba: 			if(this[y,x] == c)
6293256fec 2012-07-14        kinaba: 				ans ~= new Pos(y,x);
6293256fec 2012-07-14        kinaba: 		return ans;
6293256fec 2012-07-14        kinaba: 	}
34bbd14c1a 2012-07-15        kinaba: 
34bbd14c1a 2012-07-15        kinaba: 	Pos[] razors() const { return objects('!'); }
34bbd14c1a 2012-07-15        kinaba: 	Pos[] lambdas() const { return objects('\\'); }
9d4aca73fa 2012-07-14        kinaba: 
9d4aca73fa 2012-07-14        kinaba: 	bool cleared() const
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
6293256fec 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x)
6293256fec 2012-07-14        kinaba: 			if(this[y,x] == 'L' || this[y,x] == 'O')
6293256fec 2012-07-14        kinaba: 				return false;
6293256fec 2012-07-14        kinaba: 		return true;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
2b4f8bba2d 2012-07-15        kinaba: 	Tuple!(int,bool) command(char c, int turn)
6293256fec 2012-07-14        kinaba: 	{
3a08e528e7 2012-07-15        kinaba: 		assert( this[robot] == 'R' );
2b4f8bba2d 2012-07-15        kinaba: 		if(c=='R') return move( 0, +1, turn);
2b4f8bba2d 2012-07-15        kinaba: 		if(c=='L') return move( 0, -1, turn);
2b4f8bba2d 2012-07-15        kinaba: 		if(c=='U') return move(+1,  0, turn);
2b4f8bba2d 2012-07-15        kinaba: 		if(c=='D') return move(-1,  0, turn);
2b4f8bba2d 2012-07-15        kinaba: 		if(c=='W') return move( 0,  0, turn);
3a08e528e7 2012-07-15        kinaba: 		if(c=='S') return use_razor(turn);
6293256fec 2012-07-14        kinaba: 		assert(false);
3a08e528e7 2012-07-15        kinaba: 	}
3a08e528e7 2012-07-15        kinaba: 
3a08e528e7 2012-07-15        kinaba: 	Tuple!(int, bool) use_razor(int turn)
3a08e528e7 2012-07-15        kinaba: 	{
3a08e528e7 2012-07-15        kinaba: 		if(razor) {
3a08e528e7 2012-07-15        kinaba: 			razor--;
3a08e528e7 2012-07-15        kinaba: 			for(int dy=-1; dy<=+1; ++dy)
3a08e528e7 2012-07-15        kinaba: 			for(int dx=-1; dx<=+1; ++dx)
3a08e528e7 2012-07-15        kinaba: 				if(this[robot.y+dy,robot.x+dx] == 'W')
3a08e528e7 2012-07-15        kinaba: 					this[robot.y+dy,robot.x+dx] = ' ';
3a08e528e7 2012-07-15        kinaba: 		}
3a08e528e7 2012-07-15        kinaba: 
3a08e528e7 2012-07-15        kinaba: 		bool dead = update(turn);
3a08e528e7 2012-07-15        kinaba: 		return tuple(0,dead);
2b4f8bba2d 2012-07-15        kinaba: 	}
2b4f8bba2d 2012-07-15        kinaba: 
2b4f8bba2d 2012-07-15        kinaba: 	Tuple!(int, bool) move(int dy, int dx, int turn)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		int y = robot.y;
6293256fec 2012-07-14        kinaba: 		int x = robot.x;
6293256fec 2012-07-14        kinaba: 		int lambda = 0;
6293256fec 2012-07-14        kinaba: 		if( '\\' == this[y+dy,x+dx] )
6293256fec 2012-07-14        kinaba: 			lambda++;
41c73506fb 2012-07-15        kinaba: 		if( '!' == this[y+dy,x+dx] )
41c73506fb 2012-07-15        kinaba: 			razor++;
41c73506fb 2012-07-15        kinaba: 		if( " \\!.O".count(this[y+dy,x+dx])==1 ) {
6293256fec 2012-07-14        kinaba: 			this[y,x]=' ';
6293256fec 2012-07-14        kinaba: 			this[y+dy,x+dx]='R';
6293256fec 2012-07-14        kinaba: 			robot = new Pos(y+dy,x+dx);
6293256fec 2012-07-14        kinaba: 		} else if(dy==0 && '*'==this[y+dy,x+dx] && ' '==this[y+dy*2,x+dx*2]) {
6293256fec 2012-07-14        kinaba: 			this[y,x]=' ';
6293256fec 2012-07-14        kinaba: 			this[y+dy,x+dx]='R';
6293256fec 2012-07-14        kinaba: 			this[y+dy*2,x+dx*2]='*';
6293256fec 2012-07-14        kinaba: 			robot = new Pos(y+dy,x+dx);
deca17f61a 2012-07-14        kinaba: 		} else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') {
deca17f61a 2012-07-14        kinaba: 			this[y,x]=' ';
deca17f61a 2012-07-14        kinaba: 			Pos tp = tr_target[this[y+dy,x+dx]];
deca17f61a 2012-07-14        kinaba: 			foreach(p; tr_source[this[tp]])
deca17f61a 2012-07-14        kinaba: 				this[p] = ' ';
deca17f61a 2012-07-14        kinaba: 			this[tp] = 'R';
deca17f61a 2012-07-14        kinaba: 			robot = tp;
6293256fec 2012-07-14        kinaba: 		}
3a08e528e7 2012-07-15        kinaba: 		bool dead = update(turn);
6293256fec 2012-07-14        kinaba: 		return tuple(lambda,dead);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
2b4f8bba2d 2012-07-15        kinaba: 	bool update(int turn)
6293256fec 2012-07-14        kinaba: 	{
6293256fec 2012-07-14        kinaba: 		bool dead = false;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		char[][] next;
6293256fec 2012-07-14        kinaba: 		foreach(y,s; data)
6293256fec 2012-07-14        kinaba: 			next ~= s.dup;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		ref char access(Pos p) { return next[H-p.y][p.x-1]; }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		bool lambda = false;
6293256fec 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
6293256fec 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x)
6293256fec 2012-07-14        kinaba: 			lambda |= (this[y,x] == '\\');
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		for(int y=1; y<=H; ++y)
6293256fec 2012-07-14        kinaba: 		for(int x=1; x<=W; ++x) {
6293256fec 2012-07-14        kinaba: 			Pos p = new Pos(y,x);
6293256fec 2012-07-14        kinaba: 			if(this[p]=='*') {
6293256fec 2012-07-14        kinaba: 				if(this[p.D]==' ') {
6293256fec 2012-07-14        kinaba: 					access(p)  =' ';
6293256fec 2012-07-14        kinaba: 					access(p.D)='*';
6293256fec 2012-07-14        kinaba: 					if(robot == p.D.D)
6293256fec 2012-07-14        kinaba: 						dead=true;
6293256fec 2012-07-14        kinaba: 				}
6293256fec 2012-07-14        kinaba: 				else if((this[p.D]=='*' || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') {
6293256fec 2012-07-14        kinaba: 					access(p)=' ';
6293256fec 2012-07-14        kinaba: 					access(p.R.D)='*';
6293256fec 2012-07-14        kinaba: 					if(robot == p.R.D.D)
6293256fec 2012-07-14        kinaba: 						dead=true;
6293256fec 2012-07-14        kinaba: 				}
6293256fec 2012-07-14        kinaba: 				else if(this[p.D]=='*' && this[p.L]==' ' && this[p.L.D]==' ') {
6293256fec 2012-07-14        kinaba: 					access(p)=' ';
6293256fec 2012-07-14        kinaba: 					access(p.L.D)='*';
6293256fec 2012-07-14        kinaba: 					if(robot == p.L.D.D)
6293256fec 2012-07-14        kinaba: 						dead=true;
6293256fec 2012-07-14        kinaba: 				}
6293256fec 2012-07-14        kinaba: 			}
6293256fec 2012-07-14        kinaba: 			else if(this[p]=='L') {
6293256fec 2012-07-14        kinaba: 				if(!lambda)
6293256fec 2012-07-14        kinaba: 					access(p) = 'O';
6293256fec 2012-07-14        kinaba: 			}
2b4f8bba2d 2012-07-15        kinaba: 			else if(this[p]=='W') {
2b4f8bba2d 2012-07-15        kinaba: 				if( hige.is_growing_turn(turn) )
2b4f8bba2d 2012-07-15        kinaba: 					for(int dy=-1; dy<=+1; ++dy)
2b4f8bba2d 2012-07-15        kinaba: 					for(int dx=-1; dx<=+1; ++dx)
2b4f8bba2d 2012-07-15        kinaba: 						if(this[p.y+dy,p.x+dx] == ' ')
2b4f8bba2d 2012-07-15        kinaba: 							access(new Pos(p.y+dy,p.x+dx)) = 'W';
2b4f8bba2d 2012-07-15        kinaba: 			}
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 		data = next;
6293256fec 2012-07-14        kinaba: 		return dead;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: }
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
ff0ab77d3d 2012-07-15        kinaba: /*
6293256fec 2012-07-14        kinaba: class Game
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	mixin DeriveShow;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	static Game load(File input)
6293256fec 2012-07-14        kinaba: 	{
b1ce0206cd 2012-07-14        kinaba: 		string[]       raw_data;
b1ce0206cd 2012-07-14        kinaba: 		string[string] params;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		// Raw map data; read until empty line.
6293256fec 2012-07-14        kinaba: 		for(string line; !(line=input.readln().chomp()).empty; )
6293256fec 2012-07-14        kinaba: 			raw_data ~= line;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		// Additional commands; read until EOF.
b8acb5f918 2012-07-14        kinaba: 		char[char] trampo;
6293256fec 2012-07-14        kinaba: 		for(string line; !(line=input.readln()).empty; ) {
6293256fec 2012-07-14        kinaba: 			string[] ss = line.split();
b1ce0206cd 2012-07-14        kinaba: 			if( ss.length == 2 )
b1ce0206cd 2012-07-14        kinaba: 				params[ss[0]] = ss[1];
b8acb5f918 2012-07-14        kinaba: 			if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" )
b8acb5f918 2012-07-14        kinaba: 				trampo[ss[1][0]] = ss[3][0];
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 		return load(raw_data, params, trampo);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 	static Game load(string[] raw_data, string[string] params, char[char] trampo = null)
6293256fec 2012-07-14        kinaba: 	{
b8acb5f918 2012-07-14        kinaba: 		return new Game(raw_data, params, trampo);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
b8acb5f918 2012-07-14        kinaba: 	this(string[] raw_data, string[string] params, char[char] trampo)
6293256fec 2012-07-14        kinaba: 	{
b8acb5f918 2012-07-14        kinaba: 		this.map = Map.load(raw_data, params, trampo);
6293256fec 2012-07-14        kinaba: 		this.water = Water.load(params);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	Game clone() const { return new Game(this); }
a0c3529225 2012-07-14        kinaba: 	this(in Game g) {
6293256fec 2012-07-14        kinaba: 		map = g.map.clone();
6293256fec 2012-07-14        kinaba: 		water = g.water.clone();
6293256fec 2012-07-14        kinaba: 		turn = g.turn;
6293256fec 2012-07-14        kinaba: 		dead = g.dead;
6293256fec 2012-07-14        kinaba: 		lambda = g.lambda;
879099f815 2012-07-15        kinaba: 		cleared = g.cleared;
6293256fec 2012-07-14        kinaba: 		under_water = g.under_water;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	void command(char c)
6293256fec 2012-07-14        kinaba: 	{
879099f815 2012-07-15        kinaba: 		assert(c != 'A');
6293256fec 2012-07-14        kinaba: 		if(dead || cleared)
6293256fec 2012-07-14        kinaba: 			return;
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 		// TODO: clarify the event order
2b4f8bba2d 2012-07-15        kinaba: 		Tuple!(int,bool) ld = map.command(c, turn);
6293256fec 2012-07-14        kinaba: 		if( map.cleared() ) {
879099f815 2012-07-15        kinaba: 			cleared = true;
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 		else {
6293256fec 2012-07-14        kinaba: 			lambda += ld[0];
879099f815 2012-07-15        kinaba: 			if( ld[1] )
879099f815 2012-07-15        kinaba: 				dead = true;
879099f815 2012-07-15        kinaba: 		}
6d497011d6 2012-07-15        kinaba: 		if(!cleared) {
6d497011d6 2012-07-15        kinaba: 			if( map.robot.y <= water_level )
6d497011d6 2012-07-15        kinaba: 				++under_water;
6d497011d6 2012-07-15        kinaba: 			else
6d497011d6 2012-07-15        kinaba: 				under_water = 0;
6d497011d6 2012-07-15        kinaba: 			if( under_water > map.waterproof )
6d497011d6 2012-07-15        kinaba: 				dead = true;
6d497011d6 2012-07-15        kinaba: 		}
6293256fec 2012-07-14        kinaba: 		turn += 1;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
6293256fec 2012-07-14        kinaba: 	Map map;
6293256fec 2012-07-14        kinaba: 	Water water;
6293256fec 2012-07-14        kinaba: 	int  turn = 0;
6293256fec 2012-07-14        kinaba: 	bool dead = false;
6293256fec 2012-07-14        kinaba: 	int  lambda = 0;
6293256fec 2012-07-14        kinaba: 	int  under_water = 0;
879099f815 2012-07-15        kinaba: 	bool cleared = false;
6293256fec 2012-07-14        kinaba: 	// TODO: when adding members, take care of clone().
6293256fec 2012-07-14        kinaba: 	// TODO: fix this poor design.
6293256fec 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: 	@property const {
879099f815 2012-07-15        kinaba: 		long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L) - turn; }
6293256fec 2012-07-14        kinaba: 		int water_level() { return water.level(turn); }
6293256fec 2012-07-14        kinaba: 		int water_until_rise() { return water.until_rise(turn); }
9d983af88c 2012-07-15        kinaba: 		int hige_until_rise() { return map.hige.until_rise(turn); }
6293256fec 2012-07-14        kinaba: 		int hp() { return map.waterproof - under_water; }
879099f815 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: }
ff0ab77d3d 2012-07-15        kinaba: */
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: ////////////////////////////////////////////////////////////////////////////////
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: class Game
ff0ab77d3d 2012-07-15        kinaba: {
ff0ab77d3d 2012-07-15        kinaba: public:
ff0ab77d3d 2012-07-15        kinaba: 	this(File input)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		// Read map data
ff0ab77d3d 2012-07-15        kinaba: 		string[] map_data_lines;
ff0ab77d3d 2012-07-15        kinaba: 		for(string line; !(line=input.readln().chomp()).empty; )
ff0ab77d3d 2012-07-15        kinaba: 			map_data_lines ~= line;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		// H*W
ff0ab77d3d 2012-07-15        kinaba: 		H_ = map_data_lines.length;
ff0ab77d3d 2012-07-15        kinaba: 		W_ = 0;
ff0ab77d3d 2012-07-15        kinaba: 		foreach(mdl; map_data_lines)
ff0ab77d3d 2012-07-15        kinaba: 			W_ = max(W_, mdl.length);
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		// Copy to modifiable buffer and adjust coordinates.
ff0ab77d3d 2012-07-15        kinaba: 		raw_data_ = new char[][H_+1];
ff0ab77d3d 2012-07-15        kinaba: 		foreach(i,mdl; map_data_lines) {
ff0ab77d3d 2012-07-15        kinaba: 			char[] buf = new char[mdl.length+1];
ff0ab77d3d 2012-07-15        kinaba: 			buf[0] = '#';
ff0ab77d3d 2012-07-15        kinaba: 			buf[1..$] = mdl[];
ff0ab77d3d 2012-07-15        kinaba: 			raw_data_[H_-i] = buf;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		// Detect objects
ff0ab77d3d 2012-07-15        kinaba: 		for(int y=1; y<=H_; ++y)
ff0ab77d3d 2012-07-15        kinaba: 		for(int x=1; x<raw_data_[y].length; ++x)
ff0ab77d3d 2012-07-15        kinaba: 		{
ff0ab77d3d 2012-07-15        kinaba: 			char c = raw_data_[y][x];
ff0ab77d3d 2012-07-15        kinaba: 			switch(c)
ff0ab77d3d 2012-07-15        kinaba: 			{
ff0ab77d3d 2012-07-15        kinaba: 			case '#':
ff0ab77d3d 2012-07-15        kinaba: 			case '.':
ff0ab77d3d 2012-07-15        kinaba: 			case ' ':
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			case 'L':
ff0ab77d3d 2012-07-15        kinaba: 			case 'O':
ff0ab77d3d 2012-07-15        kinaba: 				lift_pos_ = new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			case 'A': .. case 'I':
ff0ab77d3d 2012-07-15        kinaba: 			case '1': .. case '9':
ff0ab77d3d 2012-07-15        kinaba: 				trampoline_pos_[c] = new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			case '!':
ff0ab77d3d 2012-07-15        kinaba: 				razor_pos_ ~= new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			case '\\':
ff0ab77d3d 2012-07-15        kinaba: 				lambda_pos_ ~= new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 			// Moving objects are erased from raw_data_
ff0ab77d3d 2012-07-15        kinaba: 			case 'R':
ff0ab77d3d 2012-07-15        kinaba: 				robot_pos_ = new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 				raw_data_[y][x] = ' ';
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			case '*':
ff0ab77d3d 2012-07-15        kinaba: 			case 'W':
ff0ab77d3d 2012-07-15        kinaba: 				dynamic_objects_[new Pos(y,x)] = c;
ff0ab77d3d 2012-07-15        kinaba: 				raw_data_[y][x] = ' ';
ff0ab77d3d 2012-07-15        kinaba: 				if(c=='*')
ff0ab77d3d 2012-07-15        kinaba: 					may_update_[new Pos(y,x)] = true;
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			default:
ff0ab77d3d 2012-07-15        kinaba: 				assert(false);
ff0ab77d3d 2012-07-15        kinaba: 			}
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		// Read other parameters
ff0ab77d3d 2012-07-15        kinaba: 		for(string line; !(line=input.readln()).empty; )
ff0ab77d3d 2012-07-15        kinaba: 		{
ff0ab77d3d 2012-07-15        kinaba: 			string[] ss = line.split();
ff0ab77d3d 2012-07-15        kinaba: 			if( ss.length == 2 )
ff0ab77d3d 2012-07-15        kinaba: 				switch(ss[0])
ff0ab77d3d 2012-07-15        kinaba: 				{
ff0ab77d3d 2012-07-15        kinaba: 				case "Water":      water_base_ = ss[1].to!int(); break;
ff0ab77d3d 2012-07-15        kinaba: 				case "Flooding":   water_pace_ = ss[1].to!int(); break;
ff0ab77d3d 2012-07-15        kinaba: 				case "Waterproof": max_air_    = ss[1].to!int(); break;
ff0ab77d3d 2012-07-15        kinaba: 				case "Growth":     hige_pace_  = ss[1].to!int(); break;
ff0ab77d3d 2012-07-15        kinaba: 				case "Razors":     num_razor_  = ss[1].to!int(); break;
ff0ab77d3d 2012-07-15        kinaba: 				default: assert(false);
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 			if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" )
ff0ab77d3d 2012-07-15        kinaba: 			{
ff0ab77d3d 2012-07-15        kinaba: 				char fr=ss[1][0], to=ss[3][0];
ff0ab77d3d 2012-07-15        kinaba: 				trampoline_[fr] = to;
ff0ab77d3d 2012-07-15        kinaba: 				if(to !in trampoline_rev_) trampoline_rev_[to] = [];
ff0ab77d3d 2012-07-15        kinaba: 				trampoline_rev_[to] ~= fr;
ff0ab77d3d 2012-07-15        kinaba: 			}
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		air_left_ = max_air_;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	@property const {
ff0ab77d3d 2012-07-15        kinaba: 		int H() { return H_; }
ff0ab77d3d 2012-07-15        kinaba: 		int W() { return W_; }
ff0ab77d3d 2012-07-15        kinaba: 		char trampoline(char c) { return (c in trampoline_ ? trampoline_[c] : 0); }
a03584f1c6 2012-07-15        kinaba: 		const(Pos)[] trampoline_rev(char c) {
a03584f1c6 2012-07-15        kinaba: 			const(Pos)[] pp;
a03584f1c6 2012-07-15        kinaba: 			if(c in trampoline_rev_) {
a03584f1c6 2012-07-15        kinaba: 				foreach(ch; trampoline_rev_[c])
a03584f1c6 2012-07-15        kinaba: 					pp ~= trampoline_pos_[ch];
a03584f1c6 2012-07-15        kinaba: 			}
a03584f1c6 2012-07-15        kinaba: 			return pp;
a03584f1c6 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		int water_level() {
ff0ab77d3d 2012-07-15        kinaba: 			return water_pace_ ? water_base_ + turn_/water_pace_ : water_base_;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		int water_until_rise() {
ff0ab77d3d 2012-07-15        kinaba: 			return water_pace_ ? water_pace_ - turn_%water_pace_ : int.max;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		int hige_until_rise() {
ff0ab77d3d 2012-07-15        kinaba: 			return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.max;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		bool is_hige_turn() {
ff0ab77d3d 2012-07-15        kinaba: 			return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : false;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		int hp() { return air_left_; }
ff0ab77d3d 2012-07-15        kinaba: 		int num_razor() { return num_razor_; }
ff0ab77d3d 2012-07-15        kinaba: 		bool cleared() { return cleared_; }
ff0ab77d3d 2012-07-15        kinaba: 		bool dead() { return dead_; }
ff0ab77d3d 2012-07-15        kinaba: 		long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L : 50L) - turn_; }
a03584f1c6 2012-07-15        kinaba: 		const(Pos) robot() { return robot_pos_; }
a03584f1c6 2012-07-15        kinaba: 		const(Pos) lift() { return lift_pos_; }
a03584f1c6 2012-07-15        kinaba: 		Pos[] lambdas() {
a03584f1c6 2012-07-15        kinaba: 			Pos[] pp;
a03584f1c6 2012-07-15        kinaba: 			foreach(p; lambda_pos_)
a03584f1c6 2012-07-15        kinaba: 				pp ~= p.clone();
a03584f1c6 2012-07-15        kinaba: 			return pp;
a03584f1c6 2012-07-15        kinaba: 		}
a03584f1c6 2012-07-15        kinaba: 		Pos[] razors() {
a03584f1c6 2012-07-15        kinaba: 			Pos[] pp;
a03584f1c6 2012-07-15        kinaba: 			foreach(p; razor_pos_)
a03584f1c6 2012-07-15        kinaba: 				pp ~= p.clone();
a03584f1c6 2012-07-15        kinaba: 			return pp;
a03584f1c6 2012-07-15        kinaba: 		}
a03584f1c6 2012-07-15        kinaba: 		const(Pos)[] higes() {
a03584f1c6 2012-07-15        kinaba: 			const(Pos)[] pp;
a03584f1c6 2012-07-15        kinaba: 			foreach(p,c; dynamic_objects_)
a03584f1c6 2012-07-15        kinaba: 				if(c=='W')
a03584f1c6 2012-07-15        kinaba: 					pp ~= p;
a03584f1c6 2012-07-15        kinaba: 			return pp;
a03584f1c6 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 	const {
ff0ab77d3d 2012-07-15        kinaba: 		char opIndex(in Pos p) { return opIndex(p.y, p.x); }
ff0ab77d3d 2012-07-15        kinaba: 		char opIndex(int y, int x) { return map_get(y, x); }
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: public:
ff0ab77d3d 2012-07-15        kinaba: 	void command(char c)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		if(dead || cleared)
ff0ab77d3d 2012-07-15        kinaba: 			return;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'U') command_move(+1, 0);
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'D') command_move(-1, 0);
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'L') command_move(0, -1);
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'R') command_move(0, +1);
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'S') use_razor();
ff0ab77d3d 2012-07-15        kinaba: 		if(c == 'W') {}
ff0ab77d3d 2012-07-15        kinaba: 
a03584f1c6 2012-07-15        kinaba: 		if(!cleared)
a03584f1c6 2012-07-15        kinaba: 		{
a03584f1c6 2012-07-15        kinaba: 			map_update();
a03584f1c6 2012-07-15        kinaba: 			water_update();
a03584f1c6 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		turn_ ++;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void command_move(int dy, int dx)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		int y = robot_pos_.y, x = robot_pos_.x;
ff0ab77d3d 2012-07-15        kinaba: 		char c = this[y+dy, x+dx];
ff0ab77d3d 2012-07-15        kinaba: 		Pos p = new Pos(y+dy, x+dx);
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		switch(c){
ff0ab77d3d 2012-07-15        kinaba: 		case 'O':
ff0ab77d3d 2012-07-15        kinaba: 			cleared_ = true;
ff0ab77d3d 2012-07-15        kinaba: 			move_robot_to(p);
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		case '\\':
ff0ab77d3d 2012-07-15        kinaba: 			take_lambda_at(p);
ff0ab77d3d 2012-07-15        kinaba: 			move_robot_to(p);
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		case '!':
ff0ab77d3d 2012-07-15        kinaba: 			take_razor_at(p);
ff0ab77d3d 2012-07-15        kinaba: 			move_robot_to(p);
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		case 'A': .. case 'I':
ff0ab77d3d 2012-07-15        kinaba: 			enter_trampoline_at(p, c);
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		case ' ':
ff0ab77d3d 2012-07-15        kinaba: 		case '.':
ff0ab77d3d 2012-07-15        kinaba: 			move_robot_to(p);
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		case '*':
ff0ab77d3d 2012-07-15        kinaba: 			if(dy!=0 || this[y,x+dx*2]!=' ')
ff0ab77d3d 2012-07-15        kinaba: 				break;
ff0ab77d3d 2012-07-15        kinaba: 			move_robot_to(p);
ff0ab77d3d 2012-07-15        kinaba: 			push_rock(p, new Pos(y,x+dx*2));
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		default:
ff0ab77d3d 2012-07-15        kinaba: 			break;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void use_razor()
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		if(num_razor_ == 0)
ff0ab77d3d 2012-07-15        kinaba: 			return;
ff0ab77d3d 2012-07-15        kinaba: 		num_razor_ --;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		for(int dy=-1; dy<=+1; ++dy)
ff0ab77d3d 2012-07-15        kinaba: 		for(int dx=-1; dx<=+1; ++dx) if(dy||dx)
ff0ab77d3d 2012-07-15        kinaba: 		{
ff0ab77d3d 2012-07-15        kinaba: 			Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx);
ff0ab77d3d 2012-07-15        kinaba: 			if(auto it = p in dynamic_objects_)
ff0ab77d3d 2012-07-15        kinaba: 				if(*it == 'W') {
ff0ab77d3d 2012-07-15        kinaba: 					something_gone(p);
ff0ab77d3d 2012-07-15        kinaba: 					dynamic_objects_.remove(p);
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void take_lambda_at(Pos p)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		map_set_empty(p);
ff0ab77d3d 2012-07-15        kinaba: 		num_lambda_ ++;
ff0ab77d3d 2012-07-15        kinaba: 		lambda_pos_ = lambda_pos_.erase(p);
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void take_razor_at(Pos p)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		map_set_empty(p);
ff0ab77d3d 2012-07-15        kinaba: 		num_razor_ ++;
ff0ab77d3d 2012-07-15        kinaba: 		razor_pos_ = razor_pos_.erase(p);
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void enter_trampoline_at(Pos p, char c)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		char d = trampoline(c);
ff0ab77d3d 2012-07-15        kinaba: 		foreach(cc; trampoline_rev_[d]) {
ff0ab77d3d 2012-07-15        kinaba: 			Pos pp = trampoline_pos_[cc];
ff0ab77d3d 2012-07-15        kinaba: 			something_gone(pp);
ff0ab77d3d 2012-07-15        kinaba: 			map_set_empty(pp);
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 		move_robot_to(trampoline_pos_[d]);
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void move_robot_to(Pos p)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		something_gone(robot_pos_);
ff0ab77d3d 2012-07-15        kinaba: 		map_set_empty(p.y, p.x);
ff0ab77d3d 2012-07-15        kinaba: 		robot_pos_ = p;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void push_rock(Pos fr, Pos to)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		dynamic_objects_.remove(fr);
ff0ab77d3d 2012-07-15        kinaba: 		dynamic_objects_[to] = '*';
ff0ab77d3d 2012-07-15        kinaba: 		may_update_[to] = true;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void something_gone(Pos p)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		for(int dy=0;  dy<=+1; ++dy)
ff0ab77d3d 2012-07-15        kinaba: 		for(int dx=-1; dx<=+1; ++dx) if(dy||dx)
ff0ab77d3d 2012-07-15        kinaba: 			may_update_[new Pos(p.y+dy,p.x+dx)] = true;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void map_update()
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		Pos[] may_update_list;
ff0ab77d3d 2012-07-15        kinaba: 		foreach(p,_; may_update_)
ff0ab77d3d 2012-07-15        kinaba: 			if(this[p] == '*')
ff0ab77d3d 2012-07-15        kinaba: 				may_update_list ~= p;
ff0ab77d3d 2012-07-15        kinaba: 		may_update_ = null;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		if( is_hige_turn() )
ff0ab77d3d 2012-07-15        kinaba: 			foreach(p,c; dynamic_objects_)
ff0ab77d3d 2012-07-15        kinaba: 				if(c == 'W')
ff0ab77d3d 2012-07-15        kinaba: 					may_update_list ~= p;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		sort(may_update_list);
ff0ab77d3d 2012-07-15        kinaba: 		char[Pos] to_be_written;
ff0ab77d3d 2012-07-15        kinaba: 		foreach(p; may_update_list)
ff0ab77d3d 2012-07-15        kinaba: 			if(is_hige_turn() && this[p]=='W')
ff0ab77d3d 2012-07-15        kinaba: 			{
ff0ab77d3d 2012-07-15        kinaba: 				for(int dy=-1; dy<=+1; ++dy)
ff0ab77d3d 2012-07-15        kinaba: 				for(int dx=-1; dx<=+1; ++dx) {
ff0ab77d3d 2012-07-15        kinaba: 					Pos q = new Pos(p.y+dy,p.x+dx);
ff0ab77d3d 2012-07-15        kinaba: 					if( this[q] == ' ' )
ff0ab77d3d 2012-07-15        kinaba: 						to_be_written[q] = 'W';
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 			}
ff0ab77d3d 2012-07-15        kinaba: 			else
ff0ab77d3d 2012-07-15        kinaba: 			{
ff0ab77d3d 2012-07-15        kinaba: 				int y = p.y;
ff0ab77d3d 2012-07-15        kinaba: 				int x = p.x;
ff0ab77d3d 2012-07-15        kinaba: 				char below = this[y-1,x];
ff0ab77d3d 2012-07-15        kinaba: 				// *
ff0ab77d3d 2012-07-15        kinaba: 				// _
ff0ab77d3d 2012-07-15        kinaba: 				if(below==' ') {
ff0ab77d3d 2012-07-15        kinaba: 					Pos q = new Pos(y-1,x);
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[p] = ' ';
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[q] = '*';
ff0ab77d3d 2012-07-15        kinaba: 					may_update_[q] = true;
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 				// *_      *_
ff0ab77d3d 2012-07-15        kinaba: 				// *_  or  \_
ff0ab77d3d 2012-07-15        kinaba: 				else if((below=='*'||below=='\\')&&this[y-1,x+1]==' '&&this[y,x+1]==' ') {
ff0ab77d3d 2012-07-15        kinaba: 					Pos q = new Pos(y-1,x+1);
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[p] = ' ';
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[q] = '*';
ff0ab77d3d 2012-07-15        kinaba: 					may_update_[q] = true;
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 				// _*
ff0ab77d3d 2012-07-15        kinaba: 				// _*
ff0ab77d3d 2012-07-15        kinaba: 				else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x-1]==' ') {
ff0ab77d3d 2012-07-15        kinaba: 					Pos q = new Pos(y-1,x-1);
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[p] = ' ';
ff0ab77d3d 2012-07-15        kinaba: 					to_be_written[q] = '*';
ff0ab77d3d 2012-07-15        kinaba: 					may_update_[q] = true;
ff0ab77d3d 2012-07-15        kinaba: 				}
ff0ab77d3d 2012-07-15        kinaba: 			}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		foreach(p,c; to_be_written) {
ff0ab77d3d 2012-07-15        kinaba: 			dynamic_objects_[p] = c;
ff0ab77d3d 2012-07-15        kinaba: 			if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x)
ff0ab77d3d 2012-07-15        kinaba: 				dead_ = true;
ff0ab77d3d 2012-07-15        kinaba: 		}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 		if(lambda_pos_.empty)
ff0ab77d3d 2012-07-15        kinaba: 			raw_data_[lift_pos_.y][lift_pos_.x] = 'O';
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void water_update()
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		if( robot_pos_.y <= water_level() )
ff0ab77d3d 2012-07-15        kinaba: 			air_left_ --;
ff0ab77d3d 2012-07-15        kinaba: 		else
ff0ab77d3d 2012-07-15        kinaba: 			air_left_ = max_air_;
ff0ab77d3d 2012-07-15        kinaba: 		if( air_left_ < 0 )
ff0ab77d3d 2012-07-15        kinaba: 			dead_ = true;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: private:
ff0ab77d3d 2012-07-15        kinaba: 	char map_get(int y, int x) const
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		if( y<1 || H<y || x<1 || W<x ) return '#';
ff0ab77d3d 2012-07-15        kinaba: 		Pos p = new Pos(y,x);
ff0ab77d3d 2012-07-15        kinaba: 		if(p == robot_pos_)
ff0ab77d3d 2012-07-15        kinaba: 			return 'R';
ff0ab77d3d 2012-07-15        kinaba: 		if(auto it = (p in dynamic_objects_))
ff0ab77d3d 2012-07-15        kinaba: 			return *it;
ff0ab77d3d 2012-07-15        kinaba: 		if( x<0 || raw_data_[y].length<=x ) return ' ';
ff0ab77d3d 2012-07-15        kinaba: 		return raw_data_[y][x];
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void map_set_empty(in Pos p)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		return map_set_empty(p.y, p.x);
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	void map_set_empty(int y, int x)
ff0ab77d3d 2012-07-15        kinaba: 	{
ff0ab77d3d 2012-07-15        kinaba: 		if( y<1 || H<y || x<1 || W<x ) return;
ff0ab77d3d 2012-07-15        kinaba: 		if( x<0 || raw_data_[y].length<=x ) return;
ff0ab77d3d 2012-07-15        kinaba: 		raw_data_[y][x] = ' ';
a03584f1c6 2012-07-15        kinaba: 	}
a03584f1c6 2012-07-15        kinaba: 
a03584f1c6 2012-07-15        kinaba: public:
a03584f1c6 2012-07-15        kinaba: 	Game clone() const { return new Game(this); }
a03584f1c6 2012-07-15        kinaba: 	this(in Game g) {
a03584f1c6 2012-07-15        kinaba: 		H_ = g.H_;
a03584f1c6 2012-07-15        kinaba: 		W_ = g.W_;
a03584f1c6 2012-07-15        kinaba: 		raw_data_ = new char[][g.raw_data_.length];
a03584f1c6 2012-07-15        kinaba: 		foreach(i,d; g.raw_data_) raw_data_[i] = d.dup;
a03584f1c6 2012-07-15        kinaba: 		trampoline_pos_ = cast(Pos[char]) g.trampoline_pos_;
a03584f1c6 2012-07-15        kinaba: 		razor_pos_  = (cast(Game)g).razor_pos_.dup;
a03584f1c6 2012-07-15        kinaba: 		lambda_pos_ = (cast(Game)g).lambda_pos_.dup;
a03584f1c6 2012-07-15        kinaba: 		lift_pos_   = g.lift_pos_.clone();
a03584f1c6 2012-07-15        kinaba: 		robot_pos_  = g.robot_pos_.clone();
a03584f1c6 2012-07-15        kinaba: 		dynamic_objects_ = dup(g.dynamic_objects_);
a03584f1c6 2012-07-15        kinaba: 		trampoline_     = (cast(Game)g).trampoline_;
a03584f1c6 2012-07-15        kinaba: 		trampoline_rev_ = (cast(Game)g).trampoline_rev_;
a03584f1c6 2012-07-15        kinaba: 		water_base_ = g.water_base_;
a03584f1c6 2012-07-15        kinaba: 		water_pace_ = g.water_pace_;
a03584f1c6 2012-07-15        kinaba: 		max_air_    = g.max_air_;
a03584f1c6 2012-07-15        kinaba: 		hige_pace_  = g.hige_pace_;
a03584f1c6 2012-07-15        kinaba: 		num_razor_  = g.num_razor_;
a03584f1c6 2012-07-15        kinaba: 		num_lambda_ = g.num_lambda_;
a03584f1c6 2012-07-15        kinaba: 		turn_       = g.turn_;
a03584f1c6 2012-07-15        kinaba: 		air_left_   = g.air_left_;
a03584f1c6 2012-07-15        kinaba: 		cleared_    = g.cleared_;
a03584f1c6 2012-07-15        kinaba: 		dead_       = g.dead_;
a03584f1c6 2012-07-15        kinaba: 		may_update_ = dup(g.may_update_);
a03584f1c6 2012-07-15        kinaba: 	}
a03584f1c6 2012-07-15        kinaba: 
a03584f1c6 2012-07-15        kinaba: 	V[K] dup(V,K)(in V[K] aa) {
a03584f1c6 2012-07-15        kinaba: 		V[K] aa2;
a03584f1c6 2012-07-15        kinaba: 		foreach(k,v; aa) aa2[k] = v;
a03584f1c6 2012-07-15        kinaba: 		return aa2;
ff0ab77d3d 2012-07-15        kinaba: 	}
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: private:
ff0ab77d3d 2012-07-15        kinaba: 	int          H_;
ff0ab77d3d 2012-07-15        kinaba: 	int          W_;
ff0ab77d3d 2012-07-15        kinaba: 	char[][]     raw_data_;
ff0ab77d3d 2012-07-15        kinaba: 	Pos[char]    trampoline_pos_;
ff0ab77d3d 2012-07-15        kinaba: 	Pos[]        razor_pos_;
ff0ab77d3d 2012-07-15        kinaba: 	Pos[]        lambda_pos_;
ff0ab77d3d 2012-07-15        kinaba: 	Pos          lift_pos_;
ff0ab77d3d 2012-07-15        kinaba: 	Pos          robot_pos_;
ff0ab77d3d 2012-07-15        kinaba: 	char[Pos]    dynamic_objects_;
ff0ab77d3d 2012-07-15        kinaba: 	char[char]   trampoline_;
ff0ab77d3d 2012-07-15        kinaba: 	char[][char] trampoline_rev_;
ff0ab77d3d 2012-07-15        kinaba: 	int          water_base_ = 0;
ff0ab77d3d 2012-07-15        kinaba: 	int          water_pace_ = 0;
ff0ab77d3d 2012-07-15        kinaba: 	int          max_air_    = 10;
ff0ab77d3d 2012-07-15        kinaba: 	int          hige_pace_  = 25;
ff0ab77d3d 2012-07-15        kinaba: 	int          num_razor_  = 0;
ff0ab77d3d 2012-07-15        kinaba: 	int          num_lambda_ = 0;
ff0ab77d3d 2012-07-15        kinaba: 
ff0ab77d3d 2012-07-15        kinaba: 	int turn_     = 0;
ff0ab77d3d 2012-07-15        kinaba: 	int air_left_ = 0;
ff0ab77d3d 2012-07-15        kinaba: 	bool cleared_ = false;
ff0ab77d3d 2012-07-15        kinaba: 	bool dead_    = false;
ff0ab77d3d 2012-07-15        kinaba: 	bool[Pos] may_update_;
6293256fec 2012-07-14        kinaba: }