1時間以内に解けなければプログラマ失格となってしまう5つの問題を会社の勉強会でやってみた(perl)

流行りの「[1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に](http://www.softantenna.com/wp/software/5-programming-problems/)」を会社の勉強会でやりました。
勉強会では[gistに挙げる](https://gist.github.com/kochizufan/ce34f840baf9db65c22e)ルールだったのですが、私的にはQiitaがホームグラウンドなので、こっちにも挙げておきます。

解くのは、問題4をなめていて、70分かかり、さらにバグを見つけて結局80分かかってしまいました。
先週が問題解き、今週が答え合わせだったので、ついでに1週間でCodeGolf的ワンライナーも作ってみました。

### 問題1

```perl:問題1
package Question1;
 
use strict;
use warnings;
 
sub for_type {
    my @args = @_;
    my $sum = 0;
    for (my $i=0;$i < @args;$i++) {
        $sum += $args[$i];
    }
    return $sum;
}
 
sub while_type {
    my @args = @_;
    my $sum = 0;
    while (@args) {
        $sum += shift(@args);
    }
    return $sum;
}
 
sub recursion_type {
    my @args = @_;
    return @args ? shift(@args) + recursion_type(@args) : 0;
}
 
1;
```

```shell-session:問題1のCodeGolf
perl -e'$a+=$_ for@ARGV;warn$a' 1 2 3 4
perl -e'$a+=pop while@ARGV;warn$a' 1 2 3 4
perl -e'sub a{@_?pop()+a(@_):0};warn a(@ARGV)' 1 2 3 4
```

### 問題2

```perl:問題2
package Question2;
 
use strict;
use warnings;
 
sub list_add {
    my ($l1,$l2) = @_;
    my @ret;
    my $len = @{$l1} > @{$l2} ? @{$l1} : @{$l2};
    for (my $i =0; $i < $len; $i++) {
        push(@ret,$l1->[$i]) if ($i<@{$l1});
        push(@ret,$l2->[$i]) if ($i<@{$l2});
    }
    return @ret;
}
 
1;
```

```shell-session:問題2のCodeGolf
perl -e'@a=map{[split(/,/,$_)]}@ARGV;@b=@{$a[0]};@c=@{$a[1]};$l=@b>@c?@b:@c;for(0..$l-1){push(@d,$b[$_])if(@b>$_);push(@d,$c[$_])if(@c>$_)}print@d' 1,2,3,4 a,b,c,d,e,f,g
```

### 問題3

bigint使ってるけどなんかうまく動かない...でもとりあえずロジックはあってるはず

```perl:問題3
package Question3;
 
use strict;
use warnings;
use bigint;
 
sub fibonacci {
    my $now = 0;
    my @ret = (0,1);
    for (my $i = 0; $i < 99; $i++) {
        push(@ret,$ret[$i]+$ret[$i+1]);
    }
    return @ret;
}
 
1;
```

```shell-session:問題3のCodeGolf
perl -Mbigint -e'$r[$_]=$_<2?$_:$r[$_-2]+$r[$_-1]for(0..99);warn join",",@r'
```

### 問題4

正直これが一番悩みました、他のメンバーは5の方が難しいと言ってましたが、これってもっと簡単なやり方あるんですか？
簡単にワンライナーにできるよ、と言われましたが、正直私版のこれのワンライナーは単に長い版を文字削っただけです...

```perl:問題4
package Question4;
 
use strict;
use warnings;
 
sub kanounasaidai {
    my @args = map { $_ ."" } @_;
    my @list;
    for (my $i=0;$i<@args;$i++) {
        for (my $j=0;$j<@args;$j++) {
            next if ($i == $j);
            push(@list,[$i,$j,$args[$i].$args[$j]]); 
        }
    }
    @list = sort { $b->[2] cmp $a->[2] } @list;
    return $list[0]->[2] if (@args == 2);
    my $res = $list[0];
 
    my $k = -1;
    return kanounasaidai($res->[2],grep {$k++; $k != $res->[0] && $k != $res->[1]} @args);
}
```

```shell-session:問題4のCodeGolf
perl -e'sub k{@z=map{$_.""}@_;my @l;for $i.$#z){for $j(0..$#z){next if($i==$j);push(@l,[$i,$j,$z[$i].$z[$j]])}}@l=sort{$b->[2]cmp$a->[2]}@l;return $l[0]->[2] if(@z==2);$r=$l[0];$k=-1;return k($r->[2],grep{$k++;$k!=$r->[0]&&$k!=$r->[1]}@z)}warn k(@ARGV)' 9 956 978 56
```

### 問題5

一番難しいとみんな言ってたけど、5分でできましたが（ただバグあったけど）...
eval禁止縛りとかしてるから難しいのかなと思ったら、普通にみんなeval使ってたし

```perl:問題5
package Question5;
 
use strict;
use warnings;
 
sub recursive {
    my $now = shift;
    my @list = @_;
    my @ret;
    if ($now == 1) {
        @ret = ('1','-1');
    } else {
        foreach my $l (@list) {
            push(@ret,$l."+$now");
            push(@ret,$l."-$now");
            push(@ret,$l."$now");
        }
    }
    return $now == 9 ? @ret : recursive($now+1,@ret);
}
 
sub answer {
    my @pattern = recursive(1);
    my @ans = grep {eval($_) == 100} @pattern;
    print join("\n",@ans);
}
 
1;
```

```shell-session:問題5のCodeGolf
perl -e 'sub r{$n=shift;my@r=$n==1?("1","-1"):map{($_."+$n",$_."-$n",$_.$n)}@_;$n==9?@r:r($n+1,@r)}@p=r(1);@a=grep{eval($_)==100}@p;warn join("\n",@a)'
```