ペプシ算クラス

ペプシ算 - 永字八法の続き
ペプシ算のクラスを作ってみた。
※書き直した!

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5,	# 5種類のおまけつきを
	bottle=>12	# 1ダース買う
);
$pepsi->calc; # 計算する

my $result = $pepsi->total; # 計算結果を得る
# 計算結果は、何種類そろったかをキーとして確率を格納したハッシュリファレンス

# 計算結果を表示する。
print 'buy '.$pepsi->bottle." bottles.\n";
foreach my $get_kind ( sort { $a <=> $b } keys %{$result} ) {
	print 'get '.$get_kind.' kind(s) : %'.($result->{$get_kind}*100)."\n";
}

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	open_bottle
	bottle
	kind
	get_kind
	patern
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {patern=>1, @_}=>$class;
	
	return $self;
}
sub rest_kind {
	my $self = shift;
	my $rest = $self->kind - $self->get_kind;
	return $rest;
}
sub calc {
	my $self = shift;
	$self->is_end and return;
	my @child = ();
	push @child, $self->new(
		open_bottle=>(1+$self->open_bottle),
		bottle=>$self->bottle,
		kind=>$self->kind,
		get_kind=>(1+$self->get_kind),
		patern=>($self->rest_kind * $self->patern)
	); # 新種が出た場合&最初の一本は必ず新種
	if ( $self->open_bottle > 0 ) {
		push @child, $self->new(
			open_bottle=>(1+$self->open_bottle),
			bottle=>$self->bottle,
			kind=>$self->kind,
			get_kind=>$self->get_kind,
			patern=>($self->get_kind * $self->patern)
		); # 新種が出なかった場合
	}
	$self->{child} = \@child;
	map { $_->calc } @child;
	return 1;
}
sub is_end {
	my $self = shift;
	$self->get_kind < $self->kind or return 1;
	$self->open_bottle < $self->bottle or return 1;
	return undef;
}
sub is_live {
	return shift->is_end ? undef : 1;
}
sub ends {
	my $self = shift;
	my $result = shift;
	$result ||= [];
	if ( $self->{child} ) {
		map { $_->ends($result) } @{$self->{child}};
	} else {
		push @{$result}, $self;
#		print "End!\n";
	}
	return $result;
}
sub fraction {
	my $self = shift;
	my $patern = $self->patern;
	my $open_bottle = $self->open_bottle;
	while ( $open_bottle < $self->bottle ) {
		$patern *= $self->kind;
		++ $open_bottle;
	}
	return $patern;
}
sub total_child {
	my $self = shift;
	my %hash = ();
	map { $hash{$_->get_kind} += $_->fraction } @{$self->ends};
	return \%hash;
}
sub total_mother {
	my $self = shift;
	return $self->kind ** $self->bottle;
}
sub total {
	my $self = shift;
	my $child = $self->total_child;
	my $mother = $self->total_mother;
	foreach my $num ( keys %{$child} ) {
		$child->{$num} /= $mother;
	}
	return $child;
}
1;

考え方

まず、0種類の食玩がそろっているとする。
最初のボトルをあけると、0が1になる。
次のボトルをあけると、この1が1のままか2になるか、分岐が発生する。
ボトルがそろうか、全部開けてしまうかするまで、このツリーを全て調べる。

やってみた感想

再帰を使っているので、ちょっと数が大きくなると死ぬほど時間がかかるようになります。
なので、今度は再帰を使わない方法を思いついたのでそれを実装中。

ひとのわるさ

一度、やってみたいことがある。
かかってきた資格勧誘の電話に対して、
「ノルマとかあるの?」「時給いくら?」「会社名とかどうなってんの?」「ノウハウ教えて」
とか、逆に聞いてみたい。
それと同様に、道でティッシュ配ってる人に対して、一分あたり一個ティッシュもらうからとか話つけて、具体的な数字の話を聞いてみたい。
そんなことを話したら、「どんだけ(人|性格|意地)が悪いんだ」とぶいぶい言われた。
ちぇ。

