⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unit_main.pas

📁 扫雷
💻 PAS
📖 第 1 页 / 共 5 页
字号:
  randx,randy:integer;
  i,j:integer;
  i_bombCount:integer;
  tempGridArray:TGridArray ;

  //在生成数字的过程中使用
  LargeUpGridArray:array[0..g_MaxCol+1 ,0..g_MaxRow+1 ] of integer;

begin
  tempGridArray .LocalTotalCols :=s_DownGridArray .LocalTotalCols ;
  tempGridArray .LocalTotalRows :=s_DownGridArray .LocalTotalRows ;

  //如果是重新开局的游戏,则直接将上次的雷区的情况赋值给新的雷区信息。
  if isGameofRestart then
    for I := 1 to s_DownGridArray .LocalTotalCols  do
      for j:= 1 to s_DownGridArray  .LocalTotalRows  do
      begin
        //声明:重新开局后,不能保证鼠标的第一次按键不是雷,原因不言而喻
        s_DownGridArray .Grid [i][j] :=LastDownGridArray.grid[i][j];
        //该退出了.
        exit;
      end;

  //如果不是重新开局,则按原顺序执行。。。
  for I := 1 to s_DownGridArray .LocalTotalCols  do
    for j:= 1 to s_DownGridArray  .LocalTotalRows  do
    begin
      s_DownGridArray .Grid [i][j] :=0;
      tempGridArray .Grid [i][j]:=0;
    end;
    
  //
  i_bombCount :=BombCount ;
  randomize;    //播随机种子
  while i_BombCount <> 0 do
  //严格意义上讲.这里需要有一个变量来控制 While 循环的次数,以免死循环,有些格子就是
  //得不到,但是在这里,由于雷数毕竟不是很多,所以,就没有考虑..
  begin
    randx:=random(s_DownGridArray .LocalTotalCols )+1;
    randy:=random(s_DownGridArray .LocalTotalRows )+1;
    if (s_DownGridArray .Grid [randx][randy]=0)         //没有被标过雷
        and (random(2)=1)                               //随机的几率
        and (not((randx=localx )and (randy =localy )))  //确保当前按下的那个方块不会是雷
        then
    begin
      s_DownGridArray .Grid [randx][randy]:=10;
      i_BombCount :=i_BombCount -1;
    end;
  end;

  for i := 0 to s_DownGridArray .LocalTotalCols+1  do
    for j:= 0 to s_DownGridArray  .LocalTotalRows+1  do
      LargeUpGridArray [i][j]:=0;

  for I := 1 to s_DownGridArray .LocalTotalCols  do
    for j:= 1 to s_DownGridArray  .LocalTotalRows  do
      LargeUpGridArray [i][j]:=s_DownGridArray .grid [i][j];


  for i:= 1 to s_DownGridArray .LocalTotalCols do
    for j:= 1 to s_DownGridArray .LocalTotalRows do
      if s_DownGridArray .grid[i][j]<> 10 then
        tempGridArray .grid[i][j]:= LargeUpGridArray[i-1][j-1]
                                  + LargeUpGridArray[i][j-1]
                                  + LargeUpGridArray[i+1][j-1]
                                  + LargeUpGridArray[i-1][j]
                                  + LargeUpGridArray[i+1][j]
                                  + LargeUpGridArray[i-1][j+1]
                                  + LargeUpGridArray[i][j+1]
                                  + LargeUpGridArray[i+1][j+1];

  for I := 1 to s_DownGridArray .LocalTotalCols  do
    for j:= 1 to s_DownGridArray  .LocalTotalRows  do
      s_DownGridArray .grid [i][j] :=LargeUpGridArray [i][j];


   //得到DownGridArray中除了雷以外的数字区域.(0~8)
  for i:= 1 to s_DownGridArray .LocalTotalCols do
    for j:= 1 to s_DownGridArray .LocalTotalRows do
    begin
        // "-10" 是转换到0~8 的算法.
      s_DownGridArray .grid[i][j]:=s_DownGridArray .grid[i][j]+ (tempGridArray .grid[i][j] div 10);
      LastDownGridArray.grid[i][j]:=s_DownGridArray .grid[i][j];
    end;

