From 83a8ae2b51513442d3610bcf043dc80da4d20f6f Mon Sep 17 00:00:00 2001
From: KabaevaNadezhda <nekabaeva@edu.hse.ru>
Date: Thu, 20 Mar 2025 17:40:48 +0300
Subject: [PATCH] Middle Commit

---
 Button.cpp                                    | 10 +-
 Button.h                                      |  4 +-
 CMakeLists.txt                                |  2 +-
 CommonBuilder.cpp                             | 65 ++++++++++++
 CommonBuilder.h                               | 34 +++++++
 ComplexBuilder.cpp                            | 50 ++++++++++
 ComplexBuilder.h                              | 15 +++
 Enemy.cpp                                     | 12 +--
 Enemy.h                                       |  7 +-
 Food.h                                        |  3 +-
 GameBuilderDirector.cpp                       | 23 +++--
 GameBuilderDirector.h                         | 18 +++-
 GameContext.cpp                               | 37 +++----
 GameContext.h                                 | 18 ++--
 GameState.cpp                                 | 26 +++--
 GameState.h                                   |  3 +-
 IGameBuilder.h                                | 20 ++++
 Maze.cpp                                      | 10 ++
 Maze.h                                        |  8 +-
 Menu.cpp                                      | 99 +++++++++++--------
 Menu.h                                        | 21 ++--
 Pacman.cpp                                    |  7 +-
 Pacman.h                                      |  1 +
 SelectState.cpp                               | 27 ++---
 SelectState.h                                 |  2 +-
 SimpleBuilder.cpp                             | 50 ++++++++++
 SimpleBuilder.h                               | 15 +++
 ...\320\271 \321\204\320\260\320\271\320\273" |  0
 28 files changed, 442 insertions(+), 145 deletions(-)
 create mode 100644 CommonBuilder.cpp
 create mode 100644 CommonBuilder.h
 create mode 100644 ComplexBuilder.cpp
 create mode 100644 ComplexBuilder.h
 create mode 100644 IGameBuilder.h
 create mode 100644 SimpleBuilder.cpp
 create mode 100644 SimpleBuilder.h
 create mode 100644 "\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273"

diff --git a/Button.cpp b/Button.cpp
index 22e4c13..cfc6b52 100644
--- a/Button.cpp
+++ b/Button.cpp
@@ -1,9 +1,9 @@
 // Button.cpp
 #include "Button.h"
 
-Button::Button() : m_ptr_command(nullptr), m_defaultFillColor(sf::Color::Black), m_selectedFillColor(sf::Color(70, 70, 150)) {}
+Button::Button() : m_command(*(ISelectCommand*)nullptr), m_defaultFillColor(sf::Color::Black), m_selectedFillColor(sf::Color(70, 70, 150)) {} // Provide a default value
 