ペプシ算ファイナル

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5	# 5種類のおまけつき食玩具
);
print $pepsi->percent(10); # 10本あけて、コンプする確率は?
print "\n";
print $pepsi->limit(0.9); # では、コンプ率が90%を超えるのは何本から?
print "\n";
print $pepsi->limit(0.95); # では、コンプ率が95%を超えるのは何本から?
print "\n";
my $res = $pepsi->probability(15); # 15本開けた時、どんな確率で何種類集まる?
my $num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
$res = $pepsi->get_patern(15); # 同じ内容を、分母で割る前の値で取得したい。
$num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
print $pepsi->mother(15); # その時の分母を取得する。

実行結果

0.5225472
18
21
get 0 kind(s) : % 0
get 1 kind(s) : % 0.00000000016384
get 2 kind(s) : % 0.00001073676288
get 3 kind(s) : % 0.00466963857408
get 4 kind(s) : % 0.166550372352
get 5 kind(s) : % 0.8287692521472

get 0 kind(s) : %
get 1 kind(s) : % 5
get 2 kind(s) : % 327660
get 3 kind(s) : % 142506060
get 4 kind(s) : % 5082714000
get 5 kind(s) : % 25292030400

30517578125

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	bottle
	kind
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {@_}=>$class;
	$self->init;
	return $self;
}
sub open_bottle {
	my $self = shift;
	my $now_bottle = $self->bottle;
	my $next_bottle = $now_bottle + 1;
	foreach my $kind ( 0..$self->kind ) {
		# かぶる場合
		my $new_num = $self->{table}->[$now_bottle]->[$kind] * $kind;
		$new_num and $self->{table}->[$next_bottle]->[$kind] += $new_num;
		# 新しい種類が出る場合
		$new_num = $self->{table}->[$now_bottle]->[$kind] * ($self->kind - $kind);
		$new_num and $self->{table}->[$next_bottle]->[$kind+1] += $new_num;
	}
	++ $self->{bottle};
}
sub get_patern {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	until ( $self->{table}->[$bottle] ) {
		$self->open_bottle;
	}
	return $self->{table}->[$bottle];
}
sub percent {
	my $self = shift;
	my ( $bottle, $kind ) = ();
	@_ and ( $bottle, $kind ) = @_;
	$bottle ||= $self->bottle;
	$kind ||= $self->kind;
	my $patern = $self->get_patern($bottle);
	my $result = $patern->[$kind];
	$result /= $self->mother($bottle);
	return $result;
}
sub probability {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	my $patern = $self->get_patern($bottle);
	my $mother = $self->mother($bottle);
	my @res = @{$patern};
	map { $_ /= $mother } @res;
	return \@res;
}
sub limit {
	my $self = shift;
	my $limit = shift;
	$limit ||= 0.9;
	my $bottle = 1;
	while ( $self->percent($bottle) < $limit ) {
		++ $bottle;
	}
	return $bottle;
}
sub mother {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	$self->{mother}->[$bottle] ||= $self->mother($bottle-1) * $self->kind;
	return $self->{mother}->[$bottle];
}
sub init {
	my $self = shift;
	$self->{bottle} = 0;
	$self->{mother} = [1];
	$self->{table} = [[1]];
}
1;

解説

もっとブラックボックス化できた。
食玩の種類数を指定するだけで、必要な数字を取得できるようにした。ひゃっほう。

感想

でもさあ、よく考えたら、今の食玩って中身まる見えでないといけないんだよね。コンプするのに買い込む必要がないと言うか……。

ひとのわるさ

