File Coverage

blib/lib/Games/Sequential.pm
Criterion Covered Total %
statement 49 50 98.0
branch 10 20 50.0
condition 2 6 33.3
subroutine 11 11 100.0
pod 6 6 100.0
total 78 93 83.8


line stmt bran cond sub pod time code
1             package Games::Sequential;
2 3     3   21640 use Carp;
  3         5  
  3         187  
3 3     3   62 use 5.006001;
  3         9  
  3         82  
4 3     3   14 use strict;
  3         11  
  3         87  
5 3     3   12 use warnings;
  3         15  
  3         7643  
6              
7             our $VERSION = '0.4.2';
8              
9             =head1 NAME
10              
11             Games::Sequential - sequential games framework with OO interface
12              
13             =head1 SYNOPSIS
14              
15             package My::GamePos;
16             use base qw(Games::Sequential::Position);
17              
18             sub apply { ... }
19              
20             package main;
21             use My::GamePos;
22             use Games::Sequential;
23              
24             my $pos = My::GamePos->new;
25             my $game = Games::Sequential->new($pos);
26              
27             $game->debug(1);
28             $game->move($mv);
29             $game->undo;
30              
31              
32             =head1 DESCRIPTION
33              
34             Games::Sequential is a framework for producing sequential games.
35             Among other things it keeps track of the sequence of moves, and
36             provides an unlimited C mechanism. It also has methods to
37             C or take a C of a game.
38              
39             Users must pass an object representing the initial state of the
40             game as the first argument to C. This object must provide
41             the two methods C and C. You can use
42             L as a base class, in which case the
43             C method will be provided for you. The C method
44             must take a move and apply it to the current position, producing
45             the next position in the game.
46              
47             =head1 METHODS
48              
49             Users must not modify the referred-to values of references
50             returned by any of the below methods.
51              
52             =over 4
53              
54             =item new $initialpos [@list]
55              
56             Create and return a new L object. The first
57             argument must be an object representing the initial position of
58             the game. The C option can also be set here.
59              
60             =cut
61              
62             sub new {
63 3     3 1 31 my $invocant = shift;
64 3   33     55 my $class = ref($invocant) || $invocant;
65 3         12 my $self = bless {}, $class;
66              
67 3 50       39 $self->_init(@_) or carp "Failed to init object!";
68 3         14 return $self;
69             }
70              
71              
72             =item _init [@list]
73              
74             I
75              
76             Initialize a L object.
77              
78             =cut
79              
80             sub _init {
81 3     3   9 my $self = shift;
82 3 50       14 my $pos = shift or croak "No initial position given!";
83 3 50 33     17 my $args = @_ && ref($_[0]) ? shift : { @_ };
84              
85 3         24 my %config = (
86             # Stacks for backtracking
87             pos_hist => [ $pos ],
88             move_hist => [],
89              
90             # Debug and statistics
91             debug => 0,
92             );
93              
94             # Set defaults
95 3         17 @$self{keys %config} = values %config;
96              
97             # Override defaults
98 3         16 while (my ($key, $val) = each %{ $args }) {
  3         18  
99 0 0       0 $self->{$key} = $val if exists $self->{$key};
100             }
101              
102 3 50       34 croak "no apply() method defined for position object"
103             unless $pos->can("apply");
104              
105 3         38 return $self;
106             }
107              
108              
109             =item debug [$value]
110              
111             Return current debug level and, if invoked with an argument, set
112             to new value.
113              
114             =cut
115              
116             sub debug {
117 3     3 1 7 my $self = shift;
118 3         4 my $prev = $self->{debug};
119 3 100       12 $self->{debug} = shift if @_;
120 3         13 return $prev;
121             }
122              
123              
124             =item peek_pos
125              
126             Return reference to current position.
127             Use this for drawing the board etc.
128              
129             =cut
130              
131             sub peek_pos {
132 204     204 1 331 my $self = shift;
133 204         1077 return $self->{pos_hist}[-1];
134             }
135              
136              
137             =item peek_move
138              
139             Return reference to last applied move.
140              
141             =cut
142              
143             sub peek_move {
144 4     4 1 10 my $self = shift;
145 4         20 return $self->{move_hist}[-1];
146             }
147              
148              
149             =item move $move
150              
151             Apply $move to the current position, keeping track of history.
152             A reference to the new position is returned, or undef on failure.
153              
154             =cut
155              
156             sub move {
157 67     67 1 133 my ($self, $move) = @_;
158 67         260 my ($pos, $npos) = $self->peek_pos;
159              
160 67 50       260 $npos = $pos->copy or croak "$pos->copy() failed";
161 67 50       606 $npos->apply($move) or croak "$pos->apply() failed";
162              
163 67         126 push @{ $self->{pos_hist} }, $npos;
  67         175  
164 67         85 push @{ $self->{move_hist} }, $move;
  67         149  
165              
166 67         145 return $self->peek_pos;
167             }
168              
169              
170             =item undo
171              
172             Undo last move. A reference to the previous position is returned,
173             or undef if there was no more moves to undo.
174              
175             =cut
176              
177             sub undo {
178 1     1 1 3 my $self = shift;
179 1 50       2 return unless pop @{ $self->{move_hist} };
  1         6  
180 1 50       2 pop @{ $self->{pos_hist} }
  1         4  
181             or croak "move and pos stack out of sync!";
182 1         17 return $self->peek_pos;
183             }
184              
185              
186             1; # ensure using this module works
187             __END__