-void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand* ptr_command) {
+void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand& command) {
     m_rectangle.setPosition(pos);
     m_rectangle.setSize(button_size);
     m_rectangle.setFillColor(m_defaultFillColor); // Default fill color
@@ -16,7 +16,7 @@ void Button::set(sf::Vector2f pos, sf::Vector2f button_size, const std::string&
     m_text.setFillColor(sf::Color::White); // White text color
     m_text.setPosition(pos.x + button_size.x / 2 - m_text.getLocalBounds().width / 2, pos.y + button_size.y / 2 - m_text.getLocalBounds().height / 2 - font_size / 4);
 
-    m_ptr_command = ptr_command;
+    m_command = command;
 }
 
 bool Button::is_position_in(sf::Vector2f pos) const {
@@ -24,9 +24,7 @@ bool Button::is_position_in(sf::Vector2f pos) const {
 }
 
 void Button::push() {
-    if (m_ptr_command) {
-        m_ptr_command->execute();
-    }
+    m_command.execute();
 }
 
 void Button::draw_into(sf::RenderWindow& window) {
diff --git a/Button.h b/Button.h
index be4b493..c287872 100644
--- a/Button.h
+++ b/Button.h
@@ -10,13 +10,13 @@ class Button {
 private:
     sf::Text            m_text;
     sf::RectangleShape  m_rectangle;
-    ISelectCommand* m_ptr_command;
+    ISelectCommand& m_command; // Changed to a reference
     sf::Color           m_defaultFillColor;
     sf::Color           m_selectedFillColor;
 
 public:
     Button();
-    void set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand* ptr_command);
+    void set(sf::Vector2f pos, sf::Vector2f button_size, const std::string& text, unsigned int font_size, ISelectCommand& command);
     bool is_position_in(sf::Vector2f pos) const;
     void push();
     void draw_into(sf::RenderWindow& window);
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fae7003..c30bcc2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@ add_executable(aip_lab3 "aip_lab3.cpp" "IState.h" "Application.h"
                         "ExampleState.h" "IWindowKeeper.h" 
                         "ExitState.h" "SelectState.h" 
                         "GameState.h" "StateManager.h" 
-                        "Button.h" "Button.cpp" "Menu.cpp" "SelectState.cpp" "MyFont.h" "MyFont.cpp" "ISelectCommand.h" "StartGameCommand.h" "StartGameCommand.cpp" "ExitCommand.h" "ExitCommand.cpp" "StateManager.cpp" "GameState.cpp" "ExitState.cpp" "ChangeStateCommand.h" "GameCommand.h" "GameCommand.cpp" "GameBuilderDirector.h" "GameBuilderDirector.cpp" "GameBuilder.h" "SimpleGameBuilder.h" "SimpleGameBuilder.cpp" "ChangeStateCommand.cpp" "IRoomSide.h" "Wall.h" "Wall.cpp" "Room.h" "Room.cpp" "Maze.h" "Maze.cpp" "IEntity.h" "Pass.h" "Pass.cpp" "IPreparable.h" "Pacman.h" "Pacman.cpp" "IStaticEntity.h" "IDynamicEntity.h" "Food.h" "Food.cpp" "Enemy.h" "Enemy.cpp" "GameContext.h" "GameContext.cpp" "ContextManager.h" "ContextManager.cpp")
+                        "Button.h" "Button.cpp" "Menu.cpp" "SelectState.cpp" "MyFont.h" "MyFont.cpp" "ISelectCommand.h" "StartGameCommand.h" "StartGameCommand.cpp" "ExitCommand.h" "ExitCommand.cpp" "StateManager.cpp" "GameState.cpp" "ExitState.cpp" "ChangeStateCommand.h" "GameCommand.h" "GameCommand.cpp" "GameBuilderDirector.h" "GameBuilderDirector.cpp" "GameBuilder.h" "SimpleGameBuilder.h" "SimpleGameBuilder.cpp" "ChangeStateCommand.cpp" "IRoomSide.h" "Wall.h" "Wall.cpp" "Room.h" "Room.cpp" "Maze.h" "Maze.cpp" "IEntity.h" "Pass.h" "Pass.cpp" "IPreparable.h" "Pacman.h" "Pacman.cpp" "IStaticEntity.h" "IDynamicEntity.h" "Food.h" "Food.cpp" "Enemy.h" "Enemy.cpp" "GameContext.h" "GameContext.cpp" "ContextManager.h" "ContextManager.cpp" "IGameBuilder.h" "CommonBuilder.h" "CommonBuilder.cpp" "SimpleBuilder.h" "SimpleBuilder.cpp" "ComplexBuilder.h" "ComplexBuilder.cpp")
 
 
 include(FetchContent) 
diff --git a/CommonBuilder.cpp b/CommonBuilder.cpp
new file mode 100644
index 0000000..09e1d5d
--- /dev/null
+++ b/CommonBuilder.cpp
@@ -0,0 +1,65 @@
+#include "CommonBuilder.h"
+#include "Room.h"
+#include "Wall.h"
+#include "Pass.h"
+#include "Pacman.h"
+#include "Maze.h"
+#include <random>
+#include <iostream>
+
+CommonBuilder::CommonBuilder(int width, int height, int room_size)
+    : m_width(width), m_height(height), m_room_size(room_size), m_dynamic_objects_ratio(0.0f), m_context(nullptr) {
+}
+
+CommonBuilder::~CommonBuilder() {
+    for (Room* room : m_rooms) {
+        delete room;
+    }
+}
+
+void CommonBuilder::create_context(float dynamic_objects_ratio) {
+    // Create Pacman (place him in the first room)
+    auto pacman = std::make_unique<Pacman>(m_rooms[0]);
+    // Create Maze
+    auto maze = std::make_unique<Maze>();
+    for (Room* room : m_rooms) {
+        maze->addRoom(room);
+    }
+
+    m_context = std::make_unique<GameContext>(std::move(pacman), std::move(maze));
+    m_dynamic_objects_ratio = dynamic_objects_ratio;
+
+    // Add static entities (food) to rooms
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::uniform_real_distribution<> distrib(0.0, 1.0);
+
+    for (Room* room : m_rooms) {
+        // Add food randomly
+        if (distrib(gen) < 0.5) { // Adjust probability
+            m_context->getStaticObjects().push_back(std::make_unique<Food>(room));
+        }
+    }
+    //Add enemies to rooms
+    for (Room* room : m_rooms) {
+        // Add enemies randomly
+        if (distrib(gen) < m_dynamic_objects_ratio) { // Adjust probability
+            m_context->getDynamicObjects().push_back(std::make_unique<Enemy>(room));
+        }
+    }
+}
+
+void CommonBuilder::create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) {
+    m_game_state = new GameState(state_manager);
+}
+
+void CommonBuilder::set_all_to_state() {
+    if (m_game_state) {
+        //m_game_state->set_maze(new Maze(*m_context.getMaze()));  // Remove this line
+        m_game_state->set_context(std::move(*m_context));
+    }
+}
+
+GameState* CommonBuilder::get_game() {
+    return m_game_state;
+}
\ No newline at end of file
diff --git a/CommonBuilder.h b/CommonBuilder.h
new file mode 100644
index 0000000..d4113c3
--- /dev/null
+++ b/CommonBuilder.h
@@ -0,0 +1,34 @@
+#ifndef COMMONBUILDER_H
+#define COMMONBUILDER_H
+
+#include "IGameBuilder.h"
+#include "Maze.h"
+#include "GameContext.h"
+#include <vector>
+#include "Room.h"
+#include "IStaticEntity.h"
+#include "Food.h"
+#include "Enemy.h"
+#include <random>
+
+class CommonBuilder : public IGameBuilder {
+protected:
+    int m_width;
+    int m_height;
+    int m_room_size;
+    std::vector<Room*> m_rooms; // Store rooms
+    std::unique_ptr<GameContext> m_context; // Context to build
+    GameState* m_game_state; // GameState to build
+    float m_dynamic_objects_ratio;
+
+public:
+    CommonBuilder(int width, int height, int room_size);
+    ~CommonBuilder() override;
+
+    void create_context(float dynamic_objects_ratio) override;
+    void create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) override;
+    void set_all_to_state() override;
+    GameState* get_game() override;
+};
+
+#endif
\ No newline at end of file
diff --git a/ComplexBuilder.cpp b/ComplexBuilder.cpp
new file mode 100644
index 0000000..29f3e84
--- /dev/null
+++ b/ComplexBuilder.cpp
@@ -0,0 +1,50 @@
+#include "ComplexBuilder.h"
+#include "Room.h"
+#include "Wall.h"
+#include "Pass.h"
+#include <iostream>
+
+ComplexBuilder::ComplexBuilder(int width, int height, int room_size) : CommonBuilder(width, height, room_size) {}
+
+ComplexBuilder::~ComplexBuilder() {}
+
+void ComplexBuilder::create_rooms() {
+    // Create a 3x3 grid of rooms
+    for (int y = 0; y < 3; ++y) {
+        for (int x = 0; x < 3; ++x) {
+            int roomId = y * 3 + x;
+            Room* room = new Room(roomId);
+            m_rooms.push_back(room);
+        }
+    }
+}
+
+void ComplexBuilder::set_rooms_sides() {
+    // Connect rooms with walls and passes
+    for (int y = 0; y < 3; ++y) {
+        for (int x = 0; x < 3; ++x) {
+            int roomId = y * 3 + x;
+            Room* room = m_rooms[roomId];
+
+            // Create walls
+            for (int dir = Room::LEFT; dir <= Room::DOWN; ++dir) {
+                Room::Direction direction = static_cast<Room::Direction>(dir);
+                room->setSide(direction, new Wall(room));
+            }
+
+            // Connect rooms with passes
+            if (x < 2) {
+                // Connect rooms horizontally
+                Pass* pass = new Pass(room, m_rooms[roomId + 1]);
+                room->setSide(Room::RIGHT, pass);
+                m_rooms[roomId + 1]->setSide(Room::LEFT, pass);
+            }
+            if (y < 2) {
+                // Connect rooms vertically
+                Pass* pass = new Pass(room, m_rooms[roomId + 3]);
+                room->setSide(Room::DOWN, pass);
+                m_rooms[roomId + 3]->setSide(Room::UP, pass);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ComplexBuilder.h b/ComplexBuilder.h
new file mode 100644
index 0000000..3f1b2bb
--- /dev/null
+++ b/ComplexBuilder.h
@@ -0,0 +1,15 @@
+#ifndef COMPLEXBUILDER_H
+#define COMPLEXBUILDER_H
+
+#include "CommonBuilder.h"
+
+class ComplexBuilder : public CommonBuilder {
+public:
+    ComplexBuilder(int width, int height, int room_size);
+    ~ComplexBuilder() override;
+
+    void create_rooms() override;
+    void set_rooms_sides() override;
+};
+
+#endif
\ No newline at end of file
diff --git a/Enemy.cpp b/Enemy.cpp
index 4b5926a..d3d19cd 100644
--- a/Enemy.cpp
+++ b/Enemy.cpp
@@ -1,7 +1,6 @@
-//Enemy.cpp
 #include "Enemy.h"
 #include "Room.h"
-#include "IRoomSide.h" // Include IRoomSide
+#include "IRoomSide.h"
 #include <iostream>
 
 Enemy::Enemy(Room* startRoom) : m_location(startRoom) {
@@ -10,8 +9,8 @@ Enemy::Enemy(Room* startRoom) : m_location(startRoom) {
     prepare_for_drawing();
 }
 
-//Enemy's Copy Constructor
-Enemy::Enemy(const Enemy& other) : m_location(other.m_location), m_shape(other.m_shape) {}
+// Copy constructor
+Enemy::Enemy(const Enemy& other) : m_location(other.m_location), m_shape(other.m_shape), m_stopwatch(other.m_stopwatch) {}
 
 Enemy::~Enemy() {}
 
@@ -27,7 +26,7 @@ void Enemy::setRoom(Room* room) {
 void Enemy::action() {
     auto milliseconds = static_cast<size_t>(m_stopwatch.getElapsedTime().asMilliseconds());
     if (milliseconds < rand() % 5000) {
-        return; // Enemy does nothing
+        return;
     }
 
     if (m_location) {
@@ -53,7 +52,6 @@ void Enemy::draw_into(sf::RenderWindow& window) {
 
 void Enemy::prepare_for_drawing() {
     if (m_location) {
-        // Example: Position enemy in the corner of the room
-        m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 10, 100 + (m_location->getId() * 100 / 500 * 100) + 10); // 10 is offset
+        m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 10, 100 + (m_location->getId() * 100 / 500 * 100) + 10);
     }
 }
\ No newline at end of file
diff --git a/Enemy.h b/Enemy.h
index ae06edb..cb0be8b 100644
--- a/Enemy.h
+++ b/Enemy.h
@@ -1,21 +1,20 @@
-//Enemy.h
 #ifndef ENEMY_H
 #define ENEMY_H
 
 #include "IDynamicEntity.h"
 #include "Room.h"
 #include <SFML/Graphics.hpp>
-#include <SFML/System.hpp> // Required for sf::Clock
+#include <SFML/System.hpp>
 
 class Enemy : public IDynamicEntity {
 private:
     Room* m_location;
-    sf::RectangleShape m_shape; // Visual representation
+    sf::RectangleShape m_shape;
     sf::Clock m_stopwatch;
 
 public:
     Enemy(Room* startRoom);
-    Enemy(const Enemy& other);
+    Enemy(const Enemy& other); // Copy constructor
     ~Enemy() override;
 
     Room* getRoom() const override;
diff --git a/Food.h b/Food.h
index 22a0e25..bc3f228 100644
--- a/Food.h
+++ b/Food.h
@@ -5,6 +5,7 @@
 #include "IStaticEntity.h"
 #include <SFML/Graphics.hpp>
 
+// Food.h
 class Food : public IStaticEntity {
 private:
     Room* m_location;
@@ -12,7 +13,7 @@ private:
 
 public:
     Food(Room* startRoom);
-    Food(const Food& other);
+    Food(const Food& other); // Copy constructor
     ~Food() override;
 
     Room* getRoom() const override;
diff --git a/GameBuilderDirector.cpp b/GameBuilderDirector.cpp
index 764c9b1..6a1c6a5 100644
--- a/GameBuilderDirector.cpp
+++ b/GameBuilderDirector.cpp
@@ -1,14 +1,23 @@
-// GameBuilderDirector.cpp
 #include "GameBuilderDirector.h"
-#include "GameBuilder.h" // Forward declaration
+#include "GameState.h" // Include GameState
+#include <iostream>
 
-GameBuilderDirector::GameBuilderDirector(GameBuilder* builder) : m_builder(builder) {}
+GameBuilderDirector::GameBuilderDirector(IGameBuilder* builder, sf::VideoMode mode, std::string window_title, float dynamic_objects_ratio, IStateManager& state_manager)
+    : m_builder(builder), m_mode(mode), m_window_title(window_title), m_dynamic_objects_ratio(dynamic_objects_ratio), m_state_manager(state_manager) {
+}
 
 GameBuilderDirector::~GameBuilderDirector() {}
 
-void GameBuilderDirector::constructGame(int difficulty) {
-    if (m_builder) {
-        m_builder->buildLevel(difficulty);
-        // More building steps using the builder
+GameState* GameBuilderDirector::build() {
+    if (!m_builder) {
+        std::cerr << "Error: No builder assigned to the director!" << std::endl;
+        return nullptr;
     }
+
+    m_builder->create_rooms();
+    m_builder->set_rooms_sides();
+    m_builder->create_context(m_dynamic_objects_ratio);
+    m_builder->create_state(m_state_manager, m_mode, m_window_title);
+    m_builder->set_all_to_state();
+    return m_builder->get_game();
 }
\ No newline at end of file
diff --git a/GameBuilderDirector.h b/GameBuilderDirector.h
index 2e61457..465b6cb 100644
--- a/GameBuilderDirector.h
+++ b/GameBuilderDirector.h
@@ -1,16 +1,24 @@
-// GameBuilderDirector.h
 #ifndef GAMEBUILDERDIRECTOR_H
 #define GAMEBUILDERDIRECTOR_H
 
-class GameBuilder; // Forward declaration
+#include "IGameBuilder.h"
+#include "IStateManager.h"
+#include <SFML/Graphics.hpp>
+#include "GameState.h"
 
 class GameBuilderDirector {
 private:
-    GameBuilder* m_builder;
+    IGameBuilder* m_builder;
+    sf::VideoMode m_mode;
+    std::string m_window_title;
+    float m_dynamic_objects_ratio;
+    IStateManager& m_state_manager;
+
 public:
-    GameBuilderDirector(GameBuilder* builder);
+    GameBuilderDirector(IGameBuilder* builder, sf::VideoMode mode, std::string window_title, float dynamic_objects_ratio, IStateManager& state_manager);
     ~GameBuilderDirector();
-    void constructGame(int difficulty); // Difficulty levels: 1, 2, 3
+
+    GameState* build();
 };
 
 #endif
\ No newline at end of file
diff --git a/GameContext.cpp b/GameContext.cpp
index 51ae257..a4922da 100644
--- a/GameContext.cpp
+++ b/GameContext.cpp
@@ -1,49 +1,40 @@
 #include "GameContext.h"
-#include "Food.h"     // Include Food
-#include "Enemy.h"    // Include Enemy
+#include "Food.h"
+#include "Enemy.h"
 #include "Maze.h"
 
-GameContext::GameContext(Pacman* pacman, Maze* maze) : m_pacman(pacman), m_maze(maze) {}
+GameContext::GameContext(std::unique_ptr<Pacman> pacman, std::unique_ptr<Maze> maze)
+    : m_pacman(std::move(pacman)), m_maze(std::move(maze)) {
+}
 
-// Copy constructor
 GameContext::GameContext(const GameContext& other) : m_state(other.m_state) {
-    // Copy Pacman
-    m_pacman = new Pacman(*other.m_pacman); // Use Pacman's copy constructor
-
-    // Copy Maze
-    m_maze = new Maze(*other.m_maze);
+    m_pacman = std::make_unique<Pacman>(*other.m_pacman);
+    m_maze = std::make_unique<Maze>(*other.m_maze);
 
-    // Clone static objects
     for (const auto& static_obj : other.m_static_objects) {
-        // Check if the static_obj is a Food object, and create a Food clone
         if (auto food = dynamic_cast<Food*>(static_obj.get())) {
-            m_static_objects.push_back(std::make_unique<Food>(*food)); //Use Food's copy constructor
+            m_static_objects.push_back(std::make_unique<Food>(*food));
         }
     }
 
-    // Clone dynamic objects
     for (const auto& dynamic_obj : other.m_dynamic_objects) {
-        // Check if the dynamic_obj is an Enemy object, and create a Enemy clone
         if (auto enemy = dynamic_cast<Enemy*>(dynamic_obj.get())) {
-            m_dynamic_objects.push_back(std::make_unique<Enemy>(*enemy)); //Use Enemy's copy constructor
+            m_dynamic_objects.push_back(std::make_unique<Enemy>(*enemy));
         }
     }
 }
 
-GameContext::~GameContext() {
-    delete m_pacman;
-    delete m_maze;
-}
+GameContext::~GameContext() {}
 
 Pacman* GameContext::getPacman() const {
-    return m_pacman;
+    return m_pacman.get();
 }
 
-const std::vector<std::unique_ptr<IStaticEntity>>& GameContext::getStaticObjects() const {
+std::vector<std::unique_ptr<IStaticEntity>>& GameContext::getStaticObjects() {  // <--- Changed
     return m_static_objects;
 }
 
-const std::vector<std::unique_ptr<IDynamicEntity>>& GameContext::getDynamicObjects() const {
+std::vector<std::unique_ptr<IDynamicEntity>>& GameContext::getDynamicObjects() {  // <--- Changed
     return m_dynamic_objects;
 }
 
@@ -56,5 +47,5 @@ void GameContext::setState(State state) {
 }
 
 Maze* GameContext::getMaze() const {
-    return m_maze;
+    return m_maze.get();
 }
\ No newline at end of file
diff --git a/GameContext.h b/GameContext.h
index dbd94d6..2c15871 100644
--- a/GameContext.h
+++ b/GameContext.h
@@ -2,7 +2,7 @@
 #define GAMECONTEXT_H
 
 #include <vector>
-#include <memory> // For std::unique_ptr
+#include <memory>
 #include "Pacman.h"
 #include "IStaticEntity.h"
 #include "IDynamicEntity.h"
@@ -13,27 +13,23 @@ public:
     enum class State { INGAME, WIN, LOST };
 
 private:
-    Pacman* m_pacman;
+    std::unique_ptr<Pacman> m_pacman;
     std::vector<std::unique_ptr<IStaticEntity>> m_static_objects;
     std::vector<std::unique_ptr<IDynamicEntity>> m_dynamic_objects;
     State m_state = State::INGAME;
-    Maze* m_maze; // Add Maze
+    std::unique_ptr<Maze> m_maze;
 
 public:
-    GameContext(Pacman* pacman, Maze* maze); // Add Maze
-    GameContext(const GameContext& other); // Copy constructor
+    GameContext(std::unique_ptr<Pacman> pacman, std::unique_ptr<Maze> maze);
+    GameContext(const GameContext& other);
     ~GameContext();
 
-    // Getters and setters
     Pacman* getPacman() const;
-    const std::vector<std::unique_ptr<IStaticEntity>>& getStaticObjects() const;
-    const std::vector<std::unique_ptr<IDynamicEntity>>& getDynamicObjects() const;
+    std::vector<std::unique_ptr<IStaticEntity>>& getStaticObjects();  // <--- Changed
+    std::vector<std::unique_ptr<IDynamicEntity>>& getDynamicObjects();  // <--- Changed
     State getState() const;
     void setState(State state);
-
-    // Add Maze
     Maze* getMaze() const;
-
 };
 
 #endif
\ No newline at end of file
diff --git a/GameState.cpp b/GameState.cpp
index ef17d9b..d8a7a40 100644
--- a/GameState.cpp
+++ b/GameState.cpp
@@ -19,17 +19,31 @@ bool GameState::do_step(IStateManager& state_manager) {
             window.close();
         }
     }
-
-    window.clear(sf::Color::Green);
-    window.display();
-
+    render();
     return window.isOpen();
 }
+
 //set maze using r-value reference
-void GameState::set_maze(Maze&& maze) {
-    m_maze = new Maze(maze);
+void GameState::set_maze(Maze* maze) {
+    m_maze = maze;
 }
 //set context using r-value reference
 void GameState::set_context(GameContext&& context) {
     m_context_manager.reset(std::move(context));
+}
+
+void GameState::render() {
+    window.clear(sf::Color::Green);
+    ContextManager& contextManager = m_context_manager;
+    GameContext& context = contextManager.get_current_context();
+    Maze* maze = context.getMaze();
+    if (maze) {
+        maze->draw_into(window);
+    }
+    Pacman* pacman = context.getPacman();
+    if (pacman) {
+        pacman->draw_into(window);
+    }
+
+    window.display();
 }
\ No newline at end of file
diff --git a/GameState.h b/GameState.h
index 754f49d..aa3d861 100644
--- a/GameState.h
+++ b/GameState.h
@@ -19,8 +19,9 @@ public:
     ~GameState() override;
     bool do_step(IStateManager& state_manager) override;
 
-    void set_maze(Maze&& maze);
+    void set_maze(Maze* maze);
     void set_context(GameContext&& context);
+    void render(); // Add render method
 };
 
 #endif
\ No newline at end of file
diff --git a/IGameBuilder.h b/IGameBuilder.h
new file mode 100644
index 0000000..baf39b9
--- /dev/null
+++ b/IGameBuilder.h
@@ -0,0 +1,20 @@
+#ifndef IGAMEBUILDER_H
+#define IGAMEBUILDER_H
+
+#include "Maze.h"       // Include Maze
+#include "GameContext.h" // Include GameContext
+#include "IStateManager.h" // Include
+#include "GameState.h"
+
+class IGameBuilder {
+public:
+    virtual ~IGameBuilder() {}
+    virtual void create_rooms() = 0;
+    virtual void set_rooms_sides() = 0;
+    virtual void create_context(float dynamic_objects_ratio) = 0; // Ratio of dynamic objects
+    virtual void create_state(IStateManager& state_manager, sf::VideoMode mode, std::string window_title) = 0;
+    virtual void set_all_to_state() = 0;
+    virtual GameState* get_game() = 0;
+};
+
+#endif
\ No newline at end of file
diff --git a/Maze.cpp b/Maze.cpp
index 88c58b7..be09439 100644
--- a/Maze.cpp
+++ b/Maze.cpp
@@ -8,6 +8,11 @@ Maze::~Maze() {
         delete room;
     }
 }
+Maze::Maze(const Maze& other) {
+    for (Room* room : other.m_rooms) {
+        m_rooms.push_back(new Room(*room));
+    }
+}
 
 void Maze::addRoom(Room* room) {
     m_rooms.push_back(room);
@@ -20,4 +25,9 @@ Room* Maze::getRoom(int id) const {
         }
     }
     return nullptr; // Room not found
+}
+void Maze::draw_into(sf::RenderWindow& window) {
+    for (Room* room : m_rooms) {
+        room->draw_into(window);
+    }
 }
\ No newline at end of file
diff --git a/Maze.h b/Maze.h
index 872d81f..c61dd5d 100644
--- a/Maze.h
+++ b/Maze.h
@@ -1,18 +1,22 @@
+//Maze.h
 #ifndef MAZE_H
 #define MAZE_H
 
 #include <vector>
 #include "Room.h"
+#include "IDrawable.h"
 
-class Maze {
+class Maze : public IDrawable {
 private:
     std::vector<Room*> m_rooms;
 public:
     Maze();
     ~Maze();
+    Maze(const Maze& other);
 
     void addRoom(Room* room);
     Room* getRoom(int id) const;
+    void draw_into(sf::RenderWindow& window) override;
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Menu.cpp b/Menu.cpp
index 700a9ef..f1d7a2e 100644
--- a/Menu.cpp
+++ b/Menu.cpp
@@ -1,44 +1,68 @@
-//Menu.cpp
 #include "Menu.h"
 #include "StartGameCommand.h"
 #include "ExitCommand.h"
-#include "GameCommand.h" // Include
+#include "GameCommand.h"
+#include "SimpleBuilder.h"
+#include "ComplexBuilder.h"
+#include "GameBuilderDirector.h"
 #include <iostream>
+#include <SFML/Window/VideoMode.hpp>
+#include <memory>
 
-Menu::Menu(IStateManager& state_manager) : m_state_manager(state_manager) {
-    // Example buttons (you can add more)
-    addButton(100, 100, 200, 50, "Easy");
-    addButton(100, 200, 200, 50, "Medium");
-    addButton(100, 300, 200, 50, "Hard");
-    addButton(100, 400, 200, 50, "Exit");
+Menu::Menu(IStateManager& state_manager) : m_state_manager(state_manager), m_buttons(MAX_BUTTONS) {
+    addButton(100, 100, 200, 50, "Easy", 0.2f);
+    addButton(100, 180, 200, 50, "Medium", 0.4f);
+    addButton(100, 260, 200, 50, "Hard", 0.6f);
+    addButton(100, 340, 200, 50, "Exit", 0.0f); // Exit doesn't need dynamic_objects_ratio
 }
 
-void Menu::addButton(float x, float y, float width, float height, const std::string& text) {
+void Menu::addButton(float x, float y, float width, float height, const std::string& text, float dynamic_objects_ratio) {
     if (m_buttonCount < m_buttons.size()) {
-        ISelectCommand* command = nullptr;
-        if (text == "Easy" || text == "Medium" || text == "Hard") {
-            // Create a GameBuilderDirector and GameBuilder
-            SimpleGameBuilder* builder = new SimpleGameBuilder();
-            GameBuilderDirector* director = new GameBuilderDirector(builder);
-            command = new GameCommand(m_state_manager, director);
+        std::unique_ptr<ISelectCommand> command;
+        GameBuilderDirector* director = nullptr;
+
+        if (text == "Easy") {
+            SimpleBuilder* builder = new SimpleBuilder(2, 2, 100);
+            director = new GameBuilderDirector(
+                builder,
+                sf::VideoMode(800, 600),
+                "Pacman - Easy",
+                dynamic_objects_ratio,
+                m_state_manager
+            );
+            command = std::make_unique<GameCommand>(m_state_manager, director);
+        }
+        else if (text == "Medium") {
+            ComplexBuilder* builder = new ComplexBuilder(3, 3, 100);
+            director = new GameBuilderDirector(
+                builder,
+                sf::VideoMode(800, 600),
+                "Pacman - Medium",
+                dynamic_objects_ratio,
+                m_state_manager
+            );
+            command = std::make_unique<GameCommand>(m_state_manager, director);
+        }
+        else if (text == "Hard") {
+            ComplexBuilder* builder = new ComplexBuilder(3, 3, 100);
+            director = new GameBuilderDirector(
+                builder,
+                sf::VideoMode(800, 600),
+                "Pacman - Hard",
+                dynamic_objects_ratio,
+                m_state_manager
+            );
+            command = std::make_unique<GameCommand>(m_state_manager, director);
         }
         else if (text == "Exit") {
-            command = new ExitCommand();
+            command = std::make_unique<ExitCommand>();
         }
-        m_buttons[m_buttonCount].set(sf::Vector2f(x, y), sf::Vector2f(width, height), text, 24, command);
+
+        m_buttons[m_buttonCount].set(sf::Vector2f(x, y), sf::Vector2f(width, height), text, 24, *command);
         m_buttonCount++;
-    }
-}
 
-bool Menu::handleMouseClick(sf::Vector2i mousePosition) {
-    sf::Vector2f mousePosF(static_cast<float>(mousePosition.x), static_cast<float>(mousePosition.y));
-    for (size_t i = 0; i < m_buttonCount; ++i) {
-        if (m_buttons[i].is_position_in(mousePosF)) {
-            m_buttons[i].push();
-            return true; // Click handled
-        }
+        if (director) delete director;
     }
-    return false; // No button clicked
 }
 
 void Menu::draw_into(sf::RenderWindow& window) {
@@ -47,24 +71,13 @@ void Menu::draw_into(sf::RenderWindow& window) {
     }
 }
 
-void Menu::handleMouseMove(sf::Vector2i mousePosition) {
-    sf::Vector2f mousePosF(static_cast<float>(mousePosition.x), static_cast<float>(mousePosition.y));
-    Button* newSelectedButton = nullptr;
-
+bool Menu::handleMouseClick(const sf::Vector2i& mousePos) {
+    sf::Vector2f mousePosF(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
     for (size_t i = 0; i < m_buttonCount; ++i) {
         if (m_buttons[i].is_position_in(mousePosF)) {
-            newSelectedButton = &m_buttons[i];
-            break;
-        }
-    }
-
-    if (newSelectedButton != m_selectedButton) {
-        if (m_selectedButton) {
-            m_selectedButton->select(false); // Unselect previous button
-        }
-        if (newSelectedButton) {
-            newSelectedButton->select(true); // Select current button
+            m_buttons[i].push();
+            return true; // Click handled
         }
-        m_selectedButton = newSelectedButton;
     }
+    return false; // No button clicked
 }
\ No newline at end of file
diff --git a/Menu.h b/Menu.h
index 1eecc2b..269097c 100644
--- a/Menu.h
+++ b/Menu.h
@@ -1,27 +1,24 @@
-//Menu.h
 #ifndef MENU_H
 #define MENU_H
 
-#include <SFML/Graphics.hpp>
-#include <array>
-#include "Button.h"
-#include "GameBuilderDirector.h" // Include
 #include "IStateManager.h"
-#include "SimpleGameBuilder.h" // Include
+#include <vector> // Добавлено
+#include "Button.h"
+#include <SFML/Graphics.hpp>
+#include <memory> // Добавлено
 
 class Menu {
 private:
-    std::array<Button, 4> m_buttons;
-    size_t                 m_buttonCount = 0;
     IStateManager& m_state_manager;
-    Button* m_selectedButton = nullptr;
+    std::vector<Button> m_buttons; // Изменить
+    size_t m_buttonCount = 0;
+    const size_t MAX_BUTTONS = 4; // Maximum number of buttons
 
 public:
     Menu(IStateManager& state_manager);
-    bool handleMouseClick(sf::Vector2i mousePosition);
+    void addButton(float x, float y, float width, float height, const std::string& text, float dynamic_objects_ratio);
     void draw_into(sf::RenderWindow& window);
-    void addButton(float x, float y, float width, float height, const std::string& text);
-    void handleMouseMove(sf::Vector2i mousePosition);
+    bool handleMouseClick(const sf::Vector2i& mousePos);
 };
 
 #endif
\ No newline at end of file
diff --git a/Pacman.cpp b/Pacman.cpp
index 9ab71c1..5d3689b 100644
--- a/Pacman.cpp
+++ b/Pacman.cpp
@@ -1,6 +1,6 @@
 #include "Pacman.h"
 #include "Room.h"
-#include "IRoomSide.h" // Include IRoomSide
+#include "IRoomSide.h"
 #include <iostream>
 
 Pacman::Pacman(Room* startRoom) : m_location(startRoom) {
@@ -9,6 +9,9 @@ Pacman::Pacman(Room* startRoom) : m_location(startRoom) {
     prepare_for_drawing();
 }
 
+// Copy constructor
+Pacman::Pacman(const Pacman& other) : m_location(other.m_location), m_shape(other.m_shape) {}
+
 Pacman::~Pacman() {}
 
 Room* Pacman::getRoom() const {
@@ -42,6 +45,6 @@ void Pacman::draw_into(sf::RenderWindow& window) {
 void Pacman::prepare_for_drawing() {
     if (m_location) {
         // Example: Position Pacman in the center of the room
-        m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 30, 100 + (m_location->getId() * 100 / 500 * 100) + 30); // 30 is offset
+        m_shape.setPosition(100 + (m_location->getId() * 100 % 500) + 30, 100 + (m_location->getId() * 100 / 500 * 100) + 30);
     }
 }
\ No newline at end of file
diff --git a/Pacman.h b/Pacman.h
index 455089c..5a8baea 100644
--- a/Pacman.h
+++ b/Pacman.h
@@ -12,6 +12,7 @@ private:
 
 public:
     Pacman(Room* startRoom);
+    Pacman(const Pacman& other); // Copy constructor
     ~Pacman() override;
 
     Room* getRoom() const override;
diff --git a/SelectState.cpp b/SelectState.cpp
index 7e0d69b..e96f482 100644
--- a/SelectState.cpp
+++ b/SelectState.cpp
@@ -1,18 +1,18 @@
-//SelectState.cpp
 #include "SelectState.h"
-#include "GameState.h" // Include GameState for state transitions
-#include "ExitState.h"  // Include ExitState for state transitions
+#include "GameState.h"
+#include "ExitState.h"
 #include <iostream>
-//using namespace std;
-    
+#include "SimpleBuilder.h" // Include
+#include "ComplexBuilder.h" // Include
+
 SelectState::SelectState(IStateManager& state_manager)
-    : m_state_manager(state_manager), m_window(sf::VideoMode(800, 600), "Select State"), 
+    : m_state_manager(state_manager), m_window(sf::VideoMode(800, 600), "Select State"),
     m_menu(state_manager) {
     // Add buttons to the menu
-    m_menu.addButton(100, 100, 200, 50, "Easy");
-    m_menu.addButton(100, 200, 200, 50, "Medium");
-    m_menu.addButton(100, 100, 200, 50, "Hard");
-    m_menu.addButton(100, 200, 200, 50, "Exit");
+    m_menu.addButton(100, 100, 200, 50, "Easy", 0.2f);
+    m_menu.addButton(100, 180, 200, 50, "Medium", 0.4f);
+    m_menu.addButton(100, 260, 200, 50, "Hard", 0.6f);
+    m_menu.addButton(100, 340, 200, 50, "Exit", 0.0f);
 }
 
 bool SelectState::do_step(IStateManager& state_manager) {
@@ -31,12 +31,15 @@ void SelectState::event_handling() {
         else if (event.type == sf::Event::MouseButtonPressed) {
             if (event.mouseButton.button == sf::Mouse::Left) {
                 sf::Vector2i mousePosition = sf::Mouse::getPosition(m_window);
-                m_menu.handleMouseClick(mousePosition);
+                if (m_menu.handleMouseClick(mousePosition)) {
+                    // Handle button click here, if needed
+                }
             }
         }
     }
 }
 
+
 void SelectState::update() {
     // Реализация метода update
 }
@@ -54,3 +57,5 @@ sf::RenderWindow& SelectState::getRenderWindow() {
     return m_window; // Возвращение ссылки на объект m_window
 }
 
+
+
diff --git a/SelectState.h b/SelectState.h
index c388f79..7e59185 100644
--- a/SelectState.h
+++ b/SelectState.h
@@ -17,7 +17,7 @@ private:
     Menu m_menu; // The menu is stored by value
 
 public:
-    SelectState::SelectState(IStateManager& state_manager);
+    SelectState(IStateManager& state_manager);
 
     virtual bool do_step(IStateManager& state_manager) override;
 
diff --git a/SimpleBuilder.cpp b/SimpleBuilder.cpp
new file mode 100644
index 0000000..d1ceaff
--- /dev/null
+++ b/SimpleBuilder.cpp
@@ -0,0 +1,50 @@
+#include "SimpleBuilder.h"
+#include "Room.h"
+#include "Wall.h"
+#include "Pass.h"
+#include <iostream>
+
+SimpleBuilder::SimpleBuilder(int width, int height, int room_size) : CommonBuilder(width, height, room_size) {}
+
+SimpleBuilder::~SimpleBuilder() {}
+
+void SimpleBuilder::create_rooms() {
+    // Create a simple 2x2 grid of rooms
+    for (int y = 0; y < 2; ++y) {
+        for (int x = 0; x < 2; ++x) {
+            int roomId = y * 2 + x;
+            Room* room = new Room(roomId);
+            m_rooms.push_back(room);
+        }
+    }
+}
+
+void SimpleBuilder::set_rooms_sides() {
+    // Connect rooms with simple walls and passes
+    for (int y = 0; y < 2; ++y) {
+        for (int x = 0; x < 2; ++x) {
+            int roomId = y * 2 + x;
+            Room* room = m_rooms[roomId];
+
+            // Create walls
+            for (int dir = Room::LEFT; dir <= Room::DOWN; ++dir) {
+                Room::Direction direction = static_cast<Room::Direction>(dir);
+                room->setSide(direction, new Wall(room));
+            }
+
+            // Connect rooms with passes
+            if (x < 1) {
+                // Connect rooms horizontally
+                Pass* pass = new Pass(room, m_rooms[roomId + 1]);
+                room->setSide(Room::RIGHT, pass);
+                m_rooms[roomId + 1]->setSide(Room::LEFT, pass);
+            }
+            if (y < 1) {
+                // Connect rooms vertically
+                Pass* pass = new Pass(room, m_rooms[roomId + 2]);
+                room->setSide(Room::DOWN, pass);
+                m_rooms[roomId + 2]->setSide(Room::UP, pass);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/SimpleBuilder.h b/SimpleBuilder.h
new file mode 100644
index 0000000..b140f0d
--- /dev/null
+++ b/SimpleBuilder.h
@@ -0,0 +1,15 @@
+#ifndef SIMPLEBUILDER_H
+#define SIMPLEBUILDER_H
+
+#include "CommonBuilder.h"
+
+class SimpleBuilder : public CommonBuilder {
+public:
+    SimpleBuilder(int width, int height, int room_size);
+    ~SimpleBuilder() override;
+
+    void create_rooms() override;
+    void set_rooms_sides() override;
+};
+
+#endif
\ No newline at end of file
diff --git "a/\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273" "b/\320\235\320\276\320\262\321\213\320\271 \321\204\320\260\320\271\320\273"
new file mode 100644
index 0000000..e69de29
-- 
GitLab