用J2ME实现扫雷

 
这学期J2ME告一段落了,没学到什么东西,老师已经让交作业了。时间太紧写个扫雷凑数。
写了四个类:
MineGame: 处理游戏逻辑
MineBoard: 游戏的面板(canvas)
MineMIDlet: MIDlet主类,启动游戏,调度游戏面板
MineDefs: 没别的作用,就是定义一些常量,供其它类使用。
 
下面是MineDefs类,各常量的意思从字面就能看出来
//MineDefs: 定义常量
public class MineDefs
{
      //雷方块状态
      public static final byte STATE_FLAG_MINE =0;
      public static final byte STATE_NORMAL_MINE =1;
      public static final byte STATE_FLAG_EMPTY    =2;
      public static final byte STATE_NORMAL_EMPTY   =3;
      public static final byte STATE_OPEN_0         =8;
      public static final byte STATE_OPEN_1         =9;
      public static final byte STATE_OPEN_2         =10;
      public static final byte STATE_OPEN_3         =11;
      public static final byte STATE_OPEN_4         =12;
      public static final byte STATE_OPEN_5         =13;
      public static final byte STATE_OPEN_6         =14;
      public static final byte STATE_OPEN_7         =15;
      public static final byte STATE_OPEN_8         =16;
      public static final byte STATE_OVER_BLAST    =26;
      public static final byte STATE_OVER_MINE =28;
     
      //游戏状态
      public static final byte GAMESTATE_RUN         =1;
      public static final byte GAMESTATE_OVER       =2;
      public static final byte GAMESTATE_WIN          =3;
     
      public static final byte HASOPENED              =100;
      public static final byte DONTEXPAND                =101;
      public static final byte WRONGMINENUM         =102;
     
      //格子数与雷数
      public static final byte GRIDNUM_X              =9;
      public static final byte GRIDNUM_Y              =9;
      public static final byte MINENUM            =10;
}
MineMIDlet主类,有两个按钮,退出和重新开始
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
 
public class MineMIDlet extends MIDlet implements CommandListener
{
      Display display;
      MineBoard gameCanvas;
      MineGame game;
     
      Command cmdExit=new Command("退出",Command.EXIT,0);
      Command cmdRestart=new Command("重新开始",Command.OK,1);
     
      public void startApp() throws MIDletStateChangeException
      {
          display = Display.getDisplay(this);
         
          game=new MineGame();
          gameCanvas=new MineBoard(game);
          gameCanvas.addCommand(cmdExit);
          gameCanvas.addCommand(cmdRestart);
          gameCanvas.setCommandListener(this);
         
          display.setCurrent(gameCanvas);
      }
 
      public void pauseApp(){ }
      public void destroyApp(boolean unconditional){ notifyDestroyed(); }
     
      public void commandAction(Command c, Displayable d)
      {
           if(c.equals(cmdExit))
           {
                 destroyApp(false);
           }
           else
           {
                 game.restart();
                 gameCanvas.repaint();
           }
      }
 
}
 
下面是最关键的两个类
import javax.microedition.lcdui.*;
MineBoard:游戏的面板 同时处理按键
public class MineBoard extends Canvas
{
      private int scrWidth,scrHeight;      
      private int boardWidth,boardHeight;         //雷区宽高
      private int boardLeft,boardTop;
      private int gridWidth;                //格子的边长
      private byte curPosX=0; //光标位置
      private byte curPosY=0;
      private String extraInfo="";
      private MineGame game;
     
      public MineBoard(MineGame game)
      {    //在构造函数中计算布局
           this.game=game;
           scrWidth=getWidth();
           scrHeight=getHeight();
           int tmpgridWidth=scrWidth/MineDefs.GRIDNUM_X;
           int tmpgridHeight=scrHeight/MineDefs.GRIDNUM_Y;
           if(tmpgridWidth<tmpgridHeight)
           {
                 gridWidth=tmpgridWidth;
                 boardWidth=gridWidth*MineDefs.GRIDNUM_X;
                 boardHeight=gridWidth*MineDefs.GRIDNUM_Y;
                 boardLeft=0;
                 boardTop=scrHeight-boardHeight;
           }
           else
           {
                 gridWidth=tmpgridHeight;
                 boardWidth=gridWidth*MineDefs.GRIDNUM_X;
                 boardHeight=gridWidth*MineDefs.GRIDNUM_Y;
                 boardLeft=scrWidth-boardWidth;
                 boardTop=0;
           }
      }
     
