このシリーズについて

このシリーズでは、TRPGやボードゲームでおなじみの「ダイス記法」を解釈して評価するインタプリタを作ります。
「2d6+3」や「3d8*2-1」といった文字列を読み取り、実際にダイスを振って計算結果を返すツールです。全8回を通じて、オブジェクト指向設計の実践的な手法を学んでいきます。
想定読者
- Perl入学式を卒業したばかりの方
- 「Mooで覚えるオブジェクト指向プログラミング」シリーズを読了された方
- モダンなPerlでオブジェクト指向プログラミングを身に付けたい方
このシリーズで得られること
- オブジェクト指向プログラミングの原則を深く学べます
- SOLID原則を実践的に体得できます
- デザインパターンを自然に覚えられます
- 「自作ダイス言語」という自慢できるアウトプットが手に入ります
ダイス記法とは
TRPGやボードゲームでは、「NdM」という形式でダイスを表現します。
2d6 → 6面ダイスを2個振る1d20 → 20面ダイスを1個振る3d8 → 8面ダイスを3個振る
「d」はdice(ダイス)の頭文字で、左側の数字が振る個数、右側の数字がダイスの面の数を表します。
今回はこの「NdM」形式を解釈してダイスを振るところから始めましょう。
最小限のDiceクラスを作る
まずは、ダイスを振る機能を持つシンプルなクラスを作ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| #!/usr/bin/env perl
use v5.36;
package Dice {
use Moo;
has count => (is => 'ro', required => 1); # 振る数
has sides => (is => 'ro', required => 1); # 面の数
sub roll($self) {
my $total = 0;
for (1 .. $self->count) {
$total += int(rand($self->sides)) + 1;
}
return $total;
}
}
# 使ってみる
my $dice = Dice->new(count => 2, sides => 6);
say "2d6の結果: " . $dice->roll;
my $dice20 = Dice->new(count => 1, sides => 20);
say "1d20の結果: " . $dice20->roll;
|
実行すると、毎回異なる結果が得られます。
1
2
| 2d6の結果: 8
1d20の結果: 15
|
Diceクラスは2つの属性を持ちます。
count: 振るダイスの個数sides: ダイスの面の数
rollメソッドは、指定された回数だけダイスを振り、合計を返します。
ダイス記法を解析する
「2d6」という文字列から、count=2、sides=6を取り出すパーサーを追加しましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| #!/usr/bin/env perl
use v5.36;
package Dice {
use Moo;
has count => (is => 'ro', required => 1);
has sides => (is => 'ro', required => 1);
sub roll($self) {
my $total = 0;
for (1 .. $self->count) {
$total += int(rand($self->sides)) + 1;
}
return $total;
}
sub parse($class, $notation) {
if ($notation =~ /^(\d+)d(\d+)$/) {
my ($count, $sides) = ($1, $2);
die "不正なダイス記法: $notation" if $count < 1 || $sides < 1;
return $class->new(count => $count, sides => $sides);
}
die "不正なダイス記法: $notation";
}
}
# 文字列から解析
my $dice = Dice->parse('2d6');
say "2d6の結果: " . $dice->roll;
my $dice2 = Dice->parse('3d8');
say "3d8の結果: " . $dice2->roll;
my $dice3 = Dice->parse('1d20');
say "1d20の結果: " . $dice3->roll;
|
parseメソッドは、正規表現でダイス記法を解析します。
(\d+)d(\d+) → 「数字 + d + 数字」の形式にマッチ$1がcount、$2がsidesになる
これで「2d6」のような文字列からDiceオブジェクトを作れるようになりました。
乱数のテストについて
ダイスには乱数が絡むため、テストが難しいと思われがちです。しかし、Perlではsrand関数でシードを固定することで、再現可能なテストが書けます。
1
2
3
| srand(42); # シードを固定
my $dice = Dice->new(count => 2, sides => 6);
say $dice->roll; # 常に同じ結果になる
|
開発中はシードを固定して動作確認すると便利です。
本番利用ではシード固定は解除し、毎回ランダムになるようにしておきましょう。
今回のまとめ
今回は、ダイス記法を解釈してダイスを振る最小限のDiceクラスを作りました。
- Diceクラスでダイスの個数と面数を管理
- rollメソッドで実際にダイスを振る
- parseメソッドで「2d6」形式の文字列を解析
次回は、「2d6+3」のような計算式に対応しようとして、問題に直面します。