2017-07-27

a tetris clone

this is my first """big""" project in C, made after reading the bible K&R Second Edition and after taking the Harvard course CS50.

actually I consider this as my "final project" for CS50: I enjoy C so much that I had to choose it as the main tool for the project.

here a demo video and here the source code.

why tetris?

well, first because I like it: I used to play A LOT when I was a kid on a "chinese fake GameBoy" I had and more recently on my smartphone. and then because I wanted to do something simple within my reach, but at the same time a bit challenging, considering the language I chose.

also it is often considered as an "Hello, World!" to game development so once in my life I had to do it.

the game

I tried to stick with the classic Tetris, so no "wall kick", no "hold piece", no "ghost piece", but I applied some "new" features that I like: "soft drop" (without adding points) and this random generator so that I don't have to swear to get an I.

keys to control what's on the screen are straightforward:

after the end of each game, it saves the level, score and lines along with the current date and the time spent playing (including pause time) in a text file called "scores.txt" within the folder in which the executable resides.

for now, there isn't a way to add a nickname (because you know, probably I will be the only player...).

the program

if you haven't notice yet, I used the ncurses library.

two "design choices" I made (I know I probably screw up somewhere) were: write "reusable" code (in part) and split different things in different files.

here the files tree and a bit of explanation:

project/
        Makefile
        include/
                actions.h
                colors.h
                controller.h
                drawer.h
                game.h
                grid.h
                helpers.h
                tetramino.h
        src/
                controller.c
                drawer.c
                game.c
                grid.c
                helpers.c
                main.c
                tetramino.c

for the first time in my three months adventure with C, I felt the need to use a Makefile and it turned out to be veeery useful of course.

in helpers.c there are some helpers functions (youdontsay.jpg). there is for example a "malloc wrapper" who calls exit(EXIT_FAILURE) if it was not possible allocate memory. I call it (the wrapper) every time I need memory.

grid.c contains functions to handle guess what? right, the game grid on which put blocks.

actions.h contains an enum of "actions" i.e. commands that modify the current state of the game. I think their names are self-explanatory.

the "magic" happens in the files main.c and game.c: they handle the game flow.

tetramino.c defines all you need to create a tetramino, rotate or change its shape and blindly put / remove it on / from a grid if it is not locked.

with controller.c instead, you can perform "actions" on a tetramino only if that action is allowed, depending on the current state of the grid.

that is, to move, rotate or drop a piece, game.c relies on the functions in controller.c who relies on the "raw" functions in tetramino.c after some tests.

drawer.c takes care of the "ncurses part" drawing the grid, the edges and some informations. it has a function, refresh_scene(), which is called in game.c to update what is on the screen when it's time to do so.

grid.c and even drawer.c could be easily reused in other projects, e.g. in a snake clone, tic-tac-toe, ..., basically anything who requires a simple grid, because I made them "not Tetris specific".

I tried to keep things as simple as possible (I always try to do this). for example, I hard coded all possible rotations for each piece in tetramino.c since in total they are only 4 x 7 = 28. in this way I don't have to call a function to rotate a matrix and sometimes rotate it backwards, but my functions simply increment or decrement an index in range [0,3]. of course I did this because the amount of memory used is very low.

conclusion

at the end of the day, the main goals of this project were:

and I guess I've achieved them all. even if it was not a big deal, it was my first time with many things: a multiple files program (in C), a Makefile, ncurses and small "tricks" I used in the code.

so it was worth it!

thank you for reading up to here, if you have any comment / suggestion or if you found a bug, please contact me via email. bye.