      public void paint(Graphics g)
      {
           g.setColor(150,150,255);     //清屏
           g.fillRect(0,0,scrWidth,scrHeight);
           //画游戏状态
           String state="";
           switch(game.getGameState())
           {
                 case MineDefs.GAMESTATE_OVER:
                      state="失败";
                      break;
                 case MineDefs.GAMESTATE_WIN:
                      state="胜利";
                      break;
           }
           if(scrWidth<scrHeight)
           {
                 g.setColor(255,0,0);
                 g.drawString(state,0,0,Graphics.LEFT|Graphics.TOP);
                 g.drawString("还有"+game.getMinesRemain()+"颗雷",30,0,Graphics.LEFT|Graphics.TOP);
                 g.drawString(extraInfo,0,10,Graphics.LEFT|Graphics.TOP);
           }
           //画雷区
            g.translate(boardLeft,boardTop);//调整起点
           for(byte i=0;i<MineDefs.GRIDNUM_X;++i)
           {
                 for(byte j=0;j<MineDefs.GRIDNUM_Y;++j)
                 {
                      drawGrid(i,j,game.getGridState(i,j),g);
                 }
           }
           //画光标
           g.setColor(255,0,0);
           g.drawRect(curPosX*gridWidth+1,curPosY*gridWidth+1,gridWidth-2,gridWidth-2);
      }
      //画每个雷方格的函数,如果需要可以修改这里让界面更好看
      private void drawGrid(byte x,byte y,byte gridState,Graphics g)
      {g.setColor(0,0,0);
           switch(gridState)
           {
                 case MineDefs.STATE_FLAG_MINE:
                 case MineDefs.STATE_FLAG_EMPTY://有标记
                       g.setColor(0,0,0);
                      g.fillRect(x*gridWidth,y*gridWidth,gridWidth,gridWidth);
                      break;
                 case MineDefs.STATE_NORMAL_MINE:
                 case MineDefs.STATE_NORMAL_EMPTY:   //正常未打开
                      g.setColor(255,255,255);
                      g.fillRect(x*gridWidth,y*gridWidth,gridWidth,gridWidth);
                      break;
                 case MineDefs.STATE_OPEN_0:
                       //g.drawString("0",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      g.setColor(255,255,0);
                      g.fillRect(x*gridWidth,y*gridWidth,gridWidth,gridWidth);
                      break;
                 case MineDefs.STATE_OPEN_1:
                       g.drawString("1",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_2:
                       g.drawString("2",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_3:
                       g.drawString("3",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_4:
                       g.drawString("4",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_5:
                       g.drawString("5",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_6:
                       g.drawString("6",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_7:
                       g.drawString("7",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OPEN_8:
                       g.drawString("8",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OVER_BLAST:
                       g.drawString("B",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
                 case MineDefs.STATE_OVER_MINE:
                       g.drawString("M",x*gridWidth+7,y*gridWidth,Graphics.HCENTER|Graphics.TOP);
                      break;
           }
      }
     
      protected void keyPressed(int key)
      {//处理键盘事件
           if(game.getGameState()!=MineDefs.GAMESTATE_RUN)
                 return;
           extraInfo="";
           switch ( getGameAction(key) )
           {
                 case Canvas.UP:
                      if(curPosY>0)
                      {
                            --curPosY;
                            repaint();
                      }
                      break;
                 case Canvas.DOWN:
                      if(curPosY<MineDefs.GRIDNUM_Y-1)
                      {
                            ++curPosY;
                            repaint();
                      }
                      break;
                 case Canvas.LEFT:
                      if(curPosX>0)
                      {
                            --curPosX;
                            repaint();
                      }
                      break;
                 case Canvas.RIGHT:
                      if(curPosX<MineDefs.GRIDNUM_X-1)
                      {
                            ++curPosX;
                            repaint();
                      }
                      break;
                 case Canvas.GAME_A://数字1键(切换标记)
                      //System.out.println ("标记");
                      if(game.flagGrid(curPosX,curPosY)==MineDefs.WRONGMINENUM)
                      {
                            extraInfo="雷数目不正确";
                      }
                      repaint();
                      break;
                 case Canvas.GAME_B://数字3键(展开区域)
                      //System.out.println ("拓展");
                      if(game.expand(curPosX,curPosY)==MineDefs.DONTEXPAND)
                      {//不允许扩展
                            extraInfo="不允许扩展";
                      }
                      repaint();
                      break;
                 case Canvas.FIRE:    //打开格子
                      //System.out.println ("打开");
                      if(game.hitGrid(curPosX,curPosY)==MineDefs.HASOPENED)
                      {
                            extraInfo="已经打开";
                      }
                      repaint();
                      break;
           }
      }
}
 
MineGame:游戏的核心逻辑
import java.util.*;
 
public class MineGame
{
      //表示雷区的二维数组
      private byte mines[][]=new byte[MineDefs.GRIDNUM_X][MineDefs.GRIDNUM_Y];
      private byte gameState;
      private byte minesRemain=0;
     
      public MineGame()
      {
           restart();
      }
     
      //游戏重新开始
      public void restart()
      {//System.out.println ("重新开始");
           minesRemain=0;
           clearMines();
           layMines();
           gameState=MineDefs.GAMESTATE_RUN;
      }
     
      //清空雷区
      private void clearMines()
      {
           for(byte i=0;i<MineDefs.GRIDNUM_X;++i)
           {
                 for(byte j=0;j<MineDefs.GRIDNUM_Y;++j)
                 {
                      mines[i][j]=MineDefs.STATE_NORMAL_EMPTY;
                 }
           }
      }
     
      //随即布置雷
      private void layMines()
      {
           Random random = new Random(Calendar.getInstance().getTime().getTime());
           int x,y;
           for(byte i=0;i<MineDefs.MINENUM;)
           {
                 x = Math.abs(random.nextInt()) % MineDefs.GRIDNUM_X;
              y = Math.abs(random.nextInt()) % MineDefs.GRIDNUM_Y;
              if(mines[x][y]>MineDefs.STATE_NORMAL_MINE)//后面的状态均表示无雷
              {
                   mines[x][y]=MineDefs.STATE_NORMAL_MINE;
                   ++minesRemain;
                   ++i;
              }
           }
           //dis();
      }
//     public void dis()
//     {
//          //输出雷区状态
//          for(byte i=0;i<MineDefs.GRIDNUM_Y;++i)
//          {
//                for(byte j=0;j<MineDefs.GRIDNUM_X;++j)
//                {
//                     System.out.print (mines[j][i]+" ");
//                }
//                System.out.println ();
//          }
//     }
     
      //获取方块的状态
      public byte getGridState(byte x,byte y)
      {
           return mines[x][y];
      }
     
      public byte getGameState()
      {
           return gameState;
      }
     
      public byte getMinesRemain()
      {
           return minesRemain;
      }
      //计算周围有多少雷
      private byte getAroundMine(byte x,byte y)
      {
           byte num=0;
           byte minX=(byte)((x==0)? 0:x-1);
           byte maxX=(byte)((x==MineDefs.GRIDNUM_X-1)? MineDefs.GRIDNUM_X-1:x+1);
           byte minY=(byte)((y==0)? 0:y-1);
           byte maxY=(byte)((y==MineDefs.GRIDNUM_Y-1)? MineDefs.GRIDNUM_Y-1:y+1);
           for(int i=minX;i<=maxX;++i)
           {
                 for(int j=minY;j<=maxY;++j)
                 {
                      if(mines[i][j]<=MineDefs.STATE_NORMAL_MINE)//此前状态均为有雷
                            ++num;
                 }
           }
           return num;
      }
     
      //计算周围作了几个标记
      private byte getAroundFlag(byte x,byte y)
      {
           byte num=0;
           byte minX=(byte)((x==0)? 0:x-1);
           byte maxX=(byte)((x==MineDefs.GRIDNUM_X-1)? MineDefs.GRIDNUM_X-1:x+1);
           byte minY=(byte)((y==0)? 0:y-1);
           byte maxY=(byte)((y==MineDefs.GRIDNUM_Y-1)? MineDefs.GRIDNUM_Y-1:y+1);
           for(int i=minX;i<=maxX;++i)
           {
                 for(int j=minY;j<=maxY;++j)
                 {
                       if(mines[i][j]==MineDefs.STATE_FLAG_MINE||mines[i][j]==MineDefs.STATE_FLAG_EMPTY)//有标记的
                            ++num;
                 }
           }
           return num;
      }
     
      //打开一个雷方块
      public byte hitGrid(byte x,byte y)   //返回游戏状态
      {//System.out.println (x+" "+y+" "+mines[x][y]);
           if(mines[x][y]>=MineDefs.STATE_OPEN_0)//此处已经打开
           {//System.out.println (x+" "+y+" "+mines[x][y]+" "+MineDefs.STATE_OPEN_0+"此处已经打开");
                 return MineDefs.HASOPENED;    
           }
           if(mines[x][y]<=MineDefs.STATE_NORMAL_MINE)//点中了地雷
           {//System.out.println (x+" "+y+" "+mines[x][y]+" "+MineDefs.STATE_NORMAL_MINE+"点中了地雷");
                 gameState=MineDefs.GAMESTATE_OVER;
                 for(byte i=0;i<MineDefs.GRIDNUM_X;++i)
                 {
                      for(byte j=0;j<MineDefs.GRIDNUM_Y;++j)
                      {
                            if(mines[i][j]<=MineDefs.STATE_NORMAL_MINE)//此前状态均为有雷
                                  mines[i][j]=MineDefs.STATE_OVER_MINE;
                      }
                 }
                 mines[x][y]=MineDefs.STATE_OVER_BLAST;
           }
           else     //未点中地雷,改变相应状态
           {//System.out.println (x+" "+y+" "+mines[x][y]+" "+"未点中地雷");
                 byte aroundNum=getAroundMine(x,y);//System.out.println (x+" "+y+" "+mines[x][y]+"周围有"+aroundNum);
                 mines[x][y]=(byte)(MineDefs.STATE_OPEN_0+aroundNum);//System.out.println (x+" "+y+" "+mines[x][y]);
                 if(aroundNum==0)    //周围没有雷 拓展
                 {//System.out.println (x+" "+y+" "+mines[x][y]+"拓展");
                      expand(x,y);
                 }
           }
           return gameState;
      }
     
      //标记一个雷方块
      public byte flagGrid(byte x,byte y)
      {
           if(mines[x][y]>=MineDefs.STATE_OPEN_0)//此处已经打开
                 return MineDefs.HASOPENED;    
            if(mines[x][y]==MineDefs.STATE_FLAG_MINE||mines[x][y]==MineDefs.STATE_FLAG_EMPTY)//原有标记
           {
                 ++mines[x][y];     //转换到对应的无标记状态
                 ++minesRemain;//System.out.println ("还有雷"+minesRemain);
                 if(isVictory())
                 {
                      gameState=MineDefs.GAMESTATE_WIN;
                 }
           }
           else     //原无标记
           {
                 if(minesRemain<=0)
                      return MineDefs.WRONGMINENUM;
                 --mines[x][y];
                 --minesRemain;//System.out.println ("还有雷"+minesRemain);
                 if(isVictory())
                 {
                      gameState=MineDefs.GAMESTATE_WIN;
                 }
           }
           return gameState;
      }
     
      //拓展方块(如果此方块周围没有类,或雷已标记)
      public byte expand(byte x,byte y)
      {
           byte aroundNum=getAroundMine(x,y);
           if(aroundNum!=getAroundFlag(x,y))//没有标完雷不允许展开
                 return MineDefs.DONTEXPAND;
           byte minX=(byte)((x==0)? 0:x-1);
           byte maxX=(byte)((x==MineDefs.GRIDNUM_X-1)? MineDefs.GRIDNUM_X-1:x+1);
           byte minY=(byte)((y==0)? 0:y-1);
           byte maxY=(byte)((y==MineDefs.GRIDNUM_Y-1)? MineDefs.GRIDNUM_Y-1:y+1);
           for(byte i=minX;i<=maxX;++i)
           {
                 for(byte j=minY;j<=maxY;++j)
                 {
                       if(mines[i][j]==MineDefs.STATE_NORMAL_MINE||mines[i][j]==MineDefs.STATE_NORMAL_EMPTY)
                            hitGrid(i,j);
                 }
           }
           return gameState;
      }
     
      //判断游戏是否胜利
      private  boolean isVictory()
      {
           if(minesRemain>0)
           {
                 return false;
                
           }//System.out.println ("标完");
           for(byte i=0;i<MineDefs.GRIDNUM_X;++i)
           {
                 for(byte j=0;j<MineDefs.GRIDNUM_Y;++j)
                 {
                      if(mines[i][j]==MineDefs.STATE_FLAG_EMPTY)//此前状态均为有雷
                            return false;
                 }
           }
           return true;
      }
}
 
这个扫雷具有最基本的游戏功能,如果需要,可以方便的添加其它附加功能,比如使用RMS保存游戏记录,或者加上声音。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值