getBeerreturntrue/0006-Fix-Memory-Game-Race-Conditions-with-GameState-add-t.patch

400 lines
12 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 34fe75c0a83ac9cc674f61de8a96db7bf6133b32 Mon Sep 17 00:00:00 2001
From: Angela <bwembael96241@th-nuernberg.de>
Date: Mon, 1 Dec 2025 15:24:18 +0100
Subject: [PATCH 6/6] Fix Memory Game Race Conditions with GameState + add
threading for measurements
---
CMakeLists.txt | 47 +++++++++++--
bindings.cpp | 19 ++++++
gamecube.cpp | 5 ++
main.cpp | 172 +++++++++++++++++++++++++++++++++++------------
measurements.txt | 0
5 files changed, 195 insertions(+), 48 deletions(-)
create mode 100644 bindings.cpp
create mode 100644 measurements.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ef310f2..126e7e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,23 +1,60 @@
cmake_minimum_required(VERSION 3.15)
-project(Programmieren_3b)
+project(Programmieren_3b LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
+# -----------------------------
+# Raylib
+# -----------------------------
FetchContent_Declare(
raylib
GIT_REPOSITORY https://github.com/raysan5/raylib.git
GIT_TAG 5.0
)
-
FetchContent_MakeAvailable(raylib)
-add_executable(Prog3B
+# -----------------------------
+# pybind11
+# -----------------------------
+FetchContent_Declare(
+ pybind11
+ GIT_REPOSITORY https://github.com/pybind/pybind11.git
+ GIT_TAG v2.11.1
+)
+FetchContent_MakeAvailable(pybind11)
+
+# -----------------------------
+# Executable für das Spiel
+# -----------------------------
+add_executable(Programmieren_3b
main.cpp
gamecube.cpp
gamematrix.cpp
)
-target_include_directories(Prog3B PRIVATE .)
-target_link_libraries(Prog3B raylib)
+target_link_libraries(Programmieren_3b PRIVATE raylib)
+
+# Windows-spezifische Abhängigkeiten für raylib
+if(WIN32)
+ target_link_libraries(Programmieren_3b PRIVATE opengl32 gdi32 winmm kernel32)
+endif()
+
+target_include_directories(Programmieren_3b PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
+# -----------------------------
+# Python-Modul
+# -----------------------------
+pybind11_add_module(gamematrix_python
+ bindings.cpp
+ gamematrix.cpp
+)
+
+# Python-Modul braucht die Header
+target_include_directories(gamematrix_python PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
+# Raylib ist für das Python-Modul nicht nötig, nur für C++ Executable
+# Optional: Falls du Gamematrix aus Python auch mit Raylib testen willst, kann man linken
+# target_link_libraries(gamematrix_python PRIVATE raylib)
diff --git a/bindings.cpp b/bindings.cpp
new file mode 100644
index 0000000..32e029d
--- /dev/null
+++ b/bindings.cpp
@@ -0,0 +1,19 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include "gamematrix.h"
+#include "raylib.h"
+#include "rlgl.h"
+
+namespace py = pybind11;
+
+PYBIND11_MODULE(gamematrix, m) {
+ m.doc() = "gamematrix library exposed to Python";
+
+ m.def("matmul", &gameMatrix::matmul);
+
+ m.def("translate", [](double x, double y, double z) {
+ return gameMatrix::translate({x, y, z});
+ });
+
+ m.def("rot3D", &gameMatrix::rot3D);
+}
diff --git a/gamecube.cpp b/gamecube.cpp
index 390dbf7..692691d 100644
--- a/gamecube.cpp
+++ b/gamecube.cpp
@@ -60,3 +60,8 @@ void gamecube::Draw() const
Vec3 gamecube::GetPosition() const { return position; }
float gamecube::GetRotationY() const { return rotation; }
+bool gamecube::IsFullyFlipped() const
+{
+ return rotation == 180.0f;
+}
+
diff --git a/main.cpp b/main.cpp
index 035accf..e82e793 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,18 +1,30 @@
#include "gamecube.h"
#include <algorithm>
+#include <iostream>
+#include <fstream>
#include <ctime>
#include <vector>
+#include <thread>
+#include <chrono>
// -----------------------------------------------------------
-// 3D Memory Game Hauptprogramm
+// 3D Memory Game Hauptprogramm mit GameState
// -----------------------------------------------------------
+
+// Zustände laut Aufgabenblatt
+enum class GameState
+{
+ Idle, // kein Würfel offen
+ OneFlipped, // ein Würfel offen
+ LockInput, // Würfel drehen -> Eingabe blockiert
+ CheckingMatch // beide offen, Vergleich läuft
+};
+
int main()
{
- // Zufall initialisieren
srand(time(NULL));
- // Fenster und Kamera
- InitWindow(800, 600, "3D Memory Game with Matrix3D Library");
+ InitWindow(800, 600, "3D Memory Game with GameState");
SetTargetFPS(60);
Camera3D camera{};
@@ -22,86 +34,104 @@ int main()
camera.fovy = 45.0f;
camera.projection = CAMERA_PERSPECTIVE;
- // Farben für 3 Paare
Color colors[] = { RED, GREEN, BLUE };
- // 6 Karten-Positionen im 3x2 Raster
std::vector<Vec3> positions = {
{-2, 0, -2}, {0, 0, -2}, {2, 0, -2},
{-2, 0, 0}, {0, 0, 0}, {2, 0, 0}
};
- // Doppelte Farben in einen Pool und mischen
- std::vector<Color> colorPool;
- for (int i = 0; i < 3; i++)
- {
- colorPool.push_back(colors[i]);
- colorPool.push_back(colors[i]);
+ // Farben doppelt
+ std::vector<Color> pool;
+ for (int i = 0; i < 3; i++) {
+ pool.push_back(colors[i]);
+ pool.push_back(colors[i]);
}
- for (int i = colorPool.size() - 1; i > 0; --i)
- {
- int j = rand() % (i + 1);
- std::swap(colorPool[i], colorPool[j]);
- }
+ // mischen
+ for (int i = pool.size() - 1; i > 0; --i)
+ std::swap(pool[i], pool[rand() % (i + 1)]);
- // Karten/Würfel erstellen
+ // Würfel erzeugen
std::vector<gamecube> cubes;
for (int i = 0; i < 6; i++)
- cubes.emplace_back(positions[i], colorPool[i]);
+ cubes.emplace_back(positions[i], pool[i]);
+ // GameState Variablen
+ GameState state = GameState::Idle;
gamecube* first = nullptr;
gamecube* second = nullptr;
- float flipSpeed = 5.0f;
bool gameWon = false;
+ float flipSpeed = 5.0f;
// -----------------------------------------------------------
- // Hauptspielschleife
+ // Game Loop
// -----------------------------------------------------------
while (!WindowShouldClose())
{
- // Klick-Erkennung
- if (!gameWon && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ Vector2 mouse = GetMousePosition();
+
+ // -------------------------------------------------------
+ // Eingabe NUR erlauben, wenn Idle oder OneFlipped
+ // -------------------------------------------------------
+ if (!gameWon &&
+ (state == GameState::Idle || state == GameState::OneFlipped) &&
+ IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
- Vector2 mouse = GetMousePosition();
-
for (auto &c : cubes)
{
if (!c.IsFlipped() && !c.IsMatched())
{
- Vector2 screenPos = GetWorldToScreen(
+ Vector2 screen = GetWorldToScreen(
{c.GetPosition().x, c.GetPosition().y, c.GetPosition().z},
camera
);
- if (fabs(mouse.x - screenPos.x) < 40 &&
- fabs(mouse.y - screenPos.y) < 40)
+ if (fabs(mouse.x - screen.x) < 40 &&
+ fabs(mouse.y - screen.y) < 40)
{
- c.FlipForward();
+ c.FlipForward(); // Animation starten
+
+ if (state == GameState::Idle)
+ {
+ first = &c;
+ state = GameState::OneFlipped;
+ }
+ else if (state == GameState::OneFlipped)
+ {
+ second = &c;
+ state = GameState::LockInput; // Animation läuft
+ }
+ break;
}
}
}
}
- // Animation
+ // -------------------------------------------------------
+ // Animation durchführen
+ // -------------------------------------------------------
for (auto &c : cubes)
- {
c.Update(flipSpeed);
- if (c.IsFlipped() && !c.IsMatched())
- {
- if (!first) first = &c;
- else if (!second && &c != first) second = &c;
- }
+ // Wenn beide cubes fertig gedreht → Vergleich starten
+ if (state == GameState::LockInput &&
+ first && second &&
+ first->IsFullyFlipped() &&
+ second->IsFullyFlipped())
+ {
+ state = GameState::CheckingMatch;
}
- // Matching
- if (first && second)
+ // -------------------------------------------------------
+ // Vergleich
+ // -------------------------------------------------------
+ if (state == GameState::CheckingMatch)
{
- Color col1 = first->GetColor();
- Color col2 = second->GetColor();
+ Color a = first->GetColor();
+ Color b = second->GetColor();
- if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b)
+ if (a.r == b.r && a.g == b.g && a.b == b.b)
{
first->SetMatched(true);
second->SetMatched(true);
@@ -113,16 +143,21 @@ int main()
}
first = second = nullptr;
+ state = GameState::Idle;
}
+ // -------------------------------------------------------
// Gewinnprüfung
+ // -------------------------------------------------------
if (!gameWon)
gameWon = std::all_of(
cubes.begin(), cubes.end(),
[](const gamecube &c){ return c.IsMatched(); }
);
- // Zeichnen
+ // -------------------------------------------------------
+ // Rendering
+ // -------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
@@ -133,12 +168,63 @@ int main()
EndMode3D();
if (gameWon)
- DrawText("Congrats! You found all pairs!", 150, 260, 30, DARKBLUE);
+ DrawText("Congrats! You found all pairs!", 140, 260, 30, DARKBLUE);
else
DrawText("Flip 2 cubes - find matching pairs!", 10, 10, 20, DARKGRAY);
EndDrawing();
}
+ std::vector<int> messungen;
+ std::ifstream file("measurements.txt");
+ int value;
+ while (file >> value) messungen.push_back(value);
+
+ // -------------------------
+ // Serielle Zählung
+ // -------------------------
+ auto start = std::chrono::steady_clock::now();
+ int increases = 0;
+ for (size_t i = 1; i < messungen.size(); ++i)
+ if (messungen[i] > messungen[i-1]) ++increases;
+ auto end = std::chrono::steady_clock::now();
+ std::cout << "Serial: " << increases
+ << " Took: "
+ << std::chrono::duration<double>(end - start).count()
+ << " s\n";
+
+ // -------------------------
+ // Parallele Zählung
+ // -------------------------
+ int numThreads = 4;
+ std::vector<int> results(numThreads, 0);
+ std::vector<std::thread> threads;
+
+ int totalComparisons = messungen.size() - 1;
+ int base = totalComparisons / numThreads;
+ int remainder = totalComparisons % numThreads;
+
+ int idx = 1;
+ for (int t = 0; t < numThreads; t++)
+ {
+ int startIdx = idx;
+ int count = base + (t < remainder ? 1 : 0);
+ int endIdx = idx + count - 1;
+ idx = endIdx + 1;
+
+ threads.emplace_back([&, t, startIdx, endIdx](){
+ int local = 0;
+ for (int i = startIdx; i <= endIdx; ++i)
+ if (messungen[i] > messungen[i-1]) ++local;
+ results[t] = local;
+ });
+ }
+
+ for (auto &th : threads) th.join();
+
+ int total = 0;
+ for (auto r : results) total += r;
+
+ std::cout << "Parallel: " << total << "\n";
CloseWindow();
return 0;
diff --git a/measurements.txt b/measurements.txt
new file mode 100644
index 0000000..e69de29
--
2.51.2.windows.1