/*
 SameGame(0.2)
 */

import java.applet.*;
import java.awt.*;
import java.util.Random;

public class SameGame extends Applet {
    static final int X = 20;
    static final int Y = 10;
    static final int GX = 20;
    static final int GY = 20;
    static final int SORTS = 5;

    SGMain sgmain;
    Button bn,bu;
    Random rnd;

    public static boolean selected = false;
    public static int sp;
    public static int sn;

    public static int rest;
    public static int score;
    public static int w;
    public static int h[] = new int[X];
    public static byte piece[][] = new byte[X][Y];

    public static boolean visit[][] = new boolean[X][Y];
    public static boolean update[][] = new boolean[X][Y];
 
    public void init() {
        resize(X*GX,Y*GY+80);
        sgmain = new SGMain();
        bn = new Button("New");
        bu = new Button("Undo");
        rnd = new Random();
        add(sgmain);
        add(bn);
        add(bu);
    }

    public void newGame() {
        int x,y,r;

        w = SameGame.X;
        for (x=0;x<X;x++) {
            h[x] = SameGame.Y;
            for (y=0;y<Y;y++) {
                r = rnd.nextInt();
                if (r<0) {
                    r = -r;
                }
                piece[x][y] = (byte)((r % SORTS) + 1);
                visit[x][y] = false;
            }
        }
        selected = false;
        rest = X*Y;
        score = 0;
        repaint();
        sgmain.repaint();
        showStatus("Score : "+score);
    }

    public void undoGame(){
        /* Not available */
    }

    public boolean action(Event e,Object arg) {
        if (e.target instanceof Button) {
            if ("New".equals(arg)) {
                newGame();
            } else if ("Undo".equals(arg)) {
                undoGame();
            }
        }
        return true;
    }

    public boolean mouseUp(Event e,int x,int y) {
        showStatus("Score : "+score);
        return false;
    }
}

final class SGMain extends Panel {
    public SGMain() {
        setBackground(Color.black);
        setForeground(Color.white);
        resize(SameGame.X*SameGame.GX,SameGame.Y*SameGame.GY);
        move(0,0);
        setLayout(null);
    }

    public boolean mouseDown(Event e,int x,int y) {
        int ix,iy;

        ix = x/SameGame.GX;
        iy = SameGame.Y-y/SameGame.GY-1;
        if (SameGame.selected) {
            if (SameGame.visit[ix][iy]) {
                rmvPiece();
            } else {
                cslPiece();
            }
        } else if (SameGame.piece[ix][iy]!=0) {
            selPiece(ix,iy);
        }
        return false;
    }

    public void rmvPiece() {
        int x,y,xx,yy;

        SameGame.selected = false;
        SameGame.rest -= SameGame.sn;
        SameGame.score += SameGame.sn+(SameGame.sn-2)*(SameGame.sn-2);
        if (SameGame.rest==0) {
            SameGame.score += 1000;
        }
        for (x=0;x<SameGame.w;x++) {
            for (y=0;y<SameGame.h[x];y++) {
                if (SameGame.visit[x][y]) {
                    SameGame.visit[x][y] = false;
                    SameGame.piece[x][y] = 0;
                    SameGame.update[x][y] = true;
                }
            }
        }
        for (x=0;x<SameGame.w;x++) {
            for (y=0,yy=0;y<SameGame.h[x];y++) {
                if (SameGame.piece[x][y]!=0) {
                    if (SameGame.piece[x][yy]!=SameGame.piece[x][y]) {
                        SameGame.piece[x][yy] = SameGame.piece[x][y];
                        SameGame.update[x][yy] = true;
                    }
                    yy++;
                }
            }
            for (y=yy;y<SameGame.h[x];y++) {
                if (SameGame.piece[x][y]!=0) {
                    SameGame.piece[x][y] = 0;
                    SameGame.update[x][y] = true;
                }
            }
            SameGame.h[x] = yy;
        }
        for (x=0,xx=0;x<SameGame.w;x++) {
            if (SameGame.h[x]!=0) {
                for (y=0;y<SameGame.h[x];y++) {
                    if (SameGame.piece[xx][y] != SameGame.piece[x][y]) {
                        SameGame.piece[xx][y] = SameGame.piece[x][y];
                        SameGame.update[xx][y] = true;
                    }
                }
                for (;y<SameGame.h[xx];y++) {
                    if (SameGame.piece[xx][y]!=0) {
                        SameGame.piece[xx][y] = 0;
                        SameGame.update[xx][y] = true;
                    }
                }
                SameGame.h[xx] = SameGame.h[x];
                xx++;
            }
        }
        for (x=xx;x<SameGame.w;x++) {
            for (y=0;y<SameGame.h[x];y++) {
                if (SameGame.piece[x][y] != 0) {
                    SameGame.piece[x][y] = 0;
                    SameGame.update[x][y] = true;
                }
            }
            SameGame.h[x]=0;
        }
        SameGame.w = xx;
        drawRegion(getGraphics(),0,0,SameGame.X,SameGame.Y,true);
    }

