% vim: set tw=72: % Part of Hetris \section{Pieces: Concrete implementation} The header is, as it always is for a concrete implementation of an abstract module, the same as that of the abstract specification: \begin{code} module Pieces (Piece, blocks, extent_down, extent_left, extent_right, rot_left, rot_right, pieces) where import Data \end{code} Tetris is not a particularly challenging task for today's CPUs, and the amount of RAM required is not likely to cause a problem on a modern machine. Our motivation here then is to pick a representation such that the implementation can be easily understood. At the core of a representation is a list of coordinates of blocks relative to the key square of the piece. We store an infinite list of these corresponding to the blocks used by a piece after successive left rotations. \begin{code} newtype Piece = Piece [[(Vector, Vector)]] \end{code} This makes the implementation of \hsfunction{blocks} simple---we just return the first list. \begin{code} blocks :: Piece -> [(Vector, Vector)] blocks (Piece xss) = head xss \end{code} The code to calculate the maximum extents is based on the output of \hsfunction{blocks} in the way hinted at in Section~\ref{sec:abs_pieces}. \begin{code} extent_down :: Piece -> Vector extent_down p = maximum $map snd$ blocks p extent_left :: Piece -> Vector extent_left p = negate $minimum$ map fst $blocks p extent_right :: Piece -> Vector extent_right p = maximum$ map fst \$ blocks p \end{code} To rotate a piece left we just remove the first element of the list; the correctness of this follows from the definition of the list above. Rotating right is the same as rotating left 3 times so we drop the first 3 elements of the list. \begin{code} rot_left :: Piece -> Piece rot_left (Piece xss) = Piece (tail xss) rot_right :: Piece -> Piece rot_right (Piece xss) = Piece (drop 3 xss) \end{code} The list of pieces is just that---the second part of the name is intended to be descriptive of the shape of the piece, but this is more successful in some cases than others. \begin{code} pieces :: [Piece] pieces = [piece_I, piece_L, piece_J, piece_T, piece_2, piece_5, piece_O] \end{code} We conclude with the actual definitions of the pieces. \begin{code} piece_I, piece_L, piece_J, piece_T, piece_2, piece_5, piece_O :: Piece piece_I = Piece (cycle [p1, p2]) where p1 = [(0, -1), (0, 0), (0, 1), (0, 2)] p2 = [(-1, 0), (0, 0), (1, 0), (2, 0)] piece_L = Piece (cycle [p1, p2, p3, p4]) where p1 = [(0, -1), (0, 0), (0, 1), (1, 1)] p2 = [(-1, 0), (0, 0), (1, 0), (1, -1)] p3 = [(-1, -1), (0, -1), (0, 0), (0, 1)] p4 = [(-1, 1), (-1, 0), (0, 0), (1, 0)] piece_J = Piece (cycle [p1, p2, p3, p4]) where p1 = [(0, -1), (0, 0), (0, 1), (-1, 1)] p2 = [(-1, 0), (0, 0), (1, 0), (1, 1)] p3 = [(1, -1), (0, -1), (0, 0), (0, 1)] p4 = [(-1, -1), (-1, 0), (0, 0), (1, 0)] piece_T = Piece (cycle [p1, p2, p3, p4]) where p1 = [(-1, 0), (0, 0), (1, 0), (0, 1)] p2 = [(0, -1), (0, 0), (0, 1), (1, 0)] p3 = [(-1, 0), (0, 0), (1, 0), (0, -1)] p4 = [(0, -1), (0, 0), (0, 1), (-1, 0)] piece_2 = Piece (cycle [p1, p2]) where p1 = [(1, 0), (0, 0), (0, -1), (-1, -1)] p2 = [(0, 0), (0, -1), (-1, 0), (-1, 1)] piece_5 = Piece (cycle [p1, p2]) where p1 = [(-1, 0), (0, 0), (0, -1), (1, -1)] p2 = [(0, 0), (0, -1), (1, 0), (1, 1)] piece_O = Piece (repeat [(0, 0), (0, 1), (1, 0), (1, 1)]) \end{code}