File Coverage

blib/lib/Games/2048.pm
Criterion Covered Total %
statement 30 90 33.3
branch 0 36 0.0
condition 0 21 0.0
subroutine 10 12 83.3
pod 0 2 0.0
total 40 161 24.8


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 * Add button to toggle animations on/off
25              
26             =item * Add buttons to zoom the board in and out
27              
28             =item * Add colors for 256-color terminals
29              
30             =item * Abstract input system to allow for AI or replay input
31              
32             =item * Test on more systems and terminals
33              
34             =back
35              
36             =head1 AUTHOR
37              
38             Blaise Roth
39              
40             =head1 LICENSE AND COPYRIGHT
41              
42             This software is Copyright (C) 2014 by Blaise Roth.
43              
44             This is free software; you can redistribute and/or modify it under
45             the same terms as the Perl 5 programming language system itself.
46              
47             See L for more information.
48              
49             =cut
50              
51             package Games::2048;
52 4     4   165722 use 5.012;
  4         16  
  4         153  
53 4     4   5035 use Moo;
  4         96520  
  4         200  
54              
55             our $VERSION = '0.08';
56              
57 4     4   14231 use Time::HiRes;
  4         10001  
  4         23  
58              
59             use constant {
60 4         325 FRAME_TIME => 1/15,
61 4     4   714 };
  4         8  
62              
63 4     4   2875 use Games::2048::Input;
  4         12  
  4         158  
64 4     4   4709 use Games::2048::Animation;
  4         18  
  4         171  
65 4     4   5391 use Games::2048::Tile;
  4         12  
  4         136  
66 4     4   2857 use Games::2048::Grid;
  4         12  
  4         176  
67 4     4   2969 use Games::2048::Board;
  4         15  
  4         246  
68 4     4   4321 use Games::2048::Game;
  4         17  
  4         5487  
69              
70             has size => is => 'ro', default => 4;
71             has start_tiles => is => 'ro', default => 2;
72             has best_score => is => 'rw', default => 0;
73              
74             sub run {
75 0     0 0   my $self = shift;
76              
77 0           my $quit;
78             my $game;
79 0           my $first_time = 1;
80 0           Games::2048::Input::update_window_size;
81              
82 0           while (!$quit) {
83 0 0 0       if ($first_time and $game = Games::2048::Game->restore) {
84 0           $self->update_best_score($game);
85 0 0 0       undef $game if $game->lose or !$game->is_valid;
86             }
87             else {
88 0           undef $game;
89             }
90 0 0         if (!$game) {
91 0           $game = Games::2048::Game->new(
92             size => $self->size,
93             best_score => $self->best_score,
94             );
95              
96 0           $game->insert_start_tiles($self->start_tiles);
97             }
98              
99 0 0         if ($first_time) {
100 0           $first_time = 0;
101 0           $game->draw_welcome;
102             }
103              
104 0           RUN: $game->draw;
105              
106 0           my $restart;
107 0           my $time = Time::HiRes::time;
108              
109 0           PLAY: while (1) {
110 0 0 0       if (!$game->lose and !$game->win) {
111 0           while (defined(my $key = Games::2048::Input::read_key)) {
112 0           my $vec = Games::2048::Input::key_vector($key);
113 0 0         if ($vec) {
    0          
    0          
114 0           $game->move($vec);
115             }
116             elsif ($key =~ /^[q]$/i) {
117 0           $quit = 1;
118 0           last PLAY;
119             }
120             elsif ($key =~ /^[r]$/i) {
121 0           $restart = 1;
122 0           last PLAY;
123             }
124             }
125             }
126              
127 0           $game->draw(1);
128              
129 0 0 0       if (!$game->needs_redraw and $game->lose || $game->win) {
      0        
130 0           last PLAY;
131             }
132              
133 0           my $new_time = Time::HiRes::time;
134 0           my $delta_time = $new_time - $time;
135 0           my $delay = FRAME_TIME - $delta_time;
136 0           $time = $new_time;
137 0 0         if ($delay > 0) {
138 0           Time::HiRes::sleep($delay);
139 0           $time += $delay;
140             }
141             }
142              
143 0           $game->draw_win;
144 0           $self->update_best_score($game);
145              
146 0 0 0       if (!$quit and !$restart) {
147 0 0         print $game->win ? "Keep going?" : "Try again?", " (Y/n) ";
148 0           STDOUT->flush;
149             {
150 0           my $key = Games::2048::Input::poll_key;
  0            
151 0 0         if ($key =~ /^[yn]$/i) {
152 0           print $key;
153             }
154 0 0         if ($key =~ /^[nq]$/i) {
    0          
155 0           $quit = 1;
156             }
157             elsif ($key =~ /^[yr\n]$/i) {
158 0           say "";
159             }
160             else {
161 0           redo;
162             }
163             }
164             }
165 0           say "";
166              
167 0 0         if ($game->win) {
168 0           $game->win(0);
169 0 0         goto RUN if !$quit;
170             }
171             }
172              
173 0           $game->save;
174             }
175              
176             sub update_best_score {
177 0     0 0   my ($self, $game) = @_;
178 0 0 0       if (defined $game->best_score and $game->best_score > $self->best_score) {
179 0           $self->best_score($game->best_score);
180             }
181             else {
182 0           $game->best_score($self->best_score);
183             }
184             }
185              
186             1;