end;

{
  isColorForce 是用来判断是否是一定要重新画.在改变"颜色"菜单的内容时才会时 True,其余的都是 False
}
procedure TFrm_Main.DrawBackGround(const d_UpGridArray:TGridArray ; const isColorForce:boolean);
var
  i,j:integer;

  procedure Drawimage(const argCol,argRow:integer;argimage:integer);
  var
    num:integer;
    comImage:TImage;
  begin
    //考虑颜色选项的状态
    if not  isHaveColor then
    begin
      argimage := argimage +100;
      comImage :=Image_gray_block
    end else
      comImage :=Image_Color_block ;

    case argimage of
      111,11 :num :=1 ;         //没有被按下方块
      112,12 :num :=16 ;        //被展开的没有数字的方块
      113,13 :num :=16 ;

      121,21 :num :=15 ;        //数字-1
      122,22 :num :=14 ;        //数字-2
      123,23 :num :=13 ;        //数字-3
      124,24 :num :=12 ;        //数字-4
      125,25 :num :=11 ;        //数字-5
      126,26 :num :=10 ;        //数字-6
      127,27 :num :=9 ;         //数字-7
      128,28 :num :=8 ;         //数字-8

      131,31 :num :=2 ;         //标有旗帜的方块
      132,32 :num :=3;          //没有被按下的标有问好的方块
      133,33 :num :=7 ;         //被按下的标有问好的方块

      141,41 :num :=6 ;         //显示出来的雷
      142,42 :num :=4 ;         //被炸开了的雷
      143,43 :num :=5 ;         //因标错了而炸开的雷
      else exit;
    end;

    Image_BackGround .Canvas .CopyRect(rect((argCol -1)*g_BlockWidth ,
        (argRow -1)*g_BlockHeight ,argCol*g_BlockWidth ,argRow *g_BlockHeight ),
        comImage .Canvas ,rect(0,(num -1) * g_BlockHeight  ,g_BlockWidth ,num * g_BlockHeight));
  end;

begin
  for i := 1 to UpGridArray .LocalTotalCols  do
    for j := 1 to UpGridArray .LocalTotalRows  do
      //如果有不同显示的雷区或是强行要重画的情况下需要重画数字区域
      if (LastUpGridArray .Grid [i][j] <> d_UpGridArray .Grid [i][j]) or isColorForce then
      begin
        drawimage(i,j,d_UpGridArray.grid[i][j]);
        // LastUpGridArray 供可能发生的"重新开始本局"事件时用到.
        LastUpGridArray .Grid [i][j] := d_UpGridArray .Grid[i][j];
      end;
end;

procedure TFrm_Main.DrawHead(const Count:integer;d_Dir:TDisplayDir );
var
  d_i:integer;
  d_Count:integer;
  BombCountArr:array[1..3] of integer;
  comimage:Timage;
  num:integer;
begin
  if Count >= 0 then
    d_Count :=Count
  else
    d_Count :=abs(Count);

  if Count >999 then
    d_Count :=999;

  for d_i:=3 downto 1 do
    begin
      BombCountArr [d_i]:=d_Count mod 10;
      d_Count:=d_Count div 10
    end;

  if Count < 0 then
    BombCountArr [1]:= -1;

  for d_i:=1 to 3 do
    begin
      if  not isHaveColor then
      begin
        BombCountArr [d_i] :=BombCountArr [d_i]+100;
        comimage := image_gray_num;
      end else
        comimage := Image_Color_Num;

      case BombCountArr [d_i] of
        -1,99:num:=1 ;          //数字- 负号
        0,100:num:=12 ;         //数字- 0  (以下是 1-9)
        1,101:num:=11 ;
        2,102:num:=10 ;
        3,103:num:=9 ;
        4,104:num:=8 ;
        5,105:num:=7 ;
        6,106:num:=6 ;
        7,107:num:=5 ;
        8,108:num:=4 ;
        9,109:num:=3 ;
        else exit;
      end;

      if  not isHaveColor then
        BombCountArr [d_i] :=BombCountArr [d_i] - 100;

      case d_Dir of
        d_left:
          Image_Dis_BombCount .Canvas .CopyRect(rect((d_i-1)*g_NumWidth ,
              0 ,d_i*g_NumWidth ,g_NumHeight ),comimage.Canvas ,
              rect(0,(num-1)*g_NumHeight  ,g_NumWidth  ,num * g_NumHeight ));
        d_right:
          Image_Dis_Time .Canvas .CopyRect (rect((d_i-1)*g_NumWidth  ,
               0,d_i*g_NumWidth ,g_NumHeight ),comimage.Canvas ,
              rect(0,(num-1)* g_NumHeight ,g_NumWidth ,num * g_NumHeight ));
        else exit;
      end;
    end
