packages feed

hetris-0.1: src/Data.lhs

% vim: set tw=72:

% Part of Hetris

\section{Global datatypes}\label{sec:data}

There are many points at which we could begin our design of the
program. For example, we could start with the user interface and work
down to the logic of the game, working through the modules as we explore
deeper; another possibility would be to start at the deep logic and work
outwards. However, it seems logical to instead start with what one might
call global datatypes.

The problem we are trying to solve is how information is passed from one
module to another, either as an argument to a function or as the result
of one. Hiding the details with data abstraction is not the effect we
want here---we are trying to \emph{share} the actual information, not
simply allow other modules to pass it around.

We could, with a minimum of legerdemain, make any of these types
``owned'' by the most appropriate module. However, we would not be being
honest with ourselves if we did this---these types really belong,
conceptually speaking, to the channels by which modules communicate.

There are four types that come into this category; as they just require
definitions it does not make seem worth the hassle to split them off
into four tiny modules, so instead we bundle them together into this
single module. The module export information is shown below, followed by
an explanation of each of the four types.

\begin{code}
module Data (Delay, Vector, Event(..), Change(..)) where
\end{code}

\subsection{Delay} % XXX Should this be typeset differently?

At the very heart of the game is a clock ticking away. On each tick
either the active piece is moved down or, if this is not possible, its
component blocks are added to the board and a new piece is made active.
The time between these clock ticks is a policy decision---as far as the
mechanism modules are concerned it need not even necessarily be
constant---so it should be set by the \hsmodule{Main} module. However,
the user interface will need to stop waiting for input after this time
has elapsed, so it needs to know the value too. We therefore make it a
globally known type. We will allow modules using the type to assume that
it is an instance of the \hsclass{Integral} class, counting the time
until the next tick in milliseconds; this means the \hstype{Int} type
should be sufficiently wide to hold all the values we care about.

\begin{code}
type Delay = Int
\end{code}

\subsection{Vector} % XXX Should this be typeset differently?

We need to talk about positions, widths and heights on and of the
playing area all over the place. For example, the policy module
\hsmodule{Main} will need to agree on a size, i.e., width and height,
that the mechanism module \hsmodule{UI} can display.

For an example of when positions on the playing area need to be passed
around consider what happens when the playing area is altered and the
user interface needs to be updated accordingly.
We could always pass around lists of lists, say, to describe the current state
of the board to the user interface, but it is more efficient to pass
around a list of changes which describe a change of a particular square,
i.e., a position, on the playing area.

We can use the same type for talking about both positions and the width
and height of the board, so we would like a name that conveys the
impression that its value may be either a length or position; for lack
of a better word we choose \hstype{Vector}. Again it makes sense if we
allow ourselves to assume that the type is an instance of class
\hsclass{Integral}, and again \hstype{Int} should be easily wide enough
for our purposes.

\begin{code}
type Vector = Int
\end{code}

A value of 0 refers to the the uppermost or leftmost cell as appropriate
if the \hstype{Vector} is referring to a position.

\subsection{Event} % XXX Should this be typeset differently?

The user interface will need to communicate with the policy module to
inform it of events that have happened. We don't want to pass low level
things like what key was pressed around, not least because this
precludes interfaces that don't work in this way, e.g., mouse driven
interfaces. Instead we use an abstract datatype \hstype{Event} where
each constructor corresponds to one of the possible events that can
occur.

\begin{code}
data Event = RotL
           | RotR
           | MDown
           | MLeft
           | MRight
           | Drop
           | Tick
           | Quit
           | None
    deriving Eq
\end{code}

We derive Eq as it will allow us to use slightly simpler code later on.

The meaning of each constructor is as follows:

\bigskip\noindent
\begin{tabularx}{\hsize}{@{\hspace{2em}}X@{}}
\omit\hsconstructor{RotL}, \hsconstructor{RotR}, \hsconstructor{MDown},
\hsconstructor{MLeft}, \hsconstructor{MRight}\hfil\smallskip\cr
These correspond to requests to rotate the active piece left or right or move
it down, left or right respectively.\medskip\cr
\omit\hsconstructor{Drop}\hfil\smallskip\cr
Corresponds to a request to drop the piece as far down as possible,
i.e., equivalent to multiple \hsconstructor{MDown} events.\medskip\cr
\omit\hsconstructor{Tick}\hfil\smallskip\cr
This event occurs when the time until the next clock tick
hits zero.\medskip\cr
\omit\hsconstructor{Quit}\hfil\smallskip\cr
The user has requested the program to quit.\medskip\cr
\omit\hsconstructor{None}\hfil\smallskip\cr
This is not a real event; it will be created when, for example, a user
presses a key that is not bound to any real event. Its purpose is simply
to make things more convenient for us in some circumstances.\medskip\cr
\end{tabularx}

\subsection{Change} % XXX Should this be typeset differently?

As we briefly mentioned earlier, changes in the playing area need to be
sent to the user interface module. In this simplified specification of
the game there are three things we will want to be able to do. First we
may want to turn a given square on the board on. Second we may want to
turn a square off. Finally, after deleting a complete row we may want to
pause briefly for the user to be able to see what has happened; the
amount of time we should wait is a look-and-feel issue, so we leave it
up to the user interface to decide. These map fairly directly to an
abstract datatype as shown:

\begin{code}
data Change = On Vector Vector
            | Off Vector Vector
            | Delay
\end{code}

The two \hstype{Vector}s used by the \hsconstructor{On} and
\hsconstructor{Off} constructors are $x$ and $y$ coordinates
respectively.