一度、やってみたいことがある。
かかってきた資格勧誘の電話に対して、
「ノルマとかあるの?」「時給いくら?」「会社名とかどうなってんの?」「ノウハウ教えて」
とか、逆に聞いてみたい。
それと同様に、道でティッシュ配ってる人に対して、一分あたり一個ティッシュもらうからとか話つけて、具体的な数字の話を聞いてみたい。
そんなことを話したら、「どんだけ(人|性格|意地)が悪いんだ」とぶいぶい言われた。
ちぇ。

ペプシ算クラス

ペプシ算 - 永字八法の続き
ペプシ算のクラスを作ってみた。
※書き直した!

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5,	# 5種類のおまけつきを
	bottle=>12	# 1ダース買う
);
$pepsi->calc; # 計算する

my $result = $pepsi->total; # 計算結果を得る
# 計算結果は、何種類そろったかをキーとして確率を格納したハッシュリファレンス

# 計算結果を表示する。
print 'buy '.$pepsi->bottle." bottles.\n";
foreach my $get_kind ( sort { $a <=> $b } keys %{$result} ) {
	print 'get '.$get_kind.' kind(s) : %'.($result->{$get_kind}*100)."\n";
}

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	open_bottle
	bottle
	kind
	get_kind
	patern
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {patern=>1, @_}=>$class;
	
	return $self;
}
sub rest_kind {
	my $self = shift;
	my $rest = $self->kind - $self->get_kind;
	return $rest;
}
sub calc {
	my $self = shift;
	$self->is_end and return;
	my @child = ();
	push @child, $self->new(
		open_bottle=>(1+$self->open_bottle),
		bottle=>$self->bottle,
		kind=>$self->kind,
		get_kind=>(1+$self->get_kind),
		patern=>($self->rest_kind * $self->patern)
	); # 新種が出た場合&最初の一本は必ず新種
	if ( $self->open_bottle > 0 ) {
		push @child, $self->new(
			open_bottle=>(1+$self->open_bottle),
			bottle=>$self->bottle,
			kind=>$self->kind,
			get_kind=>$self->get_kind,
			patern=>($self->get_kind * $self->patern)
		); # 新種が出なかった場合
	}
	$self->{child} = \@child;
	map { $_->calc } @child;
	return 1;
}
sub is_end {
	my $self = shift;
	$self->get_kind < $self->kind or return 1;
	$self->open_bottle < $self->bottle or return 1;
	return undef;
}
sub is_live {
	return shift->is_end ? undef : 1;
}
sub ends {
	my $self = shift;
	my $result = shift;
	$result ||= [];
	if ( $self->{child} ) {
		map { $_->ends($result) } @{$self->{child}};
	} else {
		push @{$result}, $self;
#		print "End!\n";
	}
	return $result;
}
sub fraction {
	my $self = shift;
	my $patern = $self->patern;
	my $open_bottle = $self->open_bottle;
	while ( $open_bottle < $self->bottle ) {
		$patern *= $self->kind;
		++ $open_bottle;
	}
	return $patern;
}
sub total_child {
	my $self = shift;
	my %hash = ();
	map { $hash{$_->get_kind} += $_->fraction } @{$self->ends};
	return \%hash;
}
sub total_mother {
	my $self = shift;
	return $self->kind ** $self->bottle;
}
sub total {
	my $self = shift;
	my $child = $self->total_child;
	my $mother = $self->total_mother;
	foreach my $num ( keys %{$child} ) {
		$child->{$num} /= $mother;
	}
	return $child;
}
1;

考え方

まず、0種類の食玩がそろっているとする。
最初のボトルをあけると、0が1になる。
次のボトルをあけると、この1が1のままか2になるか、分岐が発生する。
ボトルがそろうか、全部開けてしまうかするまで、このツリーを全て調べる。

やってみた感想

再帰を使っているので、ちょっと数が大きくなると死ぬほど時間がかかるようになります。
なので、今度は再帰を使わない方法を思いついたのでそれを実装中。

