File Coverage

blib/lib/Games/2048/Game.pm
Criterion Covered Total %
statement 60 74 81.0
branch 17 26 65.3
condition 11 18 61.1
subroutine 10 11 90.9
pod 0 9 0.0
total 98 138 71.0


line stmt bran cond sub pod time code
1             package Games::2048::Game;
2 4     4   116 use 5.012;
  4         23  
  4         168  
3 4     4   22 use Moo;
  4         8  
  4         26  
4              
5             extends 'Games::2048::Board';
6             with 'Games::2048::Serializable';
7              
8             has insert_tiles_on_start => is => 'rw', default => 2;
9             has insert_tiles_on_move => is => 'rw', default => 1;
10              
11             has won => is => 'rw', default => 0;
12             has goal => is => 'rw', default => 2048;
13              
14             sub insert_start_tiles {
15 2     2 0 28 my $self = shift;
16 2         13 return map $self->insert_random_tile, 1..$self->insert_tiles_on_start;
17             }
18              
19             sub insert_random_tile {
20 30     30 0 2243 my $self = shift;
21 30         78 my @available_cells = $self->available_cells;
22 30 100       322 return if !@available_cells;
23 20         126 my $cell = $available_cells[rand @available_cells];
24 20 50       97 my $value = rand() < 0.9 ? 2 : 4;
25 20         49 $self->insert_tile($cell, $value);
26 20         92 $cell;
27             }
28              
29             sub insert_tile {
30 474     474 0 2748 my ($self, $cell, $value) = @_;
31 474         11230 my $tile = Games::2048::Tile->new(value => $value);
32 474         12023 $self->set_tile($cell, $tile);
33 474         4397 $self->next::method($tile);
34             }
35              
36             sub move_tile {
37 162     162 0 220 my ($self, $cell, $next, $next_tile) = @_;
38 162         413 $self->clear_tile($cell);
39 162         1234 $self->set_tile($next, $next_tile);
40             }
41              
42             sub merged_tile {
43 60     60 0 80 my ($self, $cell, $next) = @_;
44 60         139 my $tile = $self->tile($cell);
45 60         466 my $next_tile = $self->tile($next);
46              
47 60         1608 my $merged_tile = Games::2048::Tile->new(
48             value => $tile->value + $next_tile->value,
49             merging_tiles => [ $tile, $next_tile ],
50             merged => 1,
51             );
52             }
53              
54             sub move_tiles {
55 38     38 0 620 my ($self, $vec) = @_;
56 38         67 my $moved;
57 38         74 my $move_score = "0 but true";
58              
59 38   100     224 my $reverse = $vec->[0] > 0 || $vec->[1] > 0;
60              
61 38 100       205 for my $cell ($reverse ? reverse $self->tile_cells : $self->tile_cells) {
62 400         2706 my $tile = $self->tile($cell);
63 400         2344 my $next = $cell;
64 400         345 my $farthest;
65 400   100     404 do {
66 571         1596 $farthest = $next;
67 571         2957 $next = [ map $next->[$_] + $vec->[$_], 0..1 ];
68             } while ($self->within_bounds($next)
69             and !$self->tile($next));
70              
71 400 100       2665 if ($self->cells_can_merge($cell, $next)) {
    100          
72 60         154 my $merged_tile = $self->merged_tile($cell, $next);
73 60         1718 $self->move_tile($cell, $next, $merged_tile);
74 60         493 $move_score += $merged_tile->value;
75 60         173 $moved = 1;
76             }
77             elsif (!$self->tile($farthest)) {
78 102         846 $self->move_tile($cell, $farthest, $tile);
79 102         718 $moved = 1;
80             }
81             }
82              
83 38 100       378 if ($moved) {
84 30         127 $_->merged(0) for $self->each_tile;
85 30         726 $self->next::method($vec);
86 30         1282 return $move_score;
87             }
88 8         38 return;
89             }
90              
91             sub move {
92 0     0 0 0 my ($self, $vec) = @_;
93              
94 0         0 my $move_score = $self->move_tiles($vec);
95              
96 0 0       0 if ($move_score) {
97 0         0 $self->insert_random_tile for 1..$self->insert_tiles_on_move;
98              
99 0         0 $self->score($self->score + $move_score);
100 0 0       0 $self->best_score($self->score) if $self->score > $self->best_score;
101              
102 0 0 0     0 if ($move_score >= $self->goal and !$self->won
  0   0     0  
103             and grep { $_->value >= $self->goal } $self->each_tile)
104             {
105 0         0 $self->win(1);
106 0         0 $self->won(1);
107             }
108 0 0       0 if (!$self->has_moves_remaining) {
109 0         0 $self->lose(1);
110             }
111              
112 0         0 return 1;
113             }
114 0         0 return;
115             }
116              
117             sub cells_can_merge {
118 473     473 0 522 my ($self, $cell, $next) = @_;
119 473         926 my $tile = $self->tile($cell);
120 473         3211 my $next_tile = $self->tile($next);
121 473 100 66     5507 $tile and $next_tile and !$next_tile->merged and $next_tile->value == $tile->value;
      100        
122             }
123              
124             sub has_moves_remaining {
125 6     6 0 11 my $self = shift;
126 6 100       27 return 1 if $self->has_available_cells;
127 3         35 for my $vec ([0, -1], [-1, 0]) {
128 5         13 for my $cell ($self->each_cell) {
129 73         199 my $next = [ map $cell->[$_] + $vec->[$_], 0..1 ];
130 73 100       116 return 1 if $self->cells_can_merge($cell, $next);
131             }
132             }
133 2         13 return;
134             }
135              
136             1;