added files
CMake Build / build (ubuntu-latest) (push) Has been cancelled

This commit is contained in:
2026-04-12 20:44:08 -07:00
commit 4588950b31
34 changed files with 1342 additions and 0 deletions
+244
View File
@@ -0,0 +1,244 @@
// Headers
#include <iostream>
#include <thread>
#include <string>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <random>
#include <atomic>
#include "getchar.h"
#include "setcursor.h"
#include "structs.h"
using namespace std;
// Global varialbes
extern string board[30][80];
extern string hud[30][20];
extern int board_width;
extern int board_lenght;
extern int bricks_idx[36], bricks_idy[36];
extern int hudLength;
extern int hudWidth;
extern int bricksCount;
extern std::atomic<bool> running;
extern std::atomic<bool> paused;
extern string ballChar ;
extern string block ;
extern string blockRed ;
extern string blockGreen;
extern string blockBlue ;
extern string blockYellow ;
extern string trCorner ;
extern string tlCorner ;
extern string brCorner ;
extern string blCorner ;
extern string paddeleLine ;
extern string horizontalLine ;
extern string verticalLine ;
extern Player player;
// Function Prototypes
void hudCalculation();
string bCountInString();
string scoreInString();
bool isBrick(int, int);
// Functions
void drawBoard(){
hudCalculation();
gotoxy(0, 0);
string currentChar;
cout << endl << endl;
for(int i = 0; i < board_width; i++){
cout << " ";
for(int j = 0; j < board_lenght + hudLength ; j++){
if (j < hudLength){
cout << hud[i][j];
}
else {
int boardCol = j - hudLength;
currentChar = board[i][boardCol];
if (currentChar == horizontalLine ||
currentChar == verticalLine ||
currentChar == tlCorner ||
currentChar == trCorner ||
currentChar == blCorner ||
currentChar == brCorner ||
currentChar == ballChar){
cout << currentChar;
}
else if (isBrick(i, boardCol)) {
int nameSeed1 = (int)player.name[0];
int nameSeed2 = (int)player.name[1];
std::mt19937 gen(i * nameSeed1 + j * nameSeed2); // generates a random based on seed (a combination of i and j with player's name)
std::vector<std::string> colors = {blockRed, blockBlue, blockGreen, blockYellow, block}; // Creates a dynamic array containing the colored blocks characters
std::shuffle(colors.begin(), colors.end(), gen); // shuffles the colors dynamic array
for(int k = 0; k < 5; k++) {
std::cout << colors[0];
}
j += 4;
}
else if (currentChar == paddeleLine){
for (int k = 0 ; k < 10 ; k++){
cout << paddeleLine;
}
j += 9;
}
else {
cout << " ";
}
}
}
cout << endl;
}
}
// checking if a certain location contains a brick or not
bool isBrick(int x, int y){
for(int i = 0, j = 0; i < 36; i++, j++){
if(bricks_idx[i] == x){
if(bricks_idy[i] == y){
return true;
}
}
}
return false;
}
// Head up display
void hudCalculation(){
// setting up borders
for(int i = 1; i < hudLength - 1; i++){
hud[0][i] = horizontalLine; // top
hud[hudWidth - 1][i] = horizontalLine; // bottom
}
for(int i = 1; i < hudWidth - 1; i++){
hud[i][0] = verticalLine; // right
hud[i][hudLength - 1] = verticalLine; // left
}
// setting up corners
hud[0][0] = tlCorner;
hud[0][hudLength - 1] = trCorner;
hud[hudWidth - 1][0] = blCorner;
hud[hudWidth - 1][hudLength - 1] = brCorner;
for (int i = 1; i < hudWidth - 1; i++){
for (int j = 1; j < hudLength - 1; j++){
hud[i][j] = " ";
}
}
string score = " Score : " + scoreInString();
for (int i = 0; i < 15; i++){
hud[2][i + 2] = score[i];
}
string health = " Health : " + to_string(player.health);
for (int i = 0 ; i < 11 ; i++){
hud[4][i + 2] = health[i];
}
string bricksLine = " Bricks : " + bCountInString();
for (int i = 0 ; i < 12 ; i++){
hud[6][i + 2] = bricksLine[i];
}
if (paused) {
string pauseText = " PAUSED ";
for (int i = 0; i < 8; i++){
hud[8][i + 2] = pauseText[i];
}
}
}
// Proccessing input
int inputProccessing(Paddle &paddle){
using namespace std::chrono_literals; // for sleep function
char inputChar = getch();
bool moved = false;
int temp = paddle.start_loc.x;
switch (inputChar) {
case 'p':
case 'P':
paused = !paused;
return 1;
break;
case 'a' :
case 'A' :
if (!paused && paddle.start_loc.x > 1) {
paddle.start_loc.x -= 3;
if (paddle.start_loc.x < 1) {
paddle.start_loc.x = 1;
}
moved = true;
}
break;
case 'd' :
case 'D' :
if (!paused && paddle.start_loc.x < board_lenght - 11) {
paddle.start_loc.x += 3;
if (paddle.start_loc.x > board_lenght - 11) {
paddle.start_loc.x = board_lenght - 11;
}
moved = true;
}
break;
case 'q':
return 0;
break;
case 'Q':
return 0;
break;
default:
return 1;
}
// Changing paddle location
if (!paused && moved){
board[board_width - 2][paddle.start_loc.x] = paddeleLine;
board[board_width - 2][temp] = " ";
}
return 1;
}
string scoreInString(){
string result = to_string(player.score);
result.insert(0, 6 - result.length(), '0');
return result;
}
string bCountInString(){
string result = to_string(bricksCount);
result.insert(0, 2 - result.length(), '0');
return result;
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#ifndef BOARD_H
#define BOARD_H
#include "getchar.h"
#include "structs.h"
#include <iostream>
void drawBoard();
bool isBrick(int, int);
int inputProccessing(Paddle &paddle);
#endif
+16
View File
@@ -0,0 +1,16 @@
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
void show_console_cursor(bool show) {
#if defined(_WIN32)
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(handle, &cci);
cci.bVisible = show;
SetConsoleCursorInfo(handle, &cci);
#else
std::cout << (show ? "\033[?25h" : "\033[?25l");
#endif
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
void show_console_cursor(bool show);
+25
View File
@@ -0,0 +1,25 @@
#pragma once // prevents multiple inclusion
#include <iostream>
#if defined(_WIN32) || defined(_WIN64)
#include <conio.h> // Windows
inline char mygetch() {
return _getch(); // Windows getch
}
#else
#include <termios.h>
#include <unistd.h>
inline char getch() {
char buf = 0;
struct termios old = {0};
tcgetattr(0, &old);
old.c_lflag &= ~ICANON; // disable line buffering
old.c_lflag &= ~ECHO; // disable echo
tcsetattr(0, TCSANOW, &old);
read(0, &buf, 1);
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
tcsetattr(0, TCSANOW, &old);
return buf;
}
#endif
+155
View File
@@ -0,0 +1,155 @@
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <ctime>
#include "getchar.h"
using namespace std;
extern string trCorner ;
extern string tlCorner ;
extern string brCorner ;
extern string blCorner ;
extern string paddeleLine ;
extern string horizontalLine ;
extern string verticalLine ;
/*
history format:
PlayerName, Best socre, Best socre time, Last score, Last score time
*/
void saveData(string name, int score){
ifstream history_reader("src/history.txt");
if(!history_reader.is_open()){
cout << "ERROR OPENNING HISTORY!";
return;
}
time_t now = time(nullptr);
string date = ctime(&now);
date.pop_back(); // delete \n at the end
string output = "";
bool new_player = true;
string line;
while(getline(history_reader, line)){
int splitter[4];
splitter[0] = line.find(",");
splitter[1] = line.find(",", splitter[0] + 1);
splitter[2] = line.find(",", splitter[1] + 1);
splitter[3] = line.find(",", splitter[2] + 1);
string player_name = line.substr(0, splitter[0]);
int best_score = stoi(line.substr(splitter[0] + 1, splitter[1] - splitter[0] - 1));
string best_score_date = line.substr(splitter[1] + 1, splitter[2] - splitter[1] - 1);
int last_score = stoi(line.substr(splitter[2] + 1, splitter[3] - splitter[2] - 1));
string last_score_date = line.substr(splitter[3] + 1);
if(player_name == name){
new_player = false;
if(score >= best_score){
best_score = score;
best_score_date = date;
}
last_score = score;
last_score_date = date;
}
output += player_name + "," +
to_string(best_score) + "," +
best_score_date + "," +
to_string(last_score) + "," +
last_score_date + "\n";
}
history_reader.close();
if(new_player){
output += name + "," +
to_string(score) + "," +
date + "," +
to_string(score) + "," +
date + "\n";
}
ofstream history_write("src/history.txt", ios::trunc);
history_write << output;
history_write.close();
}
void showHistory(){
ifstream history("src/history.txt");
if(!history.is_open()){
cout << "ERROR OPENNING HISTORY!";
return;
}
system("clear");
const int tableWidth = 100;
// Top border
cout << endl << endl;
cout << tlCorner;
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
cout << trCorner << endl;
// Title
cout << verticalLine
<< "\033[33m" // yellow
<< setw(tableWidth) << left << " GAME HISTORY"
<< "\033[0m" // reset
<< verticalLine << endl;
// Separator
cout << verticalLine;
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
cout << verticalLine << endl;
// Header
cout << verticalLine << " "
<< "\033[36m" // cyan
<< setw(15) << left << "Player"
<< setw(12) << "Best Score"
<< setw(25) << "Best Date"
<< setw(14) << "Last Score"
<< setw(32) << "Last Date"
<< "\033[0m" // reset
<< " " << verticalLine << endl;
// Header separator
cout << verticalLine;
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
cout << verticalLine << endl;
string line;
while(getline(history, line)){
int splitter[4];
splitter[0] = line.find(",");
splitter[1] = line.find(",", splitter[0] + 1);
splitter[2] = line.find(",", splitter[1] + 1);
splitter[3] = line.find(",", splitter[2] + 1);
string player_name = line.substr(0, splitter[0]);
string best_score = line.substr(splitter[0] + 1, splitter[1] - splitter[0] - 1);
string best_score_date = line.substr(splitter[1] + 1, splitter[2] - splitter[1] - 1);
string last_score = line.substr(splitter[2] + 1, splitter[3] - splitter[2] - 1);
string last_score_date = line.substr(splitter[3] + 1);
cout << verticalLine << " "
<< "\033[32m" << setw(15) << left << player_name << "\033[0m" // green - reset
<< "\033[35m" << setw(12) << best_score << "\033[0m" // purple - reset
<< setw(16) << best_score_date << " "
<< "\033[35m" << setw(14) << last_score << "\033[0m" // purple - reset
<< setw(32) << last_score_date
<< " " << verticalLine << endl;
}
// Bottom border
cout << blCorner;
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
cout << brCorner << endl;
// escape
getch();
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <ctime>
#include "getchar.h"
using namespace std;
void saveData(string name, int score);
void showHistory();
+216
View File
@@ -0,0 +1,216 @@
#include "structs.h"
#include "board.h"
#include <string>
#include <thread>
#include <atomic>
using namespace std;
extern Ball ball;
extern Player player;
extern int board_lenght;
extern int board_width;
extern string board[30][80];
extern string ballChar;
extern int bricks_idx[36];
extern int bricks_idy[36];
extern string paddeleLine ;
extern Paddle paddle;
extern int bricksCount;
extern std::atomic<bool> paused;
extern Brick bricks[36];
void ballmover(Ball &ball){
if (player.health == 0){
player.gameover = true;
}
else if (bricksCount == 0){
player.won = true;
}
using namespace std::chrono_literals;
// Calculate new position
int tempNewX = ball.loc.x + ball.v.vX;
int tempNewY = ball.loc.y + ball.v.vY;
// Checking collision for current position
for(int i = 0; i < 36; i++){
if(bricks_idx[i] != -1 && bricks_idy[i] != -1){
int brick_row = bricks_idx[i];
int brick_col_start = bricks_idy[i];
// Check if ball is stuck in a brick
if(ball.loc.y == brick_row &&
ball.loc.x >= brick_col_start &&
ball.loc.x <= brick_col_start + 4){
// reverse both velocities
ball.v.vX = -ball.v.vX;
ball.v.vY = -ball.v.vY;
tempNewX = ball.loc.x + ball.v.vX;
tempNewY = ball.loc.y + ball.v.vY;
// delete brick and add score
player.score += bricks[i].score;
bricksCount--;
bricks_idx[i] = -1;
bricks_idy[i] = -1;
goto skip_normal_collision; // Skip rest of collision checks
}
}
}
// Checking brick collison for new position
for(int i = 0; i < 36; i++){
if(bricks_idx[i] != -1 && bricks_idy[i] != -1){
int brick_row = bricks_idx[i];
int brick_col_start = bricks_idy[i];
int brick_col_end = brick_col_start + 4;
// checking if there is a brick there, Works like (isBrick( , )) function
if(tempNewY == brick_row &&
tempNewX >= brick_col_start &&
tempNewX <= brick_col_end){
bool bounceX = false;
bool bounceY = false;
// X direction
if(ball.v.vX > 0 && ball.loc.x < brick_col_start){ // heading right
bounceX = true;
}
else if(ball.v.vX < 0 && ball.loc.x > brick_col_end){ // heading left
bounceX = true;
}
// Y direction
if(ball.v.vY > 0 && ball.loc.y < brick_row){ // heading down
bounceY = true;
}
else if(ball.v.vY < 0 && ball.loc.y > brick_row){ // heading up
bounceY = true;
}
if(bounceX && bounceY){ // Corner hit
// fixing the special case problem. in this case two bricks collapse at once
bool special_case_handled = false; // flag
if(i < 23 && i % 12 != 0 && ball.v.vX > 0){
if(bricks_idx[i - 1] != -1 && bricks_idx[i + 12] != -1){
// delete brick and add score ( two bricks )
player.score += (bricks[i - 1].score + bricks[i + 12].score);
bricksCount -= 2;
bricks_idx[i - 1] = -1;
bricks_idy[i - 1] = -1;
bricks_idx[i + 12] = -1;
bricks_idy[i + 12] = -1;
special_case_handled = true;
}
}
else if(i < 23 && i % 12 != 11 && ball.v.vX < 0){
if(bricks_idx[i + 1] != -1 && bricks_idx[i + 12] != -1){
// delete brick and add score ( two bricks )
player.score += (bricks[i + 1].score + bricks[i + 12].score);
bricksCount -= 2;
bricks_idx[i + 1] = -1;
bricks_idy[i + 1] = -1;
bricks_idx[i + 12] = -1;
bricks_idy[i + 12] = -1;
special_case_handled = true;
}
}
if(!special_case_handled){ // no special case accured
// delete brick and add score
player.score += bricks[i].score;
bricksCount--;
bricks_idx[i] = -1;
bricks_idy[i] = -1;
}
ball.v.vX = -ball.v.vX;
ball.v.vY = -ball.v.vY;
}
else if(bounceX){ // Side hit
ball.v.vX = -ball.v.vX;
// delete brick and add score
player.score += bricks[i].score;
bricksCount--;
bricks_idx[i] = -1;
bricks_idy[i] = -1;
}
else { // Top/bottom hit
ball.v.vY = -ball.v.vY;
// delete brick and add score
player.score += bricks[i].score;
bricksCount--;
bricks_idx[i] = -1;
bricks_idy[i] = -1;
}
// Recalculate position after bounce
tempNewX = ball.loc.x + ball.v.vX;
tempNewY = ball.loc.y + ball.v.vY;
break; // Only handle one brick per frame
}
}
}
skip_normal_collision:
// Wall collision
if (tempNewX <= 0 || tempNewX >= board_lenght - 1){
ball.v.vX = -ball.v.vX;
tempNewX = ball.loc.x + ball.v.vX;
}
if (tempNewY == board_width - 1){
player.health--;
ball.v.vY = -ball.v.vY;
tempNewY = ball.loc.y + ball.v.vY;
}
else if (tempNewY <= 0 || tempNewY >= board_width - 1){
ball.v.vY = -ball.v.vY;
tempNewY = ball.loc.y + ball.v.vY;
}
if (tempNewY == board_width - 2) {
// Check if the ball's X position is inside the paddle (width 10)
if (tempNewX >= paddle.start_loc.x && tempNewX < paddle.start_loc.x + 10) {
int distanceFromPS = tempNewX - paddle.start_loc.x;
ball.v.vY = -1; // Force ball to move UP
int velocityMagnitude[10] = {3,2,2,1,1,1,1,2,2,3}; // an array that gives any x axis distance between the ball and paddle start a velocity
if (ball.v.vX > 0){
ball.v.vX = velocityMagnitude[distanceFromPS];
}
else {
ball.v.vX = -velocityMagnitude[distanceFromPS];
}
tempNewY = ball.loc.y + ball.v.vY; // Update next Y immediately
}
}
// Clear old position
if (ball.loc.x != tempNewX || ball.loc.y != tempNewY) {
board[ball.loc.y][ball.loc.x] = " ";
}
// Update position
ball.loc.x = tempNewX;
ball.loc.y = tempNewY;
// Draw ball at new position
board[ball.loc.y][ball.loc.x] = ballChar;
}
+3
View File
@@ -0,0 +1,3 @@
#include "structs.h"
void ballmover(Ball &ball);
+96
View File
@@ -0,0 +1,96 @@
#include <iostream>
#include "getchar.h"
char optionChoosenByUser(){
std::cout << "\n\n\033[33m <-------Select option!------->\033[0m" << std::endl
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<<" 1. New Game "
<<"\033[34m║ \033[0m" << std::endl
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<<" 2. Help "
<<"\033[34m║ \033[0m" << std::endl
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<<" 3. History "
<<"\033[34m║ \033[0m" << std::endl
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<<" 4. Exit "
<<"\033[34m║ \033[0m" << std::endl
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl;
char chosenOpt = getch();
return chosenOpt;
}
void helpMenu(){
system("clear");
std::cout << std::endl << std::endl
<< "\033[34m ╔══════════════════════════════════════════════════════════════════════╗ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " The game consist of few elements : "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " 1. The ball, 2. Paddel, 3. Blocks "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " The ball starts moving in a line; whenever the ball hits the wall, "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " a block or the paddel it reflects like a beam and whenever it hits "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " a block, the block gets destroyed. "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " The goal is to destroy all of the blocks "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " If your ball fall down and don't touch the paddel you lose a "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " heart; you have 3 hearts, if you lose them all you lose. "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " You can move the paddel using \"A\" & \"D\" to move left & right. "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " Press \"P\" or \"p\" to pause the game. "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " Press any button to exit. "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ║\033[0m"
<< " "
<< "\033[34m║ \033[0m" << std::endl
<< "\033[34m ╚══════════════════════════════════════════════════════════════════════╝ \033[0m" << std::endl;
getch();
}
+5
View File
@@ -0,0 +1,5 @@
#include "getchar.h"
#include <iostream>
char optionChoosenByUser();
void helpMenu();
+14
View File
@@ -0,0 +1,14 @@
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
void gotoxy(int x, int y) {
#ifdef _WIN32
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {(SHORT)x, (SHORT)y};
SetConsoleCursorPosition(hConsole, pos);
#else
printf("\033[%d;%dH", y, x);
#endif
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
void gotoxy(int x, int y);
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <string>
struct Player{
int score = 0;
std::string name;
bool initialInput = false;
int health = 3;
bool gameover = false;
bool won = false;
};
struct Location{
int x;
int y;
};
struct Brick{
Location loc;
int score;
};
struct Paddle{
Location start_loc;
// int lenght; // possible feature, right now considered 10
};
struct Velocity{
int vX;
int vY;
};
struct Ball{
Location loc;
Velocity v;
};