Package: py2048base
py2048is a clone of the famousgamebyGabriele Cirulli.
It’s probably not very interesting to people looking for playing 2048, but may
be useful for people looking for learning Python.
It’s written in pure Python 3.8 and makes an effort not to use third-party libraries.
For example, the game grid could be a numpy matrix, but I’d rather not break a butterfly
upon a wheel.
The game’s been divided in two parts:
the backend, and the frontends (or interfaces).The package in this repository provides no concrete user interface for the game,
but contains a class that must be inherited by every actual frontend.FeaturesCustomizable rulesYou can configure the size of the game grid and the winning condition
(wanna go beyond 2048?);Customizable looksBy subclassing the basic frontend and overriding its
methods, you can make the game look any way you want, without touching the
basic game logic;Automatic modeYou can replace human input with a function that picks a
random direction! More useful for testing than actual gameplay, though.How to useTo implement a frontendThe backend takes input (in the form of apy2048.Directionsobject),
processes it, and waits for the next input.
This loops until
the player exits, or
the player wins for the first time in this session, or
the player runs out of valid movements.
It’s a pure-Python implementation of the original game logic:
it makes equal numbers merge into their sum, “moving” from one tile into
another, and so on.
The backend deals only with plain Python data, such asintanddict;
it is up to each frontend to actually collect the input and display the
updated game state as a (hopefully) pretty interface.To write such frontend, subclasspy2048.basefrontend.Base2048Frontendand override the following methods:choose_directionon_player_quiton_player_victoryon_player_overvictoryon_player_losschoose_directionmust return exactly onepy2048.Directionsobject.
If writing a graphical frontend (a GUI), you’ll probably want to create a “worker”
thread that runs the backend’s loop and waits for a condition when it reaches
thechoose_directioncall.
The main thread will then be responsible for storing user input somewhere accessible
by the worker thread and “waking it up”.
The other overriden methods shouldn’t return anything.player_quitis called when the player exits the game before winning or
losing.
An “overvictory” is what happens when the grid “jams” (runs out of valid movements)
but the player had already won (had already reached the target goal number).To run testsWe’re using thepytestlibrary to check the correctness of the basic
data structures.
To run the tests, open a terminal, move into the root folder of the project
(the one which containssetup.py), and type the following:pytest-3 -v py2048/test.pyMake sure you’re in the right folder,
that there are no slashes in the command, and
that it doesn’t end with.py.
Alternatively, usemake testWishlistIn the future, I’d like to create an AI to play the game!How it worksBackendIts main components are theCelland theGrid.
TheCellclass is a wrapper over anintthat represents a tile in the game
grid.
It has alockedproperty, which is simply aboolthat determines whether it
can change its storedintin this cycle.
A cycle is what happens between the arrival of a valid user input and the moment
the game pauses to get the next input.
Thislockedproperty prevents a 2 merging into a 2 and the resulting 4 merging
into another 4 all in a single cycle, for example.
If you play the original game, you’ll notice that is not allowed.TheGridis a wrapper over adictthat maps points intoCells(and points are named tuples that store x and y coordinates).
This class (along withpy2048.basefrontend.Base2048Frontend), implements most
of the game logic.
It’s responsible for determining how and when oneCellcan merge into another,
updating the score, and so on.Frontend