File Coverage

blib/lib/Games/2048.pm
Criterion Covered Total %
statement 39 83 46.9
branch 0 24 0.0
condition 0 39 0.0
subroutine 13 17 76.4
pod 0 4 0.0
total 52 167 31.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Games::2048 - An ASCII clone of the 2048 game
4              
5             =head1 SYNOPSIS
6              
7             use Games::2048;
8             Games::2048->new->run;
9              
10             =head1 DESCRIPTION
11              
12             This module is a full clone of the L<2048 game by Gabriele Cirulli|http://gabrielecirulli.github.io/2048/>. It runs at the command-line, complete with controls identical to the original, a colorful interface, and even some text-based animations! It should work on Linux, Mac, and Windows.
13              
14             Once installed, run the game with the command:
15              
16             2048
17              
18             =head1 TODO
19              
20             =over
21              
22             =item * Add slide and merge animations
23              
24             =item * Test on more systems and terminals
25              
26             =back
27              
28             =head1 AUTHOR
29              
30             Blaise Roth
31              
32             =head1 LICENSE AND COPYRIGHT
33              
34             This software is Copyright (C) 2015 by Blaise Roth.
35              
36             This is free software; you can redistribute and/or modify it under
37             the same terms as the Perl 5 programming language system itself.
38              
39             See L for more information.
40              
41             =cut
42              
43             package Games::2048;
44 4     4   72376 use 5.012;
  4         12  
  4         136  
45 4     4   2076 use Moo;
  4         47654  
  4         25  
46 4     4   6831 use mro; # enable next::method globally
  4         9  
  4         25  
47 4     4   108 use Scalar::Util qw/blessed/;
  4         4  
  4         533  
48              
49             our $VERSION = '0.10';
50              
51 4     4   22 use constant FRAME_TIME => 1/15;
  4         6  
  4         294  
52              
53 4     4   1576 use Games::2048::Util;
  4         9  
  4         159  
54 4     4   1787 use Games::2048::Serializable;
  4         12  
  4         130  
55 4     4   1868 use Games::2048::Animation;
  4         14  
  4         169  
56 4     4   1988 use Games::2048::Tile;
  4         9  
  4         127  
57 4     4   1654 use Games::2048::Grid;
  4         12  
  4         121  
58 4     4   1694 use Games::2048::Board;
  4         23  
  4         175  
59 4     4   2098 use Games::2048::Game;
  4         13  
  4         179  
60 4     4   1864 use Games::2048::Game::Input;
  4         11  
  4         2456  
61              
62             has game => is => 'rw';
63             has game_class => is => 'rw', default => 'Games::2048::Game::Input';
64             has game_file => is => 'rw', default => 'game.dat';
65              
66             has quit => is => 'rw', default => 0;
67             has restart => is => 'rw', default => 0;
68             has first_time => is => 'rw', default => 1;
69              
70             has no_frame_delay => is => 'rw', default => 0;
71             has no_restore_game => is => 'rw', default => 0;
72             has no_save_game => is => 'rw', default => 0;
73              
74             sub run {
75 0     0 0   my $self = shift;
76              
77 0           $self->quit(0);
78 0           Games::2048::Util::update_window_size;
79              
80 0           while (!$self->quit) {
81 0 0 0       $self->restore_game if $self->first_time and !$self->no_restore_game;
82 0           $self->new_game;
83              
84 0 0         $self->game->draw_welcome if $self->first_time;
85 0           $self->game->draw;
86              
87 0           $self->first_time(0);
88              
89             # initialize the frame delay
90 0 0         Games::2048::Util::frame_delay if !$self->no_frame_delay;
91              
92 0           while (1) {
93 0 0 0       unless ($self->game->lose || $self->game->win) {
94 0           $self->game->handle_input($self);
95             }
96              
97 0           $self->game->draw(1);
98              
99 0 0 0       if ($self->quit or $self->restart
      0        
      0        
      0        
100             or $self->game->lose || $self->game->win && !$self->game->needs_redraw
101             ) {
102 0           last;
103             }
104              
105 0 0         Games::2048::Util::frame_delay(FRAME_TIME) if !$self->no_frame_delay;
106             }
107              
108 0           $self->game->draw_win;
109 0 0 0       $self->save_game if $self->game->lose and !$self->no_save_game;
110              
111 0 0 0       unless ($self->quit or $self->restart) {
112 0           $self->game->draw_win_question;
113 0           $self->game->handle_finish($self);
114 0           $self->game->draw_win_answer(!$self->quit);
115             }
116             }
117              
118 0           say "";
119 0 0         $self->save_game if !$self->no_save_game;
120             }
121              
122             sub new_game {
123 0     0 0   my $self = shift;
124              
125 0 0 0       if (!$self->restart and $self->game and $self->game->is_valid and !$self->game->lose) {
      0        
      0        
126             # this game is still going, so we use it as our new game
127 0           $self->game->win(0);
128 0           return;
129             }
130              
131 0           $self->restart(0);
132              
133 0           my @options;
134 0 0         if ($self->game) {
135 0           @options = (
136             Games::2048::Util::maybe(best_score => $self->game->best_score),
137             Games::2048::Util::maybe(no_animations => $self->game->no_animations),
138             Games::2048::Util::maybe(zoom => $self->game->zoom),
139             Games::2048::Util::maybe(colors => $self->game->colors),
140             );
141             }
142              
143 0           my $game_class = $self->game_class;
144 0           $self->game($game_class->new(@options));
145              
146 0           $self->game->insert_start_tiles;
147             }
148              
149             sub restore_game {
150 0     0 0   my $self = shift;
151              
152 0           my $game_class = $self->game_class;
153 0           $self->game($game_class->restore($self->game_file));
154              
155 0 0 0       if (!$self->game or !blessed $self->game or ref $self->game ne $self->game_class) {
      0        
156 0           $self->game(undef);
157 0           return;
158             }
159             }
160              
161             sub save_game {
162 0     0 0   my $self = shift;
163 0           $self->game->save($self->game_file);
164             }
165              
166             1;