0% found this document useful (0 votes)
104 views

Game Development in Haskell Archive

This thesis explores game development in Haskell by reimplementing the classic Asteroids game. It presents two Haskell implementations: one using the apecs entity-component system library, and another with a pure functional approach. It also analyzes an existing imperative C++ implementation. The goal is to highlight the beneficial and challenging aspects of Haskell for game programming and compare it to a more conventional approach.

Uploaded by

Peter
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
104 views

Game Development in Haskell Archive

This thesis explores game development in Haskell by reimplementing the classic Asteroids game. It presents two Haskell implementations: one using the apecs entity-component system library, and another with a pure functional approach. It also analyzes an existing imperative C++ implementation. The goal is to highlight the beneficial and challenging aspects of Haskell for game programming and compare it to a more conventional approach.

Uploaded by

Peter
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 74

MASARYK UNIVERSITY

FACULTY OF INFORMATICS

Game development in Haskell

BACHELOR'S THESIS

Jan Rychlý

B r n o , S p r i n g 2021
MASARYK UNIVERSITY
FACULTY OF INFORMATICS

Game development in Haskell

BACHELOR'S THESIS

Jan Rychlý

B r n o , S p r i n g 2021
This is where a copy of the official signed thesis assignment and a copy of the
Statement of an Author is located in the printed version of the document.
Declaration
H e r e b y I declare that this p a p e r is m y o r i g i n a l a u t h o r i a l w o r k , w h i c h
I have w o r k e d o u t o n m y o w n . A l l sources, references, a n d literature
u s e d or excerpted d u r i n g e l a b o r a t i o n of this w o r k are p r o p e r l y cited
a n d l i s t e d i n complete reference to the d u e source.

Jan Rychlý

Advisor: d o c . M g r . Jan Obdržálek, P h D .

i
Acknowledgements

I w a n t to t h a n k m y a d v i s o r , d o c . M g r . J a n O b d r ž á l e k , P h D . , f o r h i s
invaluable feedback, patience, a n d encouragement. I also w a n t to thank
m y colleagues at K I S K for tolerating m y l o u s y tempo as I was f i n i s h i n g
this thesis. Finally, special thanks go to m y fiancee for p u t t i n g u p w i t h
the lengthy explanations of m y excitement over p r o g r a m m i n g a n d m y
f r i e n d s a n d f a m i l y f o r a l l their s u p p o r t — e s p e c i a l l y m y parents f o r
not letting m e starve to d e a t h w h i l e w o r k i n g o n this thesis.

ii
Abstract
P u r e l y functional p r o g r a m m i n g offers m a n y benefits, like briefer, safer,
a n d m o r e u n d e r s t a n d a b l e code. T h i s thesis a i m s to s h o w that these
benefits also a p p l y to d e v e l o p i n g smaller-scale v i d e o games i n H a s k e l l
a n d , m o r e i m p o r t a n t l y , that the d r a w b a c k s d o not o u t w e i g h t h e m .
W e present t w o i m p l e m e n t a t i o n s of a s i m p l e game. T h e first one
uses E n t i t y - C o m p o n e n t - S y s t e m p r o v i d e d b y the apecs l i b r a r y , a n d
the second focuses o n pure-style, parallelism-capable design. Further-
m o r e , w e c o m p a r e the t w o together w i t h a n a l r e a d y existing i m p e r a -
tive i m p l e m e n t a t i o n . W e s h o w that H a s k e l l ' s p o w e r f u l t y p e s y s t e m ,
i n c l u d i n g its typeclasses a n d m o n a d i c abstraction, is of especially
great value for a g o o d design of real-time interactive applications such
as games. A t last, w e discuss h o w o u r f i n d i n g s m a y scale u p .

iii
Keywords
H a s k e l l , functional p a r a d i g m , game development, E n t i t y - C o m p o n e n t - S y s t e m ,
apecs, p a r a l l e l i s m , m o n a d i c abstraction

iv
Contents
Introduction 1

1 Motivation and used methods 3


1.1 W h y f u n c t i o n a l p r o g r a m m i n g matters 3
1.1.1 G a m e d e v e l o p m e n t specifics 3
1.1.2 Existing work 5
1.2 R e n d e r i n g a n d interfacing w i t h the O S 6
1.3 A s t e r o i d s b y A t a r i as a n example 7

2 Using the apecs library — h A s t e r o i d s 10


2.1 A b o u t apecs 10
2.2 W r i t i n g of h A s t e r o i d s 13
2.2.1 Components i n hAsteroids 13
2.2.2 Initialization and looping 15
2.2.3 Systems i n h A s t e r o i d s 15
2.3 Reflection 18

3 Focusing on f u n c t i o n a l purity — pure-asteroids 21


3.1 G a m e engines i n p u r e l y f u n c t i o n a l style 21
3.2 W r i t i n g of pure-asteroids 22
3.2.1 D a t a structures 23
3.2.2 Stepper f u n c t i o n 25
3.2.3 Event p r o c e s s i n g f u n c t i o n 28
3.3 Reflection 30

4 Analyzing an existing C++ i m p l e m e n t a t i o n 32


4.1 Differences i n features 33
4.2 H o w it w o r k s 33
4.3 Reflection 35

5 E v a l u a t i o n of the approaches 37
5.1 Comparison 37
5.1.1 F l e x i b i l i t y a n d scalability 37
5.1.2 Expressiveness a n d safeness 38
5.1.3 D e v e l o p m e n t costs 40
5.1.4 Performance 43

v
5.1.5 State abstraction 45
5.1.6 C o d e statistics 47
5.2 Observed dilemmas 48
5.2.1 F r e e d o m v s . safeness 49

5.2.2 A b s t r a c t i o n v s . explicitness 51

Conclusion 54

Bibliography 56

A Electronic attachments 59

B Build instructions 60

C Additional code examples 61


C.l E x a m p l e of m o d u l a r m o n a d d e s i g n u s i n g typeclasses . 61
C.2 M o r e examples of f u n c t i o n a l elegance 63

vi
List of Tables
2.1 A simple example of ECS represented by a table. 10
2.2 Game objects and their components. 15
5.1 Average FPS in the benchmarks. 44

vii
List of Figures
1.1 Atari Asteroids — Promotional flyer cover [15] and
gatneplay Screenshot [16]. 9
2.1 A Screenshot of hAsteroids gatneplay. 13
2.2 hAsteroids module structure. 14
3.1 A Screenshot of pure-asteroids gameplay. 22
3.2 Data flow of gameLoop in pure-asteroids. 23
3.3 Entity groups and their interactions. 28
4.1 A Screenshot of imp-asteroids. 32
5.1 Total number of lines by project. 47
5.2 Code density by project. 48
5.3 The four discussed qualities of design. 52

viii
Introduction
V i d e o games are a special k i n d of a p p l i c a t i o n that m a n y c o n s i d e r a n
art f o r m a n d r e w a r d i n g to develop. H o w e v e r , they generally involve a
c o m p l e x system w i t h a n o n - t r i v i a l state, a certain a m o u n t of p s e u d o -
r a n d o m n e s s , a n d u s e r / p l a y e r i n p u t h a n d l i n g . T h i s m a k e s for n o n -
d e t e r m i n i s t i c p r o g r a m s that are u s u a l l y i n c r e d i b l y d i f f i c u l t to test
efficiently.
Conversely, f u n c t i o n a l p r o g r a m m i n g strives to eliminate mutable
state a n d make code more deterministic, w h i c h allows for p r o g r a m s to
be safer a n d easier to test. These a n d other benefits have n a t u r a l l y l e d
to p e o p l e t r y i n g out game d e v e l o p m e n t i n f u n c t i o n a l languages, b u t
it remains mostly a matter of passion projects. That s a i d , even t h o u g h
the vast m a j o r i t y of the v i d e o game i n d u s t r y still uses i m p e r a t i v e
languages l i k e C++, the c o m m u n i t i e s are v e r y active, a n d there are
h u n d r e d s of games, b l o g posts, a n d libraries that h e l p w i t h game
p r o g r a m m i n g i n f u n c t i o n a l languages.
The focus of this thesis n a r r o w s d o w n to e x p l o r i n g game develop-
m e n t i n H a s k e l l i n the context of small-scale 2 D games. T h e g o a l is
to give a n o v e r v i e w of the process, t h e n c o m p a r e this a p p r o a c h to a
m o r e c o n v e n t i o n a l a n d i m p e r a t i v e one a n d u l t i m a t e l y h i g h l i g h t the
features of H a s k e l l that are beneficial a n d those that become h u r d l e s
i n the context of p r o g r a m m i n g a v i d e o game.
T h i s is d o n e t h r o u g h r e i m p l e m e n t i n g a single g a m e w i t h a n a l -
r e a d y e x i s t i n g i m p e r a t i v e i m p l e m e n t a t i o n i n H a s k e l l , first u s i n g the
apecs l i b r a r y a n d for a second time w i t h o u t it. A f t e r a further discus-
1

s i o n about c h o s e n technologies i n the f o l l o w i n g chapter, s a i d three


i m p l e m e n t a t i o n s are d e s c r i b e d a n d a n a l y z e d i n chapters 2, 3, a n d 4.
T h e n they are more closely c o m p a r e d a n d the pros a n d cons of H a s k e l l
i n game d e v e l o p m e n t are evaluated a n d demonstrated i n C h a p t e r 5.
W e f i n d that the apecs l i b r a r y makes d e v e l o p i n g games i n H a s k e l l
m u c h m o r e a p p r o a c h a b l e , a n d p r o v i d e s g o o d p e r f o r m a n c e . O n the
other h a n d it leads the p r o g r a m m e r against the functional philosophy,
a n d u s i n g it w i l l g e n e r a l l y result i n v e r y i m p e r a t i v e code w r a p p e d

1. C A R P A Y , Jonas, apecs: Fast Entity-Component-System library for game programming


[online] [visited on 2021-04-22]. Available from: h t t p s : //hackage . h a s k e l l . o r g /
package/apecs.

1
i n m o n a d s that lacks the expressiveness a n d a p p a r e n t safeness of
r e g u l a r H a s k e l l . Yet, f r o m the second i m p l e m e n t a t i o n , w e l e a r n that
some use of m o n a d s is beneficial, a n d it makes the code cleaner, more
elegant, a n d more flexible. It c o u l d also be m o d i f i e d to use p a r a l l e l i s m
for w o r l d u p d a t i n g a n d detecting c o l l i s i o n s since the f u n c t i o n s are
all pure a n d compartmentalized. Furthermore, w e discuss w h a t a
m i d d l e - g r o u n d s o l u t i o n m a y l o o k like w i t h the use of typeclasses a n d
m o n a d s , a n d h o w o u r f i n d i n g s m a y scale to larger games. I n b o t h
cases, the d e v e l o p m e n t w a s m o s t l y a s m o o t h experience w i t h o u t a
single major h i c c u p , u n l i k e w h a t often h a p p e n s w h e n d e a l i n g w i t h a
C++ compiler.

2
1 Motivation and used methods

1.1 Why functional programming matters


F u n c t i o n a l languages are a subset of declarative languages, w h e r e the
p r o g r a m m e r states " w h a t " i n s t e a d of " h o w " . U n l i k e i n i m p e r a t i v e
l a n g u a g e s , w e declare w h a t w e w a n t a p r o g r a m to r e t u r n b y c o m -
b i n i n g functions (other declarations) instead of g i v i n g the c o m p u t e r
serialized instructions (imperatives). That is manifested i n the lack of
a s s i g n m e n t statements a n d lesser c o n t r o l structures. O n c e variables
are a s s i g n e d their v a l u e , i t cannot b e c h a n g e d , a n d t h e " b u r d e n " of
p r e s c r i b i n g the f l o w of c o n t r o l is r e m o v e d [2]. M o r e o v e r , a p u r e func-
t i o n h a s n o s i d e effects, a n d its r e t u r n v a l u e d e p e n d s s o l e l y o n its
a r g u m e n t s . T h i s m a k e s for d e t e r m i n i s t i c p r o g r a m s that are easier to
test, d e b u g a n d argue about their correctness.
John H u g h e s describes the key benefits of the functional p a r a d i g m
i n his paper Why Functional Programming Matters [2]. H e first explains
h o w m o d u l a r i t y of code is essential, since separate m o d u l e s are easier
to w r i t e a n d test a n d then proceeds to s h o w h o w f u n c t i o n a l p r o g r a m -
m i n g increases m o d u l a r i t y t h r o u g h h i g h e r - o r d e r f u n c t i o n s a n d l a z y
e v a l u a t i o n , d e m o n s t r a t i n g their i m p o r t a n c e o n several examples.
A d d i t i o n a l l y , H a s k e l l is a p u r e l y functional p r o g r a m m i n g language
that is also strongly typed. This means that one does not need to w o r r y
about m e m o r y errors c a u s i n g crashes because the type-checker catches
everything d u r i n g c o m p i l a t i o n . The types also serve as d o c u m e n t a t i o n
a n d c a n h e l p greatly w i t h w r i t i n g a n d u n d e r s t a n d i n g code. A t the
s a m e t i m e , t h e c o m p i l e r c a n also infer t y p e s , so i t is n o t necessary
to e x p l i c i t l y declare t h e m e v e r y w h e r e . F u r t h e r m o r e , the type system
allows extensive user-defined data types, w h i c h makes the code even
m o r e expressive. A l l of this p o t e n t i a l l y increases p r o d u c t i v i t y of a
f u n c t i o n a l p r o g r a m m e r even further.

1.1.1 Game development specifics

F u n c t i o n a l languages are great tools, b u t w e k n o w that not every tool


is fit for e v e r y task. O n e of the consequences of f u n c t i o n a l p u r i t y is
that the p r o g r a m ' s state has to be m o d e l e d e x p l i c i t l y as a n a r g u m e n t

3
i . M O T I V A T I O N A N D USED METHODS

a n d is therefore i m m u t a b l e . T h e r e are m o n a d s that h e l p u s abstract


f r o m t h i s , b u t the m o n a d s themselves are, i n a w a y , still a n e x p l i c i t
workaround.
Conversely, games are real-time, interactive applications often s i m -
u l a t i n g complex systems a n d h o l d i n g a n o n - t r i v i a l state u p d a t e d m a n y
times a second. S u c h s state generally involves representing the game
w o r l d w i t h a l l the objects existing i n it, their properties a n d flags, the
current state of the i n p u t devices a n d m a n y other variables. Since its
b e g i n n i n g , the v i d e o g a m e i n d u s t r y has b e e n d o m i n a t e d b y i m p e r -
ative l a n g u a g e s that m a k e it easy to m o d e l a game w o r l d a n d alter
it g l o b a l l y t h r o u g h references a n d s i d e effects i n s i d e d e c o m p o s e d
functions. M o r e o v e r , because of their established p o s i t i o n , there are
m a n y libraries a n d game engines w i t h s u p p o r t i n g d o c u m e n t a t i o n a n d
tutorials. Besides, a c o m p a n y w i l l m o s t l i k e l y have n o p r o b l e m f i n d -
i n g s k i l l e d C++ p r o g r a m m e r s w i t h a n interest i n the g a m e i n d u s t r y ,
w h e r e a s f i n d i n g their f u n c t i o n a l c o u n t e r p a r t s m i g h t be m u c h m o r e
challenging. A d d i t i o n a l l y , i n the case of C++ the performance also fits
the requirements of b i g games.
H o w e v e r , it does come w i t h a price — m o d u l e s of s u c h p r o g r a m s
m a y be m o r e d e p e n d e n t a n d e n t a n g l e d , w h i c h m a k e s the w h o l e less
flexible a n d w i t h i m p l i c i t state m o r e p r o n e to b u g s a n d harder to test
a n d d e b u g . That is, w h i l e testing is a l r e a d y a significant issue d u e to
the n a t u r e of v i d e o games. A u t o m a t e d testing is not sufficient, a n d
companies have to hire teams of game testers to test games m a n u a l l y .
A n d i n terms of h i g h p e r f o r m a n c e , w h i c h is g e n e r a l l y c o n n e c t e d to
l o w e r - l e v e l languages, developers m u s t wrestle w i t h the l o w e r - l e v e l
nature, p r o d u c i n g p r o b l e m s as w e l l . H a s k e l l also has the edge i n the
area of p a r a l l e l i s m a n d c o n c u r r e n c y , w h i c h is b e c o m i n g m o r e rele-
vant as n e w h a r d w a r e keeps i n c r e a s i n g i n core counts, a n d c o m p l e x ,
i n t e r t w i n e d , imperative systems are c h a l l e n g i n g to r u n i n p a r a l l e l .
W e can see that v i d e o games, like any other software, c o u l d benefit
f r o m p u r e l y f u n c t i o n a l d e s i g n , p r o v i d e d that w e are able to m o d e l
the g a m e state efficiently e n o u g h . A n o t h e r c o n s i d e r a t i o n i n the real
w o r l d is the available f r a m e w o r k s a n d w h e t h e r the cost of p o t e n t i a l
p i o n e e r i n g is w o r t h it.