ペプシ算ファイナル

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5	# 5種類のおまけつき食玩具
);
print $pepsi->percent(10); # 10本あけて、コンプする確率は?
print "\n";
print $pepsi->limit(0.9); # では、コンプ率が90%を超えるのは何本から?
print "\n";
print $pepsi->limit(0.95); # では、コンプ率が95%を超えるのは何本から?
print "\n";
my $res = $pepsi->probability(15); # 15本開けた時、どんな確率で何種類集まる?
my $num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
$res = $pepsi->get_patern(15); # 同じ内容を、分母で割る前の値で取得したい。
$num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
print $pepsi->mother(15); # その時の分母を取得する。

実行結果

0.5225472
18
21
get 0 kind(s) : % 0
get 1 kind(s) : % 0.00000000016384
get 2 kind(s) : % 0.00001073676288
get 3 kind(s) : % 0.00466963857408
get 4 kind(s) : % 0.166550372352
get 5 kind(s) : % 0.8287692521472

get 0 kind(s) : %
get 1 kind(s) : % 5
get 2 kind(s) : % 327660
get 3 kind(s) : % 142506060
get 4 kind(s) : % 5082714000
get 5 kind(s) : % 25292030400

30517578125

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	bottle
	kind
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {@_}=>$class;
	$self->init;
	return $self;
}
sub open_bottle {
	my $self = shift;
	my $now_bottle = $self->bottle;
	my $next_bottle = $now_bottle + 1;
	foreach my $kind ( 0..$self->kind ) {
		# かぶる場合
		my $new_num = $self->{table}->[$now_bottle]->[$kind] * $kind;
		$new_num and $self->{table}->[$next_bottle]->[$kind] += $new_num;
		# 新しい種類が出る場合
		$new_num = $self->{table}->[$now_bottle]->[$kind] * ($self->kind - $kind);
		$new_num and $self->{table}->[$next_bottle]->[$kind+1] += $new_num;
	}
	++ $self->{bottle};
}
sub get_patern {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	until ( $self->{table}->[$bottle] ) {
		$self->open_bottle;
	}
	return $self->{table}->[$bottle];
}
sub percent {
	my $self = shift;
	my ( $bottle, $kind ) = ();
	@_ and ( $bottle, $kind ) = @_;
	$bottle ||= $self->bottle;
	$kind ||= $self->kind;
	my $patern = $self->get_patern($bottle);
	my $result = $patern->[$kind];
	$result /= $self->mother($bottle);
	return $result;
}
sub probability {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	my $patern = $self->get_patern($bottle);
	my $mother = $self->mother($bottle);
	my @res = @{$patern};
	map { $_ /= $mother } @res;
	return \@res;
}
sub limit {
	my $self = shift;
	my $limit = shift;
	$limit ||= 0.9;
	my $bottle = 1;
	while ( $self->percent($bottle) < $limit ) {
		++ $bottle;
	}
	return $bottle;
}
sub mother {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	$self->{mother}->[$bottle] ||= $self->mother($bottle-1) * $self->kind;
	return $self->{mother}->[$bottle];
}
sub init {
	my $self = shift;
	$self->{bottle} = 0;
	$self->{mother} = [1];
	$self->{table} = [[1]];
}
1;

解説

もっとブラックボックス化できた。
食玩の種類数を指定するだけで、必要な数字を取得できるようにした。ひゃっほう。

感想

でもさあ、よく考えたら、今の食玩って中身まる見えでないといけないんだよね。コンプするのに買い込む必要がないと言うか……。

ひとのわるさ

一度、やってみたいことがある。
かかってきた資格勧誘の電話に対して、
「ノルマとかあるの?」「時給いくら?」「会社名とかどうなってんの?」「ノウハウ教えて」
とか、逆に聞いてみたい。
それと同様に、道でティッシュ配ってる人に対して、一分あたり一個ティッシュもらうからとか話つけて、具体的な数字の話を聞いてみたい。
そんなことを話したら、「どんだけ(人|性格|意地)が悪いんだ」とぶいぶい言われた。
ちぇ。

