File Annotation
Not logged in
6293256fec 2012-07-14        kinaba: import util;
bee0596f0f 2012-07-14        kinaba: 
bee0596f0f 2012-07-14        kinaba: ////////////////////////////////////////////////////////////////////////////////
bee0596f0f 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: bool is_spacy(char c)
b96971b0b6 2012-07-16        kinaba: {
b96971b0b6 2012-07-16        kinaba: 	return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O';
b96971b0b6 2012-07-16        kinaba: }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: bool is_rocky(char c)
b96971b0b6 2012-07-16        kinaba: {
b96971b0b6 2012-07-16        kinaba: 	return c=='*' || c=='@';
b96971b0b6 2012-07-16        kinaba: }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: bool is_true_space(char c)
b96971b0b6 2012-07-16        kinaba: {
b96971b0b6 2012-07-16        kinaba: 	return c==' ';
b96971b0b6 2012-07-16        kinaba: }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: bool is_trampoline_source(char c)
b96971b0b6 2012-07-16        kinaba: {
b96971b0b6 2012-07-16        kinaba: 	return 'A'<=c && c<='I';
b96971b0b6 2012-07-16        kinaba: }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: bool is_rocklambda(char c)
b96971b0b6 2012-07-16        kinaba: {
b96971b0b6 2012-07-16        kinaba: 	return is_rocky(c) || c=='\\';
b96971b0b6 2012-07-16        kinaba: }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: ////////////////////////////////////////////////////////////////////////////////
b96971b0b6 2012-07-16        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: {
64f5c73b88 2012-07-15        kinaba: 	mixin DeriveShow;
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: private:
b96971b0b6 2012-07-16        kinaba: 	immutable int base, pace;
b96971b0b6 2012-07-16        kinaba: 	mixin DeriveCreate;
64f5c73b88 2012-07-15        kinaba: 	Water clone() const { return cast(Water) this; }
b1ce0206cd 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: 	mixin DeriveShow;
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: private:
b96971b0b6 2012-07-16        kinaba: 	immutable int pace;
b96971b0b6 2012-07-16        kinaba: 	mixin DeriveCreate;
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: 	mixin DeriveShow;
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: private:
b96971b0b6 2012-07-16        kinaba: 	immutable char[]   target_of_;
b96971b0b6 2012-07-16        kinaba: 	immutable char[][] source_of_;
b96971b0b6 2012-07-16        kinaba: 	immutable Pos[]    position_of_;
b96971b0b6 2012-07-16        kinaba: 	immutable char[]   source_list_;
b96971b0b6 2012-07-16        kinaba: 	immutable char[]   target_list_;
d40deaae5a 2012-07-15        kinaba: 	Trampoline clone() const { return cast(Trampoline) this; }
b96971b0b6 2012-07-16        kinaba: 
7bd1ed1180 2012-07-16        kinaba: 	this(in 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: 
b96971b0b6 2012-07-16        kinaba: public @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: 
6293256fec 2012-07-14        kinaba: class Map
6293256fec 2012-07-14        kinaba: {
6293256fec 2012-07-14        kinaba: 	mixin DeriveShow;
6293256fec 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: 	private char[][] data;
6293256fec 2012-07-14        kinaba: 	Pos robot;
6293256fec 2012-07-14        kinaba: 	Pos lift;
b96971b0b6 2012-07-16        kinaba: 	private int waterproof;
b96971b0b6 2012-07-16        kinaba: 	private int collected_razor;
de416b884b 2012-07-15        kinaba: 	int collected_lambda;
de416b884b 2012-07-15        kinaba: 	int total_lambda;
b96971b0b6 2012-07-16        kinaba: 	private bool cleared;
b96971b0b6 2012-07-16        kinaba: 	private Pos[] may_update;
6293256fec 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: 	private Map clone() const { return new Map(this); }
b96971b0b6 2012-07-16        kinaba: 	private this(in Map m) {
6293256fec 2012-07-14        kinaba: 		foreach(s; m.data)
6293256fec 2012-07-14        kinaba: 			this.data ~= s.dup;
b96971b0b6 2012-07-16        kinaba: 		this.robot      = m.robot.clone();
b96971b0b6 2012-07-16        kinaba: 		this.lift       = m.lift.clone();
6293256fec 2012-07-14        kinaba: 		this.waterproof = m.waterproof;
b96971b0b6 2012-07-16        kinaba: 		this.collected_razor  = m.collected_razor;
de416b884b 2012-07-15        kinaba: 		this.collected_lambda = m.collected_lambda;
b96971b0b6 2012-07-16        kinaba: 		this.total_lambda     = m.total_lambda;
b96971b0b6 2012-07-16        kinaba: 		this.cleared    = m.cleared;
b83558c1a5 2012-07-15        kinaba: 		this.may_update = (cast(Map)m).may_update.dup;
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: 	const {
b96971b0b6 2012-07-16        kinaba: 		@property {
b96971b0b6 2012-07-16        kinaba: 			int H() { return data.length; }
b96971b0b6 2012-07-16        kinaba: 			int W() { return data[0].length; }
b96971b0b6 2012-07-16        kinaba: 			int num_razor() { return collected_razor; }
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 			Pos[] razors()  { return objects('!'); }
b96971b0b6 2012-07-16        kinaba: 			Pos[] lambdas() { return objects('\\'); }
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		Pos[] objects(char c) {
b96971b0b6 2012-07-16        kinaba: 			Pos[] ans;
b96971b0b6 2012-07-16        kinaba: 			for(int y=1; y<=H; ++y)
b96971b0b6 2012-07-16        kinaba: 			for(int x=1; x<=W; ++x)
b96971b0b6 2012-07-16        kinaba: 				if(this[y,x] == c)
b96971b0b6 2012-07-16        kinaba: 				ans ~= new Pos(y,x);
b96971b0b6 2012-07-16        kinaba: 			return ans;
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		char opIndex(int y, int x) {
b96971b0b6 2012-07-16        kinaba: 			--y, --x;
b96971b0b6 2012-07-16        kinaba: 			if(y<0||H<=y||x<0||W<=x)
b96971b0b6 2012-07-16        kinaba: 				return '#';
b96971b0b6 2012-07-16        kinaba: 			return data[H-1-y][x];
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		char opIndex(in Pos p) {
b96971b0b6 2012-07-16        kinaba: 			return this[p.y, p.x];
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 	}
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: private:
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++;
b96971b0b6 2012-07-16        kinaba: 			if(is_rocky(this[y,x]))
b83558c1a5 2012-07-15        kinaba: 				may_update ~= new Pos(y,x);
6293256fec 2012-07-14        kinaba: 		}
6293256fec 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		this.waterproof      = params.get("Waterproof", "5").to!int();
b96971b0b6 2012-07-16        kinaba: 		this.collected_razor = params.get("Razors", "0").to!int();
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: 		--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: 
d40deaae5a 2012-07-15        kinaba: 	bool command(char c, int turn, bool hige_day, in Trampoline tr)
5491fa544d 2012-07-15        kinaba: 	{
b96971b0b6 2012-07-16        kinaba: 		switch(c)
b96971b0b6 2012-07-16        kinaba: 		{
b96971b0b6 2012-07-16        kinaba: 		case 'R': return move( 0, +1, hige_day, tr);
b96971b0b6 2012-07-16        kinaba: 		case 'L': return move( 0, -1, hige_day, tr);
b96971b0b6 2012-07-16        kinaba: 		case 'U': return move(+1,  0, hige_day, tr);
b96971b0b6 2012-07-16        kinaba: 		case 'D': return move(-1,  0, hige_day, tr);
b96971b0b6 2012-07-16        kinaba: 		case 'W': return move( 0,  0, hige_day, tr);
b96971b0b6 2012-07-16        kinaba: 		case 'S': return use_razor(hige_day);
b96971b0b6 2012-07-16        kinaba: 		default:  assert(false);
b96971b0b6 2012-07-16        kinaba: 		}
6293256fec 2012-07-14        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
5491fa544d 2012-07-15        kinaba: 	bool use_razor(bool hige_day)
6293256fec 2012-07-14        kinaba: 	{
b96971b0b6 2012-07-16        kinaba: 		if(collected_razor > 0)
b96971b0b6 2012-07-16        kinaba: 		{
b96971b0b6 2012-07-16        kinaba: 			collected_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)
03b7073abc 2012-07-16        kinaba: 				if(this[robot.y+dy,robot.x+dx] == 'W')
03b7073abc 2012-07-16        kinaba: 					emptify(new Pos(robot.y+dy,robot.x+dx));
3a08e528e7 2012-07-15        kinaba: 		}
5491fa544d 2012-07-15        kinaba: 		return update(hige_day);
5491fa544d 2012-07-15        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
b96971b0b6 2012-07-16        kinaba: 	// Register a position that may become empty in the last turn.
03b7073abc 2012-07-16        kinaba: 	void emptify(Pos p)
b96971b0b6 2012-07-16        kinaba: 	{
03b7073abc 2012-07-16        kinaba: 		this[p] = ' ';
b96971b0b6 2012-07-16        kinaba: 		for(int dy=0;  dy<=+1; ++dy)
b96971b0b6 2012-07-16        kinaba: 		for(int dx=-1; dx<=+1; ++dx)
b96971b0b6 2012-07-16        kinaba: 			may_update ~= new Pos(p.y+dy, p.x+dx);
b96971b0b6 2012-07-16        kinaba: 	}
6293256fec 2012-07-14        kinaba: 
d40deaae5a 2012-07-15        kinaba: 	bool move(int dy, int dx, bool hige_day, in Trampoline tr)
6293256fec 2012-07-14        kinaba: 	{
b96971b0b6 2012-07-16        kinaba: 		Pos next = new Pos(robot.y+dy, robot.x+dx);
b96971b0b6 2012-07-16        kinaba: 		int y=robot.y, x=robot.x;
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		if( '\\' == this[next] ) collected_lambda++;
b96971b0b6 2012-07-16        kinaba: 		if(  '!' == this[next] ) collected_razor++;
b96971b0b6 2012-07-16        kinaba: 		if( 'O'  == this[next] ) cleared = true;
b96971b0b6 2012-07-16        kinaba: 
b96971b0b6 2012-07-16        kinaba: 		if( is_spacy(this[next]) )
b96971b0b6 2012-07-16        kinaba: 		{
03b7073abc 2012-07-16        kinaba: 			emptify(robot);
b96971b0b6 2012-07-16        kinaba: 			robot = next;
03b7073abc 2012-07-16        kinaba: 			this[next] = 'R';
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 		else if(dy==0 && is_rocky(this[next]) && ' '==this[y+dy*2,x+dx*2])
b96971b0b6 2012-07-16        kinaba: 		{
b96971b0b6 2012-07-16        kinaba: 			char rock  = this[next];
03b7073abc 2012-07-16        kinaba: 			emptify(robot);
03b7073abc 2012-07-16        kinaba: 			robot = next;
b96971b0b6 2012-07-16        kinaba: 			this[next]          = 'R';
b96971b0b6 2012-07-16        kinaba: 			this[y+dy*2,x+dx*2] = rock;
bf626def96 2012-07-15        kinaba: 			may_update ~= new Pos(y+dy*2,x+dx*2);
b96971b0b6 2012-07-16        kinaba: 		}
b96971b0b6 2012-07-16        kinaba: 		else if(is_trampoline_source(this[next]))
b96971b0b6 2012-07-16        kinaba: 		{
03b7073abc 2012-07-16        kinaba: 			emptify(robot);
b96971b0b6 2012-07-16        kinaba: 			Pos tp = tr.target_pos(this[next]);
b96971b0b6 2012-07-16        kinaba: 			foreach(p; tr.source_pos(this[tp]))
03b7073abc 2012-07-16        kinaba: 				emptify(p);
deca17f61a 2012-07-14        kinaba: 			this[tp] = 'R';
b96971b0b6 2012-07-16        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];
b96971b0b6 2012-07-16        kinaba: 				if(is_rocky(wr[2]))
b83558c1a5 2012-07-15        kinaba: 					may_update ~= new Pos(wr[0],wr[1]);
b83558c1a5 2012-07-15        kinaba: 				if(wr[2]==' ')
03b7073abc 2012-07-16        kinaba: 					emptify(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];
b96971b0b6 2012-07-16        kinaba: 			if(is_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: 				}
b96971b0b6 2012-07-16        kinaba: 				else if((is_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: 				}
b96971b0b6 2012-07-16        kinaba: 				else if(is_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;
971863e35a 2012-07-16        kinaba: 
7bd1ed1180 2012-07-16        kinaba: 	private {
7bd1ed1180 2012-07-16        kinaba: 		Map map_;
7bd1ed1180 2012-07-16        kinaba: 		Water water_;
7bd1ed1180 2012-07-16        kinaba: 		Hige hige_;
7bd1ed1180 2012-07-16        kinaba: 		Trampoline tr_;
7bd1ed1180 2012-07-16        kinaba: 		int  turn = 0;
7bd1ed1180 2012-07-16        kinaba: 		bool dead_ = false;
7bd1ed1180 2012-07-16        kinaba: 		int  under_water = 0;
7bd1ed1180 2012-07-16        kinaba: 	}
7bd1ed1180 2012-07-16        kinaba: 
7bd1ed1180 2012-07-16        kinaba: 	Game clone() const { return new Game(this); }
7bd1ed1180 2012-07-16        kinaba: 	this(in Game g) {
7bd1ed1180 2012-07-16        kinaba: 		map_   = g.map_.clone();
7bd1ed1180 2012-07-16        kinaba: 		water_ = g.water_.clone();
7bd1ed1180 2012-07-16        kinaba: 		hige_  = g.hige_.clone();
7bd1ed1180 2012-07-16        kinaba: 		tr_    = g.tr_.clone();
7bd1ed1180 2012-07-16        kinaba: 		turn   = g.turn;
7bd1ed1180 2012-07-16        kinaba: 		dead_  = g.dead_;
7bd1ed1180 2012-07-16        kinaba: 		under_water = g.under_water;
7bd1ed1180 2012-07-16        kinaba: 	}
7bd1ed1180 2012-07-16        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: 
7bd1ed1180 2012-07-16        kinaba: 		this.map_   = new Map(raw_data, params, trampo);
7bd1ed1180 2012-07-16        kinaba: 		this.water_ = Water.load(params);
7bd1ed1180 2012-07-16        kinaba: 		this.hige_  = Hige.load(params);
7bd1ed1180 2012-07-16        kinaba: 		this.tr_    = new Trampoline(this.map, trampo);
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
7bd1ed1180 2012-07-16        kinaba: 		bool dead_now = map_.command(c, turn, hige.is_growing_turn(turn), tr);
64f5c73b88 2012-07-15        kinaba: 		if( dead_now )
7bd1ed1180 2012-07-16        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 )
7bd1ed1180 2012-07-16        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: 
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; }
7bd1ed1180 2012-07-16        kinaba: 	bool dead()            { return dead_; }
7bd1ed1180 2012-07-16        kinaba: 	const(Map)        map()   { return map_; }
7bd1ed1180 2012-07-16        kinaba: 	const(Water)      water() { return water_; }
7bd1ed1180 2012-07-16        kinaba: 	const(Hige)       hige()  { return hige_; }
7bd1ed1180 2012-07-16        kinaba: 	const(Trampoline) tr()    { return tr_; }
6293256fec 2012-07-14        kinaba: }