4
i . M O T I V A T I O N A N D USED METHODS

1.1.2 Existing work

Indeed, p e o p l e have t r i e d d e v e l o p i n g games i n H a s k e l l , a n d a decent


progress has been m a d e over the years. There are libraries a n d engines
l i k e Y a m p a [3] a n d H e l m [4] for f u n c t i o n a l l y reactive p r o g r a m m i n g
( F R P ) of v i d e o games a n d other general F R P libraries that have been
u s e d to m a k e games, l i k e E l e r e a [5] or N e t w i r e [6]. F r o m n o n - F R P
libraries, there is F u n G E n [7], the self-proclaimed oldest H a s k e l l game
engine, apecs [1], w h i c h w e use to p r o g r a m a game a n d describe the
process i n C h a p t e r 2, a n d m a n y others. It is i m p o r t a n t to note that
m o s t of these l i b r a r i e s or engines p r o v i d e o n l y l i m i t e d c a p a b i l i t i e s
c o m p a r e d to " r e a l " i n d u s t r y engines like U n i t y or U n r e a l E n g i n e a n d
d e p e n d i n g o n the type a n d scale of the game, there is still a lot of w o r k
left for the developer.
R e g a r d i n g existing games themselves, there are t w o — M a g i c C o o k -
ies a n d E n p u z z l e d — that have been c o m m e r c i a l l y p u b l i s h e d b y Keera
S t u d i o s , w h o also s t a n d b e h i n d the Y a m p a g a m e e n g i n e [8]. T h e n
there is C h u c k l e f i s h , i n d i e game developer studio, publisher, a n d the
creator of p o p u l a r S t a r b o u n d , w h i c h a n n o u n c e d to b e w o r k i n g o n
their next game W a y w a r d T i d e i n H a s k e l l back i n 2014 [9]. H o w e v e r ,
there has n o t b e e n a n a n n o u n c e m e n t of the release date as of 2021,
a n d the s t u d i o is f o c u s i n g o n other projects at the m o m e n t .
So it remains to be a p i o n e e r i n g process, a n d the games m a d e are
n o w h e r e close to the rest of the i n d u s t r y , b u t there are m o r e g a m e s
t h a n just the stated few. T h e y are created b y p a s s i o n a t e i n d i v i d u a l s
a n d s h a r e d w i t h the c o m m u n i t y . D o z e n s of t h e m c a n be f o u n d o n
the H a s k e l l game d e v e l o p m e n t R e d d i t p a g e for instance. M a n y have
1

also w r i t t e n b l o g posts or tutorials alongside w i t h their games like Joe


Vargas a n d his A Game in Haskell - Dino Rush [10], w h i c h goes i n - d e p t h
a n d e x p l a i n s h i s w e l l t h o u g h t o u t architecture, or A s h l e y S m i t h a n d
her Of Boxes and Threads: Games development in Haskell [11] a n d An
Introduction to Developing games in Haskell with apecs [12], that p r o v i d e
a great o v e r v i e w a n d i n s p i r a t i o n .

1. Subreddit about game development i n Haskell: h t t p : //www. r e d d i t . com/r/


haskellgamedev/

5
i . M O T I V A T I O N A N D USED METHODS

1.2 Rendering and interfacing with the OS


Essential part of a game engine is c o m m u n i c a t i n g w i t h the operating
system a n d r e n d e r i n g models or textures. To do this, we can either use
a c o m p l e t e e n g i n e l i k e the before m e n t i o n e d H e l m or a l i b r a r y b u i l t
for this p u r p o s e like Gloss [13], w h i c h aims to p r o v i d e a n easy-to-use
interface for m a n a g i n g i n p u t a n d r e n d e r i n g . O t h e r libraries p r o v i d e
o n l y H a s k e l l b i n d i n g s to existing m e d i a frameworks like G L U T , G L F W ,
a n d S D L ( G l o s s uses G L U T or G L F W for its b a c k e n d ) . T h e m a i n
g o a l of these libraries is to abstract f r o m a specific w i n d o w s y s t e m
a n d graphics h a r d w a r e , p r o v i d i n g cross-platform A P I s for r e n d e r i n g ,
m a n a g i n g w i n d o w s , a n d r e c e i v i n g i n p u t a n d events.
In b o t h experiments described i n this thesis, w e use the S D L b i n d -
ings to l o a d textures a n d fonts, p o l l i n p u t events, create w i n d o w s , a n d
render scenes. Specifically, w e use the s d l 2 , s d l 2 - i m a g e a n d s d l 2 - t t f
packages. W e chose S D L because there are already examples of its use
i n g a m e s w e c a n l e a r n f r o m , the u n d e r l y i n g C l i b r a r y w o r k s across
m u l t i p l e platforms, is w e l l d o c u m e n t e d a n d is w i d e l y used. Moreover,
2

the H a s k e l l l i b r a r y i n c l u d e b o t h h i g h - l e v e l a n d l o w - l e v e l b i n d i n g s ,
m e a n i n g w e c a n enjoy a c o m f o r t a b l e interface yet at the s a m e t i m e
the lower-level b i n d i n g s serve as a n example of the p o w e r f u l F o r e i g n
F u n c t i o n Interface ( F F I ) , w h i c h m a k e s H a s k e l l even m o r e u s e f u l i n
the real w o r l d .
H e r e are the most essential SDL functions w e use i n our two games,
a l l examples of the h i g h - l e v e l b i n d i n g s :

- SDL.createWindow
is u s e d to create a n e w w i n d o w .

- SDL.createRenderer
is u s e d to create a r e n d e r i n g context for a w i n d o w .

- SDL.Font.load
is for l o a d i n g fonts.

- SDL.Image.loadTexture
is for l o a d i n g images as textures.

2. The documentation of the C library: h t t p s : / / w i k i . l i b s d l . o r g /

6
i . M O T I V A T I O N A N D USED METHODS

- SDL.clear
clears the r e n d e r i n g target/context,

- SDL.copy a n d SDL.copyEx
copies o u r l o a d e d textures to the r e n d e r i n g target l i k e s t a m p i n g a
picture o n a canvas.

- SDL.present
displays the current state of the target i n the w i n d o w .

- SDL.pollEvents
is c a l l e d to get i n p u t events.

I n L i s t i n g 1.1, w e c a n see h o w F F I is u s e d . It s h o w s SDL. copy, w h i c h


w r a p s a r o u n d the l o w - l e v e l b i n d i n g , abstracting f r o m the p o i n t e r s ,
r e p l a c i n g t h e m w i t h H a s k e l l ' s Maybe, a n d t h r o w i n g a n error instead
of r e t u r n i n g a negative v a l u e .

1.3 Asteroids by Atari as an example

Asteroids is a n arcade game created b y A t a r i i n 1979. To evaluate H a s k e l l


as a l a n g u a g e for g a m e d e v e l o p m e n t i n general w o u l d be a task far
b e y o n d the scope of a bachelor's thesis. F o r that reason, w e n a r r o w
d o w n o u r focus to s m a l l e r t w o - d i m e n s i o n a l games a n d , at the e n d ,
o n l y speculate h o w o u r f i n d i n g s m a y scale to m o r e giant games. W e
chose A s t e r o i d s as a n example because its w o r l d comprises o n l y a few
object types, yet their r e l a t i o n s h i p s m a k e the game quite interesting.
It also does not rely o n c o m p l e x g r a p h i c s , therefore w e c a n focus o n
the code i m p l e m e n t i n g the game rules a n d behaviors.

7
i . M O T I V A T I O N A N D USED METHODS

— the C f u n c t i o n
-> (https://wiki.libsdl.org/SDL_RenderCopy):
— i n t SDL_RenderCopy(SDL_Renderer * renderer,
SDL_Texture * t e x t u r e ,
const SDL_Rect * s r c r e c t ,
const SDL_Rect * d s t r e c t ) ;

— the b i n d i n g from SDL.Raw.Video


f o r e i g n import c c a l l "SDL.h SDL_RenderCopy"
renderCopyFFI :: Renderer
-> Texture
-> P t r Rect
-> P t r Rect
-> 10 CInt

— the wrapper from SDL.Video.Renderer


copy :: MonadIO m
=> Renderer
-> Texture
-> Maybe (Rectangle CInt)
-> Maybe (Rectangle CInt)
-> m ()

L i s t i n g 1.1: E x a m p l e of FFI b i n d i n g [14].

8
i . M O T I V A T I O N A N D USED METHODS

Figure 1.1: A t a r i A s t e r o i d s — P r o m o t i o n a l flyer cover [15] a n d game-


p l a y screenshot [16].

The game can be described as f o l l o w e d : "A perfect synergy between


s i m p l i c i t y a n d intense gameplay, the game has players u s i n g buttons
to thrust a spaceship a r o u n d a n asteroid field. W h e n one rock is shot,
it b r e a k s i n t o s m a l l e r ones, often flying off i n different d i r e c t i o n s at
different speeds... E v e r y so often flying saucers enter the screen, intent
o n the player's destruction." [17] Its w o r l d comprises rocks (asteroids,
i n three s i z e s ) , projectiles, flying saucers (large a n d s m a l l , t r y i n g to
shoot the p l a y e r ) a n d the s h i p , c o n t r o l l e d b y the player, t r y i n g to
s u r v i v e a n d g a i n score p o i n t s b y s h o o t i n g d o w n r o c k s a n d flying
saucers. T h e r e are a f e w features that w e are o m i t t i n g , l i k e s o u n d
effects, some animations, a n d several m i n o r gameplay details. B u t we
still n e e d to h a n d l e i n p u t , s i m u l a t e s i m p l e p h y s i c s , detect c o l l i s i o n s ,
s p a w n entities, keep score, transition between the game a n d its menus,
a n d t h e n render e v e r y t h i n g .

9
2 Using the apecs library — hAsteroids

2.1 About apecs


"Apecs: a fast, t y p e - d r i v e n E n t i t y - C o m p o n e n t - S y s t e m l i b r a r y for game
p r o g r a m m i n g " [1] is one of the m o r e recently released libraries. E n -
t i t y - C o m p o n e n t - S y s t e m (or E C S ) is a d a t a - o r i e n t e d architectural
pattern often u s e d i n v i d e o game engines to represent the game w o r l d
state. I n a true E C S , a game object or a n entity is o n l y a n I D n u m b e r ,
a n d data is attached to it b y b e i n g stored u n d e r that I D . T h i s data is
o r g a n i z e d i n t o components, w h i c h are t h e n stored i n separate lists
w i t h other components of the same type f r o m other entities [18]. This
c a n be r e p r e s e n t e d as a table w h e r e e v e r y c o l u m n is its o w n list or
array (see Table 2.1). T h e n w e d e f i n e g a m e l o g i c as systems — a set
of functions that operate o n certain c o m p o n e n t s regardless of the en-
tity as a w h o l e . A t y p i c a l e x a m p l e of a s y s t e m is a d d i n g a n entity's
velocity to its p o s i t i o n for every entity w i t h b o t h of those components.
E C S u s u a l l y p r o v i d e better performance t h a n object-oriented designs
because of their increased data locality — a system needs to l o a d into
m e m o r y o n l y components that are relevant for it, not the w h o l e objects
as it w o u l d be w i t h O O P [19].

Table 2.1: A s i m p l e e x a m p l e of E C S represented b y a table.

Entity Position Velocity Type of U n i t Ammunition


0 (4,2) (0,0) Player 314
1 (5,1) (1,1) Enemy -
2 (2,2) (1,0) Enemy -
3 (2,3) - Obstacle -

A n d since b o t h U n i t y a n d U n r e a l E n g i n e use E n t i t y - C o m p o n e n t
d e s i g n , w e chose apecs as the current state-of-the-art H a s k e l l l i b r a r y
for the traction it has received i n the c o m m u n i t y despite it not b e i n g
the o n l y E C S l i b r a r y i n existence. 1

1. The making of the Ecstasy library was actually inspired by author's issues w i t h
apecs as she explains on her blog [20].

10
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

L i s t i n g 2.1: D e f i n i n g instance of Component.

newtype P o s i t i o n = P o s i t i o n (Double, Double)


instance Component P o s i t i o n where
type Storage P o s i t i o n = Map P o s i t i o n

To w r i t e a g a m e u s i n g apecs w e m u s t d e f i n e components a n d
systems. Systems also create n e w entities, as creating t h e m means to
w r i t e some c o m p o n e n t s u n d e r a n e w I D .
First, d e f i n i n g a component m e a n s to d e f i n e a n instance of the
typeclass Component, as w e see i n the L i s t i n g 2.1. The Component class
r e q u i r e s u s to state h o w w e w a n t to store the g i v e n c o m p o n e n t b y
a s s i g n i n g a t y p e alias to the specific storage t y p e . W e c a n define o u r
Stores o r use one of those p r o v i d e d w i t h the l i b r a r y : Map, Unique,
G l o b a l ( a n d Cashe). W i t h Map, there c a n b e m u l t i p l e c o m p o n e n t s of
that t y p e , each b e l o n g i n g to a p a r t i c u l a r entity. W i t h Unique, at most
one component m a y exist b e l o n g i n g to a particular entity. Furthermore,
w i t h Global, at most one component instance c a n exist, a n d it belongs
to the s p e c i a l g l o b a l entity together w i t h e v e r y other entity at the
same t i m e . F i n a l l y , w e c a l l makeWorld, w h i c h uses Template H a s k e l l
to generate World p r o d u c t t y p e a l o n g w i t h i n i t W o r l d f u n c t i o n a n d
instances of the Has typeclass n e e d e d f o r a l t e r i n g contents of World
t h r o u g h the other f u n c t i o n s i n apecs. T h e r e s u l t i n g World m a y l o o k
close to s o m e t h i n g as s h o w n i n L i s t i n g 2.2.

L i s t i n g 2.2: S i m p l i f i e d w o r l d state type e x a m p l e .

data World =
World
{ recordl (Unique P l a y e r )
, record2 (Map Enemy)
, record3 (Map B u l l e t )
, record4 (Map P o s i t i o n )
, record5 (Global Time)
}

11
2. U S I N G T H E APECS LIBRARY — H A S T E R O I D S

System i n apecs is a n y t h i n g w i t h the SystemT w m a r e t u r n type,


w h i c h means that it m a y alter the w o r l d state. O n e such " m i c r o - s y s t e m "
is the newEntity f u n c t i o n , w h i c h accepts a t u p l e of c o m p o n e n t s a n d
a d d s t h e m into their records u n d e r a n e w I D . M o r e n o t e w o r t h y func-
tions to b u i l d systems are the component m a p functions s h o w n i n the
L i s t i n g 2.3. T h e y are the means of altering the w o r l d state.

L i s t i n g 2.3: C o m p o n e n t m a p s d o c u m e n t a t i o n [21].

— 'w' i s the world type, 'm' i s a monad,


— 'cx','cy' and 'c' are t u p l e s of components

— I Maps a f u n c t i o n over a l l e n t i t i e s
w i t h a cx, and w r i t e s t h e i r cy.
cmap :: f o r a l l w m cx cy.
(Get w m cx, Members w m cx, Set w m cy) =>
(cx -> cy) -> SystemT w m ()
— I Monadically i t e r a t e s over a l l e n t i t i e s
w i t h a cx, and w r i t e s t h e i r cy.
cmapM :: f o r a l l w m cx cy.
(Get w m cx, Set w m cy, Members w m cx) =>
(cx -> SystemT w m cy) -> SystemT w m ()
— I Monadically i t e r a t e s over a l l e n t i t i e s w i t h a cx
cmapM_ :: f o r a l l w m c.
(Get w m c, Members w m c) =>
(c -> SystemT w m ( ) ) -> SystemT w m ()

cmap accepts a f u n c t i o n that takes a t u p l e of c o m p o n e n t s a n d re-


turns some other t u p l e of components. It i n t e r n a l l y iterates over enti-
ties w i t h at least those c o m p o n e n t s m a t c h i n g the m a p p e d function's
i n p u t t u p l e a n d w r i t e s the o u t p u t t u p l e components to those entities.
cmapM w o r k s s i m i l a r l y o n l y as its name suggests the m a p p e d f u n c t i o n
r e t u r n s the c o m p o n e n t t u p l e w r a p p e d i n the s y s t e m m o n a d , w h i c h
a l l o w s it to execute side effects. F u r t h e r m o r e , w i t h cmaM_ there is n o
direct w r i t i n g , o n l y side effects.

12
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

2.2 Writing of hAsteroids


In this section, w e outline h o w w e u s e d apecs i n the h A s t e r o i d s game.
For the exact i m p l e m e n t a t i o n , please refer to the attached source files
i n the h A s t e r o i d s directory. Figure 2.2 shows project's m o d u l e s w i t h
2

l o o s e l y i n d i c a t e d d e p e n d e n c i e s — u p p e r m o d u l e s m a y have direct
d e p e n d e n c i e s o n the l o w e r m o d u l e s , a r r o w s s h o w m o s t i m p o r t a n t
ones.