ペプシ算クラス

ペプシ算 - 永字八法の続き
ペプシ算のクラスを作ってみた。
※書き直した!

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5,	# 5種類のおまけつきを
	bottle=>12	# 1ダース買う
);
$pepsi->calc; # 計算する

my $result = $pepsi->total; # 計算結果を得る
# 計算結果は、何種類そろったかをキーとして確率を格納したハッシュリファレンス

# 計算結果を表示する。
print 'buy '.$pepsi->bottle." bottles.\n";
foreach my $get_kind ( sort { $a <=> $b } keys %{$result} ) {
	print 'get '.$get_kind.' kind(s) : %'.($result->{$get_kind}*100)."\n";
}

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	open_bottle
	bottle
	kind
	get_kind
	patern
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {patern=>1, @_}=>$class;
	
	return $self;
}
sub rest_kind {
	my $self = shift;
	my $rest = $self->kind - $self->get_kind;
	return $rest;
}
sub calc {
	my $self = shift;
	$self->is_end and return;
	my @child = ();
	push @child, $self->new(
		open_bottle=>(1+$self->open_bottle),
		bottle=>$self->bottle,
		kind=>$self->kind,
		get_kind=>(1+$self->get_kind),
		patern=>($self->rest_kind * $self->patern)
	); # 新種が出た場合&最初の一本は必ず新種
	if ( $self->open_bottle > 0 ) {
		push @child, $self->new(
			open_bottle=>(1+$self->open_bottle),
			bottle=>$self->bottle,
			kind=>$self->kind,
			get_kind=>$self->get_kind,
			patern=>($self->get_kind * $self->patern)
		); # 新種が出なかった場合
	}
	$self->{child} = \@child;
	map { $_->calc } @child;
	return 1;
}
sub is_end {
	my $self = shift;
	$self->get_kind < $self->kind or return 1;
	$self->open_bottle < $self->bottle or return 1;
	return undef;
}
sub is_live {
	return shift->is_end ? undef : 1;
}
sub ends {
	my $self = shift;
	my $result = shift;
	$result ||= [];
	if ( $self->{child} ) {
		map { $_->ends($result) } @{$self->{child}};
	} else {
		push @{$result}, $self;
#		print "End!\n";
	}
	return $result;
}
sub fraction {
	my $self = shift;
	my $patern = $self->patern;
	my $open_bottle = $self->open_bottle;
	while ( $open_bottle < $self->bottle ) {
		$patern *= $self->kind;
		++ $open_bottle;
	}
	return $patern;
}
sub total_child {
	my $self = shift;
	my %hash = ();
	map { $hash{$_->get_kind} += $_->fraction } @{$self->ends};
	return \%hash;
}
sub total_mother {
	my $self = shift;
	return $self->kind ** $self->bottle;
}
sub total {
	my $self = shift;
	my $child = $self->total_child;
	my $mother = $self->total_mother;
	foreach my $num ( keys %{$child} ) {
		$child->{$num} /= $mother;
	}
	return $child;
}
1;

考え方

まず、0種類の食玩がそろっているとする。
最初のボトルをあけると、0が1になる。
次のボトルをあけると、この1が1のままか2になるか、分岐が発生する。
ボトルがそろうか、全部開けてしまうかするまで、このツリーを全て調べる。

やってみた感想

再帰を使っているので、ちょっと数が大きくなると死ぬほど時間がかかるようになります。
なので、今度は再帰を使わない方法を思いついたのでそれを実装中。

ペプシ算ファイナル

サンプルスクリプト

