commit 53776341f9d5ebba5e3a8295c4d8d60dd4eb2893 Author: avasanatkar Date: Wed Apr 15 12:33:17 2026 +0000 Upload files to "/" diff --git a/final.cpp b/final.cpp new file mode 100644 index 0000000..cd14d2c --- /dev/null +++ b/final.cpp @@ -0,0 +1,462 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else + #include + #include + #include +#endif + +#ifndef _WIN32 +// پیاده‌سازی توابع _kbhit و _getch برای سیستم‌های غیر ویندوز +int _kbhit() { + struct termios oldt, newt; + int ch; + int oldf; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + + ch = getchar(); + + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); + + if (ch != EOF) { + ungetc(ch, stdin); + return 1; + } + return 0; +} + +int _getch() { + struct termios oldt, newt; + int ch; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + ch = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return ch; +} +#endif + +using namespace std; + +// constant ثابت های بازی +const int BOARD_WIDTH = 40; +const int BOARD_HEIGHT = 20; +const int INITIAL_LIVES = 3; +const int BRICK_ROWS = 4; +const int BRICK_COLUMNS = 10; + +// struct ساختار های بازی +struct Paddle { + int x; + int width; +}; + +struct Ball { + int x, y; + int vx, vy; +}; + +struct Brick { + int x, y; + bool active; +}; + +struct GameData { + // ذخیره تاریخچه بازی + string playerName; + int score; + int lives; + bool won; + string datetime; +}; + +struct GameState { + // وضعیت بازی در حال حاضر + Paddle paddle; + Ball ball; + vector bricks; + int score; + int lives; + bool ballLaunched; +}; + +// پاک کردن صفحه بازی +void clearScreen() { +#ifdef _WIN32 + system("cls"); +#else + system("clear"); +#endif +} + +// ذخیره و خواندن تاریخچه game history +void saveMatch(const GameData& data) { + ofstream fout("game_history.txt", ios::app); //ios::app برای اینکه تمام تاریخچه بازی‌ها ذخیره بشه + if (!fout) return; + + fout << data.playerName << "," + << data.score << "," + << data.lives << "," + << data.won << "," + << data.datetime << "\n"; + + fout.close(); +} + +vector getHistory() { + vector history; + ifstream fin("game_history.txt"); + if (!fin) return history; + + string line; + while (getline(fin, line)) { + GameData gd; + + size_t pos = 0; + vector tokens; + string temp = line; + + while ((pos = temp.find(',')) != string::npos) { + tokens.push_back(temp.substr(0, pos)); + temp.erase(0, pos + 1); + } + tokens.push_back(temp); + + if (tokens.size() == 5) { + gd.playerName = tokens[0]; + gd.score = atoi(tokens[1].c_str()); + gd.lives = atoi(tokens[2].c_str()); + gd.won = (tokens[3] == "1"); + gd.datetime = tokens[4]; + history.push_back(gd); + } + } + + fin.close(); + return history; +} +// رسم صفحه ی بازی rendering +void printBoard(const GameState& game) { + clearScreen(); + + // سقف + for (int i = 0; i < BOARD_WIDTH + 2; ++i) cout << '#'; + cout << '\n'; + + // درون صفحه + for (int y = 0; y < BOARD_HEIGHT; ++y) { + cout << '#'; + for (int x = 0; x < BOARD_WIDTH; ++x) { + bool printed = false; + + // توپ + if (x == game.ball.x && y == game.ball.y) { + cout << 'O'; + printed = true; + } + // راکت + else if (y == BOARD_HEIGHT - 1 && + x >= game.paddle.x && + x < game.paddle.x + game.paddle.width) { + cout << '='; + printed = true; + } + // آجر ها + else { + for (size_t i = 0; i < game.bricks.size(); ++i) { + if (game.bricks[i].active && + game.bricks[i].x == x && + game.bricks[i].y == y) { + cout << '*'; + printed = true; + break; + } + } + } + + if (!printed) cout << ' '; + } + cout << "#\n"; + } + + // کف + for (int i = 0; i < BOARD_WIDTH + 2; ++i) cout << '#'; + cout << '\n'; + + // HUD نمایش اطلاعات بازی + int bricksLeft = 0; + for (size_t i = 0; i < game.bricks.size(); ++i) + if (game.bricks[i].active) bricksLeft++; + + int bricksDestroyed = game.score; + + cout << "Lives: " << game.lives + << " | Score: " << game.score + << " | Bricks Left: " << bricksLeft + << " | Bricks Destroyed: " << bricksDestroyed << "\n"; +} +// گرفتن ورودی از کاربر برای حرکت و کنترل +void checkInput(GameState& game) { + if (_kbhit()) { + char key = (char)_getch(); + + // A و D کلید برای حرکت + if ((key == 'a' || key == 'A') && game.paddle.x > 0) game.paddle.x--; + else if ((key == 'd' || key == 'D') && game.paddle.x + game.paddle.width < BOARD_WIDTH) game.paddle.x++; + + // متوقف شدن + else if (key == 'p' || key == 'P') { + cout << "\nGame Paused. Press C to continue or Q to quit.\n"; + while (true) { + char c = (char)_getch(); + if (c == 'c' || c == 'C') break; + if (c == 'q' || c == 'Q') { game.lives = 0; break; } + } + } + + // پرتاب توپ با زدن کلید space + else if (!game.ballLaunched && key == ' ') { + game.ballLaunched = true; + } + + // خروج + else if (key == 'q' || key == 'Q') { + game.lives = 0; + } + } +} +// آپدیت موقعیت و برخورد با دیواره و کم کردن جان بازیکن +void moveTheBall(GameState& game) { + if (!game.ballLaunched) return; + + game.ball.x += game.ball.vx; + game.ball.y += game.ball.vy; + + // برخورد با چپ و راست + if (game.ball.x <= 0 || game.ball.x >= BOARD_WIDTH - 1) game.ball.vx *= -1; + + // برخورد با سقف + if (game.ball.y <= 0) game.ball.vy *= -1; + + // رد شدن و کم شدن جان و ریست جای توپ + if (game.ball.y >= BOARD_HEIGHT) { + game.lives--; + game.ballLaunched = false; + + game.ball.x = game.paddle.x + game.paddle.width / 2; + game.ball.y = BOARD_HEIGHT - 2; + } +} +// برخورد توپ با راکت با زاویه بر اساس محل برخورد +void checkPaddleHit(GameState& game) { + if (game.ball.y == BOARD_HEIGHT - 2 && + game.ball.x >= game.paddle.x && + game.ball.x < game.paddle.x + game.paddle.width) { + + // برگشت عمودی + game.ball.vy = -game.ball.vy; + + // براساس این که کجا برخورد کرده vx تغییر میکند + double rel = (game.ball.x - (game.paddle.x + game.paddle.width / 2.0)) + / (game.paddle.width / 2.0); + + game.ball.vx = (int)(rel * 2.0); + if (game.ball.vx == 0) game.ball.vx = (rel < 0 ? -1 : 1); + } +} +// برخورد با آجر و حذف آجر و امتیاز گرفتن و برگشت عمودی +void checkBrickHit(GameState& game) { + for (size_t i = 0; i < game.bricks.size(); ++i) { + Brick &brick = game.bricks[i]; + + if (brick.active && + game.ball.x == brick.x && + game.ball.y == brick.y) { + + brick.active = false; + game.score++; + game.ball.vy = -game.ball.vy; + break; + } + } +} +// مقادیر اولیه بازی +GameState initializeGame() { + GameState game; + game.lives = INITIAL_LIVES; + game.score = 0; + game.ballLaunched = false; + + // راکت پایین وسط + game.paddle.x = BOARD_WIDTH / 2 - 3; + game.paddle.width = 6; + + // توپ بالای راکت + game.ball.x = game.paddle.x + 3; + game.ball.y = BOARD_HEIGHT - 2; + // حرکت اولیه توپ + game.ball.vx = 1; + game.ball.vy = -1; + + // ساختن آجر ها + game.bricks.clear(); + for (int row = 0; row < BRICK_ROWS; ++row) { + for (int col = 0; col < BRICK_COLUMNS; ++col) { + Brick brick; + brick.x = col * (BOARD_WIDTH / BRICK_COLUMNS); + brick.y = row + 2; + brick.active = true; + game.bricks.push_back(brick); + } + } + + return game; +} +// حلقه بازی +void gameLoop(GameState& game, const string& playerName) { + const int FPS = 30; + chrono::milliseconds frameTime(1000 / FPS); + + while (game.lives > 0) { + chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now(); + + checkInput(game); + moveTheBall(game); + checkPaddleHit(game); + checkBrickHit(game); + printBoard(game); + + // هیچ آجر فعالی برای بردن نمانده + bool anyBricks = false; + for (size_t i = 0; i < game.bricks.size(); ++i) { + if (game.bricks[i].active) { anyBricks = true; break; } + } + if (!anyBricks) break; + + chrono::high_resolution_clock::time_point end = chrono::high_resolution_clock::now(); + chrono::duration elapsed = end - start; + if (elapsed < frameTime) this_thread::sleep_for(frameTime - elapsed); + } + + // پایان و ذخیره بازی + clearScreen(); + + GameData gd; + gd.playerName = playerName; + gd.score = game.score; + gd.lives = game.lives; + gd.won = (game.lives > 0); + + time_t now = time(0); + gd.datetime = ctime(&now); + + saveMatch(gd); + + if (game.lives <= 0) cout << "Game Over!\n"; + else cout << "Victory! All bricks destroyed!\n"; + cout << "Final Score: " << game.score << "\n"; + + cout << "\nPress Enter to return to menu..."; + cin.ignore(numeric_limits::max(), '\n'); + cin.get(); +} +// help توضیحات +void showHelp() { + clearScreen(); + cout << "=== HELP ===\n"; + cout << "A / Left : Move paddle left\n"; + cout << "D / Right : Move paddle right\n"; + cout << "Space : Launch ball\n"; + cout << "P : Pause game\n"; + cout << "Q : Quit game\n"; + + cout << "\nPress Enter to return to menu..."; + cin.ignore(numeric_limits::max(), '\n'); + cin.get(); +} +// history تاریخچه +bool higherScore(const GameData& a, const GameData& b) { + return a.score > b.score; +} + +void showGameHistory() { + clearScreen(); + vector history = getHistory(); + sort(history.begin(), history.end(), higherScore); + + cout << "=== GAME HISTORY ===\n"; + for (size_t i = 0; i < history.size(); ++i) { + cout << history[i].playerName + << " | Score: " << history[i].score + << " | Lives: " << history[i].lives + << " | " << (history[i].won ? "Won" : "Lost") + << " | " << history[i].datetime + << '\n'; + } + + cout << "\nPress Enter to return to menu..."; + cin.ignore(numeric_limits::max(), '\n'); + cin.get(); +} +// منو بازی +void showMainMenu() { + while (true) { + clearScreen(); + cout << "=== BREAKOUT GAME ===\n"; + cout << "1. New Game\n"; + cout << "2. Help\n"; + cout << "3. Game History\n"; + cout << "4. Exit\n"; + cout << "Select an option: "; + + char choice = (char)_getch(); + + if (choice == '1') { + clearScreen(); + cout << "Enter Player Name: "; + string name; + cin >> name; + + GameState game = initializeGame(); + gameLoop(game, name); + } + else if (choice == '2') { + showHelp(); + } + else if (choice == '3') { + showGameHistory(); + } + else if (choice == '4') { + break; + } + else { + // کاربر ورودی نامعتبر زد این پیام رو بده + cout << "\nInvalid option! Press any key..."; + (void)_getch(); + } + } +} +int main() { + showMainMenu(); + return 0; +}