A console-based implementation of the deck-building card game Dominion, written in modern C++ as an academic project. This project focuses on applying Object-Oriented Programming principles to build a complete and playable game engine.
- About The Project
- Key Features
- Built With
- Getting Started
- Usage
- Technical Deep Dive
- Challenges & Solutions
- License
- Acknowledgments
This project is a C++ implementation of the deck-building game Dominion. The primary goal was to apply theoretical programming concepts learned in our "Programming Tools and C++" course into a tangible, interactive application.
The game engine is built from the ground up, focusing on a robust class structure to represent the game's components (cards, players, game board) and logic. It's a 2-4 player game that runs entirely in the terminal.
- Complete Game Engine: Manages game phases (Action, Buy, Clean-up), player decks, hands, and discard piles.
- 2-4 Player Support: The game can be configured to be played by two, three, or four human players.
- Basic AI Opponent: Includes an option to play against an AI with a simple decision-making strategy.
- Save/Load Functionality: Players can save the game state at the end of their turn and resume it later. The state is serialized to a CSV file.
- Customizable Card Kingdom: Before starting a new game, players can choose the 10 Action cards that will be available in the supply, allowing for strategic variety.
- Styled Console Interface: Uses ANSI escape codes to add color to the terminal output, making the game state easier to read and more visually appealing.
- C++17
- C++ Standard Library (
<vector>,<memory>,<string>,<map>,<chrono>) - Compiler: g++ (MinGW)
- IDE: Code::Blocks
To get a local copy up and running, follow these simple steps.
You will need a C++ compiler that supports C++17. g++ is recommended.
- On Windows: You can use MinGW or WSL.
- On macOS: Install Xcode Command Line Tools.
- On Linux: Install
build-essential(sudo apt-get install build-essential).
-
Clone the repository:
git clone https://github.com/nico916/dominion-cpp.git cd dominion-cpp -
Compile the project: A
Makefileis the recommended way. If one is not provided, you can compile manually using the command below from the root directory:g++ -std=c++17 -I include/ -o Dominion main.cpp src/*.cppThis command compiles all
.cppfiles in thesrcdirectory, includes the headers from theincludedirectory, and creates an executable namedDominion. -
Run the game:
- On Linux/macOS/Git Bash:
./Dominion
- On Windows: After compiling, you can also run the game by double-clicking on
Dominion.exeinside the project folder.
- On Linux/macOS/Git Bash:
Once the application is running, it will guide you through a series of prompts in the console:
- Load Game: Choose to start a new game or resume from a saved
sauvegarde.csvfile. - Number of Players: Select between 2 and 4 players.
- AI Player: Decide if one of the players should be controlled by the AI.
- Card Selection: Choose to play with the 10 standard Action cards or to manually select 10 cards for the game's supply.
During a turn, you will be prompted to take actions, buy cards, or end your turn, with your hand and available resources displayed at each step.
The project is heavily based on OOP principles to create a modular and extensible architecture.
- Inheritance & Polymorphism: A base
Cardclass defines a common interface. Derived classes likeCarteTresor,CarteVictoire, andCarteActionimplement specific behaviors. This allows us to store all cards in a polymorphic collection (e.g.,std::vector<std::shared_ptr<Card>>) and handle them uniformly. - Encapsulation: Classes like
JoueurandPlateauJeu(GameBoard) encapsulate their own state and logic, exposing only necessary methods to interact with them.
To ensure robust and safe memory management, this project leverages modern C++ features:
- Smart Pointers:
std::shared_ptris used extensively to manage the lifecycle ofCardandJoueurobjects. This completely avoids manualnew/deletecalls, prevents memory leaks, and handles shared ownership of cards between the game board, player decks, and hands. It also made safe down-casting withstd::dynamic_pointer_caststraightforward.
The codebase is organized to separate interfaces from implementations, a standard practice in C++ development.
- Header Files (
.h): Located in theinclude/directory, these files declare the classes and their public members, defining their "contract". - Source Files (
.cpp): Located in thesrc/directory, these files contain the implementation of the methods declared in the headers. This separation improves code organization and can reduce compilation times in larger projects.
-
Challenge: Managing different card types with unique actions in a uniform way.
- Solution: Implemented specific
executerAction...methods in theCarteActionclass. A central game loop calls the correct method based on the card played, demonstrating a form of runtime polymorphism.
- Solution: Implemented specific
-
Challenge: Correctly updating player state (deck, hand) without creating unintended copies.
- Solution: Using
std::shared_ptr<Joueur>ensured that all parts of the program were referencing the exact same player object, not a copy, making state management consistent and reliable.
- Solution: Using
Distributed under the MIT License. See LICENSE file for more information.