File Coverage

File:blib/lib/Language/Homespring.pm
Coverage:88.0%

linestmtbrancondsubtimecode
1package Language::Homespring;
2
3$VERSION = 0.04;
4
5
4
4
4
17
8
30
use strict;
6
4
4
4
23
18
26
use warnings;
7
8
4
4
4
31
10
44
use Language::Homespring::Node;
9
4
4
4
39
8
37
use Language::Homespring::Salmon;
10
4
4
4
37
10
38
use Language::Homespring::Snowmelt;
11
4
4
4
32
10
35
use Language::Homespring::River;
12
13sub new {
14
26
70
        my $class = shift;
15
26
98
        my $self = bless {}, $class;
16
17
26
62
        my $options = shift;
18
26
82
        $self->{root_node} = undef;
19
26
77
        $self->{salmon} = [];
20
26
81
        $self->{snowmelt} = [];
21
26
74
        $self->{new_salmon} = [];
22
26
79
        $self->{dead_salmon} = [];
23
26
73
        $self->{output} = '';
24
26
69
        $self->{universe_ok} = 1;
25
26
26
70
        return $self;
27}
28
29sub parse {
30
26
77
        my ($self, $source) = @_;
31
32
151
322
        my @tokens =
33
151
151
363
272
                map{s/(\.$)|(^\.)/\n/g; $_}
34
151
151
340
263
                map{s/\. / /g; $_}
35
26
151
223
336
                map{s/ \././g; $_}
36                split /(?:(?<!\.) (?!\.))|(?:\n(?!\.))/, $source;
37
38        #print((join '|', @tokens)."\n\n");
39
40
26
201
        $self->{root_node} = new Language::Homespring::Node({
41                'interp' => $self,
42                'node_name' => shift @tokens,
43        });
44
26
86
        my $parent = $self->{root_node};
45
46
26
67
        for my $token(@tokens){
47
125
304
                if ($token){
48
95
504
                        my $new_node = new Language::Homespring::Node({
49                                'interp' => $self,
50                                'node_name' => $token,
51                                'parent_node' => $parent,
52                        });
53
95
363
                        $parent->add_child($new_node);
54
55
95
522
                        my $new_river = new Language::Homespring::River({
56                                'interp' => $self,
57                                'up_node' => $new_node,
58                                'down_node' => $parent,
59                        });
60
95
339
                        $parent->add_river_up($new_river);
61
95
302
                        $new_node->add_river_down($new_river);
62
63
95
309
                        $parent = $new_node;
64                }else{
65
30
114
                        if (defined $parent->{parent_node}){
66
30
108
                                $parent = $parent->{parent_node};
67                        }
68                }
69        }
70}
71
72sub tick {
73
155
383
        my ($self) = @_;
74
155
239
        my @nodes;
75
76
155
384
        $self->{output} = '';
77
78        # has our universe been smashed?
79
155
536
        return if !$self->{universe_ok};
80
81        # process snowmelts
82
151
447
                @nodes = $self->_get_nodes('snowmelt');
83
151
421
                for (@nodes){
84                        #spawn a new snowmelt
85
31
165
                        my $snowmelt = new Language::Homespring::Snowmelt({'interp' => $self, 'location' => $_});
86
31
31
68
136
                        push @{$self->{snowmelt}}, $snowmelt;
87                }
88
151
151
151
192
250
611
                $_->move() for (@{$self->{snowmelt}});
89
90                # has our universe been smashed?
91
151
523
                return if !$self->{universe_ok};
92
93
94        # process water
95
96                # turn everything off
97
149
444
                $self->_set_all('water', 0);
98
99                # water from springs
100
149
437
                @nodes = $self->_get_all_nodes();
101
149
431
                for (@nodes){
102
700
2975
                        $self->_water_downwards($_) if $_->{spring};
103                }
104
105        # process electricity
106
107                # turn everything off
108
149
576
                $self->_set_recurse($self->{root_node}, 'power', 0);
109
110                # process "powers"
111
149
454
                @nodes = $self->_get_nodes('powers');
112
149
395
                for(@nodes){
113
116
443
                        if (!$_->{destroyed}){
114
110
308
                                $self->_power_downwards($_);
115                        }
116                }
117
118                # process "hydro power"
119
149
452
                @nodes = $self->_get_nodes('hydro power');
120
149
403
                for (@nodes){
121
19
165
                        $self->_power_downwards($_) if $_->{water} && !$_->{destroyed};
122                }
123
124                # process "power invert"
125
149
426
                @nodes = $self->_get_nodes('power invert');
126
149
418
                for (@nodes){
127
18
151
                        $self->_power_downwards($_) if !$_->{power} && !$_->{destroyed};
128                }
129
130        # process salmon
131
132
149
149
149
191
248
709
                $_->move() for (@{$self->{salmon}});
133
134                # sort out dead salmon
135
149
338
444
599
                @{$self->{salmon}} = grep{
136
149
477
                        my $ok = 1;
137
338
338
540
1131
                        for my $dead(@{$self->{dead_salmon}}){
138
781
2822
                                $ok = 0 if $_ == $dead;
139                        }
140
338
781
                        $ok;
141
149
293
                }@{$self->{salmon}};
142
143                # sort out new salmon
144
149
149
149
284
390
410
                push @{$self->{salmon}}, @{$self->{new_salmon}};
145
149
445
                $self->{new_salmon} = [];
146
147        # process others
148
149
149
477
                @nodes = $self->_get_nodes('hatchery');
150
149
385
                for (@nodes){
151
149
578
                        if ($_->{power}){
152
103
103
193
342
                                my $location = @{$_->{rivers_up}}[0];
153
103
642
                                my $salmon = new Language::Homespring::Salmon({'interp' => $self,'mature' => 1, 'upstream' => 1, 'location' => $location});
154
103
103
227
482
                                push @{$self->{salmon}}, $salmon;
155                        }
156                }
157
158        # @nodes = $self->_get_nodes('bear');
159        # for (@nodes){
160        # for my $salmon($_->get_salmon()){
161        # $salmon->kill() if $salmon->{mature};
162        # }
163        # }
164
165
149
533
        return $self->{output};
166}
167
168sub run{
169
0
0
        my ($self, $max_ticks, $delimit) = @_;
170
0
0
        my $tick = 0;
171
0
0
        while(1){
172
0
0
                print $self->tick();
173
0
0
                print $delimit if defined($delimit);
174
0
0
                $tick++;
175
0
0
                return if (defined($max_ticks) && ($tick >= $max_ticks));
176
0
0
                return if !$self->{universe_ok};
177        }
178}
179
180sub _set_all {
181
149
434
        my ($self, $prop, $value) = @_;
182
149
546
        $self->_set_recurse($self->{root_node}, $prop, $value);
183}
184
185sub _set_recurse {
186
1400
4149
        my ($self, $node, $prop, $value) = @_;
187
1400
3287
        $node->{$prop} = $value;
188
1400
1400
1400
1685
2267
8314
        $self->_set_recurse($_, $prop, $value) for @{$node->{child_nodes}};
189}
190
191sub _get_nodes {
192
747
1990
        my ($self, $name) = @_;
193
747
2768
        return $self->_get_nodes_i($self->{root_node}, $name);
194}
195
196sub _get_nodes_i {
197
3512
9708
        my ($self, $node, $name) = @_;
198
3512
6770
        my @out = ();
199
3512
12581
        push @out, $node if ($node->{node_name} eq $name);
200
3512
3512
3512
4271
5576
16182
        push @out, $self->_get_nodes_i($_, $name) for @{$node->{child_nodes}};
201
3512
12635
        return @out;
202}
203
204sub _get_all_nodes {
205
149
370
        my ($self) = @_;
206
149
519
        return $self->_get_all_nodes_i($self->{root_node});
207}
208
209sub _get_all_nodes_i {
210
700
1793
        my ($self, $node) = @_;
211
700
1344
        my @out = ();
212
700
1383
        push @out, $node;
213
700
700
700
851
1120
3147
        push @out, $self->_get_all_nodes_i($_) for @{$node->{child_nodes}};
214
700
2772
        return @out;
215}
216
217sub _power_downwards {
218
337
883
        my ($self, $node) = @_;
219
220
337
1360
        return if (!$node->{parent_node});
221
222
234
690
        $node->{parent_node}->{power} = 1;
223
224
234
948
        return if ($node->{parent_node}->{node_name} eq 'power invert');
225
229
925
        return if ($node->{parent_node}->{node_name} eq 'insulated');
226
224
922
        return if ($node->{parent_node}->{node_name} eq 'force field');
227
211
1055
        return if (($node->{parent_node}->{node_name} eq 'bridge') && ($node->{parent_node}->{destroyed}));
228
229        # TODO: "sense" and "switch"
230
231
211
704
        $self->_power_downwards($node->{parent_node});
232}
233
234sub _water_downwards {
235
506
1285
        my ($self, $node) = @_;
236
237
506
1960
        return if (!$node->{parent_node});
238
239
340
1005
        $node->{parent_node}->{water} = 1;
240
241
340
1778
        return if (($node->{parent_node}->{node_name} eq 'force field') && ($node->{parent_node}->{power}));
242
334
1671
        return if (($node->{parent_node}->{node_name} eq 'bridge') && ($node->{parent_node}->{destroyed}));
243
334
1668
        return if (($node->{parent_node}->{node_name} eq 'evaporates') && ($node->{parent_node}->{power}));
244
245
334
1095
        $self->_water_downwards($node->{parent_node});
246}
247