How does it work?#
If you just want to play the game, you can safely ignore this section. However, if you want to know how we implemented the game mechanics, read on!
eggdrop is mainly implemented using basic to intermediate Python syntax, with some “advanced” features such as dataclasses sprinkled in for clarity.
It uses no additional dependencies other than what is provided in the Python standard library. It is cross-platform and runs on Windows[1], Mac OS, and Linux.
The starting point for the game is main.py, found in the root directory. The inner code, meanwhile, can be found inside the src/ directory, with the src/tests/ subdirectory containing the test suite.
There are three main files:
constants.py, containing some useful module constants and definitions
console_render.py, containing some functions for rendering to the screen, and
game_logic.py, containing most of the game logic
Take a look inside any of the files for more details.
Game logic#
The meat of the game logic can be found in game_logic.py. An overview of our game logic can be found below.
First, the game reads the file specified in the command line and loads in the map data as follows:
4 # number of rows in the map data
10 # total number of moves the user has
🧱🧱🧱🧱🧱🧱🧱🧱 # map data
🧱🪹🪹🟩🥚🥚🥚🧱
🧱🧱🪹🟩🟩🪹🪹🧱
🧱🧱🧱🧱🧱🧱🧱🧱
It then stores the map into a GameState dataclass instance which stores three important attributes: the map data, move history, and points earned.
The main.py file then asks the user for input, filters out the valid
characters, converts the letters into valid moves (LEFT, RIGHT,
FORWARDS, BACKWARDS) represented by a pair of ints, and then calls the
main function process_move.
process_move takes in two arguments: an instance of GameState
denoting the current state of the game as described above, and
direction denoting the move the user wishes to process.
It returns a generator which, at each iteration, changes the map data of
the GameState instance to display “in-between frames” or an animation
of each egg moving as the move is being processed.
These “in-between frames” are then rendered on screen via the functions defined in console_render.py. See the demo video on the homepage for more details.
The game state’s move history and number of points earned are then updated after the move is processed. These are then displayed to the user accordingly.
Move processing#
You might then ask, how exactly does eggdrop process a move? Once again, the answer is in game_logic.py, but a general overview goes as follows:
First, we find every egg in the current game state’s map data using the
_get_egg_coordinates function. Depending on the move we want to
process, the order in which we store the egg coordinates matters.
For example, if I want to process a move to the LEFT, we sort the eggs by column index in ascending order, so that the leftmost eggs are processed first. If I want to process a move BACKWARDS, we sort the eggs by row index in descending order, so that the bottommost eggs are processed first.
Then, we store the sorted egg coordinates into a list. One by one, we
process each egg and move it one space towards direction. There are
two general cases:
The EGG (🥚) moves to a GRASS (🟩) cell.
The EGG (🥚) moves to a WALL (🧱), FULL_NEST (🪺), or EGG (🥚) cell.
The EGG (🥚) moves to a FRYING_PAN (🍳) or EMPTY_NEST (🪹) cell.
For Case 1, we simply move the egg and take note of the new coordinates.
For Case 2, we simply pop the egg off the list as we are done processing that egg; it cannot move any further.
For Case 3, we move the egg, update the destination cell if needed, and then similarly pop the egg off the list as it is done processing. We also take note of the points earned or lost by this movement.
After one round of processing all the eggs, we yield so that an
“in-between” animation frame can be displayed to the user.
Then, we repeat the process until there are no more eggs to be moved.