Upload files to "/"
This commit is contained in:
@@ -0,0 +1,462 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#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<Brick> 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<GameData> getHistory() {
|
||||
vector<GameData> history;
|
||||
ifstream fin("game_history.txt");
|
||||
if (!fin) return history;
|
||||
|
||||
string line;
|
||||
while (getline(fin, line)) {
|
||||
GameData gd;
|
||||
|
||||
size_t pos = 0;
|
||||
vector<string> 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<double, milli> 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<streamsize>::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<streamsize>::max(), '\n');
|
||||
cin.get();
|
||||
}
|
||||
// history تاریخچه
|
||||
bool higherScore(const GameData& a, const GameData& b) {
|
||||
return a.score > b.score;
|
||||
}
|
||||
|
||||
void showGameHistory() {
|
||||
clearScreen();
|
||||
vector<GameData> 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<streamsize>::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;
|
||||
}
|
||||
Reference in New Issue
Block a user