zoukankan      html  css  js  c++  java
  • PHP实现开心消消乐的算法示例

    本文主要介绍了关于PHP如何实现我们大家都知道的开心消消乐的算法,分享PHP教程出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

    一、需求描述:
          1、在一个8*8的矩阵方格中随机出现5种颜色的色块。
          2、当有三个或以上色块在横向或纵向上相连,则消除这些色块。
          3、色块消除后,上方色块往下平移,并掉下颜色随机的色块填充矩阵空缺。
          4、重复2、3步骤。
          5、消除3个相同色块加10分,4个加15分,5个加20分,6个加30分,7个加40分,8个加70分,9个加100分,10个加150分,再往后每增加一个就比上一个多加50分。

    二、上代码

      1 <?php
      2 //所有图形初始化数据,key代表位置,value代表颜色
      3 $xxl = array(
      4  array('', '', '', '', '', '', '', ''),
      5  array('', '', '', '', '', '', '', ''),
      6  array('', '', '', '', '', '', '', ''),
      7  array('', '', '', '', '', '', '', ''),
      8  array('', '', '', '', '', '', '', ''),
      9  array('', '', '', '', '', '', '', ''),
     10  array('', '', '', '', '', '', '', ''),
     11  array('', '', '', '', '', '', '', ''),
     12 );
     13 $point = play($xxl, $point);//开始游戏
     14 echo "
    共获得积分数量:{$point}";
     15 
     16 /*开始消除
     17  *$xxl  array 所有图形集合
     18  *$point int  获得积分数量
     19 */
     20 $bu = 0;
     21 function play($xxl, $point){
     22  global $bu;
     23  $bu ++;
     24  echo '=================================开始第'.$bu.'步==================================';
     25  $color = array(1 => 'red',2 => 'green',3 => 'yellow',4 => 'blue',5 => 'black');//代表5种颜色
     26  $samCol = array();//列上相连色块集合
     27  $nowCol = array();//列上相连色块指针
     28  $samArr = array();//相连色块总集合
     29  $group = 1;//组指针
     30 
     31  //随机填充颜色,并获得行上相连色块start
     32  foreach($xxl as $k1 => $v1){
     33   $sam = array();//行上相连色块集合
     34   $now = 1;//行上相连色块指针
     35   foreach($v1 as $k2 => $v2){
     36    if(empty($v2) || $v2 == ' '){
     37     $v2 = $xxl[$k1][$k2] = array_rand($color);//随机填充颜色
     38    }
     39    if(!isset($nowCol[$k2])){
     40     $nowCol[$k2] = 1;
     41    }
     42    if($k1 === 0){
     43     $samCol[$k2][$nowCol[$k2]][$k1 .'-'. $k2] = array($k1, $k2, $v2, $k1 .'-'. $k2 .'-'. $v2);
     44    }else{
     45     if($v2 != $xxl[$k1-1][$k2]){//同一列上和前一个颜色不一样
     46      $nowCol[$k2] ++;
     47     }
     48     $samCol[$k2][$nowCol[$k2]][$k1 .'-'. $k2] = array($k1, $k2, $v2, $k1 .'-'. $k2 .'-'. $v2);
     49    }
     50 
     51 
     52    if($k2 === 0){
     53     $sam[$now][$k1 .'-'. $k2] = array($k1, $k2, $v2, $k1 .'-'. $k2 .'-'. $v2);
     54    }else{
     55     if($v2 != $xxl[$k1][$k2-1]){//同一行上和前一个颜色不一样
     56      $now++;
     57     }
     58     $sam[$now][$k1 .'-'. $k2] = array($k1, $k2, $v2, $k1 .'-'. $k2 .'-'. $v2);
     59    }
     60   }
     61   //获得行上相连色块start
     62   foreach($sam as $x => $y){
     63    if(count($y) > 2){
     64     $key = 'R-'.$group;
     65     foreach($y as $x2 => $y2){
     66      $y[$x2]['group']['r'] = $key;
     67     }
     68     $samArr += $y;
     69     $group ++;
     70    }
     71   }
     72   //获得行上相连色块end
     73  }
     74  //随机填充颜色,并获得行上相连色块end
     75 
     76  //获得列上相连色块start
     77  $group = 1;
     78  foreach($samCol as $k => $v){
     79   foreach($v as $x => $y){
     80    if(count($y) > 2){
     81     $key = 'L-'.$group;
     82     foreach($y as $x2 => $y2){
     83      $y[$x2]['group']['l'] = $key;
     84      if(isset($samArr[$x2]['group']['r'])){//判断本点是否已出现在横向组里
     85       $samArr[$x2]['group']['l'] = $key;
     86      }
     87     }
     88     $samArr += $y;
     89     $group ++;
     90    }
     91   }
     92  }
     93  //获得列上相连色块end
     94 
     95  //查找相连色块start
     96  $res = array();//相连色块集合
     97  $hasRes = array();
     98  foreach($samArr as $k => $v){
     99   if(isset($hasRes[$k])){
    100    continue;
    101   }
    102   $arr = array();
    103   seek($samArr, $v, $arr);
    104   $res[] = array_keys($arr);
    105   $hasRes += $arr;
    106  }
    107  //查找相连色块end
    108  show($xxl);//打印消除前的图形
    109  if(empty($res)){//如果没有相连色块则退出递归
    110   echo '=================================消除完毕!==================================';
    111   return $point;
    112  }
    113  $thisPoint = countPoint($res);//计算本次消除获得积分
    114  $point += $thisPoint;//累计到总积分
    115 
    116  //消除相连色块start
    117  $next = $xxl;
    118  foreach($res as $k => $v){
    119   foreach($v as $k2 => $v2){
    120    $y = $samArr[$v2][0];
    121    $x = $samArr[$v2][1];
    122    $xxl[$y][$x] = '*';
    123    unset($next[$y][$x]);
    124   }
    125  }
    126  //消除相连色块end
    127 
    128  show($xxl);//打印消除时的图形
    129  $next = step($next);
    130  show($next);//打印消除后的图形
    131  echo "本次消除获得积分数量:{$thisPoint}
    ";
    132  return play($next, $point);
    133 }
    134 
    135 /*计算获得积分数量
    136  *$xxl  array 相连色块集合
    137  */
    138 function countPoint($xxl){
    139  //初始化积分配置start
    140  $config = array(3 => 10, 4 => 15, 5 => 20, 6 => 30, 7 => 40, 8 => 70, 9 => 100);
    141  for($i = 10; $i <= 64; $i++){
    142   $config[$i] = 100 + ($i - 9) * 50;
    143  }
    144  //初始化积分配置end
    145  $point = 0;
    146  foreach($xxl as $v){
    147   $key = count($v);
    148   $point += $config[$key];
    149  }
    150  return $point;
    151 }
    152 
    153 /*消掉并左移
    154  *$xxl  array 所有图形集合
    155  */
    156 function step($xxl){
    157  foreach($xxl as $k => $v){
    158   $temp = array_merge($v);
    159   $count = count($temp);
    160   if($count == 8){
    161    continue;
    162   }
    163   for($i = $count; $i <= 7; $i++){
    164    $temp[$i] = ' ';
    165   }
    166   $xxl[$k] = $temp;
    167  }
    168  return $xxl;
    169 }
    170 
    171 /*找相邻点
    172  *$xxl  array 相连图形集合
    173  *$one   array 某一个点
    174  *$arr   array 图形集合里的相邻的点
    175 */
    176 function seek($xxl, $one, &$arr){
    177 // global $i;
    178  $near = array();
    179  $near['up'] = ($one[0] - 1).'-'.$one[1];//上面的点
    180  $near['down'] = ($one[0] + 1).'-'.$one[1];//下面的点
    181  $near['left'] = $one[0].'-'.($one[1] - 1);//左面的点
    182  $near['right'] = $one[0].'-'.($one[1] + 1);//右面的点
    183  foreach($near as $v){
    184   if(isset($xxl[$v]) && $xxl[$v][2] == $one[2]){//找到相邻点
    185    $xj = array_intersect($one['group'], $xxl[$v]['group']);
    186    if(empty($xj)){//如果相邻的点不是本组的就跳过
    187     continue;
    188    }
    189    if(isset($arr[$v])){//如果该点已被遍历过则跳过
    190     continue;
    191    }
    192    $arr[$v] = $xxl[$v];
    193    seek($xxl, $xxl[$v], $arr);//继续找相邻的点
    194   }
    195  }
    196 }
    197 
    198 /*打印图形
    199  *$xxl  array 所有图形集合
    200  */
    201 function show($xxl){
    202  //顺时针旋转矩阵start
    203  $arr = array();
    204  foreach($xxl as $k => $v){
    205   foreach($v as $k2 => $v2){
    206    $arr[7-$k2][$k] = $v2;
    207   }
    208  }
    209  ksort($arr);
    210  //顺时针旋转矩阵end
    211  $str = '';
    212  foreach($arr as $v){
    213   foreach($v as $v2){
    214    $str .= ' '.$v2;
    215   }
    216   $str .= "
    ";
    217  }
    218  echo "
    ".$str;
    219 }

    运行结果如下:
    12345分别代表5种颜色。

     1 =================================开始第1步==================================
     2  3 3 2 2 1 1 1 4
     3  4 3 4 3 4 1 1 3
     4  3 1 4 1 1 4 1 2
     5  2 3 4 3 1 2 4 4
     6  4 2 4 2 2 2 1 4
     7  3 3 2 1 2 3 1 1
     8  5 2 1 3 2 1 4 5
     9  3 4 5 1 3 2 3 3
    10 
    11  3 3 2 2 * * * 4
    12  4 3 * 3 4 1 * 3
    13  3 1 * 1 1 4 * 2
    14  2 3 * 3 1 2 4 4
    15  4 2 * * * * 1 4
    16  3 3 2 1 * 3 1 1
    17  5 2 1 3 * 1 4 5
    18  3 4 5 1 3 2 3 3
    19 
    20  3 3   4
    21  4 3 2  3
    22  3 1 3 1 2
    23  2 3 1 4 4 4
    24  4 2 2 3 4 2 1 4
    25  3 3 2 1 1 3 1 1
    26  5 2 1 3 1 1 4 5
    27  3 4 5 1 3 2 3 3
    28 本次消除获得积分数量:55
    29 =================================开始第2步==================================
    30  3 3 2 2 3 3 2 4
    31  4 3 3 2 1 3 3 3
    32  3 1 3 3 4 1 4 2
    33  2 3 5 1 2 4 4 4
    34  4 2 2 3 4 2 1 4
    35  3 3 2 1 1 3 1 1
    36  5 2 1 3 1 1 4 5
    37  3 4 5 1 3 2 3 3
    38 
    39  3 3 2 2 3 3 2 4
    40  4 3 3 2 1 * * *
    41  3 1 3 3 4 1 4 2
    42  2 3 5 1 2 * * *
    43  4 2 2 3 4 2 1 4
    44  3 3 2 1 1 3 1 1
    45  5 2 1 3 1 1 4 5
    46  3 4 5 1 3 2 3 3
    47 
    48  3 3 2 2 3  
    49  4 3 3 2 1  
    50  3 1 3 3 4 3 2 4
    51  2 3 5 1 2 1 4 2
    52  4 2 2 3 4 2 1 4
    53  3 3 2 1 1 3 1 1
    54  5 2 1 3 1 1 4 5
    55  3 4 5 1 3 2 3 3
    56 本次消除获得积分数量:20
    57 =================================开始第3步==================================
    58  3 3 2 2 3 4 1 3
    59  4 3 3 2 1 4 2 5
    60  3 1 3 3 4 3 2 4
    61  2 3 5 1 2 1 4 2
    62  4 2 2 3 4 2 1 4
    63  3 3 2 1 1 3 1 1
    64  5 2 1 3 1 1 4 5
    65  3 4 5 1 3 2 3 3
    66 =================================消除完毕!==================================
    67 共获得积分数量:75
  • 相关阅读:
    RTC驱动程序分析
    Linux下的RTC子系统
    [置顶] 谈EXPORT_SYMBOL使用
    《Linux内核修炼之道》精华分享与讨论(5)——Kernel地图:Kconfig与Makefile
    写出高效优美的单片机C语言代码
    哈夫曼树
    如何提高浮点数变整数的精度
    CF798C Mike and gcd problem
    CF822C Hacker, pack your bags!
    CF821C Okabe and Boxes
  • 原文地址:https://www.cnblogs.com/haohuier/p/10073052.html
Copyright © 2011-2022 走看看