use Pepsi;
# 問題設定をする。
my $pepsi = Pepsi->new(
	kind=>5	# 5種類のおまけつき食玩具
);
print $pepsi->percent(10); # 10本あけて、コンプする確率は?
print "\n";
print $pepsi->limit(0.9); # では、コンプ率が90%を超えるのは何本から?
print "\n";
print $pepsi->limit(0.95); # では、コンプ率が95%を超えるのは何本から?
print "\n";
my $res = $pepsi->probability(15); # 15本開けた時、どんな確率で何種類集まる?
my $num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
$res = $pepsi->get_patern(15); # 同じ内容を、分母で割る前の値で取得したい。
$num = 0;
foreach my $proba ( @{$res} ) {
	print 'get '.$num.' kind(s) : % '.$proba."\n";
	++ $num;
}
print "\n";
print $pepsi->mother(15); # その時の分母を取得する。

実行結果

0.5225472
18
21
get 0 kind(s) : % 0
get 1 kind(s) : % 0.00000000016384
get 2 kind(s) : % 0.00001073676288
get 3 kind(s) : % 0.00466963857408
get 4 kind(s) : % 0.166550372352
get 5 kind(s) : % 0.8287692521472

get 0 kind(s) : %
get 1 kind(s) : % 5
get 2 kind(s) : % 327660
get 3 kind(s) : % 142506060
get 4 kind(s) : % 5082714000
get 5 kind(s) : % 25292030400

30517578125

モジュール

package Pepsi;
use strict;
use bignum;
use base qw ( Class::Accessor );
__PACKAGE__->mk_accessors(qw(
	bottle
	kind
));
sub new {
	my $invocant = shift;
	my $class = ref $invocant;
	$class ||= $invocant;
	my $self = bless {@_}=>$class;
	$self->init;
	return $self;
}
sub open_bottle {
	my $self = shift;
	my $now_bottle = $self->bottle;
	my $next_bottle = $now_bottle + 1;
	foreach my $kind ( 0..$self->kind ) {
		# かぶる場合
		my $new_num = $self->{table}->[$now_bottle]->[$kind] * $kind;
		$new_num and $self->{table}->[$next_bottle]->[$kind] += $new_num;
		# 新しい種類が出る場合
		$new_num = $self->{table}->[$now_bottle]->[$kind] * ($self->kind - $kind);
		$new_num and $self->{table}->[$next_bottle]->[$kind+1] += $new_num;
	}
	++ $self->{bottle};
}
sub get_patern {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	until ( $self->{table}->[$bottle] ) {
		$self->open_bottle;
	}
	return $self->{table}->[$bottle];
}
sub percent {
	my $self = shift;
	my ( $bottle, $kind ) = ();
	@_ and ( $bottle, $kind ) = @_;
	$bottle ||= $self->bottle;
	$kind ||= $self->kind;
	my $patern = $self->get_patern($bottle);
	my $result = $patern->[$kind];
	$result /= $self->mother($bottle);
	return $result;
}
sub probability {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	my $patern = $self->get_patern($bottle);
	my $mother = $self->mother($bottle);
	my @res = @{$patern};
	map { $_ /= $mother } @res;
	return \@res;
}
sub limit {
	my $self = shift;
	my $limit = shift;
	$limit ||= 0.9;
	my $bottle = 1;
	while ( $self->percent($bottle) < $limit ) {
		++ $bottle;
	}
	return $bottle;
}
sub mother {
	my $self = shift;
	my $bottle = undef;
	if ( @_ ) {
		$bottle = shift;
	} else {
		$bottle = $self->bottle;
	}
	$bottle += 0;
	$self->{mother}->[$bottle] ||= $self->mother($bottle-1) * $self->kind;
	return $self->{mother}->[$bottle];
}
sub init {
	my $self = shift;
	$self->{bottle} = 0;
	$self->{mother} = [1];
	$self->{table} = [[1]];
}
1;

解説

もっとブラックボックス化できた。
食玩の種類数を指定するだけで、必要な数字を取得できるようにした。ひゃっほう。

感想

でもさあ、よく考えたら、今の食玩って中身まる見えでないといけないんだよね。コンプするのに買い込む必要がないと言うか……。