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: 
64f5c73b88 2012-07-15        kinaba: const @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 DeriveShow;
64f5c73b88 2012-07-15        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: 
64f5c73b88 2012-07-15        kinaba: 	int level(int turn) const
6293256fec 2012-07-14        kinaba: 	{
64f5c73b88 2012-07-15        kinaba: 		return pace ? base+(turn/pace) : base;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
64f5c73b88 2012-07-15        kinaba: 	int until_rise(int turn) const
6293256fec 2012-07-14        kinaba: 	{
64f5c73b88 2012-07-15        kinaba: 		return pace ? pace-turn%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 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: 
d40deaae5a 2012-07-15        kinaba: class Trampoline
d40deaae5a 2012-07-15        kinaba: {
d40deaae5a 2012-07-15        kinaba: 	private immutable char[]   target_of_;
d40deaae5a 2012-07-15        kinaba: 	private immutable char[][] source_of_;
d40deaae5a 2012-07-15        kinaba: 	private immutable Pos[]    position_of_;
d40deaae5a 2012-07-15        kinaba: 	private immutable char[]   source_list_;
d40deaae5a 2012-07-15        kinaba: 	private immutable char[]   target_list_;
d40deaae5a 2012-07-15        kinaba: 	mixin DeriveShow;
d40deaae5a 2012-07-15        kinaba: 	Trampoline clone() const { return cast(Trampoline) this; }
d40deaae5a 2012-07-15        kinaba: 	this(Map m, char[char] tramparam)
d40deaae5a 2012-07-15        kinaba: 	{
d40deaae5a 2012-07-15        kinaba: 		auto ta = new char['I'+1];
d40deaae5a 2012-07-15        kinaba: 		auto sr = new char[]['9'+1];
d40deaae5a 2012-07-15        kinaba: 		auto po = new Pos[max('I','9')+1];
d40deaae5a 2012-07-15        kinaba: 		char[] sl, tl;
d40deaae5a 2012-07-15        kinaba: 		foreach(fr,to; tramparam) {
d40deaae5a 2012-07-15        kinaba: 			ta[fr]  = to;
d40deaae5a 2012-07-15        kinaba: 			sr[to] ~= fr;
d40deaae5a 2012-07-15        kinaba: 		}
d40deaae5a 2012-07-15        kinaba: 		for(int y=1; y<=m.H; ++y)
d40deaae5a 2012-07-15        kinaba: 		for(int x=1; x<=m.W; ++x) {
d40deaae5a 2012-07-15        kinaba: 			char c = m[y,x];
d40deaae5a 2012-07-15        kinaba: 			if('A'<=c && c<='I') {
d40deaae5a 2012-07-15        kinaba: 				sl ~= c;
d40deaae5a 2012-07-15        kinaba: 				po[c] = new Pos(y,x);
d40deaae5a 2012-07-15        kinaba: 			}
d40deaae5a 2012-07-15        kinaba: 			if('1'<=c && c<='9') {
d40deaae5a 2012-07-15        kinaba: 				tl ~= c;
d40deaae5a 2012-07-15        kinaba: 				po[c] = new Pos(y,x);
d40deaae5a 2012-07-15        kinaba: 			}
d40deaae5a 2012-07-15        kinaba: 		}
d40deaae5a 2012-07-15        kinaba: 		target_of_ = cast(immutable) ta;
d40deaae5a 2012-07-15        kinaba: 		source_of_ = cast(immutable) sr;
d40deaae5a 2012-07-15        kinaba: 		position_of_ = cast(immutable) po;
d40deaae5a 2012-07-15        kinaba: 		source_list_ = cast(immutable) sl;
d40deaae5a 2012-07-15        kinaba: 		target_list_ = cast(immutable) tl;
d40deaae5a 2012-07-15        kinaba: 	}
d40deaae5a 2012-07-15        kinaba: 
d40deaae5a 2012-07-15        kinaba: @property const:
d40deaae5a 2012-07-15        kinaba: 	const(char[]) source_list() { return source_list_; }
d40deaae5a 2012-07-15        kinaba: 	const(char[]) target_list() { return target_list_; }
d40deaae5a 2012-07-15        kinaba: 	const(char[]) source_of(char c) { return source_of_[c]; }
d40deaae5a 2012-07-15        kinaba: 	char target_of(char c) { return target_of_[c]; }
d40deaae5a 2012-07-15        kinaba: 	Pos[] source_pos(char c) {
d40deaae5a 2012-07-15        kinaba: 		Pos[] ps;
d40deaae5a 2012-07-15        kinaba: 		foreach(s; source_of(c))
d40deaae5a 2012-07-15        kinaba: 			ps ~= position_of_[s].clone();
d40deaae5a 2012-07-15        kinaba: 		return ps;
d40deaae5a 2012-07-15        kinaba: 	}
d40deaae5a 2012-07-15        kinaba: 	Pos target_pos(char c) { return position_of_[target_of_[c]].clone(); }
d40deaae5a 2012-07-15        kinaba: }
d40deaae5a 2012-07-15        kinaba: 
d40deaae5a 2012-07-15        kinaba: ////////////////////////////////////////////////////////////////////////////////
d40deaae5a 2012-07-15        kinaba: 
64f5c73b88 2012-07-15        kinaba: class Map
64f5c73b88 2012-07-15        kinaba: {
64f5c73b88 2012-07-15        kinaba: 	mixin DeriveShow;
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;
9d983af88c 2012-07-15        kinaba: 	int razor;
de416b884b 2012-07-15        kinaba: 	int collected_lambda;
de416b884b 2012-07-15        kinaba: 	int total_lambda;
64f5c73b88 2012-07-15        kinaba: 	bool cleared;
64f5c73b88 2012-07-15        kinaba: 	Pos[] may_update;
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;
9d983af88c 2012-07-15        kinaba: 		this.razor = m.razor;
de416b884b 2012-07-15        kinaba: 		this.collected_lambda = m.collected_lambda;
de416b884b 2012-07-15        kinaba: 		this.total_lambda = m.total_lambda;
b83558c1a5 2012-07-15        kinaba: 		this.may_update = (cast(Map)m).may_update.dup;
64f5c73b88 2012-07-15        kinaba: 		this.cleared = m.cleared;
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);
de416b884b 2012-07-15        kinaba: 			if(this[y,x] == '\\' || this[y,x] == '@')
de416b884b 2012-07-15        kinaba: 				total_lambda++;
b83558c1a5 2012-07-15        kinaba: 			if(this[y,x] == '*' || this[y,x] == '@')
b83558c1a5 2012-07-15        kinaba: 				may_update ~= new Pos(y,x);
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
b1ce0206cd 2012-07-14        kinaba: 		this.waterproof = params.get("Waterproof", "5").to!int();
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: 	}
6293256fec 2012-07-14        kinaba: 
34bbd14c1a 2012-07-15        kinaba: 	Pos[] razors() const { return objects('!'); }
34bbd14c1a 2012-07-15        kinaba: 	Pos[] lambdas() const { return objects('\\'); }
6293256fec 2012-07-14        kinaba: 
d40deaae5a 2012-07-15        kinaba: 	bool command(char c, int turn, bool hige_day, in Trampoline tr)
6293256fec 2012-07-14        kinaba: 	{
3a08e528e7 2012-07-15        kinaba: 		assert( this[robot] == 'R' );
d40deaae5a 2012-07-15        kinaba: 		if(c=='R') return move( 0, +1, hige_day, tr);
d40deaae5a 2012-07-15        kinaba: 		if(c=='L') return move( 0, -1, hige_day, tr);
d40deaae5a 2012-07-15        kinaba: 		if(c=='U') return move(+1,  0, hige_day, tr);
d40deaae5a 2012-07-15        kinaba: 		if(c=='D') return move(-1,  0, hige_day, tr);
d40deaae5a 2012-07-15        kinaba: 		if(c=='W') return move( 0,  0, hige_day, tr);
5491fa544d 2012-07-15        kinaba: 		if(c=='S') return use_razor(hige_day);
6293256fec 2012-07-14        kinaba: 		assert(false);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
5491fa544d 2012-07-15        kinaba: 	bool use_razor(bool hige_day)
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)
64f5c73b88 2012-07-15        kinaba: 				if(this[robot.y+dy,robot.x+dx] == 'W') {
64f5c73b88 2012-07-15        kinaba: 					emptified(new Pos(robot.y+dy,robot.x+dx));
3a08e528e7 2012-07-15        kinaba: 					this[robot.y+dy,robot.x+dx] = ' ';
64f5c73b88 2012-07-15        kinaba: 				}
3a08e528e7 2012-07-15        kinaba: 		}
3a08e528e7 2012-07-15        kinaba: 
5491fa544d 2012-07-15        kinaba: 		return update(hige_day);
3a08e528e7 2012-07-15        kinaba: 	}
3a08e528e7 2012-07-15        kinaba: 
de416b884b 2012-07-15        kinaba: 	bool rocky(char c) { return c=='*' || c=='@'; }
64f5c73b88 2012-07-15        kinaba: 
b83558c1a5 2012-07-15        kinaba: 		void emptified(Pos p) {
b83558c1a5 2012-07-15        kinaba: 			for(int dy=0; dy<=+1; ++dy)
b83558c1a5 2012-07-15        kinaba: 			for(int dx=-1; dx<=+1; ++dx)
b83558c1a5 2012-07-15        kinaba: 				may_update ~= new Pos(p.y+dy, p.x+dx);
b83558c1a5 2012-07-15        kinaba: 		}
b83558c1a5 2012-07-15        kinaba: 
d40deaae5a 2012-07-15        kinaba: 	bool move(int dy, int dx, bool hige_day, in Trampoline tr)
6293256fec 2012-07-14        kinaba: 	{
b83558c1a5 2012-07-15        kinaba: 		emptified(robot);
b83558c1a5 2012-07-15        kinaba: 
6293256fec 2012-07-14        kinaba: 		int y = robot.y;
6293256fec 2012-07-14        kinaba: 		int x = robot.x;
6293256fec 2012-07-14        kinaba: 		if( '\\' == this[y+dy,x+dx] )
de416b884b 2012-07-15        kinaba: 			collected_lambda++;
41c73506fb 2012-07-15        kinaba: 		if( '!' == this[y+dy,x+dx] )
41c73506fb 2012-07-15        kinaba: 			razor++;
64f5c73b88 2012-07-15        kinaba: 		if( 'O' == this[y+dy,x+dx] )
64f5c73b88 2012-07-15        kinaba: 			cleared = true;
41c73506fb 2012-07-15        kinaba: 		if( " \\!.O".count(this[y+dy,x+dx])==1 ) {
41c73506fb 2012-07-15        kinaba: 			this[y,x]=' ';
41c73506fb 2012-07-15        kinaba: 			this[y+dy,x+dx]='R';
41c73506fb 2012-07-15        kinaba: 			robot = new Pos(y+dy,x+dx);
de416b884b 2012-07-15        kinaba: 		} else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+dx*2]) {
de416b884b 2012-07-15        kinaba: 			char rock = this[y+dy,x+dx];
6293256fec 2012-07-14        kinaba: 			this[y,x]=' ';
6293256fec 2012-07-14        kinaba: 			this[y+dy,x+dx]='R';
de416b884b 2012-07-15        kinaba: 			this[y+dy*2,x+dx*2]=rock;
6293256fec 2012-07-14        kinaba: 			robot = new Pos(y+dy,x+dx);
bf626def96 2012-07-15        kinaba: 			may_update ~= new Pos(y+dy*2,x+dx*2);
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]=' ';
d40deaae5a 2012-07-15        kinaba: 			Pos tp = tr.target_pos(this[y+dy,x+dx]);
d40deaae5a 2012-07-15        kinaba: 			foreach(p; tr.source_pos(this[tp])) {
b83558c1a5 2012-07-15        kinaba: 				emptified(p);
deca17f61a 2012-07-14        kinaba: 				this[p] = ' ';
b83558c1a5 2012-07-15        kinaba: 			}
deca17f61a 2012-07-14        kinaba: 			this[tp] = 'R';
deca17f61a 2012-07-14        kinaba: 			robot = tp;
6293256fec 2012-07-14        kinaba: 		}
5491fa544d 2012-07-15        kinaba: 		return update(hige_day);
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
5491fa544d 2012-07-15        kinaba: 	bool update(bool hige_day)
6293256fec 2012-07-14        kinaba: 	{
b83558c1a5 2012-07-15        kinaba: 		// Write after all the updates are processed.
b83558c1a5 2012-07-15        kinaba: 		Tuple!(int,int,char)[] write_buffer;
b83558c1a5 2012-07-15        kinaba: 		void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); }
b83558c1a5 2012-07-15        kinaba: 		void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c); }
b83558c1a5 2012-07-15        kinaba: 		scope(exit) {
b83558c1a5 2012-07-15        kinaba: 			may_update.length = 0;
b83558c1a5 2012-07-15        kinaba: 			foreach(wr; write_buffer) {
b83558c1a5 2012-07-15        kinaba: 				this[wr[0],wr[1]] = wr[2];
b83558c1a5 2012-07-15        kinaba: 				if(rocky(wr[2]))
b83558c1a5 2012-07-15        kinaba: 					may_update ~= new Pos(wr[0],wr[1]);
b83558c1a5 2012-07-15        kinaba: 				if(wr[2]==' ')
b83558c1a5 2012-07-15        kinaba: 					emptified(new Pos(wr[0], wr[1]));
b83558c1a5 2012-07-15        kinaba: 			}
b83558c1a5 2012-07-15        kinaba: 		}
b83558c1a5 2012-07-15        kinaba: 
b83558c1a5 2012-07-15        kinaba: 		if(collected_lambda == total_lambda)
b83558c1a5 2012-07-15        kinaba: 			if(this[lift]=='L')
b83558c1a5 2012-07-15        kinaba: 				this[lift] = 'O';
b83558c1a5 2012-07-15        kinaba: 
6293256fec 2012-07-14        kinaba: 		bool dead = false;
5491fa544d 2012-07-15        kinaba: 		if( hige_day ) {
5491fa544d 2012-07-15        kinaba: 			for(int y=1; y<=H; ++y)
5491fa544d 2012-07-15        kinaba: 			for(int x=1; x<=W; ++x)
5491fa544d 2012-07-15        kinaba: 				if(this[y,x]=='W')
5491fa544d 2012-07-15        kinaba: 					may_update ~= new Pos(y,x);
5491fa544d 2012-07-15        kinaba: 		}
5491fa544d 2012-07-15        kinaba: 
b83558c1a5 2012-07-15        kinaba: 		sort(may_update);
b83558c1a5 2012-07-15        kinaba: 		foreach(p; may_update) {
b83558c1a5 2012-07-15        kinaba: 			int y = p.y, x = p.x;
de416b884b 2012-07-15        kinaba: 			char rock = this[p];
de416b884b 2012-07-15        kinaba: 			if(rocky(this[p])) {
6293256fec 2012-07-14        kinaba: 				if(this[p.D]==' ') {
b83558c1a5 2012-07-15        kinaba: 					writep(p, ' ');
b83558c1a5 2012-07-15        kinaba: 					writep(p.D, (rock=='@'&&this[p.D.D]!=' ' ? '\\' : rock));
6293256fec 2012-07-14        kinaba: 					if(robot == p.D.D)
6293256fec 2012-07-14        kinaba: 						dead=true;
6293256fec 2012-07-14        kinaba: 				}
de416b884b 2012-07-15        kinaba: 				else if((rocky(this[p.D]) || this[p.D]=='\\') && this[p.R]==' ' && this[p.R.D]==' ') {
b83558c1a5 2012-07-15        kinaba: 					writep(p, ' ');
b83558c1a5 2012-07-15        kinaba: 					writep(p.R.D,(rock=='@'&&this[p.R.D.D]!=' ' ? '\\' : rock));
6293256fec 2012-07-14        kinaba: 					if(robot == p.R.D.D)
6293256fec 2012-07-14        kinaba: 						dead=true;
6293256fec 2012-07-14        kinaba: 				}
de416b884b 2012-07-15        kinaba: 				else if(rocky(this[p.D]) && this[p.L]==' ' && this[p.L.D]==' ') {
b83558c1a5 2012-07-15        kinaba: 					writep(p, ' ');
b83558c1a5 2012-07-15        kinaba: 					writep(p.L.D, (rock=='@'&&this[p.L.D.D]!=' ' ? '\\' : rock));
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: 			}
5491fa544d 2012-07-15        kinaba: 			else if(this[p]=='W') {
5491fa544d 2012-07-15        kinaba: 				if(hige_day) {
2b4f8bba2d 2012-07-15        kinaba: 					for(int dy=-1; dy<=+1; ++dy)
2b4f8bba2d 2012-07-15        kinaba: 					for(int dx=-1; dx<=+1; ++dx)
971863e35a 2012-07-16        kinaba: 						if(this[p.y+dy,p.x+dx] == ' ') {
b83558c1a5 2012-07-15        kinaba: 							write(p.y+dy,p.x+dx,'W');
971863e35a 2012-07-16        kinaba: 							if(robot.y==p.y+dy-1 && robot.x==p.x+dx)
971863e35a 2012-07-16        kinaba: 								dead = false; // guarded by hige!
971863e35a 2012-07-16        kinaba: 						}
5491fa544d 2012-07-15        kinaba: 				}
6293256fec 2012-07-14        kinaba: 			}
6293256fec 2012-07-14        kinaba: 		}
64f5c73b88 2012-07-15        kinaba: 
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: ////////////////////////////////////////////////////////////////////////////////
e02668367d 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: 
64f5c73b88 2012-07-15        kinaba: 	this(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: 
64f5c73b88 2012-07-15        kinaba: 		this.map   = new Map(raw_data, params, trampo);
bee0596f0f 2012-07-14        kinaba: 		this.water = Water.load(params);
5491fa544d 2012-07-15        kinaba: 		this.hige  = Hige.load(params);
d40deaae5a 2012-07-15        kinaba: 		this.tr    = new Trampoline(this.map, trampo);
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) {
64f5c73b88 2012-07-15        kinaba: 		map   = g.map.clone();
6293256fec 2012-07-14        kinaba: 		water = g.water.clone();
5491fa544d 2012-07-15        kinaba: 		hige  = g.hige.clone();
d40deaae5a 2012-07-15        kinaba: 		tr    = g.tr.clone();
64f5c73b88 2012-07-15        kinaba: 		turn  = g.turn;
64f5c73b88 2012-07-15        kinaba: 		dead  = g.dead;
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
d40deaae5a 2012-07-15        kinaba: 		bool dead_now = map.command(c, turn, hige.is_growing_turn(turn), tr);
64f5c73b88 2012-07-15        kinaba: 		if( dead_now )
64f5c73b88 2012-07-15        kinaba: 			dead = true;
64f5c73b88 2012-07-15        kinaba: 		if(!map.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 )
6293256fec 2012-07-14        kinaba: 				dead = true;
6293256fec 2012-07-14        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;
5491fa544d 2012-07-15        kinaba: 	Hige hige;
d40deaae5a 2012-07-15        kinaba: 	Trampoline tr;
6293256fec 2012-07-14        kinaba: 	int  turn = 0;
6293256fec 2012-07-14        kinaba: 	bool dead = false;
6293256fec 2012-07-14        kinaba: 	int  under_water = 0;
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: 
64f5c73b88 2012-07-15        kinaba: @property const:
64f5c73b88 2012-07-15        kinaba: 	long score()           { return map.collected_lambda*(dead?25L:cleared?75L:50L)-turn; }
64f5c73b88 2012-07-15        kinaba: 	int water_level()      { return water.level(turn); }
64f5c73b88 2012-07-15        kinaba: 	int water_until_rise() { return water.until_rise(turn); }
5491fa544d 2012-07-15        kinaba: 	int hige_until_rise()  { return hige.until_rise(turn); }
64f5c73b88 2012-07-15        kinaba: 	int hp()               { return map.waterproof - under_water; }
64f5c73b88 2012-07-15        kinaba: 	bool cleared()         { return map.cleared; }
6293256fec 2012-07-14        kinaba: }