Conway's Game of Life - Unlimited Edition(康威生命游戏-无限版)

最近也不知道在忙啥,反正好久没玩 codewars 了,上去看看的时候偶尔看到了一个很有意思的题目,稍微看了一下说明,感觉可以做出来,于是就开始了长达 2+2 个小时的解题过程。

下面是简单的题目说明:简单的来说,就是有一个二维数组,数组的每一个元素就是一个细胞,细胞有存活和死亡两种状态,每经过一代,细胞的状态都可以发生改变,有如下四个具体规则:

1、任何具有少于两个活邻居的活细胞都会死亡。

2、任何具有三个以上活邻居的活细胞都会死亡。

3、任何有两个或三个活邻居的活细胞都可以存活到下一代。

4、任何具有恰好三个活邻居的死细胞都将变为活细胞。

什么是邻居呢?就是围绕着该细胞的周围一圈,即八个细胞。

好了,在看完这些的时候,我的思路差不多就成型了。首先,我得获取到这个细胞周围细胞的状态,并且判断有几个活细胞,这样就能够根据规则判断各个细胞下一代的存活情况了。当我刷刷刷敲下代码,顺利地通过第一个测试的时候,我得意地提交了我的代码,结果出乎我的意料,在第三个测试之后陆续出现了问题。从此,我开始了长达半个小时的debug,但是仍然一无所获,只好绝望地看看讨论区的各位,结果,我发现了一点玄机!

首先,仔细点的朋友(不像我)就会发现,这道题的题目叫做 Conway's Game of Life - Unlimited Edition,而我目前的思路,只是前半部分,并没有体现出Unlimited Edition(无限版)。发现了这个之后,我仔细地第无数次读题目,终于找到了一个关键信息,即这个区域是无限的,出了题目给的细胞之外,还有无数的死细胞,再通过第四条规则,死细胞是有机会变成活细胞的,即会对结果产生巨大的影响!

发现了这点之后,我开始意识到,这道题不像我原先现象的那么简单,以下这个动画图能够生动地说明这个问题。我们要关心的不只是这个小小的细胞区域,而是整个可能无限的区域。


接下来,正片开始!我的思路很简单,首先着眼于死细胞唯一的再生途径,即规则四,附近有恰好三个活细胞。把关注点放在这里之后,不难想到,这个区域不是无限大的了,而顶多只是比原先的区域大一圈而已,然后再根据每一代的存活情况,慢慢变大或者不变。思路理清楚了之后,实现起来就不难了,我把优化过的代码放在这里。虽然能够解决问题,但是感觉还是不够完美,看了好久别人的代码,感觉大体思想都差不多,只是把函数封装了一下,看起来舒服一点。如果大家有更好的想法,欢迎找我谈论!

function get_generation(array $cells, int $generations): array {

  $x = count($cells);

  $y = count($cells[0]);

  while($generations--) {

    //零数组,长度为

    $emptyX = array_fill(0,count($cells[0]),0);

    //如果第一行中活细胞数大于等于3,则有可能周围死细胞会再生,需要在其前方插入一行零数组

    if(array_sum($cells[0]) >= 3) array_unshift($cells,$emptyX);

    //如果最后一行中活细胞数大于等于3,则有可能周围死细胞会再生,需要在其后方插入一行零数组

    if(array_sum($cells[count($cells)-1]) >= 3) array_push($cells,$emptyX);

    //如果第一列中活细胞数大于等于3,则有可能周围死细胞会再生,需要在其前方插入一列零数组

    while($cells != [] && array_sum(array_column($cells,0)) >= 3) {

      foreach($cells as $key=>$item) {

        array_unshift($cells[$key],0);

      }

    }

    //如果最后一列中活细胞数大于等于3,则有可能周围死细胞会再生,需要在其后方插入一列零数组

    $i = count($cells[0])-1;

    while($cells != [] && array_sum(array_column($cells,$i)) >=3 ) {

      foreach($cells as $key=>$item) {

        array_push($cells[$key],0);

      }

      $i = count($cells[0])-1;

    }

    $x = count($cells);

    $y = count($cells[0]);

    $n = 0;

    $array = [];

    for($i=0;$i<$x;$i++) {

      for($j=0;$j<$y;$j++) {

        //每个细胞目前的存活情况

        $array['self'][$n] = $cells[$i][$j];

        for($k=($i-1>=0?$i-1:0);$k<=($i+1<$x-1?$i+1:$x-1);$k++) {

          for($l=($j-1>=0?$j-1:0);$l<=($j+1<$y-1?$j+1:$y-1);$l++) {

            //统计每个细胞周围的存活情况

            $array['around'][$n] += $cells[$k][$l];

          }

        }

        $n++;

      }

    }

    //通过规则,判断每个细胞下一代的存活情况

    for($i=0;$i<$x*$y;$i++) {

      $array['around'][$i] -= $array['self'][$i];

      if($array['around'][$i] < 2) {

        $array['self'][$i] = 0;

      } elseif ($array['around'][$i] > 3) {

        $array['self'][$i] = 0;

      } elseif ($array['around'][$i] == 3) {

        $array['self'][$i] = 1;

      }

    }

    $n = 0;

    //新的一代

    for($i=0;$i<$x;$i++) {

      for($j=0;$j<$y;$j++) {

        $cells[$i][$j] = $array['self'][$n];

        $n++;

      }

    }

  }

  //如果第一行为空行,则可以删除

  while($cells != [] && empty(array_sum($cells[0]))) {

    array_splice($cells, 0, 1);

  }

  //如果最后一行为空行,则可以删除

  while($cells != [] && empty(array_sum($cells[count($cells)-1]))) {

    array_splice($cells, count($cells)-1, 1);

  }

  //如果第一列为空列,则可以删除

  while($cells != [] && empty(array_sum(array_column($cells,0)))) {

    for($j=0;$j<count($cells);$j++) {

      array_splice($cells[$j], 0, 1);

    }

  }

  //如果最后一列为空列,则可以删除

  $i = count($cells[0])-1;

  while($cells != [] && empty(array_sum(array_column($cells,$i)))) {

    for($j=0;$j<count($cells);$j++) {

      array_splice($cells[$j], $i, 1);

    }

    $i = count($cells[0])-1;

  }

  //如果没有细胞存活,则返回二维的空数组

  $sum = 0;

  for($i=0;$i<$x;$i++) {

    for($j=0;$j<$y;$j++) {

      $sum += $cells[$i][$j];

    }

  }

  return $sum == 0 ? [[]] : $cells;

}

另外,如果你有兴趣,或者是有问题想要与我探讨,欢迎来访问我的博客:https:mu-mu.cn/blog

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容