F i g u r e 2.1: A Screenshot of h A s t e r o i d s gameplay.

2.2.1 Components in hAsteroids

There are m o r e a p p r o a c h e s to d e s i g n i n g c o m p o n e n t s b u t i n h A s -
teroids, w e have three categories of c o m p o n e n t s : " m a r k e r " c o m p o -
nents, " s h a r e d " components, a n d " c o n t r o l " components. M a r k e r c o m -
ponents serve t w o p u r p o s e s : they c o n t a i n i n f o r m a t i o n that is u n i q u e
for a g i v e n t y p e of game object, a n d that w a y , t h e y also m a r k a n e n -
tity as that object. Shared components i n c l u d e characteristics that are
s h a r e d b y m o r e t y p e s of g a m e objects, l i k e p o s i t i o n . Lastly, c o n t r o l
c o m p o n e n t s are a l l g l o b a l a n d are u s e d i n one w a y or another to
c o n t r o l the r u n of the game a n d the transitions b e t w e e n scenes.

2. Attachment structure is briefly described i n A p p e n d i x A .

13
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

Main

GameLoop

ganneLocp

Input Step Draw

reactTolnput step Scene draws eerie

Initialize Collisions

initializeGame detectAndHandle-Collisions

resetWorld

SdlWrappers

Wrappers for SDL ftjncti-ons;

Resources

load Resources

runWitriResources
Utility is imported
everywhere

Utility
SDL
Constants and utilities

F i g u r e 2.2: h A s t e r o i d s m o d u l e structure.

14
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

h A s t e r o i d s has one Unique marker c o m p o n e n t c a l l e d Ship, w h i c h


m a r k s a n entity representing the player's s h i p a n d stores the angle of
the direction the ship is facing. The three other marker components are
Map stored. T h e y are A s t e r o i d — h o l d i n g asteroid size — Uf o — h o l d -
i n g saucer size a n d a c o u n t d o w n to the next U F O ' s shot b e i n g f i r e d —
and B u l l e t — storing whether the player or a U F O shot it. N e x t , there
are the shared components P o s i t i o n , V e l o c i t y a n d TimeToLive a n d
several G l o b a l control ones like ShipLives, ShipState, GameLoopState,
WaveTime a n d f e w others. Table 2.2 s h o w s w h i c h g a m e object types
s h o u l d have w h i c h c o m p o n e n t s ; h o w e v e r , it cannot be e n f o r c e d b y
types d u e to the nature of E C S .

Table 2.2: G a m e objects a n d their c o m p o n e n t s .

Object Components
Ship P o s i t i o n , V e l o c i t y , Ship
UFO P o s i t i o n , V e l o c i t y , TimeToLive, Ufo
Bullet P o s i t i o n , V e l o c i t y , TimeToLive, B u l l e t
Asteroid Position, Velocity,Asteroid

2.2.2 Initialization and looping

The main f u n c t i o n is the entry p o i n t of the p r o g r a m . It first initializes


the S D L libraries a n d t h e n creates a w i n d o w a n d a renderer. N e x t ,
u s i n g l o a d R e s o u r c e s , it l o a d s object textures i n t o a h a s h m a p , p r e -
renders fonts s a v i n g t h e m into another h a s h m a p , a n d w r a p s it a l l to-
gether w i t h the renderer a n d a few stateful r a n d o m generators into one
p r o d u c t t y p e c a l l e d Resources. T h e n the game w o r l d w i t h o u r c o m -
ponents is created b y c a l l i n g i n i t W o r l d , a n d together w i t h resources,
it is p a s s e d to the gameLoop t h r o u g h a stack of m o n a d t r a n s f o r m e r s
(SystemWithResources). W h e n the g a m e L o o p q u i t s , the w i n d o w is
destroyed, a n d resources are freed.

2.2.3 Systems in hAsteroids

gameLoop is one large c o m p o u n d system responsible for updating a n d


drawing the w o r l d a n d the m e n u s every frame of the game. W o r l d u p -

15
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

d a t i n g is s p l i t into t w o f u n c t i o n s : r e a c t T o I n p u t a n d stepScene. The


scene (a m e n u or the w o r l d ) is then d r a w n b y drawScene. It also mea-
sures elapsed time every frame a n d calls SDL. Delay if it was u p d a t e d
a n d d r a w n too q u i c k l y for the targeted 60 F P S . T h i s is t h e n repeated
u n t i l the p l a y e r quits the game.

Reacting to input

r e a c t T o I n p u t m a n a g e s the state of the i n p u t , a n d as its n a m e s u g -


gests, reacts to it. D e p e n d i n g o n the g l o b a l GameLoopState c o m p o -
nent, it either transitions between the states (inMenu, P l a y i n g , Paused,
GameOver, Quit) or w h e n i n the P l a y i n g state, it also allows the player
to c o n t r o l the s h i p . That is done b y a cmapM that changes ship's angle,
increases its velocity, o r creates a n e w b u l l e t entity — a l l c o n d i t i o n e d
by the i n p u t state.

Stepping the scene

s t e p S c e n e takes care of s i m u l a t i n g physics a n d game rules over time


w h e n the l o o p is i n the P l a y i n g state. T h i s is d i v i d e d i n t o a series of
twelve f u n c t i o n calls:

- cmap $ s t e p K i n e t i c s dT
iterates over a l l entities a n d a d d s their v e l o c i t y vector m u l t i p l i e d
by time dT to their p o s i t i o n vector a n d also takes care of w r a p p i n g
the space — if a n entity flies out of the screen o n one side, it comes
back i n f r o m the other side.

- cmap $ d e c e l e r a t e S h i p dT
s i m p l y applies deceleration to the ship b y scaling d o w n its velocity
vector s l i g h t l y

- cmapM $ s t e p S h i p S t a t e dT
is responsible for transitioning between ship states ( A l i v e , Exploding
Int, Respawning Int, w h e r e the integers serve as c o u n t d o w n timers
for the state transition) a n d the e x p l o s i o n a n i m a t i o n .

- cmapM_ $ u f o s S h o o t dT
iterates over a l l Uf o c o m p o n e n t s d e c r e m e n t i n g the t i m e to shoot,

16
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

a n d w h e n it reaches 0, it creates a n e w B u l l e t . T h e a l g o r i t h m for


f i n d i n g a shooting direction is different for the t w o U F O sizes. S m a l l
U F O s are m o r e accurate t h a n the large ones because the a l g o r i t h m
uses the l a w of sines to calculate the b u l l e t trajectory b a s e d o n the
ship's current p o s i t i o n a n d velocity. Large U F O s shoot i n a quarter
of n increments t o w a r d s the s h i p ' s current location.

- awardLifelf10000
increments s h i p ' s lives b y 1 for r e a c h i n g every 10 000 score points.

- m o d i f y g l o b a l $ \(WaveTime t ) -> WaveTime $ t + dT


s i m p l y a d d s the frame delta time dT to the w a v e time counter.

- spawnUfos
r a n d o m l y creates n e w U F O entities o n the left side of the screen,
w i t h the chances increasing as the time spent i n one wave (WaveTime)
passes.

- spawnNewAsteroidWavelfCleared
uses c f o l d f r o m apecs to count all asteroids a n d w h e n there are none
it starts c o u n t i n g u p u s i n g the WavePauseTimer. W h e n the t i m e r
reaches 1500 it calls spawnNewAsteroidWave f r o m the I n i t i a l i z e
m o d u l e , w h i c h uses the r a n d o m stateful generators f r o m the WithResources
reader m o n a d to create n e w asteroids.

- cmap $ \ ( T t l t ) -> T t l $ t - dT
s i m p l y subtracts the f r a m e d e l t a t i m e dT f r o m a l l the TimeToLive
components.

- destroyDeadBullets and destroyDeadUfos


use cmapM_ to destroy a l l the c o m p o n e n t s for entities that r u n out
of " t i m e to l i v e " .

- detectAndHandleCollisions
is defined i n its o w n m o d u l e C o l l i s i o n s . The collisions are detected
and h a n d l e d i n d i v i d u a l l y b e t w e e n each entity g r o u p . T h e general
idea is that w e use cmapM_ inside of cmapM_ as a n equivalent of nested
for loops. T h i s way, for every asteroid, w e iterate (or m a p ) over a l l
the other entities, c h e c k i n g for c o l l i s i o n . W e d o the s i m i l a r for the
rest of the c o m b i n a t i o n pairs, u s i n g i n total = 6 slighlty different

17
2. U S I N G T H E APECS LIBRARY — H A S T E R O I D S

collision detection algorithms. A l l the collisions are detected s i m p l y


as a question of "is a p o i n t or any of the points inside of a rectangle,
a n ellipse or a c i r c l e . " A detected c o l l i s i o n a l w a y s results i n some
effect — the c o l l i d i n g entities are r e m o v e d , except a n asteroid m a y
break into t w o smaller ones if it is not already the smallest size, a n d
i n the case of the s h i p , one life is subtracted.

D r a w i n g the scene

O n c e the scene is stepped, it is then d r a w n b y the already m e n t i o n e d


drawScene f u n c t i o n f r o m the Draw m o d u l e . If the l o o p state is InMenu
or GameOver, o n l y text is d r a w n o n a c l e a r e d b l a c k screen. T h a t is
d o n e b y d r a w C e n t e r e d T e x t s , w h i c h o n l y calls a m o n a d i c z i p W i t h
w i t h drawCenteredText o n a list of y coordinates a n d a list of text
keys. drawCenteredText itself t h e n l o o k s u p the text texture i n the
h a s h m a p that is p a r t of the WithResources e n v i r o n m e n t , queries its
w i d t h , a n d f i n a l l y calls drawText w i t h the coordinates for the texture
to be d r a w n centered.
W h e n the l o o p is i n the Paused state, there is text b e i n g d r a w n as
w e l l as the w o r l d . Naturally, w h e n the state is P l a y i n g , o n l y the w o r l d
is d r a w n . T h i s is t a k e n care of b y drawWorld, w h i c h calls f u n c t i o n s
to d r a w the b a c k g r o u n d , entities a n d the U I ( n u m b e r of lives a n d
the score). Entities are d r a w n u s i n g cmapM_ w i t h a l a m b d a f u n c t i o n
a n d a w r a p p e r f u n c t i o n a r o u n d the SDL. copy a n d SDL. copyEx, w h i c h
renders the c o r r e s p o n d i n g texture for every entity.

2.3 Reflection

F r o m this e x a m p l e alone, w e l e a r n that apecs m a k e s game p r o g r a m -


m i n g i n H a s k e l l s u r p r i s i n g l y accessible. Once w e u n d e r s t a n d the E C S
p r i n c i p l e , every w o r l d m o d i f i c a t i o n is " i n t u i t i v e l y i m p e r a t i v e " thanks
to the SystemT w m a m o n a d a n d the component m a p functions. A n y
system side effects can be a d d e d to a n existing cmap call w i t h a s i m p l e
change of the r e t u r n types as demonstrated i n L i s t i n g 2.4.

18
2. U S I N G T H E APECS LIBRARY — HASTEROIDS

— s t e e r and t h r u s t
handleInput input =
cmap $ \ ( S h i p a , V e l o c i t y v e l ) ->
( Ship $ a + s t e e r i n g input
, V e l o c i t y $ v e l + thrust input a
)
— we r e a l i z e d t h a t we a l s o want t o be a b l e t o pause t h e
-> game
handlelnput' input =
cmapM $ \ ( S h i p a , V e l o c i t y v e l ) -> do
when (wasPressed i n p u t escapeKeycode)
( s e t g l o b a l Paused)
pure ( Ship $ a + s t e e r i n g i n p u t
, V e l o c i t y $ v e l + thrust input a
)

L i s t i n g 2.4: W e c a n easily s w i t c h b e t w e e n non-effectful a n d effectful


calls.

M o r e o v e r , the W i t h R e s o u r c e s reader m o n a d p r o v i d e s easy access


to resources w i t h o u t p a s s i n g t h e m a l o n g e v e r y w h e r e as a f u n c t i o n
argument.
N o less important is the fact that the game w o r k s . The development
experience w a s s m o o t h , w i t h n o significant h i c c u p s . Because H a s k e l l
is a s t a t i c a l l y - t y p e d h i g h - l e v e l l a n g u a g e , there is n o reason to w o r r y
about r a n d o m i n v a l i d m e m o r y access m a k i n g o u r g a m e crash, a n d
e v e r y t h i n g is type-safe.
H o w e v e r , this a p p r o a c h is far f r o m perfect. H a n d l i n g collisions o n
a n i n d i v i d u a l basis w o u l d scale v e r y p o o r l y , so some u n i v e r s a l inter-
face w o u l d be better. T h i s c o u l d be a c h i e v e d b y d e f i n i n g a typeclass
a n d its instances for the m a r k e r c o m p o n e n t s . M o r e p o l y m o r p h i s m
c o u l d also differentiate functions that require the System m o n a d , the
W i t h R e s o u r c e s m o n a d , or b o t h . I n the c u r r e n t state, there are m a n y
functions, s u c h as r e a c t T o I n p u t , w h i c h d o not use the resources b u t
still have access to t h e m since e v e r y t h i n g r e t u r n s the t r a n s f o r m e d
SystemWithResources m o n a d that has W i t h R e s o u r c e s inside of it. Fur-

19
2. U S I N G T H E APECS LIBRARY — H A S T E R O I D S

thermore, s a i d m o n a d transformer stack includes 10, so any f u n c t i o n


3

w i t h this type can p e r f o r m i n p u t or o u t p u t effects, w h i c h goes against


f u n c t i o n a l p u r i t y a n d n u l l i f i e s m a n y of the reasons w h y one w o u l d
choose H a s k e l l as a language i n the first place.
A n o t h e r issue w e observe is p a r t i a l l y tied to the nature of E C S —
there is n o w a y to destroy a l l of a n entity's components automatically
i n apecs. O n e has to d o destroy t h e m e x p l i c i t l y . T h a t w a y , n o t h i n g
protects u s f r o m a c c i d e n t a l l y a d d i n g a c o m p o n e n t to a n entity that
w i l l never be d e s t r o y e d . T h i s c o u l d be m i t i g a t e d b y c r e a t i n g h e l p e r
functions for entity creation a n d destruction.
O v e r a l l , because apecs is so p o w e r f u l , it m a k e s it easy for the
p r o g r a m m e r to r e l y o n it too m u c h a n d p r o d u c e code that does not
reach a l l the p o t e n t i a l benefits of p u r e l y f u n c t i o n a l p r o g r a m m i n g .

3. type SystemWithResources = SystemT World (ReaderT Resources 10)


where SystemT is only a newtype around ReaderT defined i n apecs

20
3 Focusing on functional purity — pure-asteroids

3.1 Game engines in purely functional style

In the p r e v i o u s chapter, w e see h o w a p r o g r a m i n H a s k e l l c a n still be


w r i t t e n i n a v e r y i m p e r a t i v e style. T h i s is c e r t a i n l y a v a l i d a p p r o a c h
a n d has its benefits, as w e discuss further i n C h a p t e r 5. H o w e v e r , for
the s e c o n d v e r s i o n of A s t e r o i d s (project pure-asteroids), w e focus o n
f u n c t i o n a l p u r i t y , clarity, a n d p r o p e r c o m p a r t m e n t a l i z a t i o n .
T h e d e s i g n is i n s p i r e d b y a keynote [22] of J o h n C a r m a c k , the
c o - f o u n d e r of i d S o f t w a r e a n d co-creator of the D o o m a n d Q u a k e
games. A t one p o i n t i n the k e y n o t e , h e talks about h o w h e h a d b e e n
m o v i n g t o w a r d s a f u n c t i o n a l style of p r o g r a m m i n g w i t h C++ a n d
seeing the l o n g - t e r m benefits. H e also t a l k e d about h i s e x p e r i m e n t s
w i t h H a s k e l l a n d his v i s i o n for multi-core game logic. "State of w h e r e
we're at right n o w w i t h game code is that w e r u n a l l the game code i n
one thread because the idea of u s i n g locks to synchronize amongst a l l
of our current game code was just absolutely t e r r i f y i n g , " he says. T h e n ,
explains h o w independent p a r a l l e l i s m is m u c h more feasible w i t h p u r e
f u n c t i o n s a n d h o w events c a n b e u s e d f o r interactions b e t w e e n the
isolated g r o u p s .
The w o r l d - u p d a t i n g function can be split into i n d i v i d u a l sub-
f u n c t i o n s that u p d a t e each g r o u p of entities. E a c h s u b - f u n c t i o n is
p a s s e d the game w o r l d a n d the g r o u p of entities, a n d it r e t u r n s the
u p d a t e d g r o u p ; therefore, i n H a s k e l l , such f u n c t i o n cannot affect any-
t h i n g outside of the g r o u p it returns. For that reason, it c o u l d be easily
r u n i n p a r a l l e l , increasing the p e r f o r m a n c e .
W i t h this a p p r o a c h comes one m o r e advantage — a l l entities are
b e i n g u p d a t e d b a s e d o n the same image of the past state, m e a n i n g it
does n o t matter i n w h a t order entities are u p d a t e d , the result w i l l be
the same. T h i s c a n b e contrasted w i t h a n a i v e i m p e r a t i v e a p p r o a c h ,
where entities are u p d a t e d sequentially in-place based o n the current
state. S u c h a n a p p r o a c h m a y l e a d to inconsistencies if, f o r e x a m p l e ,
t w o u n i t s attack each other at the exact same t i m e . A l t e r n a t i v e l y , to
give a n e x a m p l e f r o m A s t e r o i d s , if a U F O a n d the s h i p shoot at each
other w i t h a n asteroid i n between t h e m , whichever bullet's c o l l i s i o n is
detected first w o u l d destroy the bullet a n d the asteroid, a n d the other

