Game of Life на Perl - проблема перевода кода с C ++ - PullRequest
2 голосов
/ 28 июля 2011

Я недавно начал пытаться скопировать код C ++ из Game of Life от Conway, который я написал в 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();

Ответы [ 2 ]

4 голосов
/ 28 июля 2011

Ага, нашел его.

В Perl двумерный массив - это действительно массив ссылок на массивы. Когда вы делаете @current_state = @next_state, он создает только поверхностную копию внешнего массива, так что оба массива в конечном итоге содержат ссылки на одни и те же массивы строк.

В вашем случае это просто: просто установите @next_state = () в начале цикла. Таким образом, Perl автоматически оживит для вас новый набор массивов строк.

(Кроме того, вы, вероятно, захотите исправить свои циклы, чтобы выполнять итерацию от 0 до $rows-1 и $columns-1 вместо $rows и $columns.)

3 голосов
/ 28 июля 2011

После первой итерации при изменении $next_state[$i][$j] также изменяется $current_state[$i][$j], поскольку $next_state[$i] содержит ту же ссылку, что и $current_state[$i].

Не забывайте, что двумерные массивы - это действительно массивы массивов, или, точнее, массив ссылок на массивы.

Вам нужно сделать глубокую копию вместо мелкой.

* * 1010

Вся программа, немного подчищено:

#!/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 - Я не думаю, что вы должны заглядывать за края.

...