Games::Dukedom - The classic big-iron game


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


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:

 $| = 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 = <>;
    $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 = <>;
    $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,
 sub play_game {
    my $game = Games::Dukedom->new;
    do {
        try {
        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 );

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.


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

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

It currently does not take any parameters.


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.


The current amount of grain on hand.


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


The current amount of land on hand.


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.


The current number of peasants in the Dukedom.


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!

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.


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


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.


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



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.


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


Boolean that returns 1 if the current content of $game->input is either "Y" or "N" (case insensitive) or undef otherwise.


Boolean that returns 1 if the current content of $game->input is "0" or a positive integer and undef otherwise.



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:

A good description of the goals of the game and how to play is here:

and here:


Seriously? Look at the version number.


Jim Bacon, <>


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.