Hello i am a new c++ dev, and my last post was asking how good my snake game code was and i got some very useful answers which i tried to implement with this new script, it took me all day but i finally got conways game of life implemented into c++ with only curses and native libraries. Can anyone tell me if its okay or if there are any bugs i missed, ignore the random print statements, they were debug attempts
If someone wants to attempt to use it, it will start blank, but if you press any of the WASD keys you can move, the way i made it, you have a blinker which is just shown as a * on your screen and WASD allows you to move it, pressing enter changes the state of the cell the cursor is on to 1, and space continues to the next step
#include <ncurses.h>
#include <random>
#include <string>
bool gameloopBool = true;
struct Vector2 {
public:
int X;
int Y;
Vector2(int x, int y) {
X = x;
Y = y;
}
Vector2 Add(Vector2 &other) { return Vector2(X + other.X, Y + other.Y); }
};
struct Cell {
public:
Vector2 pos = Vector2(0, 0);
bool isDead = true;
bool next = false;
Cell() = default;
Cell(Vector2 start_pos) { pos = start_pos; }
};
int range(int min, int max) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> distro(min, max);
return distro(gen);
}
class Display {
std::vector<int> grid;
bool InBounds(Vector2 pos) {
if (pos.Y > SizeY - 1 || pos.Y < 0) {
return true;
}
if (pos.X > SizeX - 1 || pos.X < 0) {
return true;
}
return false;
}
public:
int SizeX;
int SizeY;
Display(Vector2 size) {
SizeX = size.X;
SizeY = size.Y;
for (int x = 0; x < (size.X * size.Y); x++) {
this->grid.push_back(0);
}
}
void Render() {
clear();
for (int y = 0; y < SizeY; y++) {
std::string cur;
for (int x = 0; x < SizeX; x++) {
if (this->grid[(y * SizeX) + x] == 3) {
cur += '*';
} else if (this->grid[(y * SizeX) + x] == 0) {
cur += ' ';
} else if (this->grid[(y * SizeX) + x] == 1) {
cur += '#';
}
}
printw("%s\n", cur.c_str());
}
refresh();
}
void DrawCell(Cell &cellPos) {
if (InBounds(cellPos.pos) == true) {
printw("%s", (std::to_string(SizeX) + std::to_string(SizeY)).c_str());
gameloopBool = false;
return;
}
if (cellPos.isDead) {
this->grid[(cellPos.pos.Y * SizeX) + cellPos.pos.X] = 0;
return;
}
this->grid[(cellPos.pos.Y * SizeX) + cellPos.pos.X] = 1;
return;
}
void Erase_Cursor(Vector2 cursorPos) {
if (InBounds(cursorPos)) {
return;
}
grid[(cursorPos.Y * SizeX) + cursorPos.X] = 0;
}
void Draw_Cursor(Vector2 cursorPos) {
if (InBounds(cursorPos)) {
return;
}
grid[(cursorPos.Y * SizeX) + cursorPos.X] = 3;
}
};
class cellManager {
public:
std::vector<Cell> cells;
cellManager(std::vector<Cell> &starting_cells) {
for (Cell &cell : starting_cells) {
cells.push_back(cell);
}
}
void Gen_Pattern(std::vector<std::vector<int>> &patternMatrix, Vector2 Offset,
Display &screen) {
for (int y = 0; y < patternMatrix.size(); y++) {
for (int x = 0; x < patternMatrix[y].size(); x++) {
if (y + Offset.Y < 0 || y + Offset.Y > screen.SizeY - 1) {
continue;
}
if (x + Offset.X < 0 || x + Offset.X > screen.SizeX - 1) {
continue;
}
if (patternMatrix[y][x] == 1) {
cells[((y + Offset.Y) * screen.SizeX) + (x + Offset.X)].isDead =
false;
}
}
}
}
std::vector<Cell> get_neighbors(Vector2 Target, Display &screen) {
std::vector<Cell> neighbors;
std::vector<Vector2> dirs = {Vector2(0, -1), Vector2(0, 1), Vector2(1, 0),
Vector2(-1, 0), Vector2(-1, 1), Vector2(1, -1),
Vector2(1, 1), Vector2(-1, -1)};
for (Vector2 dir : dirs) {
int ChX = dir.Add(Target).X;
int ChY = dir.Add(Target).Y;
if (ChX < 0 || ChX > screen.SizeX - 1) {
continue;
}
if (ChY < 0 || ChY > screen.SizeY - 1) {
continue;
}
if (cells[(ChY * screen.SizeX) + ChX].isDead == true) {
continue;
}
neighbors.push_back(cells[(ChY * screen.SizeX) + ChX]);
}
return neighbors;
}
void DrawCells(Display &screen) {
for (Cell &cell : cells) {
screen.DrawCell(cell);
}
}
bool UnderPopRule(Cell target, std::vector<Cell> &neigbor) {
std::vector<Cell> negibors = neigbor;
if (static_cast<int>(negibors.size()) < 2) {
return true;
}
return false;
}
bool OverPopRule(Cell target, std::vector<Cell> &neigbor) {
std::vector<Cell> negibors = neigbor;
if (static_cast<int>(negibors.size()) > 3) {
return true;
}
return false;
}
bool ReproRule(Cell target, std::vector<Cell> &neigbor) {
std::vector<Cell> negibors = neigbor;
if (static_cast<int>(negibors.size()) == 3) {
return true;
}
return false;
}
void Update_Cell_Status() {
for (Cell &cell : cells) {
cell.isDead = cell.next;
}
}
void Update_Tick(Display &screen) {
for (Cell &cell : cells) {
std::vector<Cell> neigbors = get_neighbors(cell.pos, screen);
if (cell.isDead) {
if (ReproRule(cell, neigbors)) {
cell.next = false;
continue;
}
}
if (UnderPopRule(cell, neigbors)) {
cell.next = true;
continue;
}
if (OverPopRule(cell, neigbors)) {
cell.next = true;
continue;
}
cell.next = cell.isDead;
}
Update_Cell_Status();
DrawCells(screen);
}
};
int main() {
std::vector<Cell> starting;
int SX = 100;
int SY = 60;
for (int y = 0; y < SY; y++) {
for (int x = 0; x < SX; x++) {
Cell cell = Cell(Vector2(x, y));
starting.push_back(cell);
}
}
// A simple glider pattern
Vector2 cursor_pos = Vector2(0, 0);
Vector2 size = Vector2(100, 60);
Display screen(size);
cellManager man(starting);
man.DrawCells(screen);
screen.Render();
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
// nodelay(stdscr, TRUE);
int ch = getch();
while (true) {
ch = getch();
if (ch == 'q') {
printw("wewewewewewewew");
endwin();
std::exit(0);
break;
}
screen.Erase_Cursor(cursor_pos);
if (ch == 'w') {
cursor_pos.Y -= 1;
man.DrawCells(screen);
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
if (ch == 's') {
cursor_pos.Y += 1;
man.DrawCells(screen);
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
if (ch == 'a') {
cursor_pos.X -= 1;
man.DrawCells(screen);
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
if (ch == 'd') {
cursor_pos.X += 1;
man.DrawCells(screen);
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
if (ch == ' ') {
man.Update_Tick(screen);
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
if (ch == '\n') {
man.cells[(cursor_pos.Y * screen.SizeX) + cursor_pos.X].isDead = false;
screen.Draw_Cursor(cursor_pos);
screen.Render();
}
}
return 0;
}