end;



{
  重点是四连通算法的实现..
}
procedure SeekBlackBlock(s_DownGridArray:TGridArray;var s_UpGridArray:TGridArray;s_Col,s_Row:integer);
var
  HeadBlock,myBlock,newBlock:BlockPointer ;
  i,j:integer;
  s_tempGridArray:TGridArray ;
  PointerOutX,PointerOutY:integer;

  //初始化指针连表,带头结点
  procedure initPointer();
  var
    i_i,i_j:integer;
  begin
    new(myBlock);
    myBlock ^.BlockX :=0;
    myBlock ^.BlockY :=0;
    myBlock ^.preBlock :=nil;
    myBlock ^.nextBlock :=nil;
    HeadBlock :=myBlock ;

    for i_i := 1 to s_DownGridArray .LocalTotalCols  do
      for i_j:= 1 to s_DownGridArray  .LocalTotalRows  do
        s_tempGridArray .Grid [i_i][i_j]:=0;
  end;

  //入栈操作
  procedure push(h_BlockX,h_BlockY:integer);
  begin
    new(newBlock);
    newBlock ^.BlockX :=h_BlockX ;
    newBlock ^.BlockY :=h_BlockY ;
    newBlock ^.preBlock :=myBlock ;
    newBlock ^.nextBlock :=nil;
    myBlock ^.nextBlock :=newBlock ;
    myBlock :=myBlock ^.nextBlock ;

  end;

  //出栈操作
  procedure pop(var p_BlockX,p_BlockY:integer);
  begin
    p_BlockX :=myblock ^.BlockX ;
    p_BlockY :=myBlock ^.BlockY ;

    myBlock :=myBlock ^.preBlock ;
    Dispose (myBlock ^.nextBlock );
    myBlock ^.nextBlock :=nil;
  end;

  //只要处理部分
  procedure ChangeUpGridArray();
  var
    c_i,c_j:integer;
  begin
    for c_i:= -1 to 1 do
      for c_j:= -1 to 1 do
        //判断越界
        if ((PointerOutX +c_i )>=1 ) and ((PointerOutX +c_i) <= s_DownGridArray .LocalTotalCols )
            and ((PointerOutY +c_j)>=1) and ((PointerOutY +c_j)<= s_DownGridArray .LocalTotalRows) then
         // 判断在DownGridArray中不是雷的块将它显示出来
          if (s_DownGridArray .grid[PointerOutX +c_i ][PointerOutY + c_j] <> 10)
            and ((s_UpGridArray .grid[PointerOutX +c_i][PointerOutY +c_j] =11)
                  or (s_UpGridArray .grid[PointerOutX +c_i][PointerOutY +c_j] =13)
                  or (s_UpGridArray .grid[PointerOutX +c_i][PointerOutY +c_j] =33)
                  or (s_UpGridArray .grid[PointerOutX +c_i ][PointerOutY +c_j] = 32)) then
          begin
            // 判断条件是用来处理DownGridArray 中 "0" 与UpGridArray 中 "12"的关系
            if s_DownGridArray .grid[PointerOutX +c_i ][PointerOutY + c_j] = 0 then
              s_UpGridArray .grid[PointerOutX +c_i ][PointerOutY +c_j]:= 12
            else
            begin
               //20 为DownGridArray 中数字与 UpGridArray 中数字的差量
              s_UpGridArray .grid[PointerOutX +c_i ][PointerOutY +c_j]:=
                    s_DownGridArray .grid[PointerOutX +c_i ][PointerOutY + c_j]+ 20;
            end;

            BlockOpenCount :=BlockOpenCount +1;
          end;
  end;

