cpp
exercises
exercises.cpp⚙️cpp
/**
* Enums, Structs, and Unions - Exercises
* Practice problems from beginner to advanced
*/
#include <iostream>
#include <string>
#include <vector>
#include <variant>
#include <cmath>
using std::cout;
using std::endl;
using std::string;
// ============================================================================
// EXERCISE 1: Enum Class Basics (Beginner)
// ============================================================================
/**
* TODO: Create an enum class called Month with all 12 months.
* Each month should have a value from 1-12 (January = 1, December = 12).
* The underlying type should be uint8_t.
*
* Then create a function:
* string monthToString(Month m) - returns the month name as a string
* int daysInMonth(Month m, bool isLeapYear = false) - returns days in month
*/
// YOUR CODE HERE:
// enum class Month : uint8_t { ... };
// string monthToString(Month m) { ... }
// int daysInMonth(Month m, bool isLeapYear = false) { ... }
void exercise1_test() {
cout << "=== EXERCISE 1: Enum Class Basics ===" << endl;
// Uncomment to test:
/*
cout << monthToString(Month::January) << " has "
<< daysInMonth(Month::January) << " days" << endl;
cout << monthToString(Month::February) << " has "
<< daysInMonth(Month::February) << " days (non-leap)" << endl;
cout << monthToString(Month::February) << " has "
<< daysInMonth(Month::February, true) << " days (leap year)" << endl;
cout << monthToString(Month::December) << " has "
<< daysInMonth(Month::December) << " days" << endl;
*/
}
// ============================================================================
// EXERCISE 2: Enum Operations (Beginner)
// ============================================================================
/**
* TODO: Create an enum class FilePermission with flags:
* None = 0, Read = 1, Write = 2, Execute = 4
*
* Implement these operator overloads to allow combining permissions:
* operator| (combine permissions)
* operator& (check if permission is set)
* operator~ (invert permissions - within 3 bits)
*
* Create functions:
* bool hasPermission(FilePermission perms, FilePermission check)
* string permissionString(FilePermission perms) - returns "rwx" style
*/
// YOUR CODE HERE:
void exercise2_test() {
cout << "\n=== EXERCISE 2: Enum Operations ===" << endl;
// Uncomment to test:
/*
FilePermission perms = FilePermission::Read | FilePermission::Write;
cout << "Permissions: " << permissionString(perms) << endl;
cout << "Has Read? " << hasPermission(perms, FilePermission::Read) << endl;
cout << "Has Execute? " << hasPermission(perms, FilePermission::Execute) << endl;
perms = perms | FilePermission::Execute;
cout << "After adding Execute: " << permissionString(perms) << endl;
*/
}
// ============================================================================
// EXERCISE 3: Basic Struct (Beginner)
// ============================================================================
/**
* TODO: Create a struct called Vector2D with:
* - double x, y (coordinates)
* - double length() const - returns the magnitude
* - Vector2D normalize() const - returns unit vector
* - Vector2D operator+(const Vector2D& other) const
* - Vector2D operator-(const Vector2D& other) const
* - Vector2D operator*(double scalar) const
* - double dot(const Vector2D& other) const - dot product
* - void print() const - prints "(x, y)"
*/
// YOUR CODE HERE:
void exercise3_test() {
cout << "\n=== EXERCISE 3: Basic Struct ===" << endl;
// Uncomment to test:
/*
Vector2D v1{3.0, 4.0};
Vector2D v2{1.0, 2.0};
cout << "v1: "; v1.print();
cout << "v2: "; v2.print();
cout << "v1.length() = " << v1.length() << endl;
Vector2D v3 = v1 + v2;
cout << "v1 + v2 = "; v3.print();
Vector2D v4 = v1 - v2;
cout << "v1 - v2 = "; v4.print();
Vector2D v5 = v1 * 2.0;
cout << "v1 * 2 = "; v5.print();
cout << "v1.dot(v2) = " << v1.dot(v2) << endl;
Vector2D unit = v1.normalize();
cout << "v1.normalize() = "; unit.print();
cout << "Normalized length = " << unit.length() << endl;
*/
}
// ============================================================================
// EXERCISE 4: Nested Structs (Intermediate)
// ============================================================================
/**
* TODO: Design a library system with these structs:
*
* Author:
* - string firstName, lastName
* - int birthYear
* - string fullName() const
*
* Book:
* - string title
* - Author author
* - int year
* - string isbn
* - double price
* - void print() const
*
* Library:
* - string name
* - vector<Book> books
* - void addBook(const Book& book)
* - Book* findByISBN(const string& isbn)
* - vector<Book> findByAuthor(const string& lastName)
* - void printCatalog() const
*/
// YOUR CODE HERE:
void exercise4_test() {
cout << "\n=== EXERCISE 4: Nested Structs ===" << endl;
// Uncomment to test:
/*
Library lib{"City Library"};
lib.addBook({
"The C++ Programming Language",
{"Bjarne", "Stroustrup", 1950},
2013,
"978-0321563842",
59.99
});
lib.addBook({
"Effective Modern C++",
{"Scott", "Meyers", 1959},
2014,
"978-1491903995",
49.99
});
lib.printCatalog();
if (Book* book = lib.findByISBN("978-0321563842")) {
cout << "\nFound by ISBN: ";
book->print();
}
auto results = lib.findByAuthor("Meyers");
cout << "\nBooks by Meyers: " << results.size() << endl;
*/
}
// ============================================================================
// EXERCISE 5: Memory Layout Optimization (Intermediate)
// ============================================================================
/**
* TODO: Given this poorly-arranged struct, create an optimized version
* that uses less memory.
*
* Original (unoptimized):
* struct BadLayout {
* bool flag1; // 1 byte
* double value; // 8 bytes
* bool flag2; // 1 byte
* int count; // 4 bytes
* char letter; // 1 byte
* int id; // 4 bytes
* bool flag3; // 1 byte
* };
*
* Create:
* struct OptimizedLayout { ... };
*
* The optimized version should have the same members but arranged
* to minimize padding.
*/
struct BadLayout {
bool flag1;
double value;
bool flag2;
int count;
char letter;
int id;
bool flag3;
};
// YOUR CODE HERE:
// struct OptimizedLayout { ... };
void exercise5_test() {
cout << "\n=== EXERCISE 5: Memory Layout Optimization ===" << endl;
cout << "BadLayout size: " << sizeof(BadLayout) << " bytes" << endl;
// Uncomment to test:
/*
cout << "OptimizedLayout size: " << sizeof(OptimizedLayout) << " bytes" << endl;
cout << "Saved: " << (sizeof(BadLayout) - sizeof(OptimizedLayout)) << " bytes" << endl;
*/
}
// ============================================================================
// EXERCISE 6: Tagged Union (Intermediate)
// ============================================================================
/**
* TODO: Create a JSON-like value type using a tagged union:
*
* enum class JsonType { Null, Bool, Number, String, Array, Object };
*
* struct JsonValue {
* JsonType type;
* union { ... };
*
* // Factory methods
* static JsonValue null();
* static JsonValue boolean(bool b);
* static JsonValue number(double n);
* static JsonValue string(const char* s);
*
* // Type checks
* bool isNull() const;
* bool isBool() const;
* bool isNumber() const;
* bool isString() const;
*
* // Getters (should check type first)
* bool asBool() const;
* double asNumber() const;
* const char* asString() const;
*
* void print() const;
* };
*
* For simplicity, use a fixed char array for strings.
*/
// YOUR CODE HERE:
void exercise6_test() {
cout << "\n=== EXERCISE 6: Tagged Union ===" << endl;
// Uncomment to test:
/*
JsonValue values[] = {
JsonValue::null(),
JsonValue::boolean(true),
JsonValue::number(42.5),
JsonValue::string("hello")
};
for (const auto& v : values) {
v.print();
}
*/
}
// ============================================================================
// EXERCISE 7: std::variant Calculator (Intermediate)
// ============================================================================
/**
* TODO: Create a calculator that can handle different number types.
*
* using Number = std::variant<int, double, std::complex<double>>;
*
* Create functions:
* Number add(const Number& a, const Number& b)
* Number subtract(const Number& a, const Number& b)
* Number multiply(const Number& a, const Number& b)
* Number divide(const Number& a, const Number& b)
* void printNumber(const Number& n)
*
* The operations should work with any combination of types.
* When mixing types, promote to the more complex type.
*/
// YOUR CODE HERE:
void exercise7_test() {
cout << "\n=== EXERCISE 7: std::variant Calculator ===" << endl;
// Uncomment to test:
/*
Number a = 10;
Number b = 3.5;
cout << "a = "; printNumber(a);
cout << "b = "; printNumber(b);
cout << "a + b = "; printNumber(add(a, b));
cout << "a * b = "; printNumber(multiply(a, b));
cout << "a / b = "; printNumber(divide(a, b));
*/
}
// ============================================================================
// EXERCISE 8: Bit Fields for Protocol Header (Advanced)
// ============================================================================
/**
* TODO: Implement a simplified TCP header using bit fields:
*
* struct TCPHeader {
* uint16_t sourcePort; // 16 bits
* uint16_t destPort; // 16 bits
* uint32_t sequenceNum; // 32 bits
* uint32_t ackNum; // 32 bits
*
* // These should be bit fields packed into 16 bits:
* uint16_t dataOffset : 4; // 4 bits
* uint16_t reserved : 3; // 3 bits
* uint16_t ns : 1; // 1 bit (ECN-nonce)
* uint16_t cwr : 1; // 1 bit
* uint16_t ece : 1; // 1 bit
* uint16_t urg : 1; // 1 bit
* uint16_t ack : 1; // 1 bit
* uint16_t psh : 1; // 1 bit
* uint16_t rst : 1; // 1 bit
* uint16_t syn : 1; // 1 bit
* uint16_t fin : 1; // 1 bit
*
* uint16_t windowSize; // 16 bits
* uint16_t checksum; // 16 bits
* uint16_t urgentPointer; // 16 bits
*
* void print() const;
* void setFlag(const string& flagName, bool value);
* bool getFlag(const string& flagName) const;
* };
*
* Total size should be 20 bytes (160 bits).
*/
// YOUR CODE HERE:
void exercise8_test() {
cout << "\n=== EXERCISE 8: Bit Fields for Protocol Header ===" << endl;
// Uncomment to test:
/*
TCPHeader header = {};
header.sourcePort = 443;
header.destPort = 12345;
header.sequenceNum = 1000;
header.ackNum = 5000;
header.dataOffset = 5;
header.syn = 1;
header.ack = 1;
header.windowSize = 65535;
cout << "sizeof(TCPHeader) = " << sizeof(TCPHeader) << " bytes" << endl;
header.print();
cout << "\nSYN flag: " << header.getFlag("syn") << endl;
cout << "FIN flag: " << header.getFlag("fin") << endl;
*/
}
// ============================================================================
// EXERCISE 9: Shape Hierarchy with std::variant (Advanced)
// ============================================================================
/**
* TODO: Create a type-safe shape system without virtual functions.
*
* Structs for each shape:
* Circle { double radius; }
* Rectangle { double width, height; }
* Triangle { double a, b, c; } // sides
*
* using Shape = std::variant<Circle, Rectangle, Triangle>;
*
* Create visitor functions using std::visit:
* double area(const Shape& s)
* double perimeter(const Shape& s)
* string name(const Shape& s)
* void print(const Shape& s)
*
* Create a function to calculate total area of a vector of shapes.
*/
// YOUR CODE HERE:
void exercise9_test() {
cout << "\n=== EXERCISE 9: Shape Hierarchy with std::variant ===" << endl;
// Uncomment to test:
/*
std::vector<Shape> shapes = {
Circle{5.0},
Rectangle{4.0, 6.0},
Triangle{3.0, 4.0, 5.0}
};
for (const auto& shape : shapes) {
print(shape);
}
double total = 0;
for (const auto& shape : shapes) {
total += area(shape);
}
cout << "\nTotal area: " << total << endl;
*/
}
// ============================================================================
// EXERCISE 10: State Machine with Enum and Struct (Advanced)
// ============================================================================
/**
* TODO: Implement a traffic light state machine:
*
* enum class LightState { Red, Yellow, Green };
* enum class Event { Timer, Emergency, Reset };
*
* struct TrafficLight {
* LightState state;
* int redDuration;
* int yellowDuration;
* int greenDuration;
* int elapsedTime;
* bool emergencyMode;
*
* TrafficLight(int red, int yellow, int green);
*
* void processEvent(Event e);
* void tick(); // Advance time by 1 second
* bool shouldTransition() const;
* LightState nextState() const;
* void transition();
*
* string stateString() const;
* void print() const;
* };
*
* Normal flow: Red -> Green -> Yellow -> Red
* Emergency sets to Red and stays there until Reset
*/
// YOUR CODE HERE:
void exercise10_test() {
cout << "\n=== EXERCISE 10: State Machine ===" << endl;
// Uncomment to test:
/*
TrafficLight light(30, 5, 25); // Red: 30s, Yellow: 5s, Green: 25s
cout << "Initial state:" << endl;
light.print();
// Simulate some time passing
for (int i = 0; i < 35; i++) {
light.tick();
}
cout << "\nAfter 35 seconds:" << endl;
light.print();
// Test emergency
light.processEvent(Event::Emergency);
cout << "\nAfter emergency:" << endl;
light.print();
light.processEvent(Event::Reset);
cout << "\nAfter reset:" << endl;
light.print();
*/
}
// ============================================================================
// CHALLENGE: Entity Component System (Expert)
// ============================================================================
/**
* TODO: Implement a simple Entity Component System (ECS):
*
* Components (structs):
* Position { float x, y, z; }
* Velocity { float dx, dy, dz; }
* Health { int current, max; }
* Render { string mesh; string texture; }
*
* using Component = std::variant<Position, Velocity, Health, Render>;
*
* struct Entity {
* uint32_t id;
* std::vector<Component> components;
*
* template<typename T>
* void addComponent(const T& comp);
*
* template<typename T>
* T* getComponent();
*
* template<typename T>
* bool hasComponent() const;
*
* template<typename T>
* void removeComponent();
* };
*
* struct World {
* std::vector<Entity> entities;
* uint32_t nextId;
*
* Entity& createEntity();
* void destroyEntity(uint32_t id);
*
* // Process all entities with Position and Velocity
* void movementSystem(float deltaTime);
*
* // Process all entities with Health
* void healthSystem();
* };
*/
// YOUR CODE HERE:
void exercise_challenge_test() {
cout << "\n=== CHALLENGE: Entity Component System ===" << endl;
// Uncomment to test:
/*
World world;
// Create player entity
Entity& player = world.createEntity();
player.addComponent(Position{0, 0, 0});
player.addComponent(Velocity{1, 0, 0});
player.addComponent(Health{100, 100});
player.addComponent(Render{"player.obj", "player.png"});
// Create enemy entity
Entity& enemy = world.createEntity();
enemy.addComponent(Position{10, 0, 5});
enemy.addComponent(Velocity{-1, 0, 0});
enemy.addComponent(Health{50, 50});
cout << "Initial state:" << endl;
for (const auto& e : world.entities) {
if (auto* pos = e.getComponent<Position>()) {
cout << "Entity " << e.id << " at ("
<< pos->x << ", " << pos->y << ", " << pos->z << ")" << endl;
}
}
// Simulate
for (int i = 0; i < 5; i++) {
world.movementSystem(1.0f);
}
cout << "\nAfter 5 seconds:" << endl;
for (const auto& e : world.entities) {
if (auto* pos = e.getComponent<Position>()) {
cout << "Entity " << e.id << " at ("
<< pos->x << ", " << pos->y << ", " << pos->z << ")" << endl;
}
}
*/
}
// ============================================================================
// MAIN
// ============================================================================
int main() {
cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ ENUMS, STRUCTS, UNIONS - EXERCISES ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
exercise1_test();
exercise2_test();
exercise3_test();
exercise4_test();
exercise5_test();
exercise6_test();
exercise7_test();
exercise8_test();
exercise9_test();
exercise10_test();
exercise_challenge_test();
cout << "\n═══════════════════════════════════════════════════════════════" << endl;
cout << "Complete the exercises by implementing the TODO sections!" << endl;
cout << "Uncomment the test code after implementing each exercise." << endl;
return 0;
}