    public void cslPiece() {
        int x,y;

        for (x=0;x<SameGame.w;x++) {
            for (y=0;y<SameGame.h[x];y++) {
                if (SameGame.visit[x][y]) {
                    SameGame.visit[x][y] = false;
                    SameGame.update[x][y] = true;
                }
            }
        }
        SameGame.selected = false;
        drawRegion(getGraphics(),0,0,SameGame.X,SameGame.Y,true);
    }

    public void selPiece(int x,int y) {

        SameGame.selected = true;
        SameGame.sp = SameGame.piece[x][y];
        SameGame.visit[x][y] = true;
        SameGame.update[x][y] = true;
        SameGame.sn = connect(x,y);
        if (SameGame.sn==0) {
            SameGame.visit[x][y] = false;
            SameGame.update[x][y] = false;
            SameGame.selected = false;
        } else {
            SameGame.sn++;
            drawRegion(getGraphics(),0,0,SameGame.X,SameGame.Y,true);
        }
    }

    private protected int connect(int x,int y) {
        int a = 0;

        if (x!=0) {
            if (!SameGame.visit[x-1][y] && SameGame.piece[x-1][y]==SameGame.sp) {
                SameGame.visit[x-1][y]=true;
                SameGame.update[x-1][y]=true;
                a += connect(x-1,y)+1;
            }
        }
        if (x!=(SameGame.X-1)) {
            if (!SameGame.visit[x+1][y] && SameGame.piece[x+1][y]==SameGame.sp) {
                SameGame.visit[x+1][y]=true;
                SameGame.update[x+1][y]=true;
                a += connect(x+1,y)+1;
            }
        }
        if (y!=0) {
            if (!SameGame.visit[x][y-1] && SameGame.piece[x][y-1]==SameGame.sp) {
                SameGame.visit[x][y-1]=true;
                SameGame.update[x][y-1]=true;
                a += connect(x,y-1)+1;
            }
        }
        if (y!=(SameGame.Y-1)) {
            if (!SameGame.visit[x][y+1] && SameGame.piece[x][y+1]==SameGame.sp) {
                SameGame.visit[x][y+1]=true;
                SameGame.update[x][y+1]=true;
                a += connect(x,y+1)+1;
            }
        } 
        return a;
    }

    public void drawRegion(Graphics g,int sx,int sy,int ex,int ey,boolean f) {
        boolean u,v;
        int x,y,gx,gy,p;
        Color cf,cb;

        for (y=sy,gy=(SameGame.Y-1-sy)*SameGame.GY;y<ey;y++,gy-=SameGame.GY) {
            for (x=sx,gx=sx*SameGame.GX;x<ex;x++,gx+=SameGame.GX) {
                p = SameGame.piece[x][y];
                v = SameGame.visit[x][y];
                u = SameGame.update[x][y];
                if (f==true && u==false) {
                    continue;
                }
                SameGame.update[x][y] = false;
                cb = (v)?Color.white:Color.black;
                cf = Color.black;
                switch(p) {
                  case 1:
                    cf = Color.blue;
                    break;
                  case 2:
                    cf = Color.red;
                    break;
                  case 3:
                    cf = Color.magenta;
                    break;
                  case 4:
                    cf = Color.green;
                    break;
                  case 5:
                    cf = Color.cyan;
                    break;
                }
                g.setColor(cb);
                g.fillRect(gx,gy,SameGame.GX,SameGame.GY);
                if (p!=0) {
                    g.setColor(cf);
                    g.fillArc(gx+1,gy+1,SameGame.GX-2,SameGame.GY-2,0,360);
                }
            }
        }   
    }

    public void paint(Graphics g) {
        drawRegion(g,0,0,SameGame.X,SameGame.Y,false);
    }
}

