I saw Conway's Game of Life and decided to make my own.
I have a bool array to represent the world, but the edges (Top and bottom) are acting weird, random cells becomes live.
In this code, it does not print the bottom and top of the world, but this is a bad solution.
The world "wraps" at the right and the left, causing even more problems, but that is for another time.
#include <iostream>
const int height = 20;
const int width = 20;
bool now_world[height][width];
bool then_world[height][width];
void clear_world();
void place_random_live_cells();
void then_world_initialization();
void print_world();
void generation_pass();
void update_worlds();
int main(int argc, const char * argv[])
{
using namespace std;
srand((unsigned)time(NULL));
int timer = 0;
int generation = 0;
clear_world();
place_random_live_cells();
then_world_initialization();
bool running = true;
while (running) {
if (timer == 50000000) {
cout << "Generation #" << generation << endl;
print_world();
generation_pass();
update_worlds();
++generation;
timer = 0;
}
++timer;
}//While (running) ends here
return 0;
}
void place_random_live_cells()
{
int percent = 30;
int max_live_cells = ((height * width) / 100) * percent;
int current_live_cells = 0;
while (current_live_cells < max_live_cells) {
int ycoords = 0 + (rand() % (height + 1));
int xcoords = 0 + (rand() % (width + 1));
if (now_world[ycoords][xcoords] == false) {
now_world[ycoords][xcoords] = true;
} else {
current_live_cells--;
}
++current_live_cells;
}
}
//A generation pass and cells die and some cells come to life
void generation_pass()
{
using namespace std;
int neighbours = 0;
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii+1][jjj ] == true) {
++neighbours;
}
if (now_world[iii+1][jjj-1] == true) {
++neighbours;
}
if (now_world[iii ][jjj+1] == true) {
++neighbours;
}
if (now_world[iii ][jjj-1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj ] == true) {
++neighbours;
}
if (now_world[iii-1][jjj-1] == true) {
++neighbours;
}
//Apply rules to the cells
//Dead cells with three live neighbours becomes alive
if (then_world[iii][jjj] == false && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with fewer than two, they die
if (then_world[iii][jjj] == true && neighbours < 2) {
then_world[iii][jjj] = false;
}
//Alive with 2 or three live neighbours live on unchanged
if (then_world[iii][jjj] == true && neighbours == 2) {
then_world[iii][jjj] = true;
}
if (then_world[iii][jjj] == true && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with more than three, they die
if (then_world[iii][jjj] == true && neighbours > 3) {
then_world[iii][jjj] = false;
}
//Dead cells without exactly three live neighbours remain dead
//Reset neighbour value to zero
neighbours = false;
}
}
}
//Make next generation identical to current
//This is only called once
void then_world_initialization()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
then_world[iii][jjj] = now_world[iii][jjj];
}
}
}
//Make the next generation be today
//This is called every generation
void update_worlds()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = then_world[iii][jjj];
}
}
}
//Set all cells to dead
void clear_world()
{
for (long iii = 0; iii < height; iii++) {
for (long jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = false;
then_world[iii][jjj] = false;
}
}
}
//Print world
void print_world()
{
using namespace std;
char live = 'X';
char dead = '.';
for (long iii = height; iii > 0; iii--) {
for (long jjj = width; jjj > 0; jjj--) {
if (iii != 0 && iii != height) {
if (now_world[iii][jjj]) {
cout << live;
} else {
cout << dead;
}
cout << " ";
}
}
cout << endl;
}
cout << endl;
}
Having done this for a course I taught in the past, the most common issue I always see people having is going outside the bounds of the array they're using.
If you look at the if statements in your nested for loop, I think you'll find some issues. For instance, in this case, what happens when iii equals (height-1) or jjj equals (width-1)?
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
You're going outside the bounds of your array and so your results will be undefined. You may get segfaults, but you may just also get spurious data. C++ doesn't enforce you staying within the bounds of the array you define.
Make sure you also handle cases like this:
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
What if iii equals zero?
Hope that helps.
You're trying to access out-of-boundary indexes in your array.
I'm not sure what behaviour you expect, but an easy way is to not calculate updates for cells on the edges.
So in generation_pass the loops should go from 1 till height-1.
Related
Me and my group is making a game for our project and I keep running into this error, after some testing, it looks like it happens at the end of the main function. I have no idea how this happen as most of the code is from our teacher, we need to fix the intentional bugs placed by him and add additional functionalities.
This is the code:
#include <winuser.h>
#include <iostream>
#include <time.h>
#include <conio.h>
#include <thread>
using namespace std;
#define MAX_CAR 5
#define MAX_CAR_LENGTH 40
#define MAX_SPEED 3
POINT** X;
POINT Y;
int cnt = 0;
int MOVING;
int SPEED;
int HEIGHT_CONSOLE = 29, WIDTH_CONSOLE = 119;
bool STATE;
void FixConsoleWindow() {
HWND consoleWindow = GetConsoleWindow();
LONG_PTR style = GetWindowLongPtr(consoleWindow, GWL_STYLE);
style = style & ~(WS_MAXIMIZEBOX) & ~(WS_THICKFRAME);
SetWindowLongPtr(consoleWindow, GWL_STYLE, style);
}
void GotoXY(int x, int y) {
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void ResetData() {
MOVING = 'D';
SPEED = 1;
Y = { 18, 19 };
if (X == NULL) {
X = new POINT * [MAX_CAR];
for (int i = 0; i < MAX_CAR; i++) {
X[i] = new POINT[MAX_CAR_LENGTH];
}
for (int i = 0; i < MAX_CAR; i++) {
int temp = rand() % (WIDTH_CONSOLE - MAX_CAR_LENGTH) + 1;
for (int j = 0; j < MAX_CAR_LENGTH; j++) {
X[i][j].x = temp + j;
X[i][j].y = 2 + 5 * i;
}
}
}
}
void DrawBoard(int x, int y, int width, int height, int curPosX = 0, int curPosY = 0) {
GotoXY(x, y);
for (int i = 1; i < width; i++) {
cout << 'X';
}
cout << 'X';
GotoXY(x, height + y);
for (int i = 1; i < width; i++) {
cout << 'X';
}
cout << 'X';
for (int i = y + 1; i < height + y; i++) {
GotoXY(x, i);
cout << 'X';
GotoXY(x + width, i);
cout << 'X';
}
GotoXY(curPosX, curPosY);
}
void StartGame() {
system("cls");
ResetData();
DrawBoard(0, 0, WIDTH_CONSOLE, HEIGHT_CONSOLE);
STATE = true;
}
void GabageCollect() {
for (int i = 0; i < MAX_CAR; i++) {
delete[] X[i];
}
delete[] X;
}
void ExitGame(HANDLE t) {
GabageCollect();
system("cls");
TerminateThread(t, 0);
}
void PauseGame(HANDLE t) {
SuspendThread(t);
}
void ProcessDeath() {
STATE = false;
GotoXY(0, HEIGHT_CONSOLE + 2);
cout << "Dead, type y to continue or any key to exit";
}
void ProcessFinish(POINT& p) {
SPEED == MAX_SPEED ? SPEED = 1 : SPEED++;
p = { 18,19 };
MOVING = 'D';
}
void DrawCars() {
for (int i = 0; i < MAX_CAR; i++) {
for (int j = 0; j < MAX_CAR_LENGTH; j++) {
GotoXY(X[i][j].x, X[i][j].y);
std::cout << '.';
}
}
}
void DrawPlayer(const POINT& p, char s) {
GotoXY(p.x, p.y);
cout << s;
}
bool IsImpact(const POINT& p) //d=Y.y p = Y
{
if (p.y == 1 || p.y == 19) return false;
for (int i = 0; i < MAX_CAR; i++)
{
for (int j = 0; j < MAX_CAR_LENGTH; j++)
{
if (p.x == X[i][j].x && p.y == X[i][j].y) return true;
}
}
return false;
}
void MoveCars(int x1, int y1)
{
for (int i = 1; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
cnt++;
for (int j = 0; j < MAX_CAR_LENGTH - 1; j++)
{
X[i][j] = X[i][j + 1];
}
X[i][MAX_CAR_LENGTH - 1].x + 1 == WIDTH_CONSOLE + x1 ? X[i][MAX_CAR_LENGTH - 1].x = 1 : X[i][MAX_CAR_LENGTH - 1].x++;
} while (cnt < SPEED);
}
for (int i = 0; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
cnt++;
for (int j = MAX_CAR_LENGTH - 1; j > 0; j--)
{
X[i][j] = X[i][j - 1];
}
X[i][0].x - 1 == 0 + x1 ? X[i][0].x = WIDTH_CONSOLE + x1 - 1 : X[i][0].x--;
} while (cnt < SPEED);
}
}
void EraseCars()
{
for (int i = 0; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
GotoXY(X[i][MAX_CAR_LENGTH - 1 - cnt].x, X[i][MAX_CAR_LENGTH - 1 - cnt].y);
cout << " ";
cnt++;
} while (cnt < SPEED);
}
for (int i = 1; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
GotoXY(X[i][0 + cnt].x, X[i][0 + cnt].y);
cout << " ";
cnt++;
} while (cnt < SPEED);
}
}
void MoveRight()
{
if (Y.x < WIDTH_CONSOLE - 1)
{
DrawPlayer(Y, ' ');
Y.x++;
DrawPlayer(Y, 'Y');
}
}
void MoveLeft()
{
if (Y.x > 1)
{
DrawPlayer(Y, ' ');
Y.x--;
DrawPlayer(Y, 'Y');
}
}
void MoveDown()
{
if (Y.y < HEIGHT_CONSOLE - 1)
{
DrawPlayer(Y, ' ');
Y.y++;
DrawPlayer(Y, 'Y');
}
}
void MoveUp()
{
if (Y.y > 1)
{
DrawPlayer(Y, ' ');
Y.y--;
DrawPlayer(Y, 'Y');
}
}
void SubThread()
{
while (1)
{
if (STATE)
{
switch (MOVING)
{
case 'A':
MoveLeft();
break;
case 'D':
MoveRight();
break;
case'W':
MoveUp();
break;
case'S':
MoveDown();
break;
}
MOVING = ' ';
EraseCars();
MoveCars(0, 0);
DrawCars();
if (IsImpact(Y))
{
ProcessDeath();
}
if (Y.y == 1)
{
ProcessFinish(Y);
Sleep(50);
}
}
}
}
void main()
{
int temp;
FixConsoleWindow();
srand(time(NULL));
StartGame();
thread t1(SubThread);
while (1)
{
temp = toupper(_getch());
if (STATE == 1)
{
EraseCars();
if (temp == 27)
{
ExitGame(t1.native_handle());
break;
}
else if (temp == 'P')
{
PauseGame(t1.native_handle());
temp = toupper(_getch());
if (temp == 'B')
ResumeThread((HANDLE)t1.native_handle());
}
else
{
if (temp == 'D' || temp == 'A' || temp == 'W' || temp == 'S')
{
MOVING = temp;
}
}
}
else
{
if (temp == 'Y') StartGame();
else
{
ExitGame(t1.native_handle());
break;
}
}
}
}
And this is the image of the error: https://imgur.com/PGJJX2w
Basically, this is a crossing road game, every time you go to the top, it saves the location and you cannot go that location again (still working on this), game finish when you run into the cars (lines of dots as of the moment). Thanks in advance
You created a std::thread object here:
thread t1(SubThread);
but you didn't call join() nor detach() for that.
This causes that std::terminate() is called (the program aborts) when the object is destructed.
Call t1.join() if you want to wait until the thread ends or t1.detach() if you want to let the thread run freely before returning from the main() function.
Another option is using CreateThread() directly instead of std::thread to create threads. This may be better because you are using t1.native_handle() for operations on the thread.
This is my first question on this site. I learn programming for a year and I always found a answer for my problem in projects. I know that this is REALLY simple problem and here is a code:
#include "stdafx.h"
#include "Wave.h"
Wave::~Wave()
{
}
void Wave::setEnemyCount(int count) {
nemyCount = count;
}
bool Wave::createWave() {
for (int i = 0; i < enemyCount; i++) {
enemyArray.push_back(Enemy());
}
for (int i = 0; i < enemyArray.size(); i++) {
int randomPositionX = rand() % 150 + 10;
int randomPositionY = rand() % 50 + 10;
if (!enemyArray.at(i).init(randomPositionX, randomPositionY)) {
std::cout << "Create wave(init enemies) - failed\n";
return false;
}
}
return true;
}
void Wave::drawWave(Window* window) {
window->setCursor({ 0, 2 });
window->setColor(Window::Color::RED);
std::cout << "Enemies: " << enemyArray.size();
window->setColor(Window::Color::WHITE);
for (int i = 0; i < enemyArray.size(); i++) {
enemyArray.at(i).draw(window);
//std::cout << i;
}
}
void Wave::update(Bullet* bullet, Player* player) {
for (int i = 0; i < enemyArray.size(); i++) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= enemyArray.at(i).getPositionX() && bullet->getPositionX() <= enemyArray.at(i).getPositionX() + 5)) {
if ((bullet->getPositionY() >= enemyArray.at(i).getPositionY() && bullet->getPositionY() <= enemyArray.at(i).getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(enemyArray.begin() + i);
}
}
}
}
if (enemyArray.size() <= 0) {
std::cout << "WAVE COMPLETE";
Sleep(2000);
enemyCount += 5;
createWave();
}
}
int Wave::getEnemyCount() const {
return enemyCount;
}
The collision work correct, but when bullet touch a enemy of index for example: 5, a code always remove the enemy of last index, so I can remove each enemy only shoot to one enemy with index 5 or 1 or 7.
When you do enemyArray.erase(...) you shouldn't increment i because you will skip one element.
So you should rewrite the loop like this:
for (int i = 0; i < enemyArray.size();) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= enemyArray.at(i).getPositionX() && bullet->getPositionX() <= enemyArray.at(i).getPositionX() + 5)) {
if ((bullet->getPositionY() >= enemyArray.at(i).getPositionY() && bullet->getPositionY() <= enemyArray.at(i).getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(enemyArray.begin() + i);
continue;
}
}
}
++i;
}
Or, with a more idiomatic style:
for (auto it = enemyArray.begin(), end = enemyArray.end();it!=end;) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= it->getPositionX() && bullet->getPositionX() <= it->getPositionX() + 5)) {
if ((bullet->getPositionY() >= it->.getPositionY() && bullet->getPositionY() <= it->getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(it);
continue;
}
}
}
++it;
}
Of course, if you wan a single enemy to be removed at a time, you should break instead of continue in the loop, after having erased the element.
For completeness, you can also use std::remove_if if you want to remove all enemies touched by the bullet, it's more optimal than the 2 loops above, because it does less moving of elements when multiple elements are removed.
Im making this console game and the way im doing it is printing chars to the console from a 3 dimentional array called map. Which is assigned using the chars of the monsters, characters and background. The problem is i have been able to assign to the map array and print of successfully the char taken a monster class. But for some reason the derived character class objects aren't having their chars printed.
I am confident this is not an access issue cause there are no compiling errors and when the program runs there are empty gaps on the row(not the exact index but the right row index) that the characters are assigned to.
Here is the code that assigns it:
void game::assignScreen() {
for (int row = 0; row < 20; row++) {
for (int col = 0; col < 40; col++) {
if (col == 0 || col == 39) {
map[row][col] = (char) 124;
} else if (row == 0 || row == 19) {
map[row][col] = (char) 95;
} else {
map[row][col] = (char) 46;
}
}
}
switch (difficulty) {
case 1:
for (int i=0; i <2; i++){
map[enemy[i]->getPos(true)][enemy[i]->getPos(false)] = enemy[i]->getSymbol();
}
case 2:
if (difficulty == 2) {
for (int i = 0; i <4; i++) {
map[enemy[i]->getPos(true)][enemy[i]->getPos(false)] = enemy[i]->getSymbol();
}
}
map[elfPlayer.getPos(true)][elfPlayer.getPos(false)] = elfPlayer.getSymbol();
map[guardPlayer.getPos(true)][guardPlayer.getPos(false)] = guardPlayer.getSymbol();
map[knightPlayer.getPos(true)][knightPlayer.getPos(false)] = knightPlayer.getSymbol();
map[roguePlayer.getPos(true)][roguePlayer.getPos(false)] = roguePlayer.getSymbol();
break;
case 3:
for (int i = 0; i <6; i++) {
map[enemy[i]->getPos(true)][enemy[i]->getPos(false)] = enemy[i]->getSymbol();
}
case 4:
if (difficulty == 4) {
for (int i = 0; i <9; i++) {
map[enemy[i]->getPos(true)][enemy[i]->getPos(false)] = enemy[i]->getSymbol();
}
}
map[elfPlayer.getPos(true)][elfPlayer.getPos(false)] = elfPlayer.getSymbol();
map[guardPlayer.getPos(true)][guardPlayer.getPos(false)] = guardPlayer.getSymbol();
map[knightPlayer.getPos(true)][knightPlayer.getPos(false)] = knightPlayer.getSymbol();
map[roguePlayer.getPos(true)][roguePlayer.getPos(false)] = roguePlayer.getSymbol();
map[roguePlayer.getPos(true)][roguePlayer.getPos(false)] = roguePlayer.getSymbol();
break;
}
}
And this prints it
void game::printScreen(string msg) {
clearScreen();
cout << msg;
for (int row = 0; row < 20; row++) {
for (int col = 0; col < 40; col++) {
if (map[row][col] == 'E' || map[row][col] == 'G' || map[row][col] == 'K' ||
map[row][col] == 'R' || map[row][col] == 'W') {
if (getPlayer(map[row][col]).getStatus() == 1) {
changeColor(14, false);
cout << map[row][col];
changeColor(15, false);
} else if (getPlayer(map[row][col]).getStatus() == 2 || getPlayer(map[row][col]).getStatus() == 3) {
changeColor(4, false);
cout << map[row][col];
changeColor(15, false);
}
} else {
cout << map[row][col];
}
}
cout << endl;
}
}
getPlayer is a function that takes the currently saved/selected char and returns the object it belongs to
position
int character::getPos(bool getX) {
if (getX) {
return xPos;
} else {
return yPos;
}
}
returns char
char character::getSymbol() {
return symbol;
}
header file
class character
{
public:
character();
~character();
string getName();
char getSymbol();
int getStatus();
int getPos(bool);
void setPos(int, int);
void setStatus(bool, bool);
protected:
string className;
char symbol;
private:
int xPos;
int yPos;
};
from game header file
monster *enemy[21];
elf elfPlayer;
guard guardPlayer;
knight knightPlayer;
rogue roguePlayer;
wizard wizardPlayer;
printScreen(elfPlayer.getName());
cout << elfPlayer.getSymbol();
I tested whether the postions for the objects can be printed, it's working for *enemy[], the derived classes look fine. I really have no idea why it's not printing right. Maybe im making a stupid mistake id just like some insight.
What happens when the map is printed, the bottom right empty area is meant to be full of chars
I turns out it was just a very silly mistake on my part. Thanks to Simon Kraemer for finding the problem.
I just added another else to print out stuff to the character if statement inside of the printScreen method.
Btw, what does it matter if i have a get positon function like that, it uses less space and is quicker to use. Also this is not a group project so confusion is not an issue (if i was in a group perhaps id change it).
I tried to code a simple version of tic-tac-toe in C++ using the minimax algorithm but ran into a problem while trying to determine the position where the score is the best. The minEval (Returns score for min), maxEval(returns score for max) and playMove (determines which position to play and then plays the move) functions are shown below.
int maxEval(int board[9]) {
if (checkDraw(board)) {
return 0;
}
else if (checkWin(board)) {
return -1000;
}
int finalScore = -1000;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = 1;
int score = minEval(board);
if (score > finalScore) {
finalScore = score;
}
board[i] = 0;
}
}
return finalScore;
}
int minEval(int board[9]) {
if (checkDraw(board)) {
return 0;
}
else if (checkWin(board)) {
return 1000;
}
int finalScore = 1000;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = -1;
int score = maxEval(board);
if (score < finalScore) {
finalScore = score;
}
board[i] = 0;
}
}
return finalScore;
}
void playMove(int board[9], int player) {
int finalScore = player * -1000;
int position;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score;
if (player == 1) {
score = maxEval(board);
}
else {
score = minEval(board);
}
if (player == 1 && score >= finalScore) {
finalScore = score;
position = i;
}
else if (player == -1 && score <= finalScore) {
finalScore = score;
position = i;
}
board[i] = 0;
}
}
board[position] = player;
}
When I tested different positions to see whether minEval and maxEval correctly evaluate the position, the functions return the correct score (1000 for max win, -1000 for min win and 0 for a draw). However, when I make the AI play by using the playMove function, it plays very dubious moves and almost always makes "incorrect" moves.
Here is an example of a game I made the program play (with itself):
I suspect that there is something wrong with the way I set position to i, but I tried to make changes to no avail. Any suggestions as to what is wrong with the evaluate function? Thanks.
Here is the link to the entire code: http://ideone.com/6791d4
I would check up on the variations found not just the scores. Are you finding just any winning variation, or the one where the opponent plays best?
e.g. Modify your min/max Eval code to also add the move chosen to an array.
BTW it may be easier to see what is happening if you combine the min/max Eval routines into one.
WARNING UNTESTED CODE
int minmaxEval(int board[9], int player, int moves[9], int move) {
if (checkDraw(board)) {
return 0;
}
int finalScore = player * -1000;
if (checkWin(board)) {
return finalScore;
}
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score = minmaxEval(board, -player, moves, move+1);
if ( (player > 0 && score > finalScore) ||
(player < 0 && score < finalScore) ) {
finalScore = score;
moves[move] = i;
}
board[i] = 0;
}
}
return finalScore;
}
If you print out moves[] in your toplevel routine you should see the variation which gave that score. A mismatch there will inform your understanding of the algorithm e.g. is it stopping when it finds a win.
In general it is important to have a way to double check your code is doing what you expect. Look into unit testing and test-driven development.
Thanks for your insights, I solved the problem. There was a bug in the playMove function, where I mismatched maxEval and minEval, this causing the AI to not play for a win or draw. So, the corrected code is:
void playMove(int board[9], int player) {
int finalScore = player * -1000;
int position;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score;
if (player == 1) {
score = minEval(board); //Previously Mismatched
}
else {
score = maxEval(board); //Previously Mismatched
}
if (player == 1 && score >= finalScore) {
finalScore = score;
position = i;
}
else if (player == -1 && score <= finalScore) {
finalScore = score;
position = i;
}
board[i] = 0;
}
}
board[position] = player;
}
I am developing a wordsearch generator to learn c++ better and I am stuck on preventing non-overlapping words from overlapping, such as a side-to-side word writing over a letter in a top-down word. Here is the code snippet:
else if (random_choice == 1 && random_word.size() <= 10-j && words_vector.size() != 0) {
flag = true;
for (int x = 0; x < random_word.size(); x++) {
if (wordsearch[i][j+x] != '0') {
flag = false;
break;
}
}
if (flag = true) {
for (int x = 0; x < random_word.size(); x++) {
wordsearch[i][j] = random_word[x];
j += 1;
}
j -= 1;
words_found_vector.insert(words_found_vector.begin(),words_vector[random_word_number]);
//words_vector.erase(words_vector.begin()+random_word_number);
}
else {
wordsearch[i][j] = '1';
}
}
What I have done was create a two dimensional array [10][11] filled with the 0 (zero) character so when I iterate through it all spaces are filled with 0 except for the 11th space in each line with a newline character to make a 10X10 grid. In my else if loop, the first part already has a word chosen and it tests if the word will fit in its proper space by checking if a 0 is present. If it runs into a non-zero character (such as if it runs into a letter from a top-down or diagonal word) the inner loop terminates, sets the boolean flag, and inputs a 1 (or any random letter) instead of the whole word. What happens is that the whole word is inserted anyways and overwrites one letter from the top down word. What am I doing wrong? Here is the rest of the code:
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
srand(time(NULL));
const char* const a_to_z = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
int random_char;
char wordsearch [10][11] = {0};
bool flag;
string words_array[] = {"CAT", "HELLO", "GOODBYE", "DOG", "BAT", "NEW", "SAY", "MAY", "DAY", "HAY"};
vector<string> words_vector (words_array, words_array + sizeof(words_array) / sizeof(string));
string words_found_array[] = {};
vector<string> words_found_vector (words_found_array, words_found_array + sizeof(words_found_array) / sizeof(string));
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 11; j++) {
int random_choice = rand() % 5;
int random_word_number = rand() % words_vector.size();
string random_word = words_vector[random_word_number];
if (j == 10) {
wordsearch[i][j] = '\n';
}
else if (random_choice == 1 && random_word.size() <= 10-j && words_vector.size() != 0) {
flag = true;
for (int x = 0; x < random_word.size(); x++) {
if (wordsearch[i][j+x] != '0') {
flag = false;
break;
}
}
if (flag = true) {
for (int x = 0; x < random_word.size(); x++) {
wordsearch[i][j] = random_word[x];
j += 1;
}
j -= 1;
words_found_vector.insert(words_found_vector.begin(),words_vector[random_word_number]);
//words_vector.erase(words_vector.begin()+random_word_number);
}
else {
wordsearch[i][j] = '1';
}
}
else if (random_choice == 2 && random_word.size() <= 10-i && words_vector.size() != 0) {
int temp_i = i;
flag = true;
for (int x = 0; x < random_word.size(); x++) {
if (wordsearch[i+x][j] != '0') {
flag = false;
break;
}
}
if (flag = true) {
for (int x = 0; x < random_word.size(); x++) {
wordsearch[i][j] = random_word[x];
i += 1;
}
i = temp_i;
words_found_vector.insert(words_found_vector.begin(),words_vector[random_word_number]);
//words_vector.erase(words_vector.begin()+random_word_number);
}
else {
wordsearch[i][j] = '1';
}
}
else {
int random_char = rand() % 26 + 0;
wordsearch[i][j] = a_to_z[random_char];
}
}
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 11; j++) {
cout<<wordsearch[i][j];
}
}
cout<<"Your words are:"<<endl;
for (int x = 0; x < words_found_vector.size(); x++) {
cout<<words_found_vector[x]<<endl;
}
}
One more thing:
//words_vector.erase(words_vector.begin()+random_word_number);
crashes my program. I think it is a scoping issue with this:
int random_choice = rand() % 5;
int random_word_number = rand() % words_vector.size();
string random_word = words_vector[random_word_number];
What I want to do is eventually have the user give me a list of words they want to search for and this function chooses some of them and presents it to the user when playing the game. This not functioning correctly also causes duplicates to appear in the crossword and words-to-find-list.
Thank you for your help!
You have this error twice in your code:
if (flag = true)
That is not a condition, it's an assignment. It assigns true to flag, and the if-block will always execute. You need to make it a comparison condition by using ==
if (flag == true)
A more common way to write that in C++ would be just
if (flag)