import java.awt.*;
//import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.*;

public class CampoMinado extends Applet implements MouseListener {
    protected int [][] mines;
    protected int [][] field;
    protected int numCells;
    protected int numMines;
    protected int height;
    protected int width;
    protected int marked;
    protected int opened;
    protected Color bgColor;
    protected Color borderColor;
    protected Color textColor;
    protected Color openColor;
    protected Color hiddenColor;
    protected Image bi;
    protected boolean lost;
    protected boolean won;
    
    public void init() {
        bgColor=getColor("#eaeabb");
        borderColor=getColor("#000000");
        openColor=getColor("#efefcb");
        hiddenColor=getColor("#dadaab");
        textColor=getColor("#000000");
        height = 400; //Integer.parseInt(getParameter("hgt"));
        width = 400; //Integer.parseInt(getParameter("wid"));
        numMines = 10; //Integer.parseInt(getParameter("mines"));
        numCells = height * width;
        mines = new int [height][width];
        field = new int [height][width];
        resize(100+20*width,100+20*height);
        bi=createImage(20*width, 20*(height+1));
        paintBoard(bi.getGraphics());
        setVisible(true);
        addMouseListener(this);
        restart();
    }
    
    protected boolean isMined(int x, int y) {
        if (x<0 || y<0 || x>=width || y>=height)
            return false;
        return (mines[y][x]==10);
    }
    
    protected boolean isMarked(int x, int y) {
        if (x<0 || y<0 || x>=width || y>=height)
            return false;
        return (field[y][x]==2);
    }
    
    protected void mark(int x, int y) {
        if (marked==numMines) return;
        if (field[y][x]==0) {
            field[y][x]=2;
            marked++;
            drawCell(bi.getGraphics(),x,y);
        }
    }
    
    protected void unMark(int x, int y) {
        if (field[y][x]==2) {
            field[y][x]=0;
            marked--;
            drawCell(bi.getGraphics(),x,y);
        }
    }
    
    protected void open(int x,int y) {
        if (x<0 || y<0 || x>=width || y>=height || field[y][x]!=0)
            return;
        field[y][x]=1;
        opened++;
        drawCell(bi.getGraphics(),x,y);
        if (mines[y][x]==0) {
            open(x-1,y-1);
            open(x,y-1);
            open(x+1,y-1);
            open(x+1,y);
            open(x+1,y+1);
            open(x,y+1);
            open(x-1,y+1);
            open(x-1,y);
        }
    }
    
    protected void restart() {
        int i; int j;
        lost=false;
        won=false;
        opened=0;
        for (i=0; i<height; i++)
            for (j=0; j<width; j++) {
            field[i][j]=0;
            mines[i][j]=0;
            }
        for (i=0; i<numMines; i++) {
            int x; int y;
            do {
                x=(int)(Math.random()*width);
                y=(int)(Math.random()*height);
            } while (isMined(x,y));
            mines[y][x]=10;
        }
        for (i=0; i<height; i++)
            for (j=0; j<width; j++)
                if (! isMined(j,i)) {
            int total=0;
            if (isMined(j-1,i-1)) total++;
            if (isMined(j,i-1)) total++;
            if (isMined(j+1,i-1)) total++;
            if (isMined(j+1,i)) total++;
            if (isMined(j+1,i+1)) total++;
            if (isMined(j,i+1)) total++;
            if (isMined(j-1,i+1)) total++;
            if (isMined(j-1,i)) total++;
            mines[i][j]=total;
                }
        marked=0;
    }
    
    public void paint(Graphics g) {
        g.drawImage(bi,0,0,null);
        g.drawString(""+(numMines-marked),40,15+20*height);
        if (won) {
            g.setColor(openColor);
            g.fillRect(20,20,20*(width-2)-2,38);
            g.setColor(borderColor);
            g.drawRect(20,20,20*(width-2)-2,38);
            g.setColor(textColor);
            g.drawString("You won! Click to play again.",22,30+15);
        }
        if (lost) {
            g.setColor(openColor);
            g.fillRect(20,20,20*(width-2)-2,38);
            g.setColor(borderColor);
            g.drawRect(20,20,20*(width-2)-2,38);
            g.setColor(textColor);
            g.drawString("You lost! Click to play again.",22,30+15);
        }
        
        super.paint(g);
    }
    
    public void paintBoard(Graphics g) {
        int i; int j;
        g.setColor(bgColor);
        g.fillRect(0,0,width*20,(height+1)*20);
        for (i=0; i<height; i++)
            for (j=0; j<width; j++)
                drawCell(g,j,i);
        g.setColor(borderColor);
        g.drawRect(0,height*20,20*width-2,18);
        g.drawLine(20*(width-4),height*20,20*(width-4),(height+1)*20-2);
        g.setColor(textColor);
        g.drawString("Mines:",2,15+20*height);
        g.drawString("Restart",20*(width-3),15+20*height);
    }
    
    protected void drawCell(Graphics g, int x, int y) {
        int rx=20*x;
        int ry=20*y;
        if (field[y][x]!=1) {
            g.setColor(hiddenColor);
            g.fillRect(rx,ry,18,18);
            g.setColor(textColor);
            if (field[y][x]==2) {
                g.drawString(" P",rx+1,ry+15);
            }
        } else {
            g.setColor(openColor);
            g.fillRect(rx,ry,18,18);
            g.setColor(textColor);
            if (isMined(x,y)) {
                g.drawString(" o",rx+1,ry+15);
            } else if (mines[y][x]>0) {
                g.drawString(" "+mines[y][x],rx+1,ry+15);
            }
        }
        g.setColor(borderColor);
        g.drawRect(x*20,y*20,18,18);
    }
    
    public static Color getColor(Object v) {
        if (v instanceof Color) return (Color)v;
        if (!(v instanceof String)) return Color.black;
        String value=(String)v;
        Color c=null;
        if (value==null || value.length()<1) return null;
        try {
            if (value.charAt(0) == '#')
                c = new Color(Integer.decode("0x"+value.substring(1)).intValue());
            if (c == null) c = Color.white;
            return c;
        } catch (Exception e){ return null; }
    }
    
    public void mouseClicked(MouseEvent e) {
        if (won || lost) {
            restart();
            paintBoard(bi.getGraphics());
            repaint();
            return;
        }
        int x = e.getX()/20;
        int y = e.getY()/20;
        if ((e.getModifiers() & InputEvent.BUTTON1_MASK) !=0) {
            if (y==height && x>width-4 && x<width) {
                restart();
                paintBoard(bi.getGraphics());
                repaint();
                return;
            }
            open(x,y);
            if (isMined(x,y)) {
                lost=true;
            } else if (opened==numCells-numMines) {
                won=true;
            }
        } else if ((e.getModifiers() & InputEvent.BUTTON3_MASK) !=0) {
            if (isMarked(x,y))
                unMark(x,y);
            else
                mark(x,y);
        }
        repaint();
    }
    
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    
}
