diff --git a/application.cpp b/application.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0064756abb7588db3997c88f76be3ca512f8c29
--- /dev/null
+++ b/application.cpp
@@ -0,0 +1,27 @@
+#include "application.hpp"
+#include "widgets.hpp"
+
+Application::Application(int width, int height) : _width(width), _height(height) {
+    genv::gout.open(_width, _height);
+}
+
+void Application::register_widget(Widget* widget) {
+    widgets.push_back(widget);
+}
+
+void Application::event_loop() {
+    genv::event ev;
+    while (genv::gin >> ev) {
+        for (Widget* widget : widgets) {
+            widget->handle(ev);
+        }
+        for (Widget* widget : widgets) {
+            widget->draw();
+        }
+        genv::gout << genv::refresh;
+    }
+}
+
+void Application::run() {
+    event_loop();
+}
diff --git a/application.hpp b/application.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b65313e2249a1338571e00c9a410ca5cdf1d4d42
--- /dev/null
+++ b/application.hpp
@@ -0,0 +1,22 @@
+#ifndef APPLICATION_HPP
+#define APPLICATION_HPP
+
+#include "graphics.hpp"
+#include "widgets.hpp"
+#include <vector>
+
+class Widget;
+
+class Application {
+protected:
+    std::vector<Widget*> widgets;
+    int _width, _height;
+
+public:
+    Application(int width, int height);
+    void register_widget(Widget* widget);
+    void event_loop();
+    void run();
+};
+
+#endif // APPLICATION_HPP
diff --git a/board_widget.cpp b/board_widget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c7f35a12261ace33511bf2f57dcb6b5647c6c96c
--- /dev/null
+++ b/board_widget.cpp
@@ -0,0 +1,67 @@
+#include "board_widget.hpp"
+#include "graphics.hpp"
+#include <iostream>
+
+using namespace genv;
+
+BoardWidget::BoardWidget(Application* parent, JatekMester* mester, int& selected_row, int& selected_col, int x, int y, int sx, int sy)
+    : Widget(parent, x, y, sx, sy), mester(mester), selected_row(selected_row), selected_col(selected_col), BOARD_SIZE(9), CELL_SIZE(sx / BOARD_SIZE) {}
+
+void BoardWidget::draw() const {
+    // Draw cells and numbers
+    for (int i = 0; i < BOARD_SIZE; ++i) {
+        for (int j = 0; j < BOARD_SIZE; ++j) {
+            int x = _x + j * CELL_SIZE;
+            int y = _y + i * CELL_SIZE;
+            gout << move_to(x, y) << color(255, 255, 255) << box(CELL_SIZE, CELL_SIZE);
+
+            int value = mester->get_value(i, j);
+            if (value != 0) {
+                if (!mester->is_cell_valid(i, j)) {
+                    gout << color(255, 0, 0); // Piros ha helytelen
+                } else {
+                    gout << color(0, 0, 0); // Fekete ha helyes
+                }
+                gout << move_to(x + CELL_SIZE / 3, y + CELL_SIZE / 1.5) << text(std::to_string(value));
+            }
+        }
+    }
+
+    // Draw grid lines
+    for (int i = 0; i <= BOARD_SIZE; ++i) {
+        int line_thickness = (i % 3 == 0) ? 3 : 1;  // Thicker lines for block boundaries
+        gout << move_to(_x + i * CELL_SIZE, _y) << color(0, 0, 0);
+        for (int t = 0; t < line_thickness; ++t) {
+            gout << move_to(_x + i * CELL_SIZE + t, _y) << line(0, _size_y);
+        }
+        gout << move_to(_x, _y + i * CELL_SIZE) << color(0, 0, 0);
+        for (int t = 0; t < line_thickness; ++t) {
+            gout << move_to(_x, _y + i * CELL_SIZE + t) << line(_size_x, 0);
+        }
+    }
+}
+
+void BoardWidget::handle(event ev) {
+    if (ev.type == ev_mouse && ev.button == btn_left) {
+        selected_row = (ev.pos_y - _y) / CELL_SIZE;
+        selected_col = (ev.pos_x - _x) / CELL_SIZE;
+        if (selected_row < 0 || selected_row >= BOARD_SIZE || selected_col < 0 || selected_col >= BOARD_SIZE) {
+            selected_row = -1;
+            selected_col = -1;
+        } else {
+            std::cout << "Selected cell: (" << selected_row << ", " << selected_col << ")\n";
+        }
+    }
+    else if (ev.type == ev_key && selected_row != -1 && selected_col != -1) {
+        if (!mester->is_original(selected_row, selected_col)) {
+            if (ev.keycode >= '1' && ev.keycode <= '9') {
+                int number = ev.keycode - '0';
+                mester->update_value(selected_row, selected_col, number);
+            }
+            else if (ev.keycode == '0' || ev.keycode == key_backspace) {
+                mester->update_value(selected_row, selected_col, 0);
+            }
+            gout << refresh;
+        }
+    }
+}
diff --git a/board_widget.hpp b/board_widget.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..58a781833ea27202991d9bea0809ec0ba6190f09
--- /dev/null
+++ b/board_widget.hpp
@@ -0,0 +1,21 @@
+#ifndef BOARD_WIDGET_HPP
+#define BOARD_WIDGET_HPP
+
+#include "widgets.hpp"
+#include "jatek_mester.hpp"
+
+class BoardWidget : public Widget {
+private:
+    JatekMester* mester;
+    int& selected_row;
+    int& selected_col;
+    const int BOARD_SIZE;
+    const int CELL_SIZE;
+
+public:
+    BoardWidget(Application* parent, JatekMester* mester, int& selected_row, int& selected_col, int x, int y, int sx, int sy);
+    void draw() const override;
+    void handle(genv::event ev) override;
+};
+
+#endif // BOARD_WIDGET_HPP
diff --git a/jatek_mester.cpp b/jatek_mester.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8bde9538b089ef91aefe2c71712b7a2a43ae708b
--- /dev/null
+++ b/jatek_mester.cpp
@@ -0,0 +1,74 @@
+#include "jatek_mester.hpp"
+#include <fstream>
+#include <sstream>
+#include <cmath>
+
+JatekMester::JatekMester()
+    : board(9, std::vector<int>(9, 0)), original_board(9, std::vector<int>(9, 0)) {}
+
+bool JatekMester::is_valid_move(int number, int row, int col) const {
+    // Ellenőrizze a sorban
+    for (int j = 0; j < 9; ++j) {
+        if (j != col && board[row][j] == number) {
+            return false;
+        }
+    }
+
+    // Ellenőrizze az oszlopban
+    for (int i = 0; i < 9; ++i) {
+        if (i != row && board[i][col] == number) {
+            return false;
+        }
+    }
+
+    // Ellenőrizze a 3x3-as blokkban
+    int block_start_row = row - row % 3;
+    int block_start_col = col - col % 3;
+    for (int i = block_start_row; i < block_start_row + 3; ++i) {
+        for (int j = block_start_col; j < block_start_col + 3; ++j) {
+            if (i != row && j != col && board[i][j] == number) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool JatekMester::is_original(int row, int col) const {
+    return original_board[row][col] != 0;
+}
+
+void JatekMester::update_value(int row, int col, int value) {
+    if (!is_original(row, col)) {
+        board[row][col] = value;
+    }
+}
+
+int JatekMester::get_value(int row, int col) const {
+    return board[row][col];
+}
+
+bool JatekMester::load_from_file(const std::string& filename) {
+    std::ifstream file(filename);
+    if (!file.is_open()) {
+        return false;
+    }
+
+    for (int i = 0; i < 9; ++i) {
+        for (int j = 0; j < 9; ++j) {
+            if (!(file >> original_board[i][j])) {
+                return false;
+            }
+            board[i][j] = original_board[i][j];
+        }
+    }
+
+    return true;
+}
+
+bool JatekMester::is_cell_valid(int row, int col) const {
+    int value = board[row][col];
+    if (value == 0) return true;
+    return is_valid_move(value, row, col);
+}
diff --git a/jatek_mester.hpp b/jatek_mester.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..684db5b7a7559b63919c29246a319d126bc9f2dd
--- /dev/null
+++ b/jatek_mester.hpp
@@ -0,0 +1,22 @@
+#ifndef JATEK_MESTER_HPP
+#define JATEK_MESTER_HPP
+
+#include <vector>
+#include <string>
+
+class JatekMester {
+private:
+    std::vector<std::vector<int>> board;
+    std::vector<std::vector<int>> original_board;
+
+public:
+    JatekMester();
+    bool is_valid_move(int number, int row, int col) const;
+    bool is_original(int row, int col) const;
+    void update_value(int row, int col, int value);
+    int get_value(int row, int col) const;
+    bool load_from_file(const std::string& filename);
+    bool is_cell_valid(int row, int col) const; // �j f�ggv�ny
+};
+
+#endif // JATEK_MESTER_HPP
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15562afa4253b60281b61cd871f5977e755d0a53
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,22 @@
+#include <iostream>
+
+#include "application.hpp"
+#include "board_widget.hpp"
+#include "jatek_mester.hpp"
+
+
+
+int main() {
+    Application app(600, 600);
+    JatekMester mester;
+    if (!mester.load_from_file("sudoku_easy.txt")) {
+        std::cerr << "Failed to load Sudoku board from file.\n";
+        return 1;
+    }
+
+    int selected_row = -1, selected_col = -1;
+    BoardWidget board(&app, &mester, selected_row, selected_col, 50, 50, 500, 500);
+    app.run();
+
+    return 0;
+}
diff --git a/sudoku_easy.txt b/sudoku_easy.txt
new file mode 100644
index 0000000000000000000000000000000000000000..518da5ef52c9fba071b274a05c4a93854bc15ce0
--- /dev/null
+++ b/sudoku_easy.txt
@@ -0,0 +1,9 @@
+0 0 6 0 0 0 5 0 8
+1 0 2 3 8 0 0 0 4
+0 0 0 2 0 0 1 9 0
+0 0 0 0 6 3 0 4 5
+0 6 3 4 0 5 8 7 0
+5 4 0 9 2 0 0 0 0
+0 8 7 0 0 4 0 0 0
+2 0 0 0 9 8 4 0 7
+4 0 9 0 0 0 3 0 0
\ No newline at end of file
diff --git a/sudoku_hard.txt b/sudoku_hard.txt
new file mode 100644
index 0000000000000000000000000000000000000000..690c479a653088fcbbf4644a089dd450f7018707
--- /dev/null
+++ b/sudoku_hard.txt
@@ -0,0 +1,9 @@
+0 0 6 3 0 7 0 0 0
+0 0 4 0 0 0 0 0 5
+1 0 0 0 0 6 0 8 2
+2 0 5 0 3 0 1 0 6
+0 0 0 2 0 0 3 0 0
+9 0 0 0 7 0 0 0 4
+0 5 0 0 0 0 0 0 0
+0 1 0 0 0 0 0 0 0
+0 0 8 1 0 9 0 4 0
\ No newline at end of file
diff --git a/sudoku_medium.txt b/sudoku_medium.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a55da94e5db66b88f2b28293c490dc711eb8ab1
--- /dev/null
+++ b/sudoku_medium.txt
@@ -0,0 +1,9 @@
+5 3 0 0 7 0 0 0 0
+6 0 0 1 9 5 0 0 0
+0 9 8 0 0 0 0 6 0
+8 0 0 0 6 0 0 0 3
+4 0 0 8 0 3 0 0 1
+7 0 0 0 2 0 0 0 6
+0 6 0 0 0 0 2 8 0
+0 0 0 4 1 9 0 0 5
+0 0 0 0 8 0 0 7 9
diff --git a/widgets.cpp b/widgets.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3675459133b853a023a65955933279273b03aace
--- /dev/null
+++ b/widgets.cpp
@@ -0,0 +1,21 @@
+#include "widgets.hpp"
+
+Widget::Widget(Application* parent, int x, int y, int sx, int sy)
+    : _parent(parent), _x(x), _y(y), _size_x(sx), _size_y(sy), is_selected(false) {
+    if (_parent)
+        _parent->register_widget(this);
+}
+
+Widget::~Widget() {}
+
+bool Widget::contains(int x, int y) const {
+    return x >= _x && x <= _x + _size_x && y >= _y && y <= _y + _size_y;
+}
+
+void Widget::select() {
+    is_selected = true;
+}
+
+void Widget::deselect() {
+    is_selected = false;
+}
diff --git a/widgets.hpp b/widgets.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ca81c1624b2ed9c4325433af55ff3d56584a6149
--- /dev/null
+++ b/widgets.hpp
@@ -0,0 +1,28 @@
+#ifndef WIDGETS_HPP
+#define WIDGETS_HPP
+
+#include "graphics.hpp"
+#include "application.hpp"
+#include <functional>
+
+class Application; // Forward declaration
+
+class Widget {
+protected:
+    Application* _parent;
+    int _x, _y, _size_x, _size_y;
+    bool is_selected;
+
+public:
+    Widget(Application* parent, int x, int y, int sx, int sy);
+    virtual ~Widget();
+
+    virtual void draw() const = 0;
+    virtual void handle(genv::event ev) = 0;
+
+    bool contains(int x, int y) const;
+    void select();
+    void deselect();
+};
+
+#endif // WIDGETS_HPP