File Coverage

blib/lib/Games/2048/Game.pm
Criterion Covered Total %
statement 70 93 75.2
branch 16 28 57.1
condition 12 15 80.0
subroutine 11 15 73.3
pod 0 9 0.0
total 109 160 68.1


line stmt bran cond sub pod time code
1             package Games::2048::Game;
2 4     4   288 use 5.012;
  4         14  
  4         1001  
3 4     4   26 use Moo;
  4         8  
  4         29  
4              
5             # increment this whenever we break compat with older game objects
6             our $VERSION = '0.02';
7              
8 4     4   28041 use Storable;
  4         26209  
  4         499  
9 4     4   7489 use File::Spec::Functions;
  4         5476  
  4         535  
10 4     4   19044 use File::HomeDir;
  4         48482  
  4         6874  
11              
12             extends 'Games::2048::Board';
13              
14             has won => is => 'rw', default => 0;
15             has version => is => 'rw', default => __PACKAGE__->VERSION;
16              
17             sub insert_start_tiles {
18 2     2 0 1010 my ($self, $start_tiles) = @_;
19 2         9 $self->insert_random_tile for 1..$start_tiles;
20             }
21              
22             sub insert_random_tile {
23 30     30 0 2608 my $self = shift;
24 30         170 my @available_cells = $self->available_cells;
25 30 100       433 return if !@available_cells;
26 20         119 my $cell = $available_cells[rand @available_cells];
27 20 50       55 my $value = rand() < 0.9 ? 2 : 4;
28 20         332 $self->insert_tile($cell, $value);
29             }
30              
31             sub move_tiles {
32 38     38 0 1059 my ($self, $vec) = @_;
33 38         54 my $moved;
34              
35 38   100     191 my $reverse = $vec->[0] > 0 || $vec->[1] > 0;
36              
37 38         145 for my $cell (sort { $reverse } $self->tile_cells) {
  741         1108  
38 400         3042 my $tile = $self->tile($cell);
39 400         2593 my $next = $cell;
40 400         438 my $farthest;
41 400   100     435 do {
42 571         1834 $farthest = $next;
43 571         3750 $next = [ map $next->[$_] + $vec->[$_], 0..1 ];
44             } while ($self->within_bounds($next)
45             and !$self->tile($next));
46              
47 400 100       3003 if ($self->cells_can_merge($cell, $next)) {
    100          
48             # merge
49 60         472 my $next_tile = $self->tile($next);
50              
51 60         498 $tile->moving_from($cell);
52              
53 60         111 $tile->merging_tiles(undef);
54 60         207 $tile->appear(undef);
55 60         118 $next_tile->merging_tiles(undef);
56 60         129 $next_tile->appear(undef);
57              
58 60         1499 my $merged_tile = Games::2048::Tile->new(
59             value => $tile->value + $next_tile->value,
60 60         244 merging_tiles => [ sort { $reverse } $tile, $next_tile ],
61             merged => 1,
62             );
63              
64 60         1500 $self->clear_tile($cell);
65 60         515 $self->set_tile($next, $merged_tile);
66              
67 60         517 $self->score($self->score + $merged_tile->value);
68 60 50       285 $self->best_score($self->score) if $self->score > $self->best_score;
69 60 50 33     189 if ($merged_tile->value >= 2048 and !$self->won) {
70 0         0 $self->win(1);
71 0         0 $self->won(1);
72             }
73 60         169 $moved = 1;
74             }
75             elsif (!$self->tile($farthest)) {
76             # slide
77 102         1206 $tile->moving_from($cell);
78 102         221 $tile->merging_tiles(undef);
79 102         374 $tile->appear(undef);
80              
81 102         310 $self->clear_tile($cell);
82 102         10111 $self->set_tile($farthest, $tile);
83 102         823 $moved = 1;
84             }
85             }
86              
87 38         352 $_->merged(0) for $self->each_tile;
88              
89 38         798 return $moved;
90             }
91              
92             sub move {
93 0     0 0 0 my ($self, $vec) = @_;
94 0 0       0 if ($self->move_tiles($vec)) {
95 0         0 $self->insert_random_tile;
96              
97 0         0 $self->needs_redraw(1);
98 0         0 $self->moving_vec($vec);
99 0         0 $self->moving(Games::2048::Animation->new(
100             duration => 0.2,
101             ));
102              
103 0 0       0 if (!$self->has_moves_remaining) {
104 0         0 $self->lose(1);
105             }
106             }
107             }
108              
109             sub cells_can_merge {
110 473     473 0 9054 my ($self, $cell, $next) = @_;
111 473         1201 my $tile = $self->tile($cell);
112 473         3729 my $next_tile = $self->tile($next);
113 473 100 66     6442 $tile and $next_tile and !$next_tile->merged and $next_tile->value == $tile->value;
      100        
114             }
115              
116             sub has_moves_remaining {
117 6     6 0 14 my $self = shift;
118 6 100       25 return 1 if $self->has_available_cells;
119 3         43 for my $vec ([0, -1], [-1, 0]) {
120 5         14 for my $cell ($self->each_cell) {
121 73         290 my $next = [ map $cell->[$_] + $vec->[$_], 0..1 ];
122 73 100       154 return 1 if $self->cells_can_merge($cell, $next);
123             }
124             }
125 2         12 return;
126             }
127              
128             sub _game_file {
129 0     0   0 state $dir = eval {
130 0 0       0 my $my_dist_method = "my_dist_" . ($^O eq "MSWin32" ? "data" : "config");
131 0         0 File::HomeDir->$my_dist_method("Games-2048", {create => 1});
132             };
133 0 0       0 return if !defined $dir;
134 0         0 return catfile($dir, "game.dat");
135             }
136              
137             sub save {
138 0     0 0 0 my $self = shift;
139 0         0 $self->version(__PACKAGE__->VERSION);
140 0         0 eval { store($self, _game_file); 1 };
  0         0  
  0         0  
141             }
142              
143             sub restore {
144 0     0 0 0 my $self = eval { retrieve(_game_file) };
  0         0  
145 0         0 $self;
146             }
147              
148             sub is_valid {
149 1     1 0 4912 my $self = shift;
150 1 50       30 defined $self->version and $self->version >= __PACKAGE__->VERSION;
151             }
152              
153             1;