import std.algorithm;
import std.array;
import std.conv;
import std.stdio;
import std.string;
import std.typecons;
import dfl.all;
class Map
{
private char[][] data;
bool dead = false;
bool cleared = false;
int water = 0;
int flooding = 0;
int water_proof = 10;
int underwater = 0;
int flooding_counter = 0;
this(File input)
{
string line;
while( (line=input.readln().chomp()).length )
data ~= line.dup;
int width = 0;
foreach(s; data)
width = max(width, s.length);
// space padding and sentinels
foreach(ref s; data) {
int p = s.length;
s.length = width;
s[p..$] = ' ';
s = '#' ~ s ~ '#';
}
// vertical sentinel
char[] sen = new char[width+2];
sen[] = '#';
data = sen.dup ~ data ~ sen;
// flooding
water = H-1;
while( (line=input.readln()).length ) {
string[] ss = line.split();
if(ss.length==2 && ss[0]=="Water")
water = H-1 - ss[1].to!int();
else if(ss.length==2 && ss[0]=="Flooding")
flooding = ss[1].to!int();
else if(ss.length==2 && ss[0]=="Waterproof")
water_proof = ss[1].to!int();
}
}
@property const
{
int W() { return data[0].length; }
int H() { return data.length; }
string toString() {
string result;
foreach(i,s; data) {
if(i) result ~= '\n';
result ~= s.idup;
}
return result;
}
}
int command_R() { if(dead)return 0; write("R"); return move(0, +1); }
int command_L() { if(dead)return 0; write("L"); return move(0, -1); }
int command_U() { if(dead)return 0; write("U"); return move(-1, 0); }
int command_D() { if(dead)return 0; write("D"); return move(+1, 0); }
int wait() { if(dead)return 0; update(); write("W"); return -1; }
int abort() { if(dead)return 0; cleared=true; write("A"); return gained*25; }
int move(int dy, int dx) {
foreach(y,s; data)
foreach(x,c; s)
if(c == 'R')
return move(dy, dx, y, x);
assert(false);
}
int gained = 0; // TODO: atode naosu
int move(int dy, int dx, int y, int x) {
if(dead)
return 0;
int score = 0;
if(data[y+dy][x+dx]=='\\') {
score += 25;
++gained;
}
if(data[y+dy][x+dx]=='O') {
score += gained*50;
cleared = true;
}
if(data[y+dy][x+dx]==' ' || data[y+dy][x+dx]=='.'
|| data[y+dy][x+dx]=='\\' || data[y+dy][x+dx]=='O') {
data[y][x]=' ';
data[y+dy][x+dx]='R';
} else if(dy==0 && data[y+dy][x+dx]=='*' && data[y+2*dy][x+2*dx]==' ') {
data[y][x]=' ';
data[y+dy][x+dx]='R';
data[y+2*dy][x+2*dx]='*';
}
update();
return score-1;
}
void update() {
char[][] next;
foreach(y,s; data)
next ~= s.dup;
bool lambda = false;
for(int y=1; y+1<H; ++y)
for(int x=1; x+1<W; ++x)
lambda |= (data[y][x] == '\\');
for(int y=H-2; y>=1; --y)
for(int x=1; x+1<W; ++x) {
if(data[y][x]=='*') {
if(data[y+1][x]==' ') {
next[y][x]=' ';
next[y+1][x]='*';
if(next[y+2][x]=='R')
dead=true;
}
else if(data[y+1][x]=='*' && data[y][x+1]==' ' && data[y+1][x+1]==' ') {
next[y][x]=' ';
next[y+1][x+1]='*';
if(next[y+2][x+1]=='R')
dead=true;
}
else if(data[y+1][x]=='*' && data[y][x-1]==' ' && data[y+1][x-1]==' ') {
next[y][x]=' ';
next[y+1][x-1]='*';
if(next[y+2][x-1]=='R')
dead=true;
}
else if(data[y+1][x]=='\\' && data[y][x+1]==' ' && data[y+1][x+1]==' ') {
next[y][x]=' ';
next[y+1][x+1]='*';
if(next[y+2][x+1]=='R')
dead=true;
}
}
else if(data[y][x]=='L') {
if(!lambda)
next[y][x] = 'O';
}
}
data = next;
if(flooding) {
flooding_counter ++;
if(flooding_counter == flooding) {
flooding_counter = 0;
water --;
}
bool wa = false;
for(int y=water; y+1<H; ++y)
for(int x=1; x+1<W; ++x)
if(data[y][x]=='R') {
wa = true;
underwater++;
if(underwater > water_proof)
dead = true;
}
if(!wa)
underwater = 0;
}
}
int clever()
{
if(dead)
return 0;
int sy,sx;
int[] ly,lx;
int oy,ox;
for(int y=0; y<H; ++y)
for(int x=0; x<W; ++x)
if(data[y][x]=='R')
sy=y, sx=x;
else if(data[y][x]=='\\')
ly~=y, lx~=x;
else if(data[y][x]=='O')
oy=y, ox=x;
if(ly.length==0) {
auto r = search(sy,sx,oy,ox);
switch(r[0]) {
case 'D': return command_D();
case 'U': return command_U();
case 'L': return command_L();
case 'R': return command_R();
case 'A': return abort();
default: return wait();
}
}
return wait();
}
Tuple!(char,int) search(int sy, int sx, int oy, int ox)
{
alias Tuple!(int,"y",int,"x") Pt;
Pt[] q = [Pt(oy,ox)];
for(int step=1; q.length; ++step) {
Pt[] q2;
foreach(p; q) {
int[] dy=[-1,+1,0,0];
int[] dx=[0,0,-1,+1];
for(int i=0; i<4; ++i) {
int y = p.y+dy[i];
int x = p.x+dx[i];
if(y==sy && x==sx) {
if(i==0) return tuple('D',step);
if(i==1) return tuple('U',step);
if(i==2) return tuple('R',step);
if(i==3) return tuple('L',step);
} else if(data[y][x]==' '||data[y][x]=='\\') {
q2 ~= Pt(y,x);
} else if(data[y][x]=='.' && data[y-1][x]!='*') {
q2 ~= Pt(y,x);
}
}
}
q = q2;
}
q = [Pt(oy,ox)];
for(int step=1<<10; q.length; ++step) {
Pt[] q2;
foreach(p; q) {
int[] dy=[-1,+1,0,0];
int[] dx=[0,0,-1,+1];
for(int i=0; i<4; ++i) {
int y = p.y+dy[i];
int x = p.x+dx[i];
if(y==sy && x==sx) {
if(i==0) return tuple('D',step);
if(i==1) return tuple('U',step);
if(i==2) return tuple('R',step);
if(i==3) return tuple('L',step);
} else if(data[y][x]==' '||data[y][x]=='\\') {
q2 ~= Pt(y,x);
} else if(data[y][x]=='.'/* && data[y-1][x]!='*'*/) {
q2 ~= Pt(y,x);
}
}
}
q = q2;
}
return tuple('A',int.max);
}
}
class MyForm : Form
{
Map m;
int score;
this(Map m)
{
noMessageFilter();
this.m = m;
this.text = .text("Score: ", score, " air[",m.water_proof-m.underwater,"]");
this.keyDown ~= &myKey;
this.score = 0;
}
override void onResize(EventArgs ev) {
invalidate();
}
override void onPaint(PaintEventArgs ev)
{
int Z = min(this.clientSize.width/(m.W-2), this.clientSize.height/(m.H-2));
Font font = new Font("MS Gothic", Z-4);
Graphics g = ev.graphics;
g.fillRectangle(Color(0,233,255), Rect(0,Z*(m.water-1),this.clientSize.width,this.clientSize.height-(Z*(m.water-1))));
for(int y=1; y+1<m.H; ++y)
for(int x=1; x+1<m.W; ++x) {
if(m.data[y][x]=='*') {
g.drawText("岩", font, Color(0,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='\\') {
g.drawText("λ", font, Color(0,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='R') {
if(m.dead)
g.drawText("Я", font, Color(255,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
else
g.drawText("R", font, Color(128,128,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='L') {
g.drawText("扉", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='O') {
g.drawText("外", font, Color(255,255,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='#') {
g.drawText("#", font, Color(0,0,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
if(m.data[y][x]=='.') {
g.drawText("・", font, Color(128,40,0), Rect((x-1)*Z, (y-1)*Z, Z, Z));
}
}
}
void myKey(Control c, KeyEventArgs ev)
{
switch(ev.keyCode)
{
case Keys.DOWN:
score += m.command_D();
stdout.flush();
break;
case Keys.UP:
score += m.command_U();
stdout.flush();
break;
case Keys.LEFT:
score += m.command_L();
stdout.flush();
break;
case Keys.RIGHT:
score += m.command_R();
stdout.flush();
break;
case Keys.W:
score += m.wait();
stdout.flush();
break;
case Keys.A:
score += m.abort();
stdout.flush();
break;
case Keys.G:
score += m.clever();
stdout.flush();
break;
default:
break;
}
if(m.cleared) {
writeln();
writeln("Score: ", score);
Application.exit();
}
this.text = .text("Score: ", score, " air[",m.water_proof-m.underwater,"]");
invalidate();
}
}
void main(string[] args)
{
Form myForm = new MyForm(new Map(File(args[1])));
Application.run(myForm);
}