鈍足ランナーのIT日記

走るのが好きな5流のITエンジニアのブログ。

趣味の範囲は広いけど、どれも中途半端なクソブロガー楽しめるWebアプリを作ってあっと言わせたい。サーバーサイドPerl(Mojolicious)、クライアントサイドVue.js。Arduinoにも触手を伸ばす予定。

perlで「増やす減らす2倍にする」に挑戦

ATNDフルカレンダーを見ていたら (オフラインリアルタイムどう書く)http://atnd.org/events/41603 という勉強会があって、そこに興味深い問題が載っていた。 こそで、perlにて「増やす減らす2倍にする」に挑戦してみたが・・・

初めて、Perlbeginnersでytnobodyさんも紹介していた、 関数のリファレンスというのを使ってみた。

package Counter;
use strict;
use warnings;

sub calc {

    my $final_value   = shift;
    my @results_array = ( [0] );
    my $index         = 0;

    my $add_1   = sub { my $val = shift; return ++$val; };
    my $multi_2 = sub { my $val = shift; return $val * 2; };
    my $sub_1   = sub { my $val = shift; return --$val; };

    my @operations = ( $add_1, $multi_2, $sub_1 );

    while (1) {
        my @p_results = @{$results_array[ $index++]};
        my @n_results = ();
        foreach my $p_result (@p_results) {

            for my $operation (@operations) {
                my $n_result = $operation->($p_result);
                if ( $final_value == $n_result ) {
                    return $index;
                }
                if ( $n_result > 0 ){
                    push (@n_results, $n_result);
                }
            }
        }
        push (@results_array, \@n_results);
    }
}

1;

しかし、性能が悪くてテストの途中でジッと待たないといけない。。。 とりあえず、同じ数になったら間引く処理を入れないとNGかな。

というわけで、同じ数は間引く処理を追加(以下)したら、何とかすべてのテストが通りました。

package Counter;
use strict;
use warnings;

sub calc {

    my $final_value   = shift;
    my @results_array = ( [0] );
    my %displayed_values = (0 => 1);
    my $index         = 0;

    my $add_1   = sub { my $val = shift; return ++$val; };
    my $multi_2 = sub { my $val = shift; return $val * 2; };
    my $sub_1   = sub { my $val = shift; return --$val; };

    my @operations = ( $add_1, $multi_2, $sub_1 );

    while (1) {
        my @p_results = @{$results_array[ $index++]};
        my @n_results = ();
        foreach my $p_result (@p_results) {

            for my $operation (@operations) {
                my $n_result = $operation->($p_result);
                if ( $final_value == $n_result ) {
                    return $index;
                }
                if ( $n_result > 0 && !defined($displayed_values{$n_result})){
                    push (@n_results, $n_result);
                    $displayed_values{$n_result} = 1;
                }
            }
        }
        push (@results_array, \@n_results);
    }
}

1;