#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; }