Please email your solution to the TA, at courtney@apocalypse.com.
![]() |
![]() |
![]() |
a board, with n=2 (2n=4) |
a tromino | a tiling |
It will be convenient to treat the origin (0,0) as the upper left corner of the board. Just for kicks, here is a larger tiling (with n=3):
Orientation: We need a representation of the four possible orientations of a tromino. Notice how the tromino's shape resembles an "arrow." We will describe a tromino's orientation by using the direction in which the arrow points. The four possible directions are specified by the following datatype declaration:
data Orientation = NW | NE | SW | SE deriving ShowThe diagram below should make each orientation clear.
![]() |
![]() |
![]() |
![]() |
NW northwest |
NE northeast |
SW southwest |
SE southeast |
Location: We also need to specify a tromino's location on the board. We will do so using the coordinate of the "arrow point square," expressed as a pair of points (x,y) with type (int, int). The board's upper-left square has a coordinate value of (0,0).
For computing the board size, 2n, I suggest you define a function pow2 :: Int -> Int. The infix power operator in Haskell is (**), but it returns a Float, so you will need to convert it back to an Int.
Tromino representation: Thus, a tromino can be represented by its orientation and a pair of points indicating the coordinate of its "arrow point square." Such a representation can be expressed with the following declaration:
type Tromino = (Int, Int, Orientation)We can represent a tiling of the board with a list of trominoes. For example, the tiling seen at the beginning of this question can be represented by the following list:
[(0,0,NW),(3,0,NE),(3,3,SE),(0,3,SW),(1,1,NW)]
The first helper function to write is the translate function, which takes an (x,y) offset and a tromino list. The function shifts each of the given trominoes by the given offset, returning the resulting list of trominoes.
translate :: (Int,Int) -> [Tromino] -> [Tromino]For example, if given the offset (2,3) and the list of trominoes [(1,1,SW),(3,3,NE)] and then translate should return [(3,4,SW),(5,6,NE)].
Next we need to be able to flip the board about either axis. We will call these functions xflip and yflip. They will take the length of one side of the board as its first argument, then the list of trominoes. Each function returns the reflected tromino list.
xflip :: Int -> [Tromino] -> [Tromino] yflip :: Int -> [Tromino] -> [Tromino]The difference between them is illustrated in the following figure.
![]() |
![]() |
![]() |
t0 | xflip 4 t0 | yflip 4 t0 |
tile :: Int -> [Tromino]
import qualified SOEGraphics as GRemember to use qualified names (such as G.xyz) to refer to functions in the library.
The top-level function, render, will take the title of the window, a natural number n, and a list of trominoes. It will open a window and render the trominoes in different colors.
render :: String -> Int -> [Trom] -> IO ()First we must choose how many pixels to dedicate to each square of the board. I think 30 works well, but define this as a constant so it can be changed easily.
-- pixels per square pps = 30 :: IntHere is a template for the render function:
render title n ts = G.runGraphics $ do w <- G.openWindow title (dim,dim) ...other rendering operations... where dim = pow2 n * ppsWe can use this to generate and render a tiling for a board of size 2n:
renderTiling :: Int -> IO () renderTiling n = render ("tile "++show n) n (tile n)
You will probably find it useful to define an infinite stream of colors. The graphics library defines G.colorList :: [(Color,RGB)] where Color is a data type with constructors named Red, Blue, and so on. RGB is a triple of 8-bit words. The first color in the list is Black. Thus, the following code produces an infinite stream of all colors except for black.
colors = tail (map fst G.colorList) ++ colorsFeel free to substitute your own colors -- once your renderer is working!
I suggest rendering each tromino as a polygon. The library defines G.polygon :: [Point] -> Graphic for creating polygons from a list of points. Thus, the kernel of your program might be a function which generates polygon vertices for a given tromino:
trominoPolygon :: Tromino -> [Point]You will probably want other helper functions, but the rest is up to you. Try to make your code as concise and elegant as possible.