begin
  initPointer ;
  push(s_Col ,s_Row );
  while HeadBlock ^.nextBlock <> nil do
  begin
    pop(PointerOutX ,PointerOutY );
    ChangeUpGridArray ;

    for i:=-1 to 1 do
      for j:= -1 to 1 do
      begin
        if not( (i=0 ) and (j= 0)) then
          if ((PointerOutX +i )>=1 ) and ((PointerOutX +i) <= s_DownGridArray .LocalTotalCols )
              and ((PointerOutY +j)>=1) and ((PointerOutY +j)<= s_DownGridArray .LocalTotalRows) then
            if (s_tempGridArray .Grid [PointerOutX +i][PointerOutY +j] = 0)
              and (s_DownGridArray .grid[PointerOutX +i][PointerOutY +j] = 0) then
            begin
              s_tempGridArray .Grid [PointerOutX +i][PointerOutY +j] := 1;
              push(PointerOutX +i,PointerOutY +j);
            end;
      end;
  end;
end;


procedure TFrm_Main.GameWin(w_DownGridArray:TGridArray ;var w_UpGridArray:TGridArray);
var
  w_i,w_j:integer;
  New_Name:string;
begin
  Timer_Display .Enabled :=False;

  //将没有展开的方块标为雷,即插上红旗.
  for w_i:= 1 to w_DownGridArray  .LocalTotalCols do
    for w_j:= 1 to w_DownGridArray  .LocalTotalRows do
      if (w_UpGridArray .grid[w_i][w_j]=11) or (w_UpGridArray .grid[w_i][w_j]=32) then
        w_UpGridArray .grid[w_i][w_j] := 31;

  if isHaveSound then
    sndPlaySound(pchar(comdir+g_ResourceName +g_Sound_GameWin),SND_ASYNC  );

  DrawBackGround(w_UpGridArray,false);
  DrawHead(0,d_left );
  ChgSpbtnGlyph(f_glass);

  //打破记录并且级别不是自定义级别,则需要显示打破记录,输入大名的对话框
  if (TotalTime < LocalScore) and (UserLevel <> v_UserDefine) then
  begin
    Application.CreateForm(TFrm_HeroName , Frm_HeroName );
    Frm_HeroName .showmodal;
    New_Name :=Unit_HeroName.New_Name;

    Unit_Hero.InputScore(UserLevel,TotalTime ,New_Name);
    Application.CreateForm(TFrm_Hero, Frm_Hero);
    Frm_Hero.ShowModal ;

  end;
  isGameOver :=true;
  isGameWin :=true;

  //屏蔽 暂停 菜单
  Menu_Pause_Resume.Enabled :=false;

  GameStatus :=s_win;
  ChangeStatusBar(UserLevel ,UserTotalCols,UserTotalRows, UserBombCount,GameStatus,LocalScore,LanguageType);
end;


procedure TFrm_Main.GameLost(l_DownGridArray:TGridArray ;var l_UpGridArray:TGridArray;l_Col,l_Row:TOverColAndRow);
var
  l_i,l_j:integer;
begin
  Timer_Display .Enabled :=False;
  if isHaveSound then
    sndPlaySound(pchar(comdir+g_ResourceName +g_Sound_GameLost),SND_ASYNC  );

  //根据传进来的数组的值将那些是雷而没有标的块用42-爆炸的雷表示
  for l_i:=1 to 8 do
    if l_Col [l_i] <> 0 then
    begin
      l_UpGridArray .grid[l_Col [l_i]][l_Row [l_i]] := 42;
    end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -