C++ Maze Solving algorithm segmentation fault - c++

The task is to create a randomly generated maze and then solve it, the issue is that whenever I recursively search the maze for the exit, i get a segmentation fault at runtime. Most of the cout is for debugging.
The Main File (where error persists)
#include <string>
#include <cmath>
#include <cstdlib>
#include "Main.h"
#include "Maze.h"
int main(int argc, char *argv[])
{
// Process the command line arguments and seed the random number
// generator, if necessary
unsigned int seed;
if(argc == 4)
{
seed = static_cast<unsigned int>(atoi(argv[1]));
cout << "Initializing pseudorandom number generator with seed "
<< seed << endl;
srand(seed);
}
else if(argc > 4)
{
cout << "Improper usage of Main\n";
exit(0);
}
cout << "Beginning execution\n";
// The first couple of numbers don't seem quite random,
// so "prime the pump" by calling rand() twice
(void) rand(); (void) rand();
mazeTest();
cout << "Finishing execution\n";
return 0;
}
void mazeTest()
{
int height = 0;
int width = 0;
cout << "Enter height (positive integer): ";
cin >> height;
cout << height << "\n";
cout << "Enter width (positive integer): ";
cin >> width;
cout << width << "\n";
MazeBuilder theMazeBuilder(height, width);
cout << "CREATED MAZE BUILDER\n";
Maze theMaze(theMazeBuilder);
cout << "CREATED THE MAZE\n";
cout << "The Maze:\n" << theMaze.toString();
solveMaze(theMaze);
}
void solveMaze(const Maze& theMaze)
{
cout << "ENTERED solveMaze()\n";
thePath = new int[theMaze.getHeight()*theMaze.getWidth()];
bool **wasHere;
for(int i = 0; i < theMaze.getHeight(); i++)
{
for(int j = 0; i < theMaze.getWidth(); j++)
{
wasHere[i][j] = false;
}
}
cout << "PATH INITIALIZED\n";
if(search(theMaze, theMaze.getEntranceRow(), 0, wasHere, thePath, thePathLength))
{
theMaze.toString(thePath, thePathLength);
}
}
bool search(const Maze& theMaze, int row, int col,
bool**& wasHere, int *aPath, int currentPathLength)
{
if(col == theMaze.getWidth()-1 && row == theMaze.getExitRow())
{
cout << "FOUND EXIT\n";
thePathLength = currentPathLength;
thePath = aPath;
return true;
}
if(wasHere[row][col] == true)
return false;
wasHere[row][col] = true;
if(row != 0 && theMaze.at(row,col).isWall(UP) == false)
{
if(search(theMaze, row-1, col, wasHere, aPath, currentPathLength))
{
aPath[currentPathLength] = UP;
currentPathLength++;
cout << "UP\n";
return true;
}
}
if(col != theMaze.getWidth()-1 && theMaze.at(row,col).isWall(RIGHT) == false)
{
if(search(theMaze, row, col+1, wasHere, aPath, currentPathLength))
{
aPath[currentPathLength] = RIGHT;
currentPathLength++;
cout << "RIGHT\n";
return true;
}
}
if(row != theMaze.getHeight()-1 && theMaze.at(row,col).isWall(DOWN) == false)
{
if(search(theMaze, row+1,col, wasHere, aPath, currentPathLength))
{
aPath[currentPathLength] = DOWN;
currentPathLength++;
cout << "DOWN\n";
return true;
}
}
if(col != 0 && theMaze.at(row,col).isWall(LEFT) == false)
{
if(search(theMaze, row, col-1, wasHere, aPath, currentPathLength))
{
aPath[currentPathLength] = LEFT;
currentPathLength++;
cout << "LEFT\n";
return true;
}
}
cout << "DEAD END\n----------------------------\n";
return false;
}
Important methods used...
Maze::at(int row, int col)
returns the cell at given row and column
Maze::toString() or toString(int* thePath, int thePathLength)
default: prints out just the maze using ASCII characters to cmd
with parameters: Prints out maze with solution using ASCII characters to cmd
Cell::isWall(direction)
returns whether or not there is a wall in that direction
(directions are constants declared and handled in Cell)
Other Info:
Maze is a dynamic 2d array of Cells
The maze is constructed properly (can output an unsolved maze properly)

