File Coverage

blib/lib/Traveller/Subsector.pm
Criterion Covered Total %
statement 71 73 97.2
branch 8 10 80.0
condition 3 6 50.0
subroutine 14 14 100.0
pod 0 8 0.0
total 96 111 86.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # Copyright (C) 2009-2021 Alex Schroeder
3             # Copyright (C) 2020 Christian Carey
4             #
5             # This program is free software: you can redistribute it and/or modify it under
6             # the terms of the GNU General Public License as published by the Free Software
7             # Foundation, either version 3 of the License, or (at your option) any later
8             # version.
9             #
10             # This program is distributed in the hope that it will be useful, but WITHOUT
11             # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13             #
14             # You should have received a copy of the GNU General Public License along with
15             # this program. If not, see .
16              
17             package Traveller::Subsector;
18 2     2   12 use List::Util qw(shuffle);
  2         4  
  2         144  
19 2     2   375 use Traveller::Util qw(nearby in);
  2         4  
  2         92  
20 2     2   779 use Traveller::System::Classic::MPTS;
  2         5  
  2         19  
21 2     2   66 use Traveller::System::Classic;
  2         3  
  2         10  
22 2     2   44 use Traveller::System;
  2         4  
  2         8  
23 2     2   51 use Mojo::Base -base;
  2         3  
  2         6  
24              
25             has 'systems' => sub { [] };
26              
27             sub one {
28 2538     2538 0 3550 my $i = int(rand(scalar @_));
29 2538         4392 return $_[$i];
30             }
31              
32             sub compute_digraphs {
33 64     64 0 645 my @first = qw(b c d f g h j k l m n p q r s t v w x y z .
34             sc ng ch gh ph rh sh th wh zh wr qu
35             st sp tr tw fl dr pr dr);
36             # make missing vowel rare
37 64         360 my @second = qw(a e i o u a e i o u a e i o u .);
38 64         131 my @d;
39 64         237 for (1 .. 10+rand(20)) {
40 1269         2152 push(@d, one(@first));
41 1269         1898 push(@d, one(@second));
42             }
43 64         408 return \@d;
44             }
45              
46             sub add {
47 1283     1283 0 2219 my ($self, $system) = @_;
48 1283         1607 push(@{$self->systems}, $system);
  1283         2275  
49             }
50              
51             sub init {
52 2     2 0 2053 my ($self, $width, $height, $rules, $density) = @_;
53 2   50     9 $density ||= 0.5;
54 2         11 my $digraphs = $self->compute_digraphs;
55 2   50     17 $width //= 8;
56 2   50     9 $height //= 10;
57 2         7 for my $x (1..$width) {
58 64         241 for my $y (1..$height) {
59 2560 100       9530 if (rand() < $density) {
60 1283         1616 my $system;
61 1283 50       2705 if ($rules eq 'mpts') {
    50          
62 0         0 $system = Traveller::System::Classic::MPTS->new();
63             } elsif ($rules eq 'ct') {
64 0         0 $system = Traveller::System::Classic->new();
65             } else {
66 1283         3100 $system = Traveller::System->new();
67             }
68 1283         7903 $self->add($system->init($x, $y, $digraphs));
69             }
70             }
71             }
72             # Rename some systems: assume a jump-2 and a jump-1 culture per every
73             # subsector of 8×10×½ systems. Go through the list in random order.
74 2         10 for my $system (shuffle(grep { rand(20) < 1 } @{$self->systems})) {
  1283         1973  
  2         9  
75 62         873 $self->spread(
76             $system,
77             $self->compute_digraphs,
78             1 + int(rand(2)), # jump distance
79             1 + int(rand(3))); # jump number
80             }
81 2         44 return $self;
82             }
83              
84             sub spread {
85 62     62 0 189 my ($self, $system, $digraphs, $jump_distance, $jump_number) = @_;
86 62         249 my $culture = $system->compute_name($digraphs);
87             # warn sprintf("%02d%02d %s %d %d\n", $system->x, $system->y, $culture, $jump_distance, $jump_number);
88 62         192 my $network = [$system];
89 62         254 $self->grow($system, $jump_distance, $jump_number, $network);
90 62         228 for my $other (@$network) {
91 1437         9164 $other->culture($culture);
92 1437         8413 $other->name($other->compute_name($digraphs));
93             }
94             }
95              
96             sub grow {
97 715     715 0 1962 my ($self, $system, $jump_distance, $jump_number, $network) = @_;
98             my @new_neighbours =
99 1830 100       10065 grep { not $_->culture or int(rand(2)) }
100 715         2293 grep { not Traveller::Util::in($_, @$network) }
  5485         12290  
101             $self->neighbours($system, $jump_distance, $jump_number);
102             # for my $neighbour (@new_neighbours) {
103             # warn sprintf(" added %02d%02d %d %d\n", $neighbour->x, $neighbour->y, $jump_distance, $jump_number);
104             # }
105 715         5066 push(@$network, @new_neighbours);
106 715 100       2650 if ($jump_number > 0) {
107 363         876 for my $neighbour (@new_neighbours) {
108 653         2432 $self->grow($neighbour, $jump_distance, $jump_number - 1, $network);
109             }
110             }
111             }
112              
113             sub neighbours {
114 715     715 0 1643 my ($self, $system, $jump_distance, $jump_number) = @_;
115 715         2501 my @neighbours = nearby($system, $jump_distance, $self->systems);
116 715         3071 return @neighbours;
117             }
118              
119             sub str {
120 2     2 0 10 my $self = shift;
121 2         6 my $subsector;
122 2         4 foreach my $system (@{$self->systems}) {
  2         11  
123 1283         2625 $subsector .= $system->str . "\n";
124             }
125 2         158 return $subsector;
126             }
127              
128             1;