NAME

Games::Dukedom - The classic big-iron game

SYNOPSIS

use Games::Dukedom;
 
my $game = Games::Dukedom->new();
 

DESCRIPTION

This is an implementation of the classic game of "Dukedom". It is intended to be display agnostic so that it can be used not only by command line scripts such as the one included but also by graphical UIs such as Tk or web sites.

It has been implemented as an "interrupt driven" state-machine. The actual executable application need only concern itself with displaying messages and collecting appropriate input as requested.

Here is a minimal script that implements a fully functional game:

#!/usr/local/bin/perl
 
$| = 1;
 
use strict;
use warnings;
 
use Scalar::Util qw( blessed );
use Try::Tiny;
 
use Games::Dukedom;
 
my $input_yn = sub {
   my $default = shift || '';
 
   my $ans = <>;
   chomp($ans);
   $ans ||= $default;
 
   return ( $ans =~ /^(?:q|quit)\s*$/i || $ans =~ /^(?:y|n)$/i )
     ? lc($ans)
     : undef;
};
 
my $input_value = sub {
   my $default = shift || 0;
 
   my $ans = <>;
   chomp($ans);
   $ans = $default unless length($ans);
 
   return ( $ans =~ /^(?:q|quit)\s*$/i || $ans !~ /\D/ ) ? $ans : undef;
};
 
my %actions = (
   get_yn    => $input_yn,
   get_value => $input_value,
);
 
play_game();
 
exit;
 
sub play_game {
   my $game = Games::Dukedom->new;
 
   do {
       try {
           $game->play_one_year;
       }
       catch {
           if ( blessed($_) && $_->isa('Games::Dukedom::Signal') ) {
               print $_->msg if $_->msg;
               return unless defined( $_->action );
 
               my $action = $_->action;
               $game->input( &{ $actions{$action} }( $_->default ) );
           }
           else {
               die $_;
           }
       };
   } until ( $game->game_over );
 
   return;
}
 
__END__
 

The important thing to take away from this is how play_one_year is wrapped in a try/catch construct and how the script displays messages and requests input as needed. This is the heart of the state-machine design.

All of the logic for the game is provided by the module itself and any given implementation framework need only handle the I/O as needed.

CONSTRUCTOR

One begins the game by calling the expected new method like so:

my $game = Games::Dukedom->new();
 
 

It currently does not take any parameters.

ATTRIBUTES

All attributes, except for input, have read-only accessors.

It should be noted that the values in the attributes will probably not be of much use to a game implementation other than to provide specialized reports if so desired, hence the reason for being read-only (except for the obvious case of input).

On the other hand, they do provide the current environment for a given year of play and must be preserved at all times. It is anticipated that a stateless environment such as a CGI script will need to save state in some fashion when requesting input and then restore it prior to applying the input and re-entering the state-machine.

input (read-write)

This attribute should hold the latest value requested by the state-machine. It will recognize the values 'q' and 'quit' (case-insensitive) and set the game status to QUIT_GAME if either of those are submitted.

grain

The current amount of grain on hand.

king_unrest

Used to indicate the level of the King's mistrust.

land

The current amount of land on hand.

land_fertility

A hash containing "buckets" that indicate how much land is in what condition of productivity at any given time. The game assumes that land that is planted will lose 20% of it's full productivity each each it is used without being allowed to lie fallow.

Basically this means that you should have twice as much total land available as what is needed to plant to ensure 100% productivity each year.

population

The current number of peasants in the Dukedom.

status

Indicates that the game is either RUNNING or in one of the conditions that indicate that the end of the game has been reached.

A "win" is indicated by a positive value, a "loss" by a negative one.

2 - It's GOOD to be the King!
1 - You have retired
0 - Game is running
-1 - You have abandoned the game
-2 - You have been deposed
-3 - Don't mess with the King!
unrest

Holds the cummulative population unrest factor. There is also an annual unrest factor that gets reset at the start of each game year. The two are relatively independent in that an excess of either one can cause you to be deposed and end the game.

tax_paid

Total amount of taxes paid to the King since the beginnig of the game.

year

The current game year. The will automatically end with you being forced into retirement at the end of 45 years unless some other cause occurs first.

NOTE: This will be ignored if a state of war currently exists between you and the King that must be resolved.

yield

The amound of grain produced in the prior yield expressed as HL/HA.

METHODS

play_one_year

This method begins a new year of play. It initializes the temporary structures and factors and resets the state-machine.

Note: The caller should trap any errors thrown by this method to determine the correct course of action to take based on the value of the exception's msg and action attributes.

game_over

Boolean that indicates that current game is over and further play is not possible. Check status for reason if desired.

input_is_yn

Returns a boolean indicating that the current content of $game->input is either "Y" or "N" (case insensitive).

input_is_value

Returns a boolean indicating that the current content of $game->input is "0" or a positive integer.

SEE ALSO

This package is based on the logic found in this C code, which appears to have been derived from an older source written in Basic:

https://github.com/caryo/Dukedom/blob/master/imports/dukedom.c

BUGS

Seriously? Look at the version number.

AUTHOR

Jim Bacon, <jim@nortx.com>

COPYRIGHT AND LICENSE

Copyright (C) 2014 by Jim Bacon

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8 or, at your option, any later version of Perl 5 you may have available.