The problem:
bool **wasHere;
for(int i = 0; i < theMaze.getHeight(); i++)
{
for(int j = 0; i < theMaze.getWidth(); j++)
{
wasHere[i][j] = false;
The reason:
wasHere is an uninitialized pointer to a pointer to a bool. You then dereference the first pointer causing undefined behavior (such as perhaps a crash...).

Related

Tic Tac Toe minimax algorithm in C++

Ive been learning C++ and I decided to make a tictactoe project that utilizes a MiniMax algorithm. I have made all the functionality for playing, including 2 player. Why doesn't my minimax algorithm when I choose to play with the AI work ? It always moves to 0 or 8 and I can't figure out why. Any help will be appreciated
TicTacToe.h
#ifndef TICTACTOE_TICTACTOEGAME_H
#define TICTACTOE_TICTACTOEGAME_H
#include <string>
#include <iostream>
#include <vector>
class TicTacToeGame {
struct move{
int score;
int index;
};
public:
const int PLAYER1_INDEX = 1;
const int PLAYER2_INDEX = 2;
const int AI_INDEX = 3;
TicTacToeGame();
void play(TicTacToeGame);
bool hasWon() const;
bool haveTied() const;
char getMarker(int, int) const;
void setMarker(int, int);
void resetMarker(int);
int getCurrentPlayer() const;
std::vector<int> possibleMoves();
private:
char board[3][3];
std::string player1_name;
std::string player2_name;
int currentPlayer;
bool isMultiplayer;
int moveCount = 0;
void init();
void printBoard();
void setPlayer1Name(std::string);
void setPlayer2Name(std::string);
std::string getPlayer1Name() const;
std::string getPlayer2Name() const;
void switchCurrentPlayer();
std::string winMessage();
int getRow(int) const;
int getColumn(int) const;
bool checkMarker(int, int);
void makeAIMove(TicTacToeGame);
move miniMax(TicTacToeGame, int);
};
#endif //TICTACTOE_TICTACTOEGAME_H
TicTacToe.cpp
#include "TicTacToeGame.h"
// Player is MINIMIZER, AI is MAXIMIZER
TicTacToeGame::move TicTacToeGame::miniMax(TicTacToeGame board, int player) {
move current, best;
int otherPlayer = (player == 1) ? 3 : 1;
if (board.hasWon()){
if(player == PLAYER1_INDEX){
best.score = 10;
return best;
} else if(player == AI_INDEX){
best.score = -10;
return best;
}
} else if(board.haveTied()){
best.score = 0;
return best;
}
if(player == AI_INDEX){
best.score = -9999999;
} else best.score = 9999999;
std::vector<int> possibleMoves = board.possibleMoves();
for (int i = 0; i < possibleMoves.size(); i++) {
board.setMarker(possibleMoves[i], player);
current = miniMax(board, otherPlayer);
current.index = possibleMoves[i];
if(player == AI_INDEX){
if(current.score > best.score) {
best = current;
}
} else
if(current.score < best.score){
best = current;
}
board.resetMarker(possibleMoves[i]);
}
std::cout << "best index: " << best.index << " best score: " << best.score << std::endl;
return best;
}
void TicTacToeGame::makeAIMove(TicTacToeGame board) {
int move = miniMax(board, getCurrentPlayer()).index;
setMarker(move, getCurrentPlayer());
std::cout << "\nThe AI has moved to " << move << std::endl;
}
std::vector<int> TicTacToeGame::possibleMoves() {
std::vector<int> possibleMoves;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if(board[i][j] != 'X' && board[i][j] != 'O'){
possibleMoves.push_back(3 * i +j);
}
}
}
return possibleMoves;
}
TicTacToeGame::TicTacToeGame() {
init();
}
// Create the board with indexes
void TicTacToeGame::init() {
currentPlayer = 2;
int k = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++, k++) {
board[i][j] = '0' + k;
}
}
}
// Prints the board int he format of a TicTacToe game
void TicTacToeGame::printBoard() {
std::cout << "\n";
for (int i = 0; i < 3; i++) {
if (i != 0) std::cout << "\n --------------------\n";
for (int j = 0; j < 3; j++) {
std::cout << "\t" << board[i][j];
if (j != 2) std::cout << "\t|";
}
}
}
// Handles the playing
void TicTacToeGame::play(TicTacToeGame game) {
std::string welcome = "\t\t*********************************************\n\t\t*\t\tWelcome to the TicTacToe game !\t\t*\n\t\t*********************************************\n\n\n";
int position = -1;
char multiplayer;
char playAgain;
std::cout << welcome;
while (true){
std::cout << "Do you want to play multiplayer ? (y/n): ";
std::cin >> multiplayer;
multiplayer = tolower(multiplayer);
// Checks if input is valid, asks for another input if not
while (std::cin.fail() || (multiplayer != 'y' && multiplayer != 'n')) {
std::cout << "Invalid entry ! Enter either y OR n: ";
std::cin.clear();
std::cin.ignore(256, '\n');
std::cin >> multiplayer;
multiplayer = tolower(multiplayer);
}
if (multiplayer == 'y') isMultiplayer = true;
else if (multiplayer == 'n') isMultiplayer = false;
break;
}
// Initializing players
std::cout << "Player 1, please type in your name: ";
std::cin >> player1_name;
// Checks if input is valid, asks for another input if not
while (std::cin.fail()) {
std::cout << "Invalid entry ! Re-enter your name: ";
std::cin.clear();
std::cin.ignore(256, '\n');
std::cin >> player1_name;
}
setPlayer1Name(player1_name);
std::cout << getPlayer1Name() << " will be X." << std::endl;
// Only initializes player 2 if it's a multiplayer game
if (isMultiplayer){
std::cout << "\nPlayer 2, please type in your name: ";
std::cin >> player2_name;
// Checks if input is valid, asks for another input if not
while (std::cin.fail()) {
std::cout << "Invalid entry ! Re-enter your name: ";
std::cin.clear();
std::cin.ignore(256, '\n');
std::cin >> player2_name;
}
setPlayer2Name(player2_name);
std::cout << getPlayer2Name() << " will be O.\n" << std::endl;
}
std::cout << "Starting game: \nINSTRUCTIONS: Select the number of the position where you want to play" << std::endl;
// Play loop
while (!hasWon()) {
printBoard();
// Alternate between players after evey move
switchCurrentPlayer();
std::cout << "\ncurrent player is " << currentPlayer << std::endl;
// Player's move
if (currentPlayer == PLAYER1_INDEX || currentPlayer == PLAYER2_INDEX){
while (true) {
std::cin >> position;
// Checks if input is an integer, asks for another input if not
while (std::cin.fail() || position < 0 || position > 8) {
std::cout << "Invalid entry ! Enter a number between 0 and 8 inclusive: ";
std::cin.clear();
std::cin.ignore(256, '\n');
std::cin >> position;
}
// Check if there's an X or O in that position already, if yes - ask for another position to if so. If no - writes X/O
if (checkMarker(getRow(position), getColumn(position))) {
setMarker(position, getCurrentPlayer());
break;
} else {
std::cout
<< "There's already an X/O in that position. Try place it in an empty spot.\nEnter a new position: ";
}
}
}
// AI's move
else if (currentPlayer == AI_INDEX){
makeAIMove(game);
}
moveCount++;
// Checks for a winner or a tie after every move
if (hasWon() || haveTied()) {
if (hasWon()) std::cout << winMessage() << std::endl;
else if(haveTied()) std::cout << "The game is a tie !" << std::endl;
std::cout << "\n\nDo you want to play again ? Enter y OR n: ";
std::cin >> playAgain;
playAgain = tolower(playAgain); // converts to lowercase
// If there's a winner ask if user wants to play another game, stops application if not
while (true) {
if (playAgain != 'y' && playAgain != 'n') {
std::cout << playAgain << std::endl;
std::cout << "Invalid expression ! Enter either y OR n: ";
std::cin >> playAgain;
playAgain = tolower(playAgain); // converts to lowercase
} else if (playAgain == 'y' || playAgain == 'n') break;
}
if (playAgain == 'y') {
std::cout << "Generating a new board " << std::endl;
init();
moveCount = 0;
} else if (playAgain == 'n') {
std::cout << "\nThank you for playing the TicTacToe game !\nExiting the game.";
break;
}
}
}
}
std::string TicTacToeGame::winMessage() {
if (getCurrentPlayer() == 1) { return "\n\n" + getPlayer1Name() + " has won !"; }
else if (getCurrentPlayer() == 2) return "\n\n" + getPlayer2Name() + "has won !";
else return "\n\nThe AI has won !";
}
// Checks for winning conditions
bool TicTacToeGame::hasWon() const {
for (int i = 0; i < 3; ++i) {
// Checking horizontals
if (getMarker(0, i) == getMarker(1, i) && getMarker(1, i) == getMarker(2, i)) {
//cout << "horizontal alignment";
return true;
}
// Chekcing verticals
if (getMarker(i, 0) == getMarker(i, 1) && getMarker(i, 1) == getMarker(i, 2)) {
//cout << "vertical alignment";
return true;
}
}
// Checking diagonals
if (getMarker(0, 0) == getMarker(1, 1) && getMarker(1, 1) == getMarker(2, 2)) return true;
if (getMarker(0, 2) == getMarker(1, 1) && getMarker(1, 1) == getMarker(2, 0)) return true;
// If no alignment
return false;
}
void TicTacToeGame::setPlayer1Name(std::string name) {
player1_name = name;
}
void TicTacToeGame::setPlayer2Name(std::string name) {
player2_name = name;
}
std::string TicTacToeGame::getPlayer1Name() const {
return player1_name;
}
std::string TicTacToeGame::getPlayer2Name() const {
return player2_name;
}
int TicTacToeGame::getCurrentPlayer() const {
return currentPlayer;
}
int TicTacToeGame::getRow(int row) const{
return row / 3;
}
int TicTacToeGame::getColumn(int column) const {
return column % 3;
}
bool TicTacToeGame::checkMarker(int row, int column) {
if (getMarker(row, column) == 'X' || getMarker(row, column) == 'O') return false;
return true;
}
char TicTacToeGame::getMarker(int row, int column) const {
return board[row][column];
}
void TicTacToeGame::setMarker(int position, int player) {
board[getRow(position)][getColumn(position)] = player == 1 ? 'X' : 'O';
}
/* Switches the play either from:
* - PLAYER1 to PLAYER2
* - PLAYER 2 to PLAYER1
* - AI to PLAYER1
* - PLAYER1 to AI
*/
void TicTacToeGame::switchCurrentPlayer() {
if (currentPlayer == PLAYER1_INDEX && !isMultiplayer){
currentPlayer = AI_INDEX;
std::cout << "\n\nIt's the AI's turn now" << std::endl;
} else if (currentPlayer == PLAYER1_INDEX) {
currentPlayer = PLAYER2_INDEX;
std::cout << "\n\nIt's " << getPlayer2Name() << "'s turn, select the position you want to move to:";
} else if (currentPlayer == PLAYER2_INDEX || currentPlayer == AI_INDEX) {
currentPlayer = PLAYER1_INDEX;
std::cout << "\n\nIt's " << getPlayer1Name() << "'s turn, select the position you want to move to:";
}
}
bool TicTacToeGame::haveTied() const {
if (moveCount == 9) return true;
return false;
}
void TicTacToeGame::resetMarker(int position) {
board[getRow(position)][getColumn(position)] = (char) position;
}
main.cpp
#include "TicTacToeGame.h"
int main() {
TicTacToeGame game;
game.play(game);
return 0;
}
This line:
std::cout << "best index: " << best.index << " best score: " << best.score << std::endl;
best.index is uninitialized when this line is printed. That is, you never set best.index to a value.
Further, you are passing an instance of TicTacBoard by value as a parameter to another instance of methods on the same class. Some of your code operates on the board parameter. Other parts work implicitly on this. You probably want to eliminate the passing around of board by value.
Change your code such that it's invoked like this in main.
TicTacToeGame game;
game.play();
And remove all the places where you pass board as a parameter.