21
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

bullet w o u l d f l y t h r o u g h , k i l l i n g either the U F O or the ship. H o w e v e r ,


the o p p o s i t e a p p r o a c h c o m e s w i t h a caveat, a n d that is the issue of
t w o objects m o v i n g into a c o m m o n space w h e n they are n o t a l l o w e d
to overlap. J o h n C a r m a c k addresses this i n h i s a l r e a d y m e n t i o n e d
keynote [22] a n d says it c a n b e s o l v e d , for instance, b y s o m e k i n d of
r e p u l s i o n force. Fortunately, this is a n o n - i s s u e i n A s t e r o i d s because
a l l objects m a y overlap, u s u a l l y c a u s i n g a c o l l i s i o n a n d destruction.

3.2 Writing of pure-asteroids

F i g u r e 3.1: A screenshot of pure-asteroids gameplay.

In this section, w e describe h o w pure-asteroids implements a p u r e style


engine d e s c r i b e d i n the p r e v i o u s section. F o r the exact i m p l e m e n t a -
t i o n , please refer to the attached source files i n the p u r e - a s t e r o i d s
d i r e c t o r y . T h e p r o g r a m ' s m a i n f u n c t i o n is v e r y s i m i l a r to the one
1

f r o m h A s t e r o i d s except f o r texture l o a d i n g because p u r e - a s t e r o i d s


d r a w s vector graphics m u c h l i k e the o r i g i n a l A s t e r o i d s . There is also
n o reader m o n a d , a n d gameLoop is passed e v e r y t h i n g e x p l i c i t l y as ar-
guments. The l o o p i n g itself is also similar to h A s t e r o i d s , b u t naturally,
the w o r l d u p d a t i n g a n d d r a w i n g differ. The w o r l d state passes t h r o u g h
p r o c e s s W o r l d E v e n t s , w h i c h fulfils a l l the requests f r o m events, t h r o u g h
s t e p W o r l d , w h i c h s i m u l a t e s p h y s i c s a n d g a m e r u l e s a n d generates

1. Attachment structure is briefly described i n A p p e n d i x A .

22
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

n e w events, drawScene d r a w s it a n d r e s e t I f NewGame returns a r e i n i -


t i a l i z e d w o r l d o n l y i f the l o o p state is t r a n s i t i o n i n g f r o m InMenu to
Playing. T h i s is i l l u s t r a t e d i n F i g u r e 3.2. N e x t , w e describe the u s e d
data structures a n d then e x p l a i n h o w the stepper function a n d event
processing use t h e m .

in drawScene
to
"E T3
ID
> a
LU
to
*• World2
to
ID
>

R
to
LU
NewEvents

