import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
///usr/java/jdk1.5.0_09/bin/javac -g:none T.java;/usr/java/jdk1.5.0_09/bin/jar cvfm bomb.jar manifest.txt *.class;ls -la bomb.jar
public class T extends JPanel implements KeyListener, ActionListener{   
    public static int w=11;
    public static int h=11;
    public static T c;
    public static short sc=16;
    boolean kd[];

    float x,y;
    int nb,mxb;
    int spn,lvs,scr,lvl;
    
    int glf[],gst[];

    Vector en;
    int wtg;
    int tm;
    String msg;
    boolean llv;
    public T(){
	en=new Vector();
	kd=new boolean[1024];
	mxb=1;
	lvs=3;
	spn=1;
	lvl=0;
	scr=0;
 	for(int i=0;i<kd.length;i++)
	    kd[i]=false;

	glf=new int[w*h];
	gst=new int[w*h];

	r();
    }
    private void r(){
	msg=null;
	wtg=30*3;
	this.x=this.y=0;
	nb=mxb;
	String s="000M00EE55501510101015005050055550101010101550050050000015101010100505000005051010101010550005005005151515151500050500=55340066700000055555015101010150050500=5550101010101M50050050000015101010100005000000051010101010550005000005151010101000000500000340066700000050500015101010150050500050501010101015500100500000151=101010050500000505101010101055000E0050051010151515000505005553400667";
	char ar[]=s.toCharArray();
	int lvi=0;
	int ind=0;
	for(;lvi<=lvl;lvi++){
	    en.clear();
	    for(int y=0;y<w*h;y++,ind++){
		gst[y]=ar[ind]-'0';
		glf[y]=0x7FFFFFFF;
	    }
	    int nem=ar[ind++]-'0';
	    for(int i=0;i<nem;i++){
		float f[]=new float[5];
		f[0]=ar[ind++]-'0';
		f[1]=ar[ind++]-'0';
		f[2]=0;
		f[3]=0;
		f[4]=0.125f+lvi*0.0625f;//speed
		en.addElement(f);
		//en.addElement(new E(br.read()-'0',br.read()-'0'));
		
	    }
	}
	llv=(ind==ar.length);
	tm=3000;
	/*
	for(int y=0;y<h;y++){
	    for(int x=0;x<w;x++){
		grid[y*w+x]=new BF(0);
		if(x%2==1 && y%2==1){
		    grid[y*w+x]=new BF(1);//solid block
		}
		else if(Math.random()<0.2){
		    grid[y*w+x]=new BF(5);
		}
		
	    }
	}
	for(int i=0;i<4;i++){
	    int xi=(int)Math.round(Math.random()*(w-1));
	    int yi=(int)Math.round(Math.random()*(h-1));
	    if(grid[yi*w+xi].st==0)
		en.addElement(new E(xi,yi));
	    else
		i--;
	}
	*/
    }
    public void paint(Graphics gin){
	//Image img = (new ImageIcon("im")).getImage();
	Graphics2D g=(Graphics2D)gin;
	g.clearRect(0,0,getWidth(),getHeight());
	
	g.drawString("Bomb:"+nb+"/"+mxb+" Lives:"+lvs+" Score:"+scr+" Time:"+(tm/30),0,10);

	g.translate((getWidth()-w*sc)/2,25);

	//for(int y=0;y<h;y++){
	for(int ind=0;ind<w*h;ind++){
	    int y=ind/w;
	    int x=ind%w;
	    //for(int x=0;x<w;x++){
		int st=gst[y*w+x];
		int stl=st&0x7;
		int stu=st&~0x7;
		int lf=glf[y*w+x];
		g.setColor(Color.BLACK);
		g.drawRect(x*sc,y*sc,sc,sc);

		//exit
		if(stu==0x8){
		    //g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,128,16,144,null);
		    g.setColor(Color.GREEN);
		    g.fillRect(x*sc,y*sc,sc,sc);
		}
		//bomb
		else if(stu==0x10){
		    /*g.setColor(Color.GREEN);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,32,16,48,null);*/
		    
		    g.setColor(Color.GREEN);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.setColor(Color.YELLOW);
		    g.fillRect(x*sc+2,y*sc+2,sc-4,sc-4);
		    g.setColor(Color.BLACK);
		    g.fillOval(x*sc+2,y*sc+2,sc-4,sc-4);
		}
		//flame
		else if(st==0x18){
		    /*g.setColor(Color.GREEN);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,48,16,64,null);*/
		    g.setColor(Color.GREEN);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.setColor(Color.YELLOW);
		    g.fillRect(x*sc+2,y*sc+2,sc-4,sc-4);
		    g.setColor(Color.RED);
		    g.fillOval(x*sc+2,y*sc+2,sc-4,sc-4);
		}

		double s=(Math.sin(((float)lf)/4.0f))*0.125+0.875f;
		if(stl==3){
		    /*int x0=(int)(x*sc+(1.0-s)*sc/2.0);
		    int y0=(int)(y*sc+(1.0-s)*sc/2.0);
		    g.drawImage(img,x0,y0,x0+(int)(sc*s),y0+(int)(sc*s),0,32,16,48,null);*/
		    g.setColor(Color.BLACK);
		    g.fillOval((int)(x*sc+(1-s)*sc/2),
		    (int)(y*sc+(1-s)*sc/2),(int)(sc*s),(int)(sc*s));
		    continue;
		}
		else if(stl==1){
		    //g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,0,16,16,null);
		    g.setColor(Color.GRAY);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.setColor(Color.DARK_GRAY);
		    g.fillRect(x*sc+2,y*sc+2,sc-4,sc-4);
		}
		else if((stl&0x4)==0x4){
		    //g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,16,16,32,null);
		    g.setColor(Color.LIGHT_GRAY);
		    g.fillRect(x*sc,y*sc,sc,sc);
		    g.setColor(Color.GRAY);
		    g.fillRect(x*sc+2,y*sc+2,12,4);
		    g.fillRect(x*sc+2,y*sc+9,12,4);
		}

		if((stl&0x2)==2){
		    /*g.drawImage(img,x*sc,y*sc,(x+1)*sc,(y+1)*sc,0,48,16,64,null);
		    if(x>0 && (gst[y*w+x-1]&0x2)==2)
			g.drawImage(img,x*sc-8,y*sc,(x+1)*sc-8,(y+1)*sc,0,48,16,64,null);
		    if(y>0 && (gst[y*w+x-w]&0x2)==2)
		    g.drawImage(img,x*sc,y*sc-8,(x+1)*sc,(y+1)*sc-8,0,48,16,64,null);*/
		    //g.setColor(new Color(1.0f,0.0f,0.0f,(float)s));
		    g.setColor(Color.RED);
		    g.fillOval(x*sc,y*sc,sc,sc);
		    if(x>0 && (gst[y*w+x-1]&0x2)==2){
			g.fillOval(x*sc-sc/2,y*sc,sc,sc);
		    }
		    if(y>0 && (gst[y*w+x-w]&0x2)==2)
			g.fillOval(x*sc,y*sc-sc/2,sc,sc);
		}

		//}
	}
	for(int i=0;i<en.size();i++){
	    float e[]=(float[])en.elementAt(i);
	    //g.drawImage(img,(int)(e[0]*sc),(int)(e[1]*sc),
	    //	(int)(e[0]*sc)+sc,(int)(e[1]*sc)+sc,0,64,16,80,null);
	    
	    g.setColor(Color.ORANGE);
	    g.fillOval((int)(e[0]*sc),(int)(e[1]*sc),sc,sc);
	    g.setColor(Color.BLACK);
	    int offsx=(int)e[2];
	    int offsy=(int)e[3];
	    g.fillOval((int)(e[0]*sc)+4+offsx,6+(int)(e[1]*sc)+offsy,2,4);
	    g.fillOval((int)(e[0]*sc)+10+offsx,6+(int)(e[1]*sc)+offsy,2,4);
	}
	//draw man
	/*
	int ind=((int)((this.x+this.y)*7.0f))%2;
	g.drawImage(img,(int)(this.x*sc),(int)(this.y*sc)-8,
		    (int)(this.x*sc)+16,(int)(this.y*sc)+16,0,80+ind*24,16,104+ind*24,null);
	*/
	g.setColor(Color.BLUE);
	g.fillOval((int)(this.x*sc)+4,(int)(this.y*sc)-4,sc-8,sc-8);
	g.fillOval((int)(this.x*sc)+2,(int)(this.y*sc)+2,sc-4,sc-4);
	g.setColor(Color.WHITE);
	g.drawString("~",(int)(this.x*sc)+4,(int)(this.y*sc)+4);

	if(wtg>0){
	    g.setFont(new Font("Serif",Font.BOLD,16));
	    g.setColor(Color.BLACK);
	    String s=msg;
	    if(s==null)
		s="Ready ";//+(wtg/30);
	    g.drawString(s,getWidth()/2-s.length()*8,getHeight()/2-20);
	}
    }
    private void bexp(int ind){
	boolean xp=true,yp=true,xm=true,ym=true;
	nb++;

	glf[ind]=15;
	gst[ind]=2;//don't need to worry about powerup-s beneath bomb

	int x=ind%w;
	int y=ind/w;
	for(int i=1;i<=spn;i++){
	    if(x+i<w && xp){
		int curst=gst[ind+i];
		if(curst==3)
		    bexp(ind+i);
		else if(curst!=1){
		    glf[ind+i]=15;
		    gst[ind+i]|=2;
		}
	        xp=(curst&0x1)==0;
	    }
	    if(x-i>=0 && xm){
		int curst=gst[ind-i];
		if(curst==3)
		    bexp(ind-i);
		else if(curst!=1){
		    glf[ind-i]=15;
		    gst[ind-i]|=2;
		}
		xm=(curst&0x1)==0;
	    }
	    if(y+i<h && yp){
		int curst=gst[ind+i*w];
		if(curst==3)
		    bexp(ind+i*w);
		else if(curst!=1){
		    glf[ind+i*w]=15;
		    gst[ind+i*w]|=2;
		}
		yp=(curst&0x1)==0;
	    }
	    if(y-i>=0 && ym){
		int curst=gst[ind-i*w];
		if(curst==3)
		    bexp(ind-i*w);
		else if(curst!=1){
		    glf[ind-i*w]=15;
		    gst[ind-i*w]|=2;
		}
		ym=(curst&0x1)==0;
	    }
	}
    }
    public void keyPressed(KeyEvent ke){
	kd[ke.getKeyCode()]=true;

	if(kd[KeyEvent.VK_SPACE] && nb>0){
	    int yi=Math.round(y);
	    int xi=Math.round(x);
	    if((gst[yi*w+xi]&0x1)==0){
		//drop bomb
		gst[yi*w+xi]=3|(gst[yi*w+xi]&~0x7);;
		glf[yi*w+xi]=90;
		nb--;
	    }
	}
    }
    public void keyReleased(KeyEvent ke){
	kd[ke.getKeyCode()]=false;
	if(ke.getKeyCode()==KeyEvent.VK_R){
	    mxb=1;
	    spn=1;
	    lvs=3;
	    scr=0;
	    lvl=0;
	    r();
	}
    }
    public void keyTyped(KeyEvent ke){
	
    }
    //called by timer
    public void actionPerformed(ActionEvent ae){
	if(wtg>0){
	    wtg--;
	    if(wtg==0 && msg!=null)
		r();//reset now
	    repaint();
	    return;
	}
	tm--;
	if(tm<0){
	    msg="Too Slow";
	    wtg=100;
	    lvs--;
	    if(lvs==0){
		msg="Game Over";
		wtg=10000000;
	    }
	}
	///else of wtg>0
	
	boolean hor=false;
	boolean ver=false;
	float xbf=this.x;
	float ybf=this.y;
	float dx=0;
	float dy=0;
	int xb=Math.round(this.x);
	int yb=Math.round(this.y);
	
	if(kd[KeyEvent.VK_LEFT]){
	    dx=-0.25f;
	    this.x-=0.2f;
	    if(this.x<0)this.x=0;
	    hor=true;
	}
	else if(kd[KeyEvent.VK_RIGHT]){
	    this.x+=0.2f;
	    dx=0.25f;
	    if(this.x>=(w-1))this.x=(w-1);
	    hor=true;
	}
	else if(kd[KeyEvent.VK_UP]){
	    this.y-=0.2f;
	    dy=-0.25f;
	    if(this.y<0)this.y=0;
	    ver=true;
	}
	else if(kd[KeyEvent.VK_DOWN]){
	    this.y+=0.2f;
	    dy=0.25f;
	    if(this.y>=(h-1))this.y=(h-1);
	    ver=true;
	}
	int xi=(int)this.x;
	int yi=(int)this.y;
	float a=this.x-xi;
	float b=this.y-yi;
	if(a<=0.5 && a>0.1 && ver)this.x=0.1f+xi;
	if(a>0.5 &&  a<0.9 && ver)this.x=0.9f+xi;
	
	if(b<=0.5 && b>0.1 && hor)this.y=0.1f+yi;
	if(b>0.5  && b<0.9 && hor)this.y=0.9f+yi;
	
	int xa=Math.round(this.x+dx);
	int ya=Math.round(this.y+dy);
	if((xa!=xb||ya!=yb)&&(gst[ya*w+xa]&0x1)==1){
	    this.x=xbf;
	    this.y=ybf;
	}
	xa=Math.round(this.x);
	ya=Math.round(this.y);
	//Damage player here 
	if((gst[ya*w+xa]&0x7)==2){
	    lvs--;
	    msg="Death";
	    wtg=100;
	    if(lvs==0){
		msg="Game Over";
		wtg=10000000;
	    }
	    //r();
	    //reset
	}
	//pick up bomb
	if(gst[ya*w+xa]==0x10){
	    mxb++;
	    nb++;
	    gst[ya*w+xa]=0;
	}
	//flame
	else if(gst[ya*w+xa]==0x18){
	    spn++;
	    gst[ya*w+xa]=0;
	}

	for(int i=0;i<w*h;i++){
	    //for(int x=0;x<w;x++){
	    glf[i]--;
	    if(glf[i]==0){
		int stu=(gst[i]&~0x7);
		if(gst[i]==3){
		    //Bomb exploded
		    bexp(i);
		}
		//flame extinguish
		else if((gst[i]&0x7)==2 && stu>0){
		    //if we hit a powerup or exit, add enemies
		    for(int k=0;k<=lvl;k++){
			float f[]=new float[5];
			f[0]=i%w;
			f[1]=i/w;
			f[2]=0;
			f[3]=0;
			f[4]=0.125f+lvl*0.0625f;//speed
			en.add(f);
		    }
		    if(stu!=0x8)
			gst[i]=0;//destroy powerup
		    else gst[i]&=~0x7;
		}
		else{
		    gst[i]&=~0x7;//was set to 0 before
		}
	    }
	}
	//Move and damage en here (and damage player by enemy)
	for(int i=0;i<en.size();i++){
	    float e[]=(float[])en.elementAt(i);

	    if(e[2]==0 && e[3]==0){
		e[2]=1;
	    }
	    xi=(int)e[0];
	    yi=(int)e[1];
	    a=e[0]-xi;
	    b=e[1]-yi;
	    //in line with grid, pick random direction
	    if(a==0 && b==0 && Math.random()<0.1){
		boolean b1=Math.random()<0.5;
		boolean b2=Math.random()<0.5;
		
		e[2]=0;
		e[3]=0;
		if(b1){
		    if(b2)
			e[2]=1;
		    else e[2]=-1;
		}
		else
		{
		    if(b2)
			e[3]=1;
		    else e[3]=-1;
		}
	    }
	    e[0]+=e[2]*e[4];
	    e[1]+=e[3]*e[4];
	    xi=Math.round(e[0]+e[2]*0.25f);
	    yi=Math.round(e[1]+e[3]*0.25f);
	    if(xi<0||yi<0||xi>=w||yi>=h||(gst[yi*w+xi]&0x1)==1){
		e[2]=-e[2];
		e[3]=-e[3];
		e[0]+=e[2]*e[4];
		e[1]+=e[3]*e[4];
	    }
	    xi=Math.round(e[0]);
	    yi=Math.round(e[1]);
	    //Enemy has been hit by flame
	    if(gst[yi*w+xi]==2){
		en.remove(e);
		scr+=100*(lvl+1);
		i--;		
	    }
	    //kill player
	    if(xi==xa && yi==ya){
		lvs--;
		msg="Death";
		wtg=100;
		if(lvs==0){
		    msg="Game Over";
		    wtg=10000000;
		}
		    
		//r();
	    }
	}
	//proceed to next lvl
	if(en.size()==0 && (gst[ya*w+xa])==0x8){
	    lvl++;	    
	    msg="Done";
	    wtg=100;
	    scr+=tm/3;
	    if(llv){
		msg="You Win";
		wtg=10000000;
	    }
	    //r();
	}
	repaint();
    }
    public static void main(String args[]){
	JFrame frame=new JFrame();
        c=new T();
	frame.setSize(240,260);
	//frame.setLocation(0,0);
	frame.getContentPane().add(c);
	frame.setVisible(true);
	//frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	frame.addKeyListener(c);
	new Timer(30,c).start();
    }
};