Artifact Content
Not logged in

Artifact d9955daaabe58d54b6fd8c555e5b3fee9a98496f


     1  import std.algorithm;
     2  import std.array;
     3  import std.conv;
     4  import std.stdio;
     5  import std.string;
     6  import std.typecons;
     7  import core.stdc.signal;
     8  import core.stdc.stdlib;
     9  import dfl.all;
    10  
    11  class Map
    12  {
    13  	private char[][] data;
    14  	bool dead = false;
    15  	bool cleared = false;
    16  	int water = 0;
    17  	int flooding = 0;
    18  	int water_proof = 10;
    19  	int underwater = 0;
    20  	int flooding_counter = 0;
    21  
    22  	this(File input)
    23  	{
    24  		string line;
    25  		while( (line=input.readln().chomp()).length )
    26  			data ~= line.dup;
    27  
    28  		int width = 0;
    29  		foreach(s; data)
    30  			width = max(width, s.length);
    31  
    32  		// space padding and sentinels
    33  		foreach(ref s; data) {
    34  			int p = s.length;
    35  			s.length = width;
    36  			s[p..$] = ' ';
    37  			s = '#' ~ s ~ '#';
    38  		}
    39  
    40  		// vertical sentinel
    41  		char[] sen = new char[width+2];
    42  		sen[] = '#';
    43  		data = sen.dup ~ data ~ sen;
    44  
    45  		// flooding
    46  		water = H-1;
    47  		while( (line=input.readln()).length ) {
    48  			string[] ss = line.split();
    49  			if(ss.length==2 && ss[0]=="Water")
    50  				water = H-1 - ss[1].to!int();
    51  			else if(ss.length==2 && ss[0]=="Flooding")
    52  				flooding = ss[1].to!int();
    53  			else if(ss.length==2 && ss[0]=="Waterproof")
    54  				water_proof = ss[1].to!int();
    55  		}
    56  	}
    57  
    58  	@property const
    59  	{
    60  		int W() { return data[0].length; }
    61  		int H() { return data.length; }
    62  		string toString() {
    63  			string result;
    64  			foreach(i,s; data) {
    65  				if(i) result ~= '\n';
    66  				result ~= s.idup;
    67  			}
    68  			return result;
    69  		}
    70  	}
    71  
    72  	int command_R() { if(dead)return 0; write("R"); return move(0, +1); }
    73  	int command_L() { if(dead)return 0; write("L"); return move(0, -1); }
    74  	int command_U() { if(dead)return 0; write("U"); return move(-1, 0); }
    75  	int command_D() { if(dead)return 0; write("D"); return move(+1, 0); }
    76  	int wait() { if(dead)return 0; update(); write("W"); return -1; }
    77  	int abort() { if(dead)return 0; cleared=true; write("A"); return gained*25; }
    78  
    79  	int move(int dy, int dx) {
    80  		foreach(y,s; data)
    81  		foreach(x,c; s)
    82  			if(c == 'R')
    83  				return move(dy, dx, y, x);
    84  		assert(false);
    85  	}
    86  
    87  	int gained = 0; // TODO: atode naosu
    88  	int move(int dy, int dx, int y, int x) {
    89  		if(dead)
    90  			return 0;
    91  		int score = 0;
    92  		if(data[y+dy][x+dx]=='\\') {
    93  			score += 25;
    94  			++gained;
    95  		}
    96  		if(data[y+dy][x+dx]=='O') {
    97  			score += gained*50;
    98  			cleared = true;
    99  		}
   100  
   101  		if(data[y+dy][x+dx]==' ' || data[y+dy][x+dx]=='.'
   102  		   || data[y+dy][x+dx]=='\\' || data[y+dy][x+dx]=='O') {
   103  			data[y][x]=' ';
   104  			data[y+dy][x+dx]='R';
   105  		} else if(dy==0 && data[y+dy][x+dx]=='*' && data[y+2*dy][x+2*dx]==' ') {
   106  			data[y][x]=' ';
   107  			data[y+dy][x+dx]='R';
   108  			data[y+2*dy][x+2*dx]='*';
   109  		}
   110  		update();
   111  		return score-1;
   112  	}
   113  
   114  	void update() {
   115  		char[][] next;
   116  		foreach(y,s; data)
   117  			next ~= s.dup;
   118  
   119  		bool lambda = false;
   120  		for(int y=1; y+1<H; ++y)
   121  		for(int x=1; x+1<W; ++x)
   122  			lambda |= (data[y][x] == '\\');
   123  
   124  		for(int y=H-2; y>=1; --y)
   125  		for(int x=1; x+1<W; ++x) {
   126  			if(data[y][x]=='*') {
   127  				if(data[y+1][x]==' ') {
   128  					next[y][x]=' ';
   129  					next[y+1][x]='*';
   130  					if(next[y+2][x]=='R')
   131  						dead=true;
   132  				}
   133  				else if(data[y+1][x]=='*' && data[y][x+1]==' ' && data[y+1][x+1]==' ') {
   134  					next[y][x]=' ';
   135  					next[y+1][x+1]='*';
   136  					if(next[y+2][x+1]=='R')
   137  						dead=true;
   138  				}
   139  				else if(data[y+1][x]=='*' && data[y][x-1]==' ' && data[y+1][x-1]==' ') {
   140  					next[y][x]=' ';
   141  					next[y+1][x-1]='*';
   142  					if(next[y+2][x-1]=='R')
   143  						dead=true;
   144  				}
   145  				else if(data[y+1][x]=='\\' && data[y][x+1]==' ' && data[y+1][x+1]==' ') {
   146  					next[y][x]=' ';
   147  					next[y+1][x+1]='*';
   148  					if(next[y+2][x+1]=='R')
   149  						dead=true;
   150  				}
   151  			}
   152  			else if(data[y][x]=='L') {
   153  				if(!lambda)
   154  					next[y][x] = 'O';
   155  			}
   156  		}
   157  		data = next;
   158  
   159  		if(flooding) {
   160  			bool wa = false;
   161  			for(int y=water; y+1<H; ++y)
   162  			for(int x=1; x+1<W; ++x)
   163  				if(data[y][x]=='R') {
   164  					wa = true;
   165  					underwater++;
   166  					if(underwater > water_proof)
   167  						dead = true;
   168  				}
   169  			flooding_counter ++;
   170  			if(flooding_counter == flooding) {
   171  				flooding_counter = 0;
   172  				water --;
   173  			}
   174  		}
   175  	}
   176  
   177  	int clever()
   178  	{
   179  		if(dead)
   180  			return 0;
   181  		int sy,sx;
   182  		int[] ly,lx;
   183  		int oy,ox;
   184  		for(int y=0; y<H; ++y)
   185  		for(int x=0; x<W; ++x)
   186  			if(data[y][x]=='R')
   187  				sy=y, sx=x;
   188  			else if(data[y][x]=='\\')
   189  				ly~=y, lx~=x;
   190  			else if(data[y][x]=='O')
   191  				oy=y, ox=x;
   192  		if(ly.length==0) {
   193  			auto r = search(sy,sx,oy,ox);
   194  			switch(r[0]) {
   195  			case 'D': return command_D();
   196  			case 'U': return command_U();
   197  			case 'L': return command_L();
   198  			case 'R': return command_R();
   199  			case 'A': return abort();
   200  			default: return wait();
   201  			}
   202  		} else {
   203  			Tuple!(char,int)[] cand;
   204  			for(int i=0; i<ly.length; ++i) {
   205  				auto r = search(sy,sx,ly[i],lx[i]);
   206  				cand ~= r;
   207  			}
   208  			sort!((Tuple!(char,int) c1, Tuple!(char,int) c2){
   209  				if(c1[1] != c2[1])
   210  					return c1[1] < c2[1];
   211  				return c1[0] < c2[0];
   212  			})(cand);
   213  			switch(cand[0][0]) {
   214  			case 'D': return command_D();
   215  			case 'U': return command_U();
   216  			case 'L': return command_L();
   217  			case 'R': return command_R();
   218  			case 'A': return abort();
   219  			default: return wait();
   220  			}
   221  		}
   222  		return wait();
   223  	}
   224  	Tuple!(char,int) search(int sy, int sx, int oy, int ox)
   225  	{
   226  		alias Tuple!(int,"y",int,"x") Pt;
   227  		Pt[] q = [Pt(oy,ox)];
   228  		bool[][] v = new bool[][](H,W);
   229  		for(int step=1; q.length; ++step) {
   230  			Pt[] q2;
   231  			foreach(p; q) {
   232  				int[] dy=[-1,+1,0,0];
   233  				int[] dx=[0,0,-1,+1];
   234  				for(int i=0; i<4; ++i) {
   235  					int y = p.y+dy[i];
   236  					int x = p.x+dx[i];
   237  					if(v[y][x]) continue;
   238  					if(y==sy && x==sx) {
   239  						if(i==0) return tuple('D',step);
   240  						if(i==1) return tuple('U',step);
   241  						if(i==2) return tuple('R',step);
   242  						if(i==3) return tuple('L',step);
   243  					} else if(data[y][x]==' '||data[y][x]=='\\') {
   244  						q2 ~= Pt(y,x);
   245  						v[y][x]=true;
   246  					} else if(data[y][x]=='.' && data[y-1][x]!='*') {
   247  						q2 ~= Pt(y,x);
   248  						v[y][x]=true;
   249  					}
   250  				}
   251  			}
   252  			q = q2;
   253  		}
   254  		q = [Pt(oy,ox)];
   255  		v = new bool[][](H,W);
   256  		for(int step=1<<10; q.length; ++step) {
   257  			Pt[] q2;
   258  			foreach(p; q) {
   259  
   260  				int[] dy=[-1,+1,0,0];
   261  				int[] dx=[0,0,-1,+1];
   262  				for(int i=0; i<4; ++i) {
   263  					int y = p.y+dy[i];
   264  					int x = p.x+dx[i];
   265  					if(v[y][x]) continue;
   266  					if(y==sy && x==sx) {
   267  						if(i==0) return tuple('D',step);
   268  						if(i==1) return tuple('U',step);
   269  						if(i==2) return tuple('R',step);
   270  						if(i==3) return tuple('L',step);
   271  					} else if(data[y][x]==' '||data[y][x]=='\\') {
   272  						q2 ~= Pt(y,x);
   273  						v[y][x]=true;
   274  					} else if(data[y][x]=='.'/* && data[y-1][x]!='*'*/) {
   275  						q2 ~= Pt(y,x);
   276  						v[y][x]=true;
   277  					}
   278  				}
   279  			}
   280  			q = q2;
   281  		}
   282  		return tuple('A',int.max);
   283  	}
   284  }
   285  
   286  class MyForm : Form
   287  {
   288  	Map m;
   289  	int score;
   290  
   291  	this(Map m)
   292  	{
   293  		noMessageFilter();
   294  		this.m = m;
   295  		this.text = .text("Score: ", score, "  air[",m.water_proof-m.underwater,"]");
   296  		this.keyDown ~= &myKey;
   297  		this.score = 0;
   298  	}
   299  	override void onResize(EventArgs ev) {
   300  		invalidate();
   301  	}
   302  	override void onPaint(PaintEventArgs ev)
   303  	{
   304  		int Z = min(this.clientSize.width/(m.W-2), this.clientSize.height/(m.H-2));
   305  		Font font = new Font("MS Gothic", Z-4);
   306  		Graphics g = ev.graphics;
   307  		g.fillRectangle(Color(0,233,255), Rect(0,Z*(m.water-1),this.clientSize.width,this.clientSize.height-(Z*(m.water-1))));
   308  		for(int y=1; y+1<m.H; ++y)
   309  		for(int x=1; x+1<m.W; ++x) {
   310  			if(m.data[y][x]=='*') {
   311  				g.drawText("岩", font, Color(0,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   312  			}
   313  			if(m.data[y][x]=='\\') {
   314  				g.drawText("λ", font, Color(0,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   315  			}
   316  			if(m.data[y][x]=='R') {
   317  				if(m.dead)
   318  					g.drawText("Я", font, Color(255,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   319  				else
   320  					g.drawText("R", font, Color(128,128,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   321  			}
   322  			if(m.data[y][x]=='L') {
   323  				g.drawText("扉", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   324  			}
   325  			if(m.data[y][x]=='O') {
   326  				g.drawText("外", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   327  			}
   328  			if(m.data[y][x]=='#') {
   329  				g.drawText("#", font, Color(0,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   330  			}
   331  			if(m.data[y][x]=='.') {
   332  				g.drawText("・", font, Color(128,40,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
   333  			}
   334  		}
   335  	}
   336  	void myKey(Control c, KeyEventArgs ev)
   337  	{
   338  		switch(ev.keyCode)
   339  		{
   340  		case Keys.DOWN:
   341  			score += m.command_D();
   342  			stdout.flush();
   343  			break;
   344  		case Keys.UP:
   345  			score += m.command_U();
   346  			stdout.flush();
   347  			break;
   348  		case Keys.LEFT:
   349  			score += m.command_L();
   350  			stdout.flush();
   351  			break;
   352  		case Keys.RIGHT:
   353  			score += m.command_R();
   354  			stdout.flush();
   355  			break;
   356  		case Keys.W:
   357  			score += m.wait();
   358  			stdout.flush();
   359  			break;
   360  		case Keys.A:
   361  			score += m.abort();
   362  			stdout.flush();
   363  			break;
   364  		case Keys.G:
   365  			score += m.clever();
   366  			stdout.flush();
   367  			break;
   368  		default:
   369  			break;
   370  		}
   371  		if(m.cleared) {
   372  			writeln();
   373  			writeln("Score: ", score);
   374  			Application.exit();
   375  		}
   376  		this.text = .text("Score: ", score, "  air[",m.water_proof-m.underwater,"]");
   377  		invalidate();
   378  	}
   379  }
   380  
   381  extern(C) {
   382  	void sigint(int) {
   383  		write("A");
   384  		stdout.flush();
   385  		exit(0);
   386  	}
   387  }
   388  
   389  void main(string[] args)
   390  {
   391  	signal(SIGINT, &sigint);
   392  
   393  	Form myForm = new MyForm(new Map(File(args[1])));
   394  	Application.run(myForm);
   395  }