( IO Input i

F i g u r e 3.2: D a t a f l o w of gameLoop i n pure-asteroids.

3.2.1 Data structures

The t w o p r i m a r y data structures, as a l r e a d y s h o w n i n F i g u r e 3.2, are


the w o r l d state represented b y World a n d the events for c o m m u n i c a -
t i o n b e t w e e n entity g r o u p s represented b y WorldEvents.
T h e d e f i n i t i o n of World c a n b e seen i n L i s t i n g 3.1. World contains
separate g r o u p s of entities a n d some other state variables. A s t e r o i d s ,
Uf os a n d B u l l e t s are type aliases for h a s h m a p s of the respective enti-
ties. T h e entities themselves t h e n c o n t a i n similar data as components
i n h A s t e r o i d s , o n l y here, the data is a l l i n o n e place, g r o u p e d b y the
game object. L i s t i n g 3.2 shows Ship d e f i n i t i o n as a n example. W e c a n
notice the p r e c e d i n g underscores i n the record names. This is u s e d to
generate lenses b y u s i n g makeLenses f r o m the m t l package to facilitate
easier data m a n i p u l a t i o n i n o u r nested structures.

23
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

— I Game world s t a t e s t r u c t u r e
data World =
World
wShip Ship
wAsteroids Asteroids
wBullets Bullets
wUf os Ufos
wWaveTime Time
wWavePause Time
_wWaveNum Int
wScore Score

Listing 3.1: World structure i n pure-asteroids.

— I Ship s t a t e s t r u c t u r e
data Ship =
Ship
{ _ s P o s i t i o n :: P o s i t i o n
, _ s V e l o c i t y :: V e l o c i t y
, _sAngle :: Angle
, _sLives :: I n t
, _sState :: ShipState

data ShipState
= ShipAlive
I ShipExploding Time
I ShipRespawning Time

Listing 3.2: The Ship representation i n pure-asteroids.

24
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

L i s t i n g 3 . 3 shows the event package type WorldEvents. It also has


an instance of Monoid, w h i c h a l l o w s us to collect the packages f r o m
each entity g r o u p a n d combine t h e m into one i n the stepper f u n c t i o n .
T h e n w e distribute the events to their addressed entity g r o u p s i n event
p r o c e s s i n g . The i n d i v i d u a l event types a n d the i n f o r m a t i o n they carry
are described later, w i t h the f u n c t i o n s that process t h e m .

— I S t r u c t u r e f o r event p a s s i n g between e n t i t y groups


data WorldEvents =
WorldEvents
{ _ f o r A s t e r o i d s :: [AsteroidEvent]
, _forShip :: [ShipEvent]
, _forUfos :: [UfoEvent]
, _forBullets :: [BulletEvent]
, _forScore :: [ScoreEvent]
}

L i s t i n g 3 . 3 : The event package structure.

3.2.2 Stepper function

W e can see the c o m b i n i n g of event packages h a p p e n i n the d e f i n i t i o n


of stepWorld i n L i s t i n g 3 . 4 . The events are r e t u r n e d b y the i n d i v i d u a l
steppers of each entity g r o u p together w i t h the s t e p p e d v e r s i o n s of
those g r o u p s . N o t e h o w lenses are u s e d to " f o c u s " o n the contents
of the w o r l d state a n d change t h e m w i t h the setter operator . ~ or the
f u n c t i o n a p p l i c a t o r °/„~ (or also the lens e q u i v a l e n t of +=). E a c h " s u b -
stepper" is c o m p a r t m e n t a l i z e d a n d c o u l d be m a d e to r u n i n p a r a l l e l .

25
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

— I Update the world


s i m u l a t i n g physics and r e a c t i n g t o input
stepWorld :: Time -> InputState -> RandomStream Double ->
-> World -> (WorldEvents, World)
stepWorld dT input rand oldW =
let
(eventsS, newShip) = stepShip dT input oldW $
-> oldW ~. wShip
(eventsB, newBullets) = s t e p B u l l e t s dT input oldW
$ oldW ~. wBullets
(eventsU, newUfos) = stepUfos dT rand oldW $
-> oldW ~. wUfos
(eventsScr, newScore) = stepScore dT $ oldW ~.
-> wScore
in
(,) (eventsS <> eventsB <> eventsU <> eventsScr) $
checkWave $
oldW
& wShip .~ newShip
& wAsteroids %~ stepAsteroids dT
& wBullets .~ newBullets
& wUfos .~ newUfos
& wWaveTime +~ dT
& wScore .~ newScore

L i s t i n g 3 . 4 : The stepper f u n c t i o n .

F i g u r e 3 . 3 s h o w s w h i c h events, r e p r e s e n t e d b y their v a l u e c o n -
structors, entities m a y s e n d to others. The w o r k i n g of the i n d i v i d u a l
substeppers c a n be s u m m a r i z e d as f o l l o w s :

- stepShip
changes the ship's angle a n d velocity based o n the i n p u t a n d updates
its p o s i t i o n . It also detects c o l l i s i o n s w i t h asteroids a n d U F O s . I n
the case of a c o l l i s i o n , it a d d s a n event w i t h the entity's i d to the
event package. Moreover, it subtracts a life i n that case a n d changes
the s h i p ' s state attribute, w h i c h results i n a s p i n n i n g e x p l o s i o n
a n i m a t i o n next f e w frames. T h e n a p o s i t i o n reset f o l l o w e d b y a

26
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

second of i n v i n c i b i l i t y . A l l of that is d o n e i n s t e p S h i p c o n d i t i o n e d
by the state.

- stepAsteroids
does not send any events, o n l y updates the p o s i t i o n of a l l asteroids.

- stepBullets
first filters out b u l l e t s that r u n out of t i m e to l i v e ( T T L ) , a n d t h e n
it uses t r a v e r s e to c a l l s t e p B u l l e t o n a l l the b u l l e t s , c o l l e c t i n g
all events as a n A p p l i c a t i v e side effect. s t e p B u l l e t then updates
2

p o s i t i o n , decrements T T L , or marks the bullet for deletion b y setting


T T L to 0 if a collision was detected. Bullets check for collisions w i t h
everybody else a n d send t h e m events, together w i t h a r e w a r d event
for Score if the b u l l e t was shot b y the ship. Finally, w e insert a n e w
bullet if the space b a r w a s pressed.

- stepUfos
operates s i m i l a r l y to s t e p B u l l e t s . It filters out the ones out of T T L ,
traverses over a l l of t h e m , a n d at the e n d , it r a n d o m l y inserts a
new U F O . D u r i n g the traversal, positions, T T L s , a n d "time-to-shoot"
counters are u p d a t e d . It checks for c o l l i s i o n s w i t h asteroids a n d
sends a n event together w i t h setting its T T L to 0 if that h a p p e n s .
A d d i t i o n a l l y , w h e n the time-to-shoot timer reaches 0, it is refreshed
to 2000 m s , a n d a n event is sent to B u l l e t s as a request to insert
their shot w i t h i n f o r m a t i o n a b o u t the d i r e c t i o n a n d p o s i t i o n . T h e
d i r e c t i o n is c a l c u l a t e d u s i n g one of the same t w o a l g o r i t h m s as i n
hAsteroids.

- stepScore
sends a n event to the s h i p , a w a r d i n g it w i t h a n extra life for every
10 000 p o i n t s g a i n e d .

A f t e r that, checkWave takes care of s p a w n i n g n e w waves of asteroids,


a n d t h e n the s t e p p e d w o r l d is p a i r e d w i t h the c o l l e c t e d , generated
events a n d r e t u r n e d .

2. We use the predefined i n s t a n c e Monoid a => A p p l i c a t i v e ( ( , ) a), where


a is our WorldEvents package.

27
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

3.2.3 Event processing function

In L i s t i n g 3.5, w e c a n see the i m p l e m e n t a t i o n of event p r o c e s s i n g


a n d a g a i n the use of lenses. S i m i l a r to s t e p W o r l d , the w o r k is c o m -
p a r t m e n t a l i z e d a n d c o u l d be m a d e to r u n i n p a r a l l e l , e v e n t h o u g h
there are not that m a n y events sent e a c h f r a m e i n the c u r r e n t game.
p r o c e s s W o r l d E v e n t s calls the i n d i v i d u a l event processors a n d passes
t h e m their share of events. A l l of those w o r k i n a s i m i l a r f a s h i o n :
they use f o l d l or f o l d r to f o l d a l l the events into the c h a n g e d entity
collection. H e r e is a n e x a m p l e of Uf oEvent processing:

p r o c e s s U f o s E v e n t s : : [UfoEvent] -> U f o s -> U f o s


processUfosEvents =
f l i p $ foldr resolveDestruction
where
r e s o l v e D e s t r u c t i o n (DestroyE idU) =
HM.delete idU

The rest of the "subprocessors" differ i n the f u n c t i o n u s e d to a p p l y


an event to the collection to f u l f i l the request. A l l the possible events are

28
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

processWorldEvents :: WorldEvents -> World -> World


processWorldEvents events world =
world
& wAsteroids %- processAsteroidsEvents
(events ~. f o r A s t e r o i d s )
& wShip processShipEvents
(events ~. f o r S h i p )
& wUfos processUfosEvents
(events ~. forUfos)
& wBullets processBulletEvents
(events ~. f o r B u l l e t s )
& wScore processScoreEvents
(events ~. forScore)

L i s t i n g 3 . 5 : The event p r o c e s s i n g f u n c t i o n .

also s h o w n i n Figure 3 . 3 , here w e list their value constructor definitions


a n d b r i e f l y describe w h a t they cause or request:

- BreakE Int
causes the addressed asteroid to break into t w o or to be deleted if it
is the smallest size.

- HitE | GainLifeE
causes the ship to either lose a life a n d set the state to Exploding or
to g a i n a n extra life.

- DestroyE Int
targets a U F O a n d s i m p l y requests its deletion.

- UfoShootsE P o s i t i o n V e l o c i t y
gives the B u l l e t s a l l the n e e d e d i n f o r m a t i o n for i n s e r t i n g a n e w
bullet shot b y U F O .

- IncreaseE Int
says h o w m a n y p o i n t s s h o u l d be a d d e d to the current score.

29
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

3.3 Reflection
O v e r a l l , pure-asteroids achieves w h a t it set out to d o — we can observe
m a n y of the benefits described i n Section 1.1. Because it does not use
m u c h abstraction, the code is p e r c e i v a b l y safer a n d m o r e expressive.
For e x a m p l e , w e c a n l o o k at shoot f r o m the S t e p . B u l l e t s m o d u l e :

shoot : : I n p u t S t a t e -> W o r l d -> B u l l e t s -> Bullets


shoot i n p u t w =
i f w a s P r e s s e d i n p u t spaceKeycode
then i n s e r t B u l l e t
else i d

W e i m m e d i a t e l y see f r o m the n a m e a n d the t y p e signature that the


f u n c t i o n p r e s u m a b l y s o m e h o w alters the collection of B u l l e t s based
o n the i n p u t a n d that the alteration is p r o b a b l y a d d i n g a n e w b u l l e t ,
w h i c h is c o n f i r m e d b y l o o k i n g at the f o l l o w i n g four lines of light code.
Moreover, this also means that it is the only thing the f u n c t i o n can do —
it clearly cannot change the state of the s h i p , read f r o m a file, or render
a w h i t e square o n the screen.
It also incorporates w h a t w e m a y call functional elegance. T h r o u g h -
out the code base, w e use f u n c t i o n s l i k e map, f i l t e r , f o l d , t r a v e r s e
a n d m a n y others that H a s k e l l p r o g r a m m e r s are f a m i l i a r w i t h a n d
w h i c h m a k e the code brief a n d save us time.
M o s t i m p o r t a n t l y , as w e have d e m o n s t r a t e d , the d e s i g n c o u l d be
a d a p t e d to use p a r a l l e l i s m , w h i c h w e expect w o u l d increase p e r f o r -
mance. Parallel c o m p u t a t i o n w o u l d be especially beneficial if the game
were of a larger scale a n d the c o m p u t a t i o n were m o r e d e m a n d i n g —
for instance, c o l l i s i o n detection i n pure-asteroids is elementary, b u t it
c o u l d be i m p r o v e d b y u s i n g m o r e c o m p l i c a t e d a l g o r i t h m s .
H o w e v e r , even t h o u g h w e c o u l d use p a r a l l e l i s m , the scalability of
our d e s i g n is s o m e w h a t l a c k i n g . It w o u l d be appropriate to use more
typeclasses i n general — a class interface for c o l l i s i o n detection, step-
p i n g , c o m m u n i c a t i o n v i a events, a n d u s i n g resources. Pure-asteroids
is too e x p l i c i t , w h i c h m a k e s it r e l a t i v e l y r i g i d — a d d i n g a r a n d o m
n u m b e r generator to a bottom-level f u n c t i o n requires p a s s i n g it f r o m
the top l e v e l as a n a r g u m e n t t h r o u g h the w h o l e f u n c t i o n c h a i n . Be-
sides, the l o n g t y p e signatures of the t o p - l e v e l f u n c t i o n s m a k e t h e m
less clear.

30
3. F O C U S I N G O N F U N C T I O N A L PURITY — PURE-ASTEROIDS

U l t i m a t e l y , w e see that explicitness is g o o d b u t has its b o u n d a r i e s


a n d that some level of abstraction is needed. It s h o u l d also be p o i n t e d
out that d e s i g n i n g the complete engine f r o m scratch took a significant
effort, despite the d e v e l o p m e n t b e i n g s m o o t h a n d the f i n a l p r o d u c t
working well.

31
4 Analyzing an existing C++ implementation
This chapter, describes the imperative i m p l e m e n t a t i o n that w e later use
to compare against i n Chapter 5. W e shall refer to it as " i m p - a s t e r o i d s " .
It w a s m a d e b y J a s o n H a l v e r s o n , a n d its G i t H u b r e p o s i t o r y c a n be
f o u n d at h t t p s : / / g i t h u b . c o m / H a l v e r s o n - J a s o n / A s t e r o i d s . W e cre-
ated a f o r k of this r e p o s i t o r y w i t h a b r a n c h n a m e d o r g a n i z e d [23]
w i t h the o r i g i n a l g a m e w i t h r e o r g a n i z e d a n d r e f o r m a t t e d files for
convenience.
W e acknowledge that C++ m a y not be the most relevant c o m p a r i s o n
as there are other choices for m a k i n g a simple game quickly. However,
we chose this example because it does not use any t h i r d - p a r t y engines.
T h a t w a y , w e c a n easily c o m p a r e it to o u r i m p l e m e n t a t i o n s w i t h o u t
a n extra layer of complexity.
F u r t h e r m o r e , the o p t i o n s available a l l t u r n e d out to be of gener-
ally l o w e r q u a l i t y L i k e o u r t w o i m p l e m e n t a t i o n s , this v e r s i o n is not
flawless, b u t w e p o i n t out its mistakes a n d present t h e m as a possible
1

o u t c o m e of this language choice. T h o u g h , the choice does not i m p l y


n o r c o n d i t i o n s u c h a n outcome.

LA
O

Oh
0
F i g u r e 4.1: A Screenshot of imp-asteroids.

1. The game was made as a school assignment, and f r o m the commented TODOs
throughout the code, we can judge that there were certain time limitations.

32
4. A N A L Y Z I N G A N EXISTING C + + IMPLEMENTATION

4.1 Differences in features


This version differs f r o m o u r two implementations i n m a n y w a y s , other
than the language a n d style used. W e w a n t to list the most significant
ones here:

- It uses G L U T w i t h a custom w r a p p e r instead of S D L to d r a w vector


graphics.

- A s t e r o i d s have m o r e jagged shapes, rotate as they f l y a r o u n d , a n d


the s h i p has a thrust a n i m a t i o n .

- There are n o m e n u s , lives o r score a n d the s h i p does not r e s p a w n .

- Waves d o not increase i n the n u m b e r of asteroids.

- It does not have U F O s .

- Physics are closer to the o r i g i n a l .

- It does not s u p p o r t v a r i a b l e refresh rate. E v e r y f r a m e u p d a t e s the


w o r l d b y a single i m p l i c i t u n i t of time.

4.2 How it works


The main f u n c t i o n is v e r y simple. It constructs a n e w Game object, a n d
a n e w I n t e r f a c e object. T h e n it calls r u n o n the I n t e r f a c e p a s s i n g
it a p o i n t e r the the g a m e object a n d a c a l l b a c k f u n c t i o n . T h e c a l l -
b a c k f u n c t i o n s h o w n i n L i s t i n g 4.1 is t h e n registered i n G L U T as the
d r a w C a l l b a c k . T h a t w a y it gets c a l l e d f r o m w i t h i n g l u t M a i n L o o p ev-
ery frame.
T h e Game object has a p o i n t e r to a S h i p object, a n s t d : : v e c t o r of
B u l l e t pointers, a n d a n s t d : : l i s t of A s t e r o i d pointers. A l l the entity
objects inherit f r o m the class F l y i n g O b j e c t , w h i c h p r o v i d e s p o s i t i o n ,
r o t a t i o n , velocity, p o s i t i o n u p d a t i n g ( F l y i n g O b j e c t : : advance ( ) ) , a
universal c o l l i s i o n detection u s i n g r a d i i , a n d a few more miscellaneous
attributes a n d m e t h o d s .

33
4. A N A L Y Z I N G A N EXISTING C + + I M P L E M E N T A T I O N

v o i d c a l l B a c k ( c o n s t I n t e r f a c e *pUI, v o i d *p)
{
Game *pGame = (Game *)p;

pGame->advance();
pGame->handleInput(*pUI);
pGame->draw(*pUI);

L i s t i n g 4.1: The core of i m p - a s t e r o i d s m a i n l o o p .

S t e p p i n g the w o r l d

Game: : advance () is u s e d to " a d v a n c e " the w o r l d b y one u n i t of time.


It calls these subfunctions to d o so:

- Game::advanceBullets()
iterates over a l l the b u l l e t pointers a n d calls advance o n t h e m .

- Game::advanceAsteroids()
iterates over a l l the asteroid pointers a n d calls advance o n t h e m . If
the c o l l e c t i o n is empty, it inserts five n e w large asteroids.

- Game::advanceShip()
calls advance o n the s h i p .

- Game::handleCollisions()
iterates over every bullet a n d asteroid, a n d i n the case of a collision it
marks the bullet a n d the asteroid as d e a d , a n d creates n e w asteroids
unless the destroyed one w a s a l r e a d y the smallest size.

- Game::cleanUpZombies()
checks if entities are d e a d a n d deletes t h e m if so. D e l a y i n g the dele-
tion prevents inconsistencies caused b y serial u p d a t i n g of entities —
this w a y the order of iteration does not matter.

34
4- A N A L Y Z I N G A N E X I S T I N G C++ IMPLEMENTATION

Input h a n d l i n g

Game: : h a n d l e l n p u t checks t h r o u g h the I n t e r f a c e object whether the


controls were pressed, a n d calls ship's appropriate methods or inserts
a n e w b u l l e t as necessary.

Rendering

F i n a l l y , Game: : draw iterates over a l l the entities a n d calls their draw


methods. O n l y unexpected t h i n g is the call of B u l l e t : : s e t H e a l t h for
all the bullets. This m e t h o d decrements the bullet's health every frame
a n d m a r k s it as d e a d if the v a l u e gets to zero, s i m i l a r l y to T T L i n o u r
implementations.

4.3 Reflection
The game benefits f r o m O O P as most of the top-level f u n c t i o n (method)
calls are v e r y intuitive. It also avoids d u p l i c i t y of code b y u s i n g i n h e r i -
tance for p o s i t i o n u p d a t i n g a n d p o l y m o r p h i s m for u n i v e r s a l c o l l i s i o n
detection. It offers decent s c a l a b i l i t y i n a d d i n g n e w entities or fea-
tures; h o w e v e r , there s h o u l d be separate m a n a g e r classes for each
entity g r o u p . W e also u s e d v a l g r i n d for m e m o r y p r o f i l i n g , a n d it
discovered several usages of u n i n i t i a l i z e d values a n d m e m o r y leaks.
W e also d i s l i k e G L U T ' s use of callbacks a n d g l o b a l state, m a k i n g
things c o n f u s i n g a n d difficult to test. A l t h o u g h , w e u n d e r s t a n d that the
goal of this particular i m p l e m e n t a t i o n was not to be overly a m b i t i o u s
about s c a l a b i l i t y since the game is s t r a i g h t f o r w a r d . M o r e o v e r , side
effects c a n be present a n y w h e r e , a n d m u t a t i o n of the game's state
also is not l i m i t e d v e r y strongly. T h i s is n a t u r a l l y a challenge for a l l
imperative languages.
O n e c o u l d argue that this is n o t a n issue a n d that p r o g r a m m e r s
o n l y n e e d be m o r e c o m p e t e n t about their usage of these p o w e r s . To
combat this, the a l r e a d y q u o t e d J o h n C a r m a c k t a l k e d about h o w be-
i n g a t e c h n i c a l director over m i l l i o n s of lines of c o d e , he s a w h o w
" e v e r y t h i n g that is s y n t a c t i c a l l y l e g a l that the c o m p i l e r w i l l accept,
w i l l eventually w i n d u p i n y o u r codebase." [22] H e also s a i d that "it's
just a m a z i n g h o w m a n y m i s t a k e s , a n d h o w b a d p r o g r a m m e r s c a n
b e . " [22] Because p r o g r a m m e r s are, after a l l , o n l y h u m a n s , systems

35
4. A N A L Y Z I N G A N EXISTING C + + IMPLEMENTATION

l i k e the f u n c t i o n a l p a r a d i g m , that l i m i t their a b i l i t y to be " b a d " can


be of great use, as w e demonstrate further i n the f o l l o w i n g chapter.

36
5 Evaluation of the approaches
I n this chapter, w e first c o m p a r e H a s k e l l to i m p e r a t i v e languages i n
general or specifically to C++, often referencing back to the p r o m i s e d
benefits of H a s k e l l f r o m S e c t i o n 1.1. T h e n w e d i s c u s s the conflicts
observed i n the c o m p a r i s o n s a n d their possible solutions.

5.1 Comparison
T h i s section c o m p a r e s the three e x a m p l e i m p l e m e n t a t i o n s or, m o r e
b r o a d l y , H a s k e l l a n d i m p e r a t i v e l a n g u a g e s r e p r e s e n t e d b y C++. F o r
this, w e reference the p r e v i o u s chapters about i n d i v i d u a l i m p l e m e n t a -
tions. It is important to note that C++ is b y no means meant to represent
i m p e r a t i v e languages f u l l y ; e v e n less so is the c h o s e n i m p e r a t i v e i m -
plementation of A s t e r o i d s (further referred to as imp-asteroids) meant
to represent the i d e a l game d e s i g n i n C++. N o t o n l y it has f l a w s , b u t
it is also a n e v e n s i m p l e r v e r s i o n of the o r i g i n a l game i n s o m e w a y s
t h a n o u r t w o i m p l e m e n t a t i o n s . W e t r y to address this i n e s p e c i a l l y
relevant places; i n others, it is left out for the sake of conciseness a n d
readability.
T h e c o m p a r i s o n is o r g a n i z e d b y q u a l i t i e s i m p o r t a n t i n g a m e de-
v e l o p m e n t : f l e x i b i l i t y a n d scalability, expressiveness a n d safeness,
d e v e l o p m e n t costs, performance. The section is t h e n closed off b y a n
a d d i t i o n a l c o m p a r i s o n of state abstraction a n d f e w statistical observa-
tions about the codebases.

5.1.1 Flexibility and scalability

Both h A s t e r o i d s a n d i m p - a s t e r o i d s are v e r y flexible designs. Because


i n h A s t e r o i d s , the m o n a d r e t u r n t y p e of m o s t f u n c t i o n s is not v e r y
restrictive at a l l , we can a d d i n a n d take away effects or resources w i t h
ease. S i m i l a r l y , the i m p e r a t i v e v e r s i o n is h i g h l y flexible i n this sense.
W h e n it comes to scalability, b o t h d o decently w e l l . A d d i n g n e w game
objects i n h A s t e r o i d s c a n be d o n e b y d e f i n i n g m o r e c o m p o n e n t s a n d
n e e d e d systems. A l r e a d y e x i s t i n g c o m p o n e n t s a n d systems c a n be
reused l i k e P o s i t i o n , V e l o c i t y a n d s t e p K i n e t i c s . O n e issue w o u l d
be the expansion of collision detection, w h i c h is done o n a n i n d i v i d u a l

37
5- E V A L U A T I O N O F T H E A P P R O A C H E S

basis; therefore, the a m o u n t of w o r k w o u l d g r o w l i n e a r l y w i t h a n


i n c r e a s i n g n u m b e r of game objects. Imp-asteroids does better i n this
r e g a r d — k i n e t i c p r o p e r t i e s c a n b e i n h e r i t e d f r o m F l y i n g O b j e c t as
w e l l as the a b i l i t y to detect c o l l i s i o n s . T h e issue here m i g h t b e if w e
w a n t e d to inherit o n l y parts of F l y i n g O b j e c t . A l s o , w i t h a large scale,
the safeness b e c o m e s m o r e of a c o n c e r n f o r b o t h games — m o r e o n
that i n the f o l l o w i n g subsection.
W e have a l r e a d y d e s c r i b e d h o w pure-asteroids are rather r i g i d
because of their lack of abstraction. Scalability is also w o r s e t h a n the
other two since a d d i n g n e w objects w o u l d require w r i t i n g their w h o l e
" s u b s t e p p e r " a n d n e w event paths, a n d c o l l i s i o n detection is h a n d l e d
s i m i l a r l y to h A s t e r o i d s .

5.1.2 Expressiveness and safeness

A s w e have a l r e a d y d i s c u s s e d i n C h a p t e r 1, f u n c t i o n a l languages
are d e s i g n e d to b e clearer (expressiveness) a n d to better c o n t r o l side
effects (safeness) t h a n c o n v e n t i o n a l i m p e r a t i v e languages. N o w the
i m p e r a t i v e c o d e c a n b e e v e n m o r e o r less unsafe d e p e n d i n g o n its
type system. C++ is m o s t l y strongly a n d statically t y p e d , p r o v i d i n g a
certain a m o u n t of assurance. Some other languages are not. T h i s c a n
protect u s f r o m t r y i n g to a d d a n object to a n u m b e r , for instance.
M a n y languages also take v a r i o u s steps t o w a r d s c o n t r o l l i n g side
effects. O n e such example c o u l d be the c o n s t k e y w o r d u s e d to define
a v a r i a b l e that cannot b e m u t a t e d . I n C++, this k e y w o r d c a n also be
u s e d o n methods to prevent t h e m f r o m c h a n g i n g the state of the object,
a l l o w i n g us to call these methods even o n c o n s t objects. Usage of this
k e y w o r d w o u l d prevent the author of imp-asteroids f r o m w r i t i n g the
d r a w i n g f u n c t i o n seen i n L i s t i n g 5.1 that u n e x p e c t e d l y also changes
the state of b u l l e t s . H o w e v e r , l a n g u a g e s l i k e Java o r P y t h o n d o n o t
support i m m u t a b l e objects, a n d w e c a n see h o w control of side effects,
i n general, is a " p l a n B " i n the imperative p a r a d i g m .

38
5- E V A L U A T I O N O F T H E A P P R O A C H E S

v o i d Game::draw(const I n t e r f a c e &ui) {

/* ... other objects are drawn... */

f o r ( i n t i = 0 ; i < b u l l e t s . s i z e ( ) ; i++) {
i f ( b u l l e t s [ i ] -> i s A l i v e ( ) ) {
b u l l e t s [ i ] - >draw();
b u l l e t s [ i ] - >setHealth(); // a s e t t e r ? !
}
}
}

L i s t i n g 5.1 The danger of side effects.

C o n v e r s e l y , since H a s k e l l o r i g i n a t e d as a n a c a d e m i c l a n g u a g e ,
f u n c t i o n a l p u r i t y w a s a l l o w e d to be p l a n A , a n d h a v i n g side effects
w a s a c t u a l l y p l a n B i n this case. W e s a w h o w t h i s , together w i t h the
t y p e s y s t e m , w o r k s out w e l l for expressiveness a n d c l a r i t y i n the
example of pure-asteroids, as showcased o n a n exemplary f u n c t i o n at
the b e g i n n i n g of Section 3.3. A n d because a l l variables are i m m u t a b l e ,
change is m a d e explicit as a new r e t u r n e d v a l u e that we pass f o r w a r d .
M o r e o v e r , a n y i n p u t / o u t p u t side effects are clearly separated b y the
1 0 m o n a d , a n d the rest of the c o d e is e n t i r e l y d e t e r m i n i s t i c , w h i c h
alltogether w i t h strong static t y p i n g makes for a v e r y safe language —
not o n l y there is less p o t e n t i a l sources of b u g s , b u t the correctness of
a p r o g r a m is easier to perceive a n d argue about.
That is if u s e d w e l l — hAsteroids t u r n e d out to be a v e r y interest-
i n g game, apecs m a k e s game p r o g r a m m i n g i n H a s k e l l approachable
and p r o v i d e s excellent performance b y b e i n g strict and imperative. This
i n n e r i m p e r a t i v e n e s s m a k e s p u r i t y sort of a p l a n B a g a i n , a n d the
p r o g r a m m e r has to be clever about u s i n g m o n a d p o l y m o r p h i s m if
they w a n t to keep " t h e d a n g e r of 1 0 " c o n t a i n e d . T h i s has o c c u r r e d
to us i n the m i d d l e of the h A s t e r o i d s d e v e l o p m e n t process, so w e
d e c i d e d to embrace it a n d see w h e r e it leads. If w e h a d redesigned the
types, we c o u l d have reached better safeness a n d even expressiveness.
H o w e v e r , w i t h the game w o r l d state abstracted, it is still not a l w a y s
clear w h a t f u n c t i o n s d o w h e n a p p l i e d t h r o u g h cmapM or cmapM_.

39
5- E V A L U A T I O N O F T H E A P P R O A C H E S

5.1.3 D e v e l o p m e n t costs

The p u r p o s e of any language feature can u l t i m a t e l y be seen as reduc-


i n g the cost of d e v e l o p m e n t . The already discussed H a s k e l l features
1

all b r i n g the costs d o w n i n certain scenarios, b u t there is more that w e


w a n t to l o o k at t h r o u g h the lens of d e v e l o p m e n t speed a n d comfort.
B o t h p u r e - a s t e r o i d s a n d h A s t e r o i d s m o r e or less benefit f r o m these.

Interpreter

O n e of s u c h features is G H C i , " G H C ' s interactive e n v i r o n m e n t , i n


w h i c h H a s k e l l expressions c a n be interactively e v a l u a t e d , a n d p r o -
g r a m s c a n be i n t e r p r e t e d . " [24] H a s k e l l is a c o m p i l e d language that
comes w i t h a n interpreter as w e l l . A n interpreter a l l o w s u s to test
short expressions quickly, either to t r y something n e w or to r u n bits of
already existing code. GHCi c a n also p r i n t the types of expressions or
i n f o r m a t i o n about typeclasses. W e have u s e d the interpreter frequently
d u r i n g d e v e l o p m e n t for r e m i n d i n g ourselves of type signatures, test-
i n g vector m a n i p u l a t i o n , a n d m o r e .

F u n c t i o n a l elegance

F u r t h e r m o r e , there is m a n y p r e d e f i n e d h i g h - o r d e r functions l i k e map,


f i l t e r , f o l d l a n d so forth. This way, a part of the job is already done,
a n d w e o n l y n e e d to p r o v i d e the e l e m e n t a l f u n c t i o n to f o l d w i t h ,
for instance. T h i s , together w i t h b e i n g able to a p p l y f u n c t i o n s p a r -
tially, a l l o w s us to w r i t e v e r y b r i e f a n d elegant code. I n L i s t i n g 5.2,
we c a n see asteroid stepper i m p l e m e n t a t i o n s f r o m imp-asteroids a n d
pure-asteroids. The H a s k e l l version uses map w i t h a partially a p p l i e d
2

f u n c t i o n , w h i l e too b e i n g o n l y p a r t i a l l y a p p l i e d . G r a n t e d , other l a n -
guages have structures to m a k e this sort of task at least slightly m o r e
elegant too a n d e v e n C++ itself has s t d : : f o r e a c h , w h i c h c o u l d be
u s e d to make this piece of code more concise. H o w e v e r , this character-
istic extends to the w h o l e H a s k e l l code base — i n b o t h of o u r games

1. By development costs, we mean mainly time and endured frustration. Generally


speaking, any piece of software can be written i n any language; what differs is the
cost.
2. The C++ version also spawns a new wave of asteroids if the current has been
cleared. That part of the code was omitted as it is irrelevant for the example.

40
5- E V A L U A T I O N O F T H E A P P R O A C H E S

there is o n l y three instances of e x p l i c i t r e c u r s i o n i n total: the g a m e


l o o p s a n d d r a w L i n e s i n pure-asteroids. T h i s is rather impressive c o n -
s i d e r i n g the games have to m a n i p u l a t e collections of events, textures,
entities, c o m p o n e n t s a n d others. M o r e e x a m p l e s of elegant code are
a p p e n d e d at the e n d of this thesis i n A p p e n d i x C . 2 . W e also address
conciseness further, i n Subsection 5.1.6 ( C o d e statistics).

// C++
void Game::advanceAsteroids() {
for (list<Asteroid*>::iterator i t = asteroids.begin();
i t != asteroids.end(); it++) {
(*it)->advance();
}
}

— Haskell
stepAsteroids :: Time -> Asteroids -> Asteroids
stepAsteroids dT = HM.map (stepAsteroid dT)

L i s t i n g 5.2: A s t e r o i d s t e p p i n g w i t h f o r - l o o p a n d m a p .

Testing a n d d e b u g g i n g

A n o t h e r benefit d i s c u s s e d at the b e g i n n i n g i n Section 1.1 is the ease


of testing and debugging. Testing a p u r e f u n c t i o n is as s i m p l e or as
c o m p l i c a t e d as the f u n c t i o n ' s parameters a n d its o u t p u t . Testing a n
i m p u r e f u n c t i o n is theoretically n e a r l y i m p o s s i b l e to d o exhaustively
since w i t h o u t l o o k i n g at its d e f i n i t i o n , w e d o n o t k n o w w h e t h e r it
reads f r o m a file or not, for instance. Practically, w e d o not n e e d to
be completely exhaustive a n d c a n m a k e assumptions; however, those
u n c h e c k e d assumptions are the w e a k spots that m a y cause p r o b l e m s .
D u e to time constraints, H a s k e l l ' s safeness a n d the s i m p l e nature
of A s t e r o i d s , w e d i d not use any automated tests d u r i n g o u r develop-
ment. Still, to substantiate the c l a i m of easier testing w e l o o k at the two
f u n c t i o n s i n L i s t i n g 5.3, a n d consider h o w w e w o u l d go about testing
3

them. To test s t e p B u l l e t s w e need to p r o v i d e three arguments. First

3. The examples are again taken f r o m imp-asteroids and pure-asteroids.


s t e p B u l l e t s has been simplified i n this case. The real version also inserts new

41
5- E V A L U A T I O N O F T H E A P P R O A C H E S

// C++
void Game::advanceBullets() {
f o r ( i n t i = 0; i < b u l l e t s . s i z e ( ) ; i++) {
if (bullets[i]->isAlive()) {
bullets[i]->advance();
if (!isOnScreen(bullets[i]->getPoint())) {
bullets[i]->kill();
}

— Haskell
s t e p B u l l e t s : : Time -> W o r l d -> B u l l e t s -> ( W o r l d E v e n t s ,
Bullets)
s t e p B u l l e t s dT w =
t r a v e r s e ( s t e p B u l l e t dT w) . f i l t e r D e a d B u l l e t s

L i s t i n g 5.3: I m p u r e a n d p u r e s t e p p i n g of bullets.

is a s i m p l e integer, a n d the other t w o are m u c h m o r e c o m p l e x b u t


still c o u l d be generated r a n d o m l y u s i n g H a s k e l l Q u i c k C h e c k or p r o -
v i d e d " m a n u a l l y " . The o n l y effect p r o d u c e d is the r e t u r n e d p a i r that
c a n be c h e c k e d for correctness b y other f u n c t i o n s . O n the contrary,
to test a d v a n c e B u l l e t s w e n e e d to set u p a Game object w i t h its c o n -
tents, m a n y of w h i c h are p r i v a t e . That requires refactoring, a n d the
same applies to testing the state after a d v a n c e B u l l e t s has been called.
A d d i t i o n a l l y , w e m a y w a n t to test not o n l y w h e t h e r the c o l l e c t i o n of
bullets has c h a n g e d correctly b u t also w h e t h e r the rest of the state is
correct.
h Asteroids is no better as the test needs to r u n inside of the SystemT
w m a m o n a d , w h e r e w e set u p components u s i n g n e w E n t i t y f u n c t i o n
a n d t h e n after r u n n i n g tested s y s t e m c h e c k i n g the v a l i d i t y of a l l the
components.

bullets based on the input state, w h i c h happens elsewhere i n the C++ implementa-
tion.

42
5- E V A L U A T I O N O F T H E A P P R O A C H E S

Tools

Lastly, a n o b v i o u s d i s a d v a n t a g e is the fact that w r i t i n g a g a m e i n


H a s k e l l is still largely a p i o n e e r i n g process. There is a decent a m o u n t
of e x i s t i n g general tools, one of t h e m b e i n g the a l r e a d y d e s c r i b e d
interpreter, w h i c h c a n also be u s e d to set u p b r e a k p o i n t s a n d step
t h r o u g h e v a l u a t i o n . M o r e extensive debuggers l i k e H a t exist as w e l l .
W e u s e d Stack for easy management of the package a n d its d e p e n d e n -
cies. H o w e v e r , even some general tools such as a robust I D E are easier
to f i n d for other languages, a n d i n terms of game development specific
tools, there are not m a n y besides the several libraries like apecs listed
i n Section 1.1.2. T h i s c a n be contrasted w i t h the c o m p l e t e , general
engines that c o m e i n c l u d e d w i t h tools for the w h o l e d e v e l o p m e n t
p i p e l i n e , s u c h as U n i t y .
T h i s w a s e x p e c t e d , a n d it t u r n e d out not to be a n issue as o u r
example game w a s v e r y s i m p l e . A l t h o u g h , w e can i m a g i n e that w i t h
a larger game, w e w o u l d start to feel the n e e d for m o r e tools.

5.1.4 Performance

Performance i n games is v e r y important since there is a real m i n i m u m


r e q u i r e m e n t g i v e n b y d e s i r e d f r a m e rate a n d the p l a y e r ' s expected
h a r d w a r e . A g a m e c a n offer a decent experience at 60 F P S , w h i c h
gives u s r o u g h l y 16 m s to d o a n y c o m p u t a t i o n w e n e e d for a single
frame. W i t h s m a l l e r games, this is p l e n t y , b u t as the e n t i t y c o u n t s
g r o w a n d rules get more c o m p l e x , performance o p t i m i z a t i o n becomes
essential. For that reason, we w a n t to compare the performance of o u r
i m p l e m e n t a t i o n s a n d the tools available to o p t i m i z e it.
W e p u t together simple benchmarking versions of a l l three games
a n d r a n t h e m to f i n d h o w m a n y frames c a n be r e n d e r e d i n a g i v e n
time i n s i m i l a r situations. The games were altered to s p a w n v a r i o u s ,
4

a b n o r m a l quantities of asteroids a n d r u n for ten seconds w i t h the


s h i p constantly s p i n n i n g a n d s h o o t i n g one b u l l e t p e r frame. N o t e
that the results are rather i l l u s t r a t i o n a l as the differences b e t w e e n

4. The benchmarking versions can be found in their respective GitHub repositories


on a branch called bench:
https://github.com/honzaflash/cpp-asteroids/tree/bench
https://github.com/honzaflash/ba-thesis/tree/bench/hAsteroids
https://github.com/honzaflash/ba-thesis/tree/bench/pure-asteroids

43
5- E V A L U A T I O N O F T H E A P P R O A C H E S

games were not c o n t r o l l e d v e r y w e l l : i m p - a s t e r o i d s uses G L U T w i t h


the F P S l i m i t e d to a m a x i m u m of 59, because of issues w i t h s t a c k
exec s e e m i n g l y n o t r u n n i n g the p r o g r a m s at a l l o n W i n d o w s , the
H a s k e l l games were r u n i n the interpreter, h A s t e r o i d s renders textures
instead of d r a w i n g vectors like the other t w o , a n d there are other m i n o r
differences. T h e b e n c h m a r k w a s r u n at least three times for e v e r y
asteroid count, a n d the m e d i a n is s h o w n i n the results i n Table 5.1.

Table 5.1: Average F P S i n the b e n c h m a r k s .

Asteroid c o u n t imp-asteroids hAsteroids 5


pure-asteroids 5

10000 41 2 1
500 59 30 16
250 59 46 23
100 59 55 37
50 59 74 92
25 59 117 140
10 59 141 154

W e r a n the b e n c h m a r k for 100 asteroids also i n a v i r t u a l m a c h i n e


w i t h U b u n t u , w h e r e s t a c k exec w o r k e d n o r m a l l y , a n d the results
w e r e quite different e v e n if w e account for the s l o w e r " v i r t u a l h a r d -
w a r e " : 46, 21, a n d 34 F P S respectively for i m p - a s t e r o i d s , h A s t e r o i d s ,
a n d p u r e - a s t e r o i d s . F r o m these results, w i t h a l l three games b e i n g
c o m p i l e d , w e c a n assume, w h a t is s a i d to be true for H a s k e l l i n other
fields, that its performance is mostly comparable to C++. Unfortunately,
w e d i d not have t i m e to d i a g n o s e w h y apecs p e r f o r m e d so p o o r l y i n
this case. H o w e v e r , w h e n c o m p a r i n g the t w o versions (hAsteroids a n d
pure-asteroids) r u n n i n g i n G H C i o n a p h y s i c a l m a c h i n e , h A s t e r o i d s
w i t h apecs does o u t p e r f o r m p u r e - a s t e r o i d s b y u p to 100 % for h i g h
entity counts. T h i s w a s e x p e c t e d as apecs p r o v i d e s a d a t a - o r i e n t e d
d e s i g n that o p t i m i z e s data l o c a l i t y i n m e m o r y .
W o r t h y of note is also the p r o f i l i n g w e d i d o n the r u n s i n U b u n t u .
Interestingly, w e f o u n d out that d r a w i n g i n h A s t e r o i d s accounts for

5. hAsteroids and pure-asteroids were r u n i n the interpreter due to a problem


w i t h stack exec on Windows.

44
5- E V A L U A T I O N O F T H E A P P R O A C H E S

less u s e d t i m e a n d a l l o c a t e d m e m o r y t h a n i n p u r e - a s t e r o i d s . T h i s
eliminates the p o s s i b i l i t y of h A s t e r o i d s b e i n g bottlenecked b y d r a w i n g
textures instead of vectors. M o s t i m p o r t a n t l y , it s h o w e d that neither
of the games h a d issues w i t h G a r b a g e C o l l e c t i o n ( G C ) as this c a n
become a p r o b l e m w i t h larger l a z y systems. The p r o d u c t i v i t y reported
by the - s p r o f i l i n g flag was 99.1 % for h A s t e r o i d s a n d 97.6 % for p u r e -
asteroids, m e a n i n g G C is n o t c a u s i n g a n y m e a n i n g f u l delays i n o u r
games.
T h i s b r i n g s us to the t o o l s available a n d ease of o p t i m i z a t i o n i n
general. A s m e n t i o n e d i n the p r e v i o u s subsection, there are v a r i o u s
tools, i n c l u d i n g profilers for H a s k e l l , b u t C++ w i l l have a larger variety.
A n o t h e r advantage for C++ i n this d i s c i p l i n e is its l o w - l e v e l access to
h a r d w a r e a n d m e m o r y m a n a g e m e n t . G e n e r a l l y , the less abstracted
code is easier to o p t i m i z e since it is closer to w h a t the C P U w i l l actually
execute. W i t h m o r e abstraction, m o r e w o r k m u s t be done to f i n d out
w h a t the C P U does i n the e n d . T h i s is especially the case for H a s k e l l ,
w h i c h has a h i g h l e v e l of abstraction a n d d u r i n g c o m p i l a t i o n goes
t h r o u g h three i n t e r m e d i a t e languages, therefore if one desires to see
h o w the code gets "unabstracted", he m u s t first learn at least the first
of the i n t e r m e d i a t e languages ( C o r e ) . To m a k e u p for this at least
partially, as w e have also stated before, G H C can d o a lot of o p t i m i z i n g
o n its o w n , a n d p u r e l y f u n c t i o n a l c o d e is also easier to execute i n
p a r a l l e l a n d concurrently, w h i c h H a s k e l l is v e r y g o o d at.

5.1.5 State a b s t r a c t i o n

O n e of the largest differences b e t w e e n the i m p l e m e n t a t i o n s is h o w


they m o d e l the game's state. T h r o u g h this p r i s m , w e c a n see once
again h o w h A s t e r o i d s a n d i m p - a s t e r o i d s are v e r y similar. A s w e have
m e n t i o n e d before, because of the abstraction, the code i n h A s t e r o i d s
has a certain a m o u n t of imperative style, a n d that includes the state of
the game w o r l d kept i n a m o n a d . Similarly, despite C++ h a v i n g a lower-
level a p p r o a c h to m e m o r y a n d some other things, the object-oriented

6. The profiling results can be found on the mentioned bench branch of our
G i t H u b repository: h t t p s : / / g i t h u b . com/honzaf l a s h / b a - t h e s i s / t r e e / b e n c h /
p u r e - a s t e r o i d s / r e s u l t s and h t t p s : / / g i t h u b . c o m / h o n z a f l a s h / b a - t h e s i s /
t r e e / b e n c h / h A s t e r o i d s / r e s u l t s . Specifically, the profiling of cost centers is i n
folders o p t - p .

45
5- E V A L U A T I O N O F T H E A P P R O A C H E S

p a r a d i g m a l l o w s u s to abstract the state i n a r e l a t i v e l y elegant w a y .


Object's attributes define its current state, w h i c h is i m p l i c i t l y passed
to any of its m e t h o d s .
The m o n a d state is technically p u r e because, i n reality, its change
is o n l y a c o m p u t a t i o n h i d d e n b e h i n d the » = operator that passes
the change as a new v a l u e f o r w a r d w i t h o u t a n y m u t a t i o n , a n d the
operator itself t h e n c a n be f u r t h e r h i d d e n u s i n g the do b l o c k . B u t 7

f r o m a practical standpoint, there is o n l y a little difference between a


m o n a d state a n d a n object's state. Just as a n object gives a context to
a m e t h o d ' s side effects, a state m o n a d gives context to the m o n a d i c
c o m p u t a t i o n ' s side effects. I n the s a m e w a y that a n object stored i n
a single v a r i a b l e is c h a n g e d , a m o n a d state c a n change w i t h o u t a n y
outer signs. L i s t i n g 5.4 shows h o w similar i n appearance are the m a i n
game l o o p s of h A s t e r o i d s a n d imp-asteroids.

— gameLoop returns SystemWithResourc.es ()


reactToInput deltaTime
stepScene deltaTime
drawScene

// pGame i s a p o i n t e r t o Game object


pGame->advance();
pGame->handleInput(*pUI);
pGame->draw(*pUI);

L i s t i n g 5.4: C o r e s of the m a i n l o o p s i n h A s t e r o i d s a n d imp-asteroids.

This brings us to the argument of w h y w e w a n t to a v o i d m u t a b i l i t y


i n the first place. M u t a b i l i t y makes code harder to reason about, easier
to make mistakes i n , a n d v e r y difficult to r u n i n parallel. G r a n t e d , since
the state m o n a d is technically p u r e , the h i d d e n syntax w i l l not a l l o w
shared mutability, w h i c h is w h a t makes p a r a l l e l systems complicated.
W i t h that i n m i n d , it also makes some things m u c h simpler to p r o g r a m .
A s w e have a l r e a d y p o i n t e d out, pure-asteroids steers clear of
m o n a d s w h e n possible, m o d e l i n g the state explicitly. This does i n d e e d

7. Reminder: do s t r <- g e t L i n e ; p u t S t r s t r is a shorthand for g e t L i n e »=


(\str -> p u t S t r s t r )

46
5- E V A L U A T I O N O F T H E A P P R O A C H E S

make things easier to reason about, b u t it w a s m u c h more complicated


to w r i t e . W e d i s c u s s t h i s n e e d for b a l a n c e later, i n S e c t i o n 5.2 about
the o b s e r v e d d i l e m m a s .

5.1.6 Code statistics

A s a b o n u s , w e i n c l u d e f e w s i m p l e statistics a b o u t c o d e l e n g t h . W e
counted the lines, w o r d s a n d characters u s i n g the wc c o m m a n d . T h e n
8

we plotted the total line counts (Figure 5.1) a n d ratios between w o r d s ,


lines, a n d characters i n each file (Figure 5.2) u s i n g P y t h o n a n d s e a b o r n .
W e m u s t take i n t o account the differences b e t w e e n the i m p l e m e n -
tations because i m p - a s t e r o i d s uses a c u s t o m d r a w i n g l i b r a r y b u i l t
a r o u n d G L U T , w h i c h i n c l u d e s several lengthy l i n e - d r a w i n g functions
a n d it is m u c h m o r e h e a v i l y c o m m e n t e d , b u t it also does not i m p l e -
9

m e n t U F O s , score, s h i p lives, or m e n u s .

3000 counted
l lines

2500

2000

hAsteroids pure-asteroids imp-asteroids


projectname

F i g u r e 5.1: Total n u m b e r of lines b y project.

8. wc defines a w o r d as a sequence of any printable characters delimited by white


space.
9. U s i n g grep we found 850 lines of comments i n the imp-asteroids project and
only 110 and 50 i n hAsteroids and pure-asteroids.

47
5- E V A L U A T I O N O F T H E A P P R O A C H E S

hAsteroids pure-asteroids imp-asteroids


project name

F i g u r e 5.2: C o d e d e n s i t y b y project.

F r o m the ratios i n F i g u r e 5.2, w e see that the codebases have a


s i m i l a r d e n s i t y ; therefore, w e k n o w it is not shorter l i n e s i n f l a t i n g
the total l i n e count, b u t generally longer code. T h i s f u r t h e r s u p p o r t s
the c l a i m for H a s k e l l ' s a b i l i t y to be b r i e f a n d concise. W e c a n also
notice the slight, opposite tendencies of w o r d s per line a n d characters
p e r w o r d . It w o u l d a p p e a r that i n the C++ c o d e , w o r d s are longer,
a n d there are fewer of t h e m p e r l i n e , w h i c h c a n be e x p l a i n e d b y wc
u n d e r s t a n d i n g strings like a s t e r o i d s . e r a s e ( i t ) ; as one w o r d as are
also u n d e r s t o o d operators, m o r e frequent i n H a s k e l l .

5.2 Observed dilemmas


H e r e w e discuss further the conflicts observed i n the p r e v i o u s section
a n d suggest p o s s i b l e better c o m p r o m i s e s or s o l u t i o n s . N a m e l y w e

48
5- E V A L U A T I O N O F T H E A P P R O A C H E S

i d e n t i f y the t e n s i o n b e t w e e n f r e e d o m of effects a n d safeness, a n d


between abstraction a n d explicitness.

5.2.1 Freedom vs. safeness

W e saw examples of two extremes — pure-asteroids w i t h h i g h safeness


b u t l o w f l e x i b i l i t y a n d h A s t e r o i d s together w i t h i m p - a s t e r o i d s w i t h
h i g h f l e x i b i l i t y b u t l o w safeness. It m a y s e e m as t h o u g h the t w o are
m u t u a l l y exclusive. H o w e v e r , w e see another characteristic h i d i n g
b e h i n d the flexibility label: freedom of side effects or u n b o u n d flexibility.
That is w h a t cannot be achieved s i m u l t a n e o u s l y as complete safeness
r o o t e d i n c o n t r o l a n d l i m i t s . N e v e r t h e l e s s , it d e f i n i t e l y is p o s s i b l e to
design a system that includes constraints a n d control i m p l e m e n t e d i n
a relatively flexible way.
W e w o u l d argue that c o m p l e t e f r e e d o m is r a r e l y e v e n desirable.
It m a y be tolerable for s m a l l e r p r o g r a m s , p o s s i b l y beneficial for s i m -
p l e scripts, b u t for any m o r e extensive a p p l i c a t i o n , p r o g r a m m e r s are
taught " g o o d practices" such as " d o not use g l o b a l variables" a n d " d o
not use goto." A safe d e s i g n can be achieved w i t h g o o d practices i n a
language like C , b u t m o d e r n languages h e l p us save time a n d money.
For this r e a s o n , it is of great use w h e n a l a n g u a g e s u p p o r t s r o b u s t
c o n t r o l of side effects.
B e i n g able to c o m p r o m i s e o n u n l i m i t e d side effects then, w e believe
that a reasonably flexible system can b y designed i n H a s k e l l , w h i c h is
also v e r y safe. The a d d i t i o n of typeclasses w a s a great break t h r o u g h
for H a s k e l l a n d it is exactly this feature that is u s e d for g o o d , m o d u l a r ,
flexible a n d safe d e s i g n of c o m p l e x systems, typeclasses are u s e d to
p u t constraints o n types a n d c a n be also c o m p o u n d e d , that w a y the
a d d i t i o n or r e m o v a l of l i m i t s is r e l a t i v e l y easy. T h i s n o t o n l y h e l p s
c o n t r o l l i n g the r e t u r n t y p e , b u t c a n also h e l p w i t h p o l y m o r p h o u s
arguments, m a k i n g code m o r e u s e f u l w h i l e staying safe.
W e have c r i t i c i z e d b o t h of o u r o w n i m p l e m e n t a t i o n s for the w a y
they m o d e l state a n d pass a l o n g resources or access to 10. In L i s t i n g 5.5,
we can see a m u c h better m o d u l a r design suggestion, w i t h types of the
functions u s i n g it i n L i s t i n g 5.6. The complete w o r k i n g toy example can
be f o u n d i n A p p e n d i x C . l . T h e m a i n reader m o n a d W i t h R e s o u r c e s
that a l l o w s f u n c t i o n s to access a n y of its contents a n d p e r f o r m I / O
is restricted t h r o u g h p o l y m o r p h i s m w h e n s u b f u n c t i o n s are c a l l e d .

49
5- E V A L U A T I O N O F T H E A P P R O A C H E S

c l a s s MonadReader r m => TexturesReader r m where


askForTextures :: m Textures

c l a s s MonadReader r m => RandomReader r m where


askForRandom :: m RandGen

type WithResources a = ReaderT Resources 1 0 a

data Resources =
Res
{ textures :: Textures
, random :: RandGen
}

instance Monad m => TexturesReader Resources (ReaderT


-> Resources m) where
askForTextures = asks textures

instance Monad m => RandomReader Resources (ReaderT


-> Resources m) where
askForRandom = asks random

L i s t i n g 5.5: M o d u l a r reader m o n a d d e s i g n .

Constraints can be a d d e d to a function's type to grant access to m o r e


of the state or or r e m o v e d to l i m i t it. M o r e o v e r , the Resources t y p e
a n d the typeclasses c o u l d be e x p a n d e d to a c c o m m o d a t e for m o r e
resources.
That w a y w e c a n achieve decent system flexibility a n d still clearly
c o m p a r t m e n t a l i z e f u n c t i o n s , l i m i t i n g their access to w h a t w o u l d be
otherwise v e r y close to a global, imperative-like state. I n c l u d e d i n that
is the " e v i l " I / O access w h i c h c a n be a d d e d or r e m o v e d u s i n g the
MonadIO class, w h i c h ReaderT r 1 0 a l r e a d y has a n instance for.

50
5- E V A L U A T I O N O F T H E A P P R O A C H E S

gameLoop :: World -> WithResources ()

step :: (RandomReader r m) => World -> m World

draw :: (MonadIO m, TexturesReader r m) => World -> m ()

L i s t i n g 5.6: M o d u l a r reader m o n a d usage example.

5.2.2 Abstraction vs. explicitness

In t h e p r e v i o u s subsection, w e have a l r e a d y m e n t i o n e d abstraction


as the means of g a i n i n g flexibility. Excessive abstraction results i n too
m u c h flexibility, as seen i n h A s t e r o i d s . Conversely, too m u c h explicit-
ness leads to a lack of flexibility, as seen i n pure-asteroids.
H o w e v e r , despite explicitness b e i n g o n e of the k e y features that
make functional p r o g r a m m i n g safer a n d easier to argue about, expres-
siveness is t h e feature m o r e w o r t h y of p u r s u i n g . W e c a n see e x p l i c i t
data f l o w as the w a y of r e a c h i n g f o r m a l safeness, b u t it is expressive-
ness that h e l p s u s h u m a n s see it. F u r t h e r m o r e , explicitness does not
i m p l y expressiveness. The f l o w of data can be described v e r y precisely,
but it m a y be so complicated that it does not make the code any clearer.
That is w h e n abstraction steps i n place, a n d w h e n u s e d wisely, it leads
to a m o r e u n d e r s t a n d a b l e code w i t h fewer distractions. A l l of that,
w h i l e i n the b a c k g r o u n d still b e i n g technically p u r e a n d f o r m a l l y safe.
Figure 5.3 illustrates the relationships between o u r four i d e n t i f i e d
f o r e g r o u n d attributes a n d t h e t w o m a i n b a c k g r o u n d attributes w e
s h o u l d be seeking.
A s w i t h m a n y things i n life, we n e e d to f i n d a balance between ab-
straction a n d explicitness so that our p r o g r a m s are still easily provable
to be correct w h i l e not b e i n g p a i n f u l to w r i t e a n d m o d i f y .
W h e n c o m p a r i n g the m o d e l i n g of state i n o u r three games i n Sub-
section 5.1.5, w e have a l r e a d y p o i n t e d at h o w m o n a d s c a n e m u l a t e
certain features of i m p e r a t i v e l a n g u a g e s , a n d at t h e s a m e t i m e , stay
technically p u r e . W e see the example i n listing 5.6 as a g o o d balance
10

between abstraction a n d explicitness. W e l e a n t o w a r d s m o d e l i n g the


game w o r l d state as a n explicit variable since it is the most i m p o r t a n t
data structure. Mistakes i n m a n i p u l a t i o n w i t h it m a y be critical, a n d as

51
5- E V A L U A T I O N O F T H E A P P R O A C H E S

/ \

Freedom

T
How we perceive it What we can do

F i g u r e 5.3: The f o u r d i s c u s s e d qualities of d e s i g n .

the l i k e l y most extensive data structure, it c o u l d be h i g h l y beneficial


to process it i n p a r a l l e l .
O n the other h a n d , things like the state of a r a n d o m n u m b e r gener-
ator or other resources meant o n l y for r e a d i n g , such as textures, can 11

be h i d d e n i n a n a p p r o p r i a t e l y n a m e d m o n a d w i t h o u t a n issue. That
way, w e keep expressiveness b u t a l l o w for flexibility. A s a n a d d i t i o n a l
s u p p o r t i n g e x a m p l e , w e consider the f o l l o w i n g t w o f u n c t i o n types:

step (RandomReader r m) => World -> m World

step' :: (RandomReader s m, WorldState s m) => m ()

O n e f u n c t i o n takes a v a l u e of t y p e World a n d returns a n e w v a l u e of


the same type u n d e r the influence of a reader m o n a d . W h i l e the other
is obscurer a n d returns n o t h i n g b u t m o n a d i c effects. A t last, we a d m i t

10. Philip Wadler speaks more on "combining the indulgences of impurity with the
blessings of p u r i t y " by using monads i n his paper Comprehending Monads [25].
11. In a larger game, textures may need to load dynamically; still, they are read-
mostly data.

52
5. E V A L U A T I O N OF T H E APPROACHES

that this is to a n extent a matter of p e r s o n a l taste a n d that some m a y


prefer the effectful a p p r o a c h , despite w h a t w e have a r g u e d .
12

12. A n example of such an approach can be seen i n the Dino Rush game, described in
the blog post A Game in Haskell - Dino Rush [10] mentioned previously i n Section 1.1.2.

53
Conclusion
In this thesis, w e u s e d t w o a p p r o a c h e s to r e i m p l e m e n t A s t e r o i d s
b y A t a r i i n H a s k e l l r e s u l t i n g i n t w o projects: h A s t e r o i d s a n d p u r e -
asteroids. W e have described each i m p l e m e n t a t i o n i n Chapters 2 a n d 3.
A d d i t i o n a l l y , w e p i c k e d a n existing imperative reimplementation f r o m
G i t H u b a n d also o u t l i n e d its operation i n Chapter 4. T h e n , i n Chapter 5,
w e have c o m p a r e d the i m p l e m e n t a t i o n s to d e t e r m i n e w h e t h e r the
f u n c t i o n a l p r o g r a m m i n g p a r a d i g m ' s general benefits a p p l y to game
development.
W e have gathered that o u r t w o approaches are opposite extremes
o n the s p e c t r u m of abstraction a n d explicitness. M o r e o v e r , w e d i s -
cussed the relationship of those characteristics w i t h f r e e d o m of effects
a n d safeness, c o n c l u d i n g that the focus s h o u l d b e o n expressiveness
a n d flexibility. W e a r g u e d that the latter t w o qualities are achieved b y
balancing the former two pairs a n d s h o w e d h o w H a s k e l l ' s typeclasses
c o u l d be u s e d together w i t h m o n a d s to achieve the d e s i r e d balance.
W e have r e d i s c o v e r e d that H a s k e l l c a n b e v e r y i m p e r a t i v e , as ex-
p l a i n e d b y S i m o n P. Jones a n d P h i l i p W a d l e r i n their paper Imperative
Functional Programming [26]. In that paper, they described for the first
time h o w m o n a d s c o u l d be u s e d for i n p u t / o u t p u t operations i n l a z y
languages a n d c o n f i r m e d w h a t w e see as the result i n h A s t e r o i d s
— w i t h the 10 m o n a d , H a s k e l l c a n v e r y c l o s e l y resemble C . Yet, it
keeps the benefits of f u n c t i o n a l style intact b y clearly separating the
imperative f r o m the f u n c t i o n a l .
S i m u l t a n e o u s l y , w h i l e the creators of H a s k e l l argue for laziness,
it c a n cause p e r f o r m a n c e issues. T h i s h a p p e n s w h e n extensive u n -
evaluated data accumulates a n d results i n l o n g delays caused b y the
Garbage C o l l e c t i o n ( G C ) . This is especially of concern for v i d e o games
w h e r e the t i m e to c o m p u t e a n d r e n d e r a frame is l i m i t e d . M o r e o v e r ,
f i n d i n g the sources of those " l a z y m e m o r y l e a k s " a n d d o i n g other
o p t i m i z a t i o n s c a n b e m o r e c h a l l e n g i n g d u e to the language's s t r o n g
abstraction. H o w e v e r , w e d i d n o t experience a n y p r o b l e m s w i t h G C
i n o u r small-scale experiments.
F u r t h e r m o r e , w e have f o u n d that the apecs l i b r a r y m a k e s game
p r o g r a m m i n g i n H a s k e l l s u r p r i s i n g l y accessible. h A s t e r o i d s outper-
f o r m e d pure-asteroids b y u p to 100 % for h i g h entity counts because

54
5- E V A L U A T I O N O F T H E A P P R O A C H E S

of the E n t i t y - C o m p o n e n t - S y s t e m d e s i g n (a d a t a - o r i e n t e d d e s i g n )
p r o v i d e d b y apecs. C r e a t i n g pure-asteroids was more d e m a n d i n g , but
its d e s i g n is clearer, a n d it keeps p a r a l l e l i s m i n m i n d . E v e n t h o u g h
it does n o t a c t u a l l y i m p l e m e n t it, w e p a i d attention to m a k i n g the
architecture easy to m o d i f y for p a r a l l e l c o m p u t a t i o n .
U l t i m a t e l y , w e believe that the game's code c a n be m o r e m o d u l a r ,
i n parts briefer, easier to u n d e r s t a n d a n d to argue about its correct-
ness t h a n its i m p e r a t i v e equivalent. It does c o m e at a h i g h e r u p f r o n t
cost, especially c o n s i d e r i n g the l i m i t e d libraries a n d tools (at least
c o m p a r e d to the rest of the i n d u s t r y ) . Regardless, w e judge o u r devel-
o p m e n t experience as v e r y p o s i t i v e , a n d w e w o u l d encourage others
interested i n g a m e p r o g r a m m i n g to t r y H a s k e l l themselves. It m a y
not c u r r e n t l y be the safest w a y to b r i n g a g a m e to the market, b u t at
the bare m i n i m u m , it is a v a l u a b l e l e a r n i n g experience a n d , at best,a
step for the w h o l e i n d u s t r y t o w a r d s better g a m e engines w i t h a l l of
the p e r k s of p u r e l y f u n c t i o n a l p r o g r a m m i n g .
T h e benefits of p u r e l y f u n c t i o n a l d e s i g n b e c o m e most significant
i n the l o n g t e r m a n d large scale. H o w e v e r , o u r e x a m p l e s are s m a l l
i n scale, a n d so it r e m a i n s to be p r o v e n i n practice that o u r f i n d i n g s
are a p p l i c a b l e to m o r e c o m p l e x games w i t h o u t r u n n i n g i n t o issues
w i t h laziness, for instance. M o r e o v e r , w e w o u l d be c u r i o u s to see
w h e t h e r a d d i n g the p a r a l l e l i s m i n t o pure-asteroids w o u l d better the
performance even at that scale, a n d further, h o w it w o u l d compare to
the data-oriented d e s i g n of apecs as the entity counts g r o w .

55
Bibliography
1. C A R P A Y , Jonas, apecs: Fast Entity-Component-System library for
game programming [online] [ v i s i t e d o n 2021-04-22]. A v a i l a b l e
from: h t t p s : //hackage. h a s k e l l . org/package/apecs.
2. H U G H E S , John. W h y Functional P r o g r a m m i n g Matters. The Com-
puter Journal [online]. 1989, v o l . 32, n o . 2 [visited o n 2021-04-25].
ISSN 0010-4620. A v a i l a b l e f r o m DOI: 1 0 . 1 0 9 3 / c o m j n l / 3 2 . 2 . 9 8 .
3. N I L S S O N , H e n r i k ; C O U R T N E Y , A n o t n y . Yampa: Elegant Func-
tional Reactive Programming Language for Hybrid Systems [online]
[visited o n 2021-05-01]. A v a i l a b l e f r o m : h t t p : / / h a c k a g e . h a s k e l l
org/package/Yampa.
4. C O R R , Zack. Helm: A functionally reactive game engine [online] [vis-
i t e d o n 2021-05-01]. A v a i l a b l e f r o m : h t t p : / / h a c k a g e . h a s k e l l .
org/package/helm.
5. G E R G E L Y , Patai. elerea: A minimalistic FRP library [online] [vis-
i t e d o n 2021-05-01]. A v a i l a b l e f r o m : h t t p : / / h a c k a g e . h a s k e l l .
org/package/elerea.
6. S O Y L E M E Z , E r t u g r u l . netwire: Functional reactive programming
library [online] [ v i s i t e d o n 2021-05-01]. A v a i l a b l e f r o m : h t t p :
//hackage.haskell.org/package/netwire.
7. F U R T A D O , A n d r e . FunGEn: A lightweight, cross-platform, OpenGL-
basedgame engine [online] [visited o n 2021-05-01]. A v a i l a b l e f r o m :
http://hackage.haskell.org/package/FunGEn.
8. K E E R A S T U D I O S . Products and Services [ o n l i n e ] . N o t t i n g h a m
[visited o n 2021-05-04]. A v a i l a b l e f r o m : h t t p s : / / k e e r a . c o . u k /
products-and-services/.
9. P A L F R E Y , Jack. Wayward Tide: Technical Info [online]. C h u c k l e f i s h
[visited o n 2021-05-04]. A v a i l a b l e f r o m : h t t p s : / / c h u c k l e f i s h .
org/blog/wayward-tide-technical-details/.
10. V A R G A S , Joe. A Game in Haskell - Dino Rush [online]. 2018-02-28
[ v i s i t e d o n 2021-05-04]. A v a i l a b l e f r o m : h t t p : / / j x v . i o / b l o g /
2018-02-28-A-Game-in-Haskell.

56
BIBLIOGRAPHY

11. S M I T H , Ashley. Of Boxes and Threads: Games development in Haskell


[online]. 2018-06-09 [visited o n 2021-05-04]. Available f r o m : h t t p s :
//aas.sh/blog/of-boxes-and-threads/.
12. S M I T H , A s h l e y . An Introduction to Developing games in Haskell
with Apecs [online]. 2018-09-10 [visited o n 2021-05-04]. A v a i l a b l e
from: https : / / a a s . s h / b l o g / m a k i n g - a - g a m e - w i t h - h a s k e l l -
and-apecs/.

13. L I P P M E I E R , B e n . gloss: Painless 2D vector graphics, animations


and simulations [online] [visited o n 2021-05-01]. A v a i l a b l e f r o m :
http://hackage.haskell.org/package/gloss.
14. P E T U R S S O N , G a b r i e l A r t h u r ; C H A R L E S , O l i v e r , sdll: Both high-
and low-level bindings to the SDL library (version 2.0.6+) [online]
[visited o n 2021-05-16]. Available f r o m : h t t p s : / / h a c k a g e . h a s k e l l .
org/package/sdl2.
15. W I K I P E D I A C O N T R I B U T O R S . File:Asteroids-arcadegame.jpg —
Wikipedia, The Free Encyclopedia [online]. 2018 [visited o n 2021-05-
12]. A v a i l a b l e f r o m : h t t p s : / / e n . w i k i p e d i a . o r g / w / i n d e x . php?
title=File:Asteroids-arcadegame.jpg&oldid=820309311.

16. W I K I P E D I A C O N T R I B U T O R S . FileAsteroil .png — Wikipedia, The


Free Encyclopedia [online]. 2017 [visited o n 2021-05-12]. A v a i l a b l e
from: h t t p s : / / e n . w i k i p e d i a . o r g / w / i n d e x . p h p ? t i t l e = F i l e :
Asteroil.png&oldid=781748912.
17. T H E D O T E A T E R S . Asteroids - Rockin' the Arcades [ o n l i n e ] . 2013
[visited o n 2021-05-05]. A v a i l a b l e f r o m : h t t p s : / / w e b . a r c h i v e .
org/web/20131023233640/http://thedoteaters.com/?bitstory=
asteroids.

18. J O R D A N , M a r k . Entities, components and systems [online]. M e d i u m ,


2018-11-20 [ v i s i t e d o n 2021-05-05]. A v a i l a b l e f r o m : h t t p s : / /
medium . c o m / i n g e n i o u s l y s i m p l e / e n t i t i e s - c o m p o n e n t s - a n d -
systems-89c31464240d.
19. C A R P A Y , Jonas. Apecs: A Type-Driven Entity-Component-System
Framework [online]. G i t H u b , 2018-11-18 [visited o n 2021-05-01].
Available from: https : / / g i t h u b . com/jonascarpay/apecs /
blob/master/apecs/prepub.pdf.

57
BIBLIOGRAPHY

20. M A G U I R E , Sandy. Why Take Ecstasy [online]. 2018-01-28 [visited


o n 2021-05-01]. A v a i l a b l e f r o m : h t t p s : / / r e a s o n a b l y p o l y m o r p h i c .
com/blog/why-take-ecstasy/.
21. C A R P A Y , Jonas. Apecs [online] [visited o n 2021-04-22]. A v a i l a b l e
from: https://hackage.haskell.org/package/apecs-0.9.2/
docs/Apecs.html.
22. C A R M A C K , John. John Carmack's keynote at Quakecon 2013 part 4
[online]. YouTube, 2013 [visited o n 2021-05-06]. A v a i l a b l e f r o m :
https://youtu.be/lPhArSujR_A?t=125.
23. H A L V E R S O N , Jason; RYCHLÝ, Jan. cpp-asteroids: Clone of Atari
Asteroids made by Jason Halverson [online] [ v i s i t e d o n 2021-05-
20]. A v a i l a b l e f r o m : h t t p s : / / g i t h u b . c o m / h o n z a f l a s h / c p p -
asteroids/tree/organized.
24. H A S K E L L W I K I . GHC/GHCi — HaskelMiki, [online]. 2020 [vis-
i t e d o n 2021-05-19]. A v a i l a b l e f r o m : h t t p s : / / w i k i . h a s k e l l .
org/index.php?title=GHC/GHCi&oldid=63309.
25. W A D L E R , P h i l i p . M o n a d s f o r f u n c t i o n a l p r o g r a m m i n g . In: Ad-
vanced Functional Programming [online]. B e r l i n , H e i d e l b e r g : Springer,
1995, p p . 24-52 [visited o n 2021-05-15]. ISBN 978-3-540-59451-2.
A v a i l a b l e f r o m : h t t p : / / s t a f f . urn . edu . m t / a f r a l / s e m i n a r /
monads.pdf.
26. P E Y T O N J O N E S , S i m o n L . ; W A D L E R , P h i l i p . Imperative F u n c -
t i o n a l P r o g r a m m i n g . I n : Proceedings of the 20th ACM SIGPLAN-
SIGACT Symposium on Principles of Programming Languages [ o n -
l i n e ] . Charleston, S o u t h C a r o l i n a , U S A : A s s o c i a t i o n for C o m p u t -
i n g M a c h i n e r y , 1993, p p . 71-84 [visited o n 2021-05-15]. P O P L '93.
ISBN 0897915607. A v a i l a b l e f r o m DOI: 10.1145/158511.158524.

58
A Electronic attachments
T h e i m p l e m e n t a t i o n s d e s c r i b e d i n this thesis are attached w i t h it i n
a n archive file. T h e contents of the archive are o u t l i n e d here:
implementations
_hAsteroids the h A s t e r o i d s project root
-fPP
L_ M a i n . hs the entry p o i n t
.resources textures a n d fonts
.src library modules
. p a c k a g e . yaml package details i n c l u d i n g dependencies
_ s t a c k . yaml stack c o n f i g u r a t i o n
_pure-asteroids the pure-asteroids project root
^app
1_ M a i n . hs the entry p o i n t
.resources fonts
.src library modules
. p a c k a g e . yaml package details i n c l u d i n g dependencies
. s t a c k . yaml stack c o n f i g u r a t i o n
. README. md r e a d m e file f r o m the G i t H u b repository
The b u i l d instructions are p r o v i d e d i n the f o l l o w i n g a p p e n d i x .
Latest v e r s i o n of projects can be f o u n d at h t t p s : / / g i t h u b . com/honzaf l a s h /
ba-thesis.

59
B Build instructions
The b u i l d process for b o t h h A s t e r o i d s a n d pure-asteroids is v e r y s i m i -
lar. The f o l l o w i n g r e q u i r e m e n t s m u s t be met first.
Haskell Tool Stack
B o t h games are projects m a n a g e d u s i n g the H a s k e l l T o o l Stack; 1

therefore, s t a c k n e e d s to b e i n s t a l l e d . W e r e c o m m e n d r u n n i n g
s t a c k upgrade before a t t e m p t i n g the b u i l d .
S D L libraries
The u s e d H a s k e l l S D L b i n d i n g s r e q u i r e the C l i b r a r i e s to be i n -
stalled. Specifically, b o t h projects n e e d S D L a n d S D L _ t t f , a n d
h A s t e r o i d s also uses S D L _ i m a g e

To install a l l three o n U b u n t u , y o u c a n use this c o m m a n d :

sudo apt i n s t a l l l i b s d l 2 - d e v libsdl2-ttf-dev


-> libsdl2-image-dev

To install a l l three o n W i n d o w s w i t h the h e l p of s t a c k :

stack exec — pacman --s


mingw64/mingw--w64--x86. .64- -pkg-config
mingw64/mingw--w64--x86. .64- -SDL2
mingw64/mingw--w64--x86. .64- -SDL2_ttf
mingw64/mingw--w64--x86. .64- -SDL2_image

Operating System
Stack a n d S D L s u p p o r t L i n u x , W i n d o w s , a n d M a c O S . The b u i l d
was tested o n U b u n t u 20.04 a n d W i n d o w s 10 b u i l d 19042.
W i t h that, w e can r u n s t a c k b u i l d i n the project's root directory. This
m a y take a w h i l e as s t a c k d o w n l o a d s a n d installs a l l the d e p e n d e n -
cies. To l a u n c h the g a m e w h e n project is b u i l t successfully, execute
s t a c k r u n or s t a c k exec < n a m e - o f - t h e - e x e c u t a b l e > , a g a i n , i n the
project's root directory. W e were unable to m a k e s t a c k exec w o r k o n
W i n d o w s , so alternatively, w e c a n r u n s t a c k g h c i a n d t h e n r u n the
main f u n c t i o n i n G H C i .

1. About stack: https://docs.haskellstack.org/en/stable/README/

60
C Additional code examples

C.l Example of modular monad design using


typeclasses
H e r e w e list a w o r k i n g toy example, i m p l e m e n t i n g the m o d u l a r design
we o u t l i n e d at the e n d of Section 5.2.

{-# LANGUAGE F l e x i b l e l n s t a n c e s #-}


{-# LANGUAGE MultiParamTypeClasses #-}

import Control.Monad.10.Class
import Control.Monad.Reader

c l a s s MonadReader r m => TexturesReader r m where


askForTextures :: m Textures

c l a s s MonadReader r m => RandomReader r m where


askForRandom :: m RandGen

type WithResources a = ReaderT Resources 10 a

type Textures = S t r i n g
type RandGen = [Int]
data Resources =
Res
{ t e x t u r e s :: Textures
, random :: RandGen
}

instance Monad m => TexturesReader Resources (ReaderT


-> Resources m) where
askForTextures = asks t e x t u r e s

instance Monad m => RandomReader Resources (ReaderT


-> Resources m) where
askForRandom = asks random

61
C . ADDITIONAL CODE EXAMPLES

newtype World = World I n t d e r i v i n g Show

main :: 10 ()
main = do
l e t world = World 10
l e t resources = Res
{ t e x t u r e s = "Current world s t a t e : "
, random = [4, 2]
}
runReaderT (gameLoop world) resources

gameLoop :: World -> WithResources ()


gameLopo w = do
newW <- step w
draw w
q u i t <- l i f t I O $ getLine
unless (quit == "q") $
gameLoop newW

step :: (RandomReader r m) => World -> m World


step (World state)= do
rand <- head <$> askForRandom
— performing I/O i s i l l e g a l because 'm'
— does not have the MonadIO c o n s t r a i n t on i t
— l i f t I O $ putStrLn "C i s the s u p e r i o r language"
r e t u r n $ World $ s t a t e + rand

draw :: (MonadIO m, TexturesReader r m) => World -> m ()


draw w = do
t <- askForTextures
l i f t I O $ putStrLn $ t ++ show w

62
C . ADDITIONAL CODE EXAMPLES

C.2 More examples of functional elegance


H e r e w e list a few m o r e e x a m p l e s of elegant, concise c o d e f r o m o u r
implementations.

N o n e e d for explicit iteration w h e n l o a d i n g textures:

loadTextures :: SDL.Renderer -> 10 Textures


loadTextures r = ioOrDie " F a i l e d t o load t e x t u r e s " $
HM.fromList <$> mapM mapPathToTexture keyPathList
where
mapPathToTexture = mapM (IMG.loadTexture r )

M o r e m a p usage w i t h p a r t i a l l y e v a l u a t e d functions:

— I C a l c u l a t e s the ship v e r t i c e s ' p o s i t i o n s


shipPoints :: Ship -> [V2 Double]
shipPoints s =
map (+ sPos)
[ -17 *~ ( f a c i n g - perp facing) — l e f t
, 25 *~ f a c i n g — front t i p
, -17 *~ ( f a c i n g + perp facing) — r i g h t
, -8 *~ f a c i n g — back point
]
where
sPos = s ~. s P o s i t i o n . pVect
f a c i n g = angle $ s ~. sAngle

D r a w i n g a n arbitrary n u m b e r of textures w i t h text stacked vertically,


u t i l i z i n g laziness a n d list c o m p r e h e n s i o n :

drawCenteredTexts :: SDL.Renderer -> Texts -> [TextKey] ->


- 10 ()
drawCenteredTexts renderer t e x t s =
zipWithM_
(drawCenteredText renderer t e x t s )
[100 * i I i <- [2. .]]

63

You might also like