Knight's Tour C++ using stack

I am currently working on Knight tour Chessboard game in c++ using Stack to store my move. I encounter a weird loop that does not end the program. Can anybody help me with the code?
#include <iostream>
#include <stack>
#include <map>
#include <cstdlib>
using namespace std;
struct whereIam
{
int row, col;
};
struct L_shape_pattern
{
int Lrow[8]={1,1,2,2,-1,-1,-2,-2};
int Lcol[8]={2,-2,1,-1,2,-2,1,-1};
};
bool check_if_valid(int row, int col)
{
if ((row >= 0 && col >= 0) && (row < 8 && col < 8))
{
// cout << "here in valid " <<endl;
return true ;
}
else
return false;
}
bool check_empty(bool board[8][8], whereIam position)
{
// if (board[position.row][position.col] == false)
// return false;
// else
// return true;
if (board[position.row][position.col] == true)
{
// cout << "here in check empty" <<endl;
return true;
}
else
return false;
}
bool isReady(whereIam &position,bool board[8][8])
{
// cout << "here" << endl;
int ready = 0;
for (int i = 0 ; i < 8 ; i ++)
{
for (int j = 0 ; j < 8 ; j++)
{
if(board[i][j] == false)
{
ready += 1;
}
}
}
cout << "ready: " <<ready << endl;
if (ready == 64)
{
cout << "done" << endl;
return true;
}
else
return false;
}
void findspot(whereIam &position,bool board[8][8], stack<whereIam> &sequence)
{
L_shape_pattern Lshape;
// stack<whereIam> initial;
stack<int> counter;
for (int j = 0 ; j< 9 ;j++)
{
//nothing is assign here
if (check_if_valid(position.row+Lshape.Lrow[j],position.col+Lshape.Lcol[j]) /*&& check_empty(board,position)*/)
{
// cout << "here in valid in spot " <<endl;
whereIam hello;
hello.row = position.row+Lshape.Lrow[j];
hello.col = position.col+Lshape.Lcol[j];
// cout << hello.row << " " << hello.col << endl;
if (check_empty(board,hello))
{
// cout << "here in empty" <<endl;
// int possible_row = position.row+Lshape.Lrow[j];
// int possible_col = position.col+Lshape.Lcol[j];
// position.row = possible_row;
// position.col = possible_col;
position.row = hello.row;
position.col = hello.col;
sequence.push(position);
// initial.push(position);
// cout << position.row << " " << position.col << endl;
counter.push(j);
board[position.row][position.col] = false;
j = -1;
if (isReady(position,board) == true)
{
cout << "in if ready" << endl;
exit(0);
}
}
}
if (j == 8 )
{
// cout << "here in j = 8" <<endl;
board[position.row][position.col] = true;
// cout << " pop board " << position.row <<" " << position.col << endl;
sequence.pop();
position = sequence.top();
// increment to the position where it need to be backtracking and it increment by one
j = counter.top();
counter.pop();
if (isReady(position,board) == true)
{
cout << "in if ready" << endl;
exit(0);
}
}
}
}
//bool movetheKnight(whereIam &position,bool board[8][8], stack<whereIam> &sequence)
//{
//}
void open_all_spot( bool board[8][8])
{
for (int i = 0 ; i< 8 ; i++)
for (int j= 0 ; j <8 ; j++)
{
board[i][j] = true;
}
}
int main()
{
bool board[8][8];
open_all_spot(board);
whereIam position;
stack<whereIam> sequence;
cout << "Enter the initial position" << endl;
cout << "row : " ;
cin >> position.row;
cout << "column:";
cin >> position.col;
sequence.push(position);
//assign the initial position to be occupied already
board[position.row][position.col] = false;
findspot(position,board,sequence);
cout << "here end all" << endl;
return 0;
}
Some part I just created to debug and see how each function work so ignore those part.
The loop always goes on and never seems to end at all. I tried to track data in the stack but it does seems reasonable to me.
Any help would be appreciated.
When looking at this part of your code:
for ( int j = 0; j < 9; j++ ) {
if ( check_if_valid(position.row+Lshape.Lrow[j],position.col+Lshape.Lcol[j]) /*&& check_empty(board,position)*/) {
// code...
if ( checkEmpty( board, hello ) {
// code...
j = -1;
if ( isReady(position, board) == true ) { // == true not needed
// code...
}
}
}
if ( j == 8 ) {
// code...
j = counter.top()
// code...
if ( isReady(position, board) == true ) { // == true not needed
// code...
}
}
} // for loop
Think about what happens in the 1st nested if statement within the for loop when the condition is returned true. You are changing j to be -1.
Again in the 2nd if statement within the for loop if j==8 you again are changing j to be counter.top().
This behavior will cause infinite recursion of the for loop. Here is a simple example:
#include <iostream>
#include <iomanip>
int main() {
int counter = 0;
for ( int i = 0; i < 5; i++ ) {
if ( i == 4 ) {
i = 0;
}
++counter;
std::cout << "Count the recursion: "
<< std::setw( 2 ) << counter << " " << i << '\n';
// just to stop the recursion
if ( counter == 10 ) break;
}
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
The above program without the last if statement will simulate what is happening in your program. I only included that so as to stop the loop just to show the progression of the output.
I don't know if you intentionally want an infinite recursion of a for loop or not; but if you do you need to check your counter variable(s) in a debugger to make sure that they match the value needed to execute the statement involved in exiting the loop to stop the recursion. Just as I have shown in my small example above; without the condition of the counter being equal to 10. The loop would of continued on forever.
As a side note if you do intend to have an infinite loop; it is usually better to structure them in this manner this way it is more clear as to what you intended to do.
int counter = 0;
for ( ; ; ) {
++counter;
// do some work;
if ( counter == exit condition ) break;
}
or
int counter = 0;
for ( ; ; ) {
// do some work;
if work above is valid
increment counter
else
break;
}
or you can use a while loop instead
counter = some value
while ( true ) {
check counter for condition;
do some work
increment or set counter;
}

Removing and shifting remaining elements in an array C++

List.cpp (class definitions)
I have been working on code that is suppose to help familiarize with classes. My code currently has a function that displays a menu of options for the users. Option [1] is suppose to add a string, option [2] is suppose to remove a string from the list, option [3] prints the string list, option [4] exits. My option [1] seems to work okay as the user is able to input one string at a time but I am having a hard time with the removal of a string. The strings are currently stored in an array of 10 elements. I believe the function I wrote for the string removal is okay as I have debugged it and it seems successful, however, I am not seeing results on my console window.
My array is located in a private class in my class: string items[MAX_ITEMS]; along with another variable called: int totalItems;
The class is then called in my main function using a switch case:
//This code snippet below is located in a separate cpp file with main
cout << "Please enter the text you want to remove: " << endl;
cin >> userInput;
list1.remove(userInput);
////////////////////////////////////////////////////////////////////
//preprocessor directives
#include <iostream>
#include <string>
//header files
#include "list.h"
using namespace std;
List::List()
{
//clear array prior to starting (set everything to NULL)
for (int i = 0; i < MAX_ITEMS; i++)
{
items[i] = " ";
}
totalItems = 0;
}
//void List::init()
//{
// string items[MAX_ITEMS];
// totalItems = 0;
//}
bool List::insert(const string& data)
{
//verifies that string is not empty, not in the list, and not full
if (data.empty() == true || inList(data) == true || isFull() == true)
{
return false;
}
else
{
// items[isFull)] = data;
// totalItems++;
items[totalItems++] = data;
return true;
}
}
bool List::isEmpty() const
{
//runs through loop to verify array is empty
for (int i = 0; i < MAX_ITEMS; i++)
{
if (items[i].empty() != true)
{
return false;
}
}
return true;
}
//identifies whether the string is full or not
bool List::isFull() const
{
if (totalItems == MAX_ITEMS)
{
return true;
}
else
{
return false;
}
}
//identifies whether the string is already in the list or not
bool List::inList(const string& theList)
{
for (int i = 0; i < MAX_ITEMS; i++)
{
if (items[i] == theList)
{
return true;
}
}
return false;
}
bool List::remove(const string& data)
{
if (inList(data) == true || data.empty() == true)
{
return false;
}
for (int i = 0; i < MAX_ITEMS; i++)
{
if (items[i] == data)
{
items[i] == " ";
for (int j = i; j < MAX_ITEMS; j++)
{
items[j] = items[j + 1];
items[MAX_ITEMS - 1] == " ";
break;
}
}
}
totalItems--;
return true;
}
//prints list
void List::printList()
{
for (int i = 0; i < MAX_ITEMS; i++)
{
cout << i << items[i] << '\t';
}
}
list_test.cpp (main.cpp)
#include <iostream>
#include <string>
//header files
#include "list.h"
using namespace std;
//function prototypes
int showSelection();
int main()
{
List list1;
string userInput = "";
int userChoice;
// list1.init();
userChoice = showSelection();
while (userChoice != 4)
{
switch(userChoice)
{
case 1:
cout << "Please enter the text you want to add: " << endl;
cin >> userInput;
list1.insert(userInput);
/*if (list1.inList(userInput) == false)
{
cout << "Text is already entered in the list!" << endl;
}*/
if (list1.isFull() == true)
{
cout << "You have entered the MAXIMUM amount of elements!" << endl;
}
break;
case 2:
cout << "Please enter the text you want to remove: " << endl;
cin >> userInput;
list1.remove(userInput);
break;
case 3:
cout << "Printed list: " << endl;
list1.printList();
break;
}
userChoice = showSelection();
}
cout << "Goodbye. Please press enter to exit." << endl;
//TESTING PURPOSES FOR FUNCTIONS
cout << list1.insert(userInput) << endl;
cout << list1.isEmpty() << endl;
cout << list1.isFull() << endl;
cout << list1.inList(userInput) << endl;
return 0;
}
/* ===========================================
Name: showSelection
Desc: displays menu for user to choose options
for their inputted string(s).
Args: none
Retn: none
=========================================== */
int showSelection()
{
int userChoice;
bool exit = false;
while (exit == false)
{
cout << "\nTo select an option, please enter the corresponding number: " << endl;
cout << "[1] to add a string" << endl;
cout << "[2] to remove a string" << endl;
cout << "[3] to print a string" << endl;
cout << "[4] to exit" << endl << endl;
cin >> userChoice;
cout << "You entered option: " << userChoice << endl;
cout << '\n';
if (userChoice == 1 || userChoice == 2 || userChoice == 3 || userChoice == 4)
{
exit = true;
}
else
{
cout << "Invalid selection" << endl;
}
}`enter code here`
return userChoice;
}
Here is how you code should probably look:
bool List::remove(const string& data) {
// only check if the list is empty so you don't nececarily go through it
// you shoudn't ask here if the given string is in the list
// because you will search for it anyway just below
if (data.empty())
return false;
for (int i = 0; i < MAX_ITEMS; ++i) {
if (items[i] == data) { // now if it was found
items[i] = " "; // set it to your empty value
--totalItems; // prefix -- is faster then postfix one (no copy is created)
for (int j = i; j < MAX_ITEMS - 1; ++j) {
// stop at j < MAX_ITEMS - 1 because you wouldn't want
// to swap last element with the next because there
// is none behind it
if (items[j + 1] == " ")
// if the next item is already empty you don't need to shift any more
return true;
// swap the next item with much more
// efficient std::swap function
std::swap(items[j], items[j + 1]);
}
return true; // value is removed and items shifted so you can now return
}
}
// if function gets to this point that means the value wasn't found
return false;
}
If you would like to make your code more efficient, I can give you more suggestions on how to do it. This above should answer your question.
Also using an array for a struct like this isn't optimal at all. Using linked listed would mean no shifting would be required.
Edit: replaced long text with a code example
Edit2: added return statement if shifting is no longer necessary
FOR me it's unclear what you want to do as unavailability of full code to run.
But I think this should work as of what I think yo want to do
bool List::remove(const string& data){
for (int i = 0; i < totalItems; i++)
{
if (items[i] == data)
{
for (int j = i; j < totalItems-1; j++)
{
items[j] = items[j+1];
}
totalItems--;
return true;
}
}
return false;
if (inList(data) == true || data.empty() == true)
{
return false;
}
If the data parameter is in your list object, you return without removing anything? this should be !inList(data)
Additionally, when you make it into the loop below this code this loop:
for (int j = i; j < MAX_ITEMS; j++)
{
items[j] = items[j + 1];
items[MAX_ITEMS - 1] == " ";
break;
}
will only execute for j=i, the "break" statement will stop execution of this inner loop, and go back to the outer loop.
EDIT: this is how I personally would go about this problem.
bool List::remove(const string& data)
{
bool retVal;
if (!inList(data) || data.empty())
{
retVal = false;
}
else{
for (int i = 0; i < MAX_ITEMS; i++)
{
if (items[i] == data)
{
items[i] = " ";
for (int j = i; j < (MAX_ITEMS - 1); j++)
{
items[j] = items[j + 1];
}
items[MAX_ITEMS-1] = " ";
}
}
totalItems--;
retVal = true;
}
return retVal;
}

C++ Bowling Simulator Program

I recently received an assignment to create a bowling program in C++ that simulates two people bowling and outputs the correct score for each frame. My program works by first generating all the throws for each frame and then accumulating the score afterwards in a separate method. I was able to get the program to work when the player bowls a non-perfect game and a perfect game, but I am having problems with when a player bowls all spares. I rigged the code to make it so I have 9 for a first throw and 1 for the second throw (this is in frame.cpp). The total should be 190, but I am getting 191 and I can't seem to find the error. Each bowling class contains an array of 11 frames. I know there are only 10 frames but this is to account for if the player gets a strike on the tenth frame. Any help would be appreciated, thanks.
Here is the frame. h file
#ifndef FRAME_H
#define FRAME_H
#include<iostream>
using namespace std;
class Frame
{
private: int throw1;
int throw2;
int score;
bool spare;
bool strike;
public: Frame();
int genThrow(int size);
int getFirstThrow();
int getSecondThrow();
int getScore();
void setScore(int);
void setFirstThrow(int value1);
void setSecondThrow(int value2);
void setStrike(bool value);
void setSpare(bool value);
bool getStrike();
bool getSpare();
};
#endif
Here is the frame.cpp file
#include "Frame.h"
#include<iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
Frame::Frame()
{
spare = false;
strike = false;
throw1 = 0;
throw2 = 0;
score = 0;
}
//generates a random throw
int Frame::genThrow(int size)
{
int randomNumber = 0;
if (size < 10 || throw1 != 10)
{
randomNumber = 0 + rand() % (11 - throw1); //generate a number between 0 and 10
}
else
{
randomNumber = 0 + rand() % (11);
}
//cout << randomNumber << endl;
return randomNumber;
}
//get first throw
int Frame::getFirstThrow()
{
return throw1;
}
//get second throw
int Frame::getSecondThrow()
{
return throw2;
}
//get the score of both throws
int Frame::getScore()
{
return score;
}
//set the score
void Frame::setScore(int value)
{
score = value;
}
//set the first throw
void Frame::setFirstThrow(int value1)
{
//throw1 = genThrow(value1); //normal generator
//throw1 = 10; //strike game rigged
throw1 = 9; //spare game rigged
}
//set the second throw
void Frame::setSecondThrow(int value2)
{
//throw2 = genThrow(value2); //normal generator
throw2 = 1; //spare game rigged
//throw2 = 10; //strike game rigged
}
//set the strike
void Frame::setStrike(bool value)
{
strike = value;
}
//set the spare
void Frame::setSpare(bool value)
{
spare = value;
}
//get the strike
bool Frame::getStrike()
{
return strike;
}
//get the spare
bool Frame::getSpare()
{
return spare;
}
Here is the bowling.h file
#ifndef BOWLING_H
#define BOWLING_H
#include "Frame.h"
#include<iostream>
using namespace std;
class Bowling
{
private: Frame a[11];
public: void accumulateScore();
void bowl();
void printData();
};
#endif
Here is the bowling.cpp file
#include "Bowling.h"
#include<iostream>
using namespace std;
//takes all of the throw values after bowling and accumulates the correct score
void Bowling::accumulateScore()
{
int totalSum = 0;
for (int x = 0; x < 10; x++)
{
if (a[x].getFirstThrow() + a[x].getSecondThrow() < 10) //not a strike or spare
{
totalSum += a[x].getFirstThrow() + a[x].getSecondThrow();
a[x].setScore(totalSum);
}
else if (a[x].getFirstThrow() == 10) //throws a strike
{
if (x < 9)
{
totalSum += 10 + a[x + 1].getFirstThrow() + a[x + 1].getSecondThrow();
if (a[x + 2].getStrike() == true)
{
totalSum += 10;
}
a[x].setScore(totalSum);
}
}
else if (a[x].getFirstThrow() + a[x].getSecondThrow() == 10) //throws a spare
{
if(x < 10)
{
totalSum += 10 + a[x + 1].getFirstThrow();
a[x].setScore(totalSum);
}
}
}
//player got the 11th frame
if (a[9].getStrike() == true)
{
totalSum += 10 + a[10].getFirstThrow() + a[10].getSecondThrow();
a[9].setScore(totalSum);
}
else if (a[9].getSpare() == true)
{
totalSum += 10;
a[9].setScore(totalSum);
}
}
void Bowling::bowl()
{
//generate all throws and store them in the frames
for (int x = 0; x < 10; x++)
{
a[x].setFirstThrow(x);
if (a[x].getFirstThrow() == 10)
{
a[x].setStrike(true);
}
if (a[x].getStrike() == false)
{
a[x].setSecondThrow(x);
if (a[x].getFirstThrow() + a[x].getSecondThrow() == 10)
{
a[x].setSpare(true);
}
}
a[x].setScore(a[x].getFirstThrow() + a[x].getSecondThrow());
}
//play the 11th frame if they got a strike on the tenth frame
if(a[9].getStrike() == true)
{
a[10].setFirstThrow(10);
if (a[10].getFirstThrow() == 10)
{
a[10].setStrike(true);
}
a[10].setSecondThrow(10);
cout << "The second throw is this value: " << a[10].getSecondThrow() << endl;
if (a[10].getSecondThrow() == 10)
{
a[10].setStrike(true);
}
else if (a[10].getFirstThrow() + a[10].getSecondThrow() == 10)
{
a[10].setSpare(true);
}
a[9].setScore(a[10].getFirstThrow() + a[10].getSecondThrow());
}
}
void Bowling::printData()
{
for (int x = 0; x < 10; x++)
{
cout << "*****************************" << endl;
cout << "Frame " << x + 1 << endl;
cout << "First throw: ";
if (a[x].getStrike() == true)
{
cout << "Strike!" << endl;
}
else
{
cout << a[x].getFirstThrow() << endl;
}
cout << "Second throw: ";
if (a[x].getStrike() == false)
{
if (a[x].getSpare() == true)
{
cout << "Spare!" << endl;
}
else if(a[x].getSpare() == false)
{
cout << a[x].getSecondThrow() << endl;
}
else
{
cout << endl;
}
}
cout << "Score: " << a[x].getScore();
cout << endl;
}
if (a[9].getStrike() == true)
{
cout << "*****************" << endl;
cout << "Frame 11" << endl;
cout << "First throw: ";
if (a[10].getStrike() == true)
{
cout << "Strike!" << endl;
}
else
{
cout << a[10].getFirstThrow() << endl;
}
cout << "Second throw: ";
if (a[10].getStrike() == false)
{
if (a[10].getSpare() == true)
{
cout << "Spare!" << endl;
}
else
{
cout << a[10].getSecondThrow() << endl;
}
}
else
{
cout << "Strike!" << endl;
}
//cout << "Score: " << a[10].getScore();
cout << endl;
}
}
Here is where I test it in main
#include "Bowling.h"
#include<iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand(time(0));
int dummy = 0;
//create two players that can bowl
Bowling player1;
Bowling player2;
int player1Score = 0;
int player2Score = 0;
//have the players bowl their throws before accumulating score
player1.bowl();
player2.bowl();
//accumulate the score after all of the throws have been done
player1.accumulateScore();
player2.accumulateScore();
//print player 1 data
cout << "Here are the throws and score for the first player: " << endl;
player1.printData();
//spacing
cout << endl << endl;
//print player 2 data
cout << "Here are the throws and score for the second player: " << endl;
player2.printData();
cout << "Enter a dummy number:" << endl;
cin >> dummy;
return 0;
}

C++ advice how to break a while loop

I'm building a battleships game and I need some advices how to deal with this problem.
Okey so the problem is that the game ends when both players has shoot down all the ships, this is controlled by a while loop and i want it to break as fast as one player has shot down the opponent.
The problem is at the function void ShootAtShip(int board1[], int board2[], string names[], int cap) and the while loop says while ((board1[i] != 0 || board2[i] != 0)) what I think is the problem is that the while loop has to run all the way from top to bottom before it ends, I want it to break in the middle IF board1 gets all 0's.
bool isGameOver(int board1[], int board2[], int cap)
{
bool lost1 = true;
bool lost2 = true;
for (int i = 0; i < cap && lost1 != false; ++i)
if (board1[i] != 0)
lost1 = false;
if (lost1)
return true;
for (int i = 0; i < cap && lost2 != false; ++i)
if (board2[i] != 0)
lost2 = false;
return lost2;
}
void ShootAtShip(int board1[], int board2[], string names[], int cap) {
const int hit = 0;
int shot = 0;
int temp;
isGameOver(board1, board2, cap);
for (int i = 0; i < cap; i++) {
while ((board1[i] != 0 || board2[i] != 0)) { //detects if any board has all their ships shot down
cout << names[1] << " set a position to shoot." << endl;
cin >> shot;
temp = shot;
while ((shot >= cap) || (shot < 0)) { //detects if the number is allowed
cout << "That number is not allowed, " << names[1] << " set a position to shoot." << endl;
cin >> shot;
}
if (board1[shot] != 0) {
board1[shot] = 0;
cout << "Hit!" << endl;
}
else {
cout << "You missed." << endl;
}
shot = 0;
cout << names[0] << " set a position to shoot." << endl;
cin >> shot;
while ((shot >= cap) || (shot < 0)) { //detects if the number is allowed
cout << "That number is not allowed, " << names[0] << " set a position to shoot." << endl;
cin >> shot;
}
if (board2[shot] != 0) {
board2[shot] = 0;
cout << "Hit!" << endl;
}
else {
cout << "You missed." << endl;
}
}
}
cout << "Testing is while loop stops";
}
So the reason the loop does not break is because you are using the wrong logic operator in your condition.
while ((board1[i] != 0 || board2[i] != 0))
should be
while (board1[i] && board2[i])
I believe you're thinking "if board 1 is empty or board 2 is empty, then break", but what you typed out is "if board 1 has anything left, or board 2 has anything left, keep going".
Also, do note that if (n != 0) is potentially more efficient (and just the same) as if (n).