2

我最近开始尝试将我编写的康威生命游戏的 C++ 代码复制到 Perl 中,并且几乎是逐字复制。但是,C++ 代码的输出与 Perl 的输出有很大不同。C++ 代码运行完美,但 Perl 代码给出了奇怪的行为。任何看过生命游戏的人都应该知道,以下游戏状态很奇怪:

  [][]  []  []  []  [][][]  []  []              []    []  []  []    [][]      []
  []    []  []  []  []      []  []    [][]  []    []    [][]  []          []  []
  []  [][]  []  []  []          []  []      [][][][]  []  []  [][][][][]  []  []
  []      [][]  []  []        []    [][][][]  []  []  []      []      [][]  []
[]  [][]        []  []  [][][]  []        []          []      []  [][]  []  []
[]  []  [][][][][]  []  []    [][]  [][]  []          [][]  []      [][][]  []
[]    []                    []  [][][]  [][]  [][][]          [][][]    []  []
  []  []  [][][][][][][][][][]                      [][][][][]      []      []
[][]  []                      [][][][][][][]  [][][]        [][]      [][]  []
    []  []      [][][][]        []  []    []  []    [][][]  []
  [][]  []  []        []                  []  []  [][]  []  [][]
    []  []  [][]      []    [][][][]    [][]  []        []
      [][]    []    [][][][][]    [][][]          [][][][][][][][]  [][]
  []      []  []  []            []        [][][][]                  [][]
[][]      []  []  []  []  []    []  [][][]          [][][][][][][][]
        [][]  []    []      []  []  []  []  [][][][]  []          [][]      [][]
[]            [][]  []    [][]  []          []            [][][][]    [][][]
[]      [][][][]    []  []      []  []  []        []  []  []  []  []  []      []
                [][][]  [][][]      []  [][]        [][]  []      []  []      []
  []                [][][]    []  [][]  [][]          []  []      []    [][]  []
  [][]            []        []        [][][][][][]        [][]  []  []  []
      []          []  [][][][][][][][][]          []    []    []    []    [][][]
    [][]  [][][]  []  []                  [][]  []      []  []  [][]  []  []  []
  []    []      []        [][]  [][][][][][][]  []  [][]    []    []  []      []

每个[]代表一个活细胞,而任何两个空白代表一个死细胞。奇怪的部分是在许多运行代码的尝试中出现的水平线和垂直线。我还没有看到预期的行为(滑翔机、振荡器等)。

我的代码如下;我将不胜感激任何帮助/澄清。提前致谢!

#!/usr/bin/perl

use warnings;
use strict;
use Curses;
use Time::HiRes 'usleep';

my $iterations = 100;
$iterations = $ARGV[0] if @ARGV;

initscr;
getmaxyx(my $rows, my $columns);
$columns = int($columns / 2);
my ($i, $j);
my @initial_state;
foreach $i (0 .. $rows) {
        foreach $j (0 .. $columns) {
                $initial_state[$i][$j] = int rand(2);
        }
}

my @current_state = @initial_state;
my @next_state;
my $iteration;
my ($up, $down, $right, $left);
my $adjacent_cells;

foreach $iteration (0 .. $iterations) {
        foreach $i (0 .. $rows) {
                foreach $j (0 .. $columns) {
                        $up     = ($i + 1) % $rows;
                        $down   = ($i - 1) % $rows;
                        $right  = ($j + 1) % $columns;
                        $left   = ($j - 1) % $columns;
                        $adjacent_cells = $current_state[$i][$right] 
                                        + $current_state[$i][$left] 
                                        + $current_state[$up][$right] 
                                        + $current_state[$up][$left] 
                                        + $current_state[$down][$right] 
                                        + $current_state[$down][$left] 
                                        + $current_state[$up][$j] 
                                        + $current_state[$down][$j];
                        if ( $current_state[$i][$j] ) {
                                $next_state[$i][$j] = $adjacent_cells == 2 || $adjacent_cells == 3 ? 1 : 0;
                                addstr($i, 2*$j, '[]');
                        }
                        else {
                                $next_state[$i][$j] = $adjacent_cells == 3 ? 1 : 0;
                                addstr($i, 2*$j, '  ');
                        }
                }
        }
        @current_state = @next_state unless $iteration == $iterations;
        usleep 10000;
        refresh();
}

getch();
endwin();
4

2 回答 2

4

啊哈,找到了。

在 Perl 中,二维数组实际上是对数组的引用数组。当您这样做时@current_state = @next_state,它只会制作外部数组的浅表副本,因此两个数组最终都包含对相同行数组的引用。

在您的情况下,修复很简单:只需@next_state = ()在循环的开头设置。这样,perl 将为您自动激活一组新的行数组。

(此外,您可能希望修复循环,以便从 0 迭代到$rows-1and$columns-1而不是 to $rowsand $columns。)

于 2011-07-28T08:56:48.170 回答
3

在第一次迭代之后,由于包含与 相同的引用,更改$next_state[$i][$j]也会发生变化。$current_state[$i][$j]$next_state[$i]$current_state[$i]

不要忘记 2d 数组实际上是 Arrays of Arrays,或者更具体地说,是 Array of References to Arrays。

您需要制作深拷贝而不是浅拷贝。

@current_state = map { [ @$_ ] } @next_state;

整个程序,清理了一些:

#!/usr/bin/perl

use strict;
use warnings;

use Curses;
use Time::HiRes qw( usleep );
use List::Util  qw( sum );

my $iterations = $ARGV[0] || 100;

initscr;
getmaxyx(my $rows, my $cols);
$cols = int($cols / 2);
my @initial_state;
for my $i (0 .. $rows-1) {
        for my $j (0 .. $cols-1) {
                $initial_state[$i][$j] = int rand(2);
        }
}

my @current_state = map { [ @$_ ] } @initial_state;
my @next_state;
my $iteration = 0;
for (;;) {
        for my $i (0 .. $rows-1) {
                for my $j (0 .. $cols-1) {
                        addstr($i, 2*$j, $current_state[$i][$j] ? '[]' : '  ');
                }
        }

        last if ++$iteration == $iterations;

        for my $i (0 .. $rows-1) {
                for my $j (0 .. $cols-1) {
                        my $up     = ($i + 1) % $rows;
                        my $down   = ($i - 1) % $rows;
                        my $right  = ($j + 1) % $cols;
                        my $left   = ($j - 1) % $cols;
                        my $adjacent_cells = sum
                                $current_state[$i][$right],
                                $current_state[$i][$left],
                                $current_state[$up][$right],
                                $current_state[$up][$left],
                                $current_state[$down][$right],
                                $current_state[$down][$left],
                                $current_state[$up][$j],
                                $current_state[$down][$j];

                        if ( $current_state[$i][$j] ) {
                                $next_state[$i][$j] = ($adjacent_cells == 2 || $adjacent_cells == 3) ? 1 : 0;
                        }
                        else {
                                $next_state[$i][$j] = $adjacent_cells == 3 ? 1 : 0;
                        }
                }
        }

        @current_state = map { [ @$_ ] } @next_state;

        usleep 100000;
        refresh();
}

getch();
endwin();

PS - 我认为你不应该在边缘偷看。

于 2011-07-28T09:00:01.430 回答