I'm trying to print a hollow square. I currently have the top, bottom, and left borders drawn but for some reason cannot get the right side to draw in the correct place. I'm sure its a simple fix but I'm new to this so sorry for noobness.
int main()
{
const int boardX = 10;
const int boardY = 10;
char gameBoard[boardX][boardY];
for (int i = 0; i != boardX; i++)
{
for (int k = 0; k != boardY; k++)
{
if (i == 0 || i == 9 || k == 0 || k == 9)
{
gameBoard[i][k] = '*';
cout << gameBoard[i][k];
}
}
cout << "\n";
}
system("pause");
return 0;
}
You forgot to print spaces to make the square hollow:
int main()
{
const int boardX = 10;
const int boardY = 10;
char gameBoard[boardX][boardY];
for (int i = 0; i != boardX; i++)
{
for (int k = 0; k != boardY; k++)
{
if (i == 0 || i == 9 || k == 0 || k == 9)
{
gameBoard[i][k] = '*';
cout << gameBoard[i][k];
}
else
{
gameBoard[i][k] = ' ';
cout << gameBoard[i][k];
}
}
cout << "\n";
}
return 0;
}
Note: I followed your style to make the changed part stand out, but normally you would separate the construction of the board and printing it to the screen into separate code blocks/functions.
Related
I have changed a Tic-Tac-Toe program from using a normal 3x3 grid to a grid-size chosen by the user (between 3 and 9). I am using a global constant 'SIZE' to hold the value the user chooses. My issue is adapting my winMove(); function so that it adjusts to check for the winning move based on the current board size chosen by the user(SIZE). I have tried different loops but can't get it to work. Right now it will only work with a 3x3 board.
I am still learning c++ and I have been stuck on this for a few days so I'm hoping a friendly person can help. This is my full program so far, hope it's not too much of a mess!
#include <iostream>
using namespace std;
struct TicTacToe
{
char **board;
};
void makeBoard(TicTacToe&);
void deallocBoard(TicTacToe&);
void printBoard(TicTacToe);
bool isDraw(TicTacToe);
void convertInput(char, char, int&, int&);
char winMove(TicTacToe, int, int);
bool validateSIZE(int);
int SIZE = 1;
int main(){
while(SIZE < 3 || SIZE > 9)
{
cout << "Enter number between 3 and 9 for the length of board.\n";
cout << "Example: 4 will make a board with 4 rows and 4 columns: ";
cin >> SIZE;
validateSIZE(SIZE);
}
TicTacToe game;
makeBoard(game);
char winner = 0;
char turn = 'X';
char rowIn, colIn;
int row, column;
while(!winner && !isDraw(game))
{
printBoard(game);
cout << "\nPlayer " << turn << "'s move (input format: a1): ";
cin >> rowIn >> colIn;
convertInput(rowIn, colIn, row, column);
if (game.board[row][column]==' ')
{
game.board[row][column] = turn;
if (turn == 'X')
{turn = 'O';}
else
{turn = 'X';}
winner = winMove(game, row, column);
}
else
cout << "Taken, try again!\n";
}
printBoard(game);
if (winner == 'X' || winner == 'O')
{cout << " Congrats, the winner is " << winner << '.' << endl;}
else
{cout << " Game ends in a draw." << endl;}
cout << endl << "Game Over!" << endl << endl;
deallocBoard(game);
return 0;
}
// Need help with this function.
char winMove(TicTacToe gameIn, int i, int j)
{
//row win
if (gameIn.board[i][0]==gameIn.board[i][1] &&
gameIn.board[i][0]==gameIn.board[i][2])
{
return gameIn.board[i][j];
}
//column win
if (gameIn.board[0][j]==gameIn.board[1][j] &&
gameIn.board[0][j]==gameIn.board[2][j])
{
return gameIn.board[i][j];
}
//left diagonal win
if (gameIn.board[0][0] != ' ' &&
gameIn.board[0][0] == gameIn.board[1][1] &&
gameIn.board[0][0] == gameIn.board[2][2])
{
return gameIn.board[i][j];
}
//right diagonal win
if (gameIn.board[0][2] != ' ' &&
gameIn.board[0][2] == gameIn.board[1][1] &&
gameIn.board[0][2] == gameIn.board[2][0])
{
return gameIn.board[i][j];
}
return 0;
}
bool validateSIZE(int SIZE)
{
if(SIZE < 3 || SIZE > 9)
{
cout << "\n\nNumber must be between 3 and 9!\nTry again!\nPlease ";
return false;
}
return true;
};
void makeBoard(TicTacToe& gameIn)
{
gameIn.board = new char*[SIZE];
for(int i = 0; i < SIZE; i++)
{gameIn.board[i] = new char[SIZE];}
for(int j =0; j < SIZE; j++)
for(int k = 0; k < SIZE; k++)
{gameIn.board[j][k] = ' ';}
}
void deallocBoard(TicTacToe& gameIn)
{
for(int i = 0; i < SIZE; i++)
delete [] gameIn.board[i];
delete [] gameIn.board;
gameIn.board = NULL;
}
void printBoard(TicTacToe gameIn)
{
int temp = 1;
cout << " ";
while(temp < SIZE + 1)
{
cout << temp << " ";
temp++;
}
temp = 1;
cout << endl;
for(int i = 0; i < SIZE; i++)
{
cout << char(i + 'a') << '|';
for(int j = 0; j < SIZE; j++)
{
cout << gameIn.board[i][j] << '|';
}
cout << endl;
}
}
bool isDraw(TicTacToe gameIn)
{
bool full = true;
for(int i = 0; full && i < SIZE; i++)
for(int j = 0; full && j < SIZE; j++)
full = gameIn.board[i][j] != ' ';
return full;
}
void convertInput(char rowIn, char colIn, int& row, int& column)
{
row = toupper(rowIn) - 'A';
column = colIn - '1';
}
You can easily use 2 for loops to iterate every starting point and its direction to preform victory checking. Something that would look like this:
// hor ver diagonals
// dx[4] = {1, 0, 1, 1};
// dy[4] = {0, 1, 1, -1};
// check horizontal win
for(int i = 0; i < SIZE; ++i)
{
bool win = true;
for(int j = 1; j < SIZE; ++j)
{
if(gameIn.board[j][i] != gameIn.board[j - 1][i])
{
win = false;
break;
}
}
if(win == true){return ;}
}
// check vertical win
.
.
.
// check diagonal 1 win
for(int i = 1; i < SIZE; ++i)
{
if(gameIn.board[i][i] != gameIn.board[i - 1][i - 1])
break;
if(i == SIZE - 1)return ;
}
// check diagonal 2 win
for(int i = 1; i < SIZE; ++i)
{
if(gameIn.board[i][SIZE - i - 1] != gameIn.board[i - 1][SIZE - i])
break;
if(i == SIZE - 1)return ;
}
I'll leave the vertical win for you.
i'm trying to make a unbeatable tic tac toe for a side project and i can't make it right (i can actually beat it ironically).
It's actually a implementation of the MiniMax algorithm; i came with this code
#include <iostream>
#include <string>
using namespace std;
struct Move
{
int line, columns;
};
//Return the number of remainings turn based on the number of lest boxes
int remainingsTurns(char grid[3][3])
{
int remainingTurn = 0;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
remainingTurn++;
}
}
}
return remainingTurn;
}
//Print the grid on screen
void printGrid(char grid[3][3])
{
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
cout << "| " << grid[k][i] << " ";
}
cout << "|" << endl;
}
}
//Give a value to the board
int evaluateBoard(char grid[3][3])
{
//Check the board for lines
for (int k = 0; k < 3; k++)
{
if (grid[k][0] == grid[k][1] && grid[k][1] == grid[k][2])
{
if (grid[k][0] == 'x')
{
return +10;
}
else if (grid[k][0] == 'o')
{
return -10;
}
}
}
//Check the board for columns
for (int k = 0; k < 3; k++)
{
if (grid[0][k] == grid[1][k] && grid[1][k] == grid[2][k])
{
if (grid[0][k] == 'x')
{
return +10;
}
else if (grid[0][k] == 'o')
{
return -10;
}
}
}
//Check the board for diagonals
if (grid[0][0] == grid[1][1] && grid[0][0] == grid[2][2])
{
if (grid[0][0] == 'x')
{
return +10;
}
else if (grid[0][0] == 'o')
{
return -10;
}
}
if (grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0])
{
if (grid[0][0] == 'x')
{
return +10;
}
else if (grid[0][0] == 'o')
{
return -10;
}
}
//if no ictory return 0
return 0;
}
// MiniMax algorithm
int miniMax(char grid[3][3], int turn, bool maxMove)
{
int score = evaluateBoard(grid);
if (score == 10)
{
return score;
}
if (score == -10)
{
return score;
}
//Check if the game is a tie
if (remainingsTurns(grid) == 0)
{
return 0;
}
if (maxMove)
{
int best = -1000;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'x';
best = max(best, miniMax(grid, turn + 1, !maxMove));
grid[k][i] = ' ';
}
}
}
return best;
}
else
{
int best = 1000;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'o';
best = min(best, miniMax(grid, turn + 1, !maxMove));
grid[k][i] = ' ';
}
}
}
return best;
}
}
Move playerMov(char grid[3][3])
{
Move playerMove;
int input = -1;
cout << "Enter the column you want to play (1, 2 or 3)" << endl;
cin >> input;
if (input == 1 || input == 2 || input == 3)
{
playerMove.columns = input-1;
input = -1;
}
else
{
cout << "Error, enter a valid number!" << endl;
playerMov(grid);
}
cout << "Enter the line you want to play (1, 2 or 3)" << endl;
cin >> input;
if (input == 1 || input == 2 || input == 3)
{
playerMove.line = input-1;
input = -1;
}
else
{
cout << "Error, enter a valid number!" << endl;
playerMov(grid);
}
return playerMove;
}
//return the best move using the MiniMax
Move findMove(char grid[3][3])
{
int best = -1000;
Move move;
move.line = -1;
move.columns = -1;
//Check all move to find if this move is the best possible move
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'x';
int moveValue = miniMax(grid, 0, false);
grid[k][i] = ' ';
if (moveValue > best)
{
move.line = k;
move.columns = i;
}
}
}
}
return move;
}
int main()
{
char grid[3][3];
int turn = 0;
Move playerMove, algoMove;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
grid[k][i] = ' ';
}
}
cout << "Welcome to the unbeatable Tic Tac Toe !" << endl;
do
{
printGrid(grid);
playerMove = playerMov(grid);
grid[playerMove.line][playerMove.columns] = 'o';
Move computerMove = findMove(grid);
grid[computerMove.line][computerMove.columns] = 'x';
} while (remainingsTurns(grid) > 0);
cout << endl;
}
but the movements of the algorithm doesn't seems right, it always choose the bottom right corner and i don't understand why...
This implementation is largely inspired by this article from Geek for Geek where i tried to steal the algorithm but i can't get it right to make it fit for single player.
What do i miss?
There are multiple bugs in your code:
You are checking the value of grid[0][0] in grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0] case of the function evaluateBoard. It should be grid[0][2].
playerMov(grid); in the function playerMov should be return playerMov(grid);. Otherwise, the re-entered "correct" values will be dropped and (partly) uninitalized playerMov will be returned.
You should update best to moveValue when moveValue > best in the function findMove. (this should be the cause of the issue on your question)
So I went to the next step in learning c++ and that's a matrix. I tried to do an easy tic tac toe game but my game fails to correctly check if the game is over. If you put height = 2 and width = 2 in the first round it says you won... I don't see where could I have messed it up, all seemed pretty good in my mind...
int map[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
map[i][j] = 0;
}
}
bool finished = false;
int player = 1;
while (!finished) {
//attack
cout << "player " << player << " it is your turn"<< endl;
cout << "The map looks like this:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << map[i][j] << " ";
}
cout << endl;
}
bool correctMove;
int height, width;
do
{
correctMove = true;
cout << "Where do you want to attack?" << endl;
cout << "height = "; cin >> height;
cout << "width = "; cin >> width;
if (map[height][width] != 0 || width > 2 || height > 2) {
correctMove = false;
}
} while (!correctMove);
map[height][width] = player;
//check finish game
bool foundSequenceLine = true;
for (int i = 0; i < 3; i++) {
if (map[height][i] != player) {
foundSequenceLine = false;
}
}
bool foundSequenceColumn = true;
for (int i = 0; i < 3; i++) {
if (map[i][width] != player) {
foundSequenceColumn = false;
}
}
bool foundSequenceDiag1 = true;
if (height == width) {
for (int i = 0; i < 3; i++) {
if (map[i][i] != player) {
foundSequenceDiag1 = false;
}
}
}
bool foundSequenceDiag2 = true;
if (height + width == 2) {
for (int i = 0; i < 3; i++) {
if (map[2-i][i] != player) {
foundSequenceDiag2 = false;
}
}
}
if (foundSequenceColumn || foundSequenceLine || foundSequenceDiag1 || foundSequenceDiag2) {
finished = true;
cout << "Congrats player " << player << " you won!!!";
}
//change turn
if (player == 1) {
player++;
}
else {
player--;
}
}
}
code makes an assumption, then avoids checking it.
Your code assumes the player has won unless you can exhaustively prove they haven't.
The problem is that you then short-circuit two of the tests that prove a move is not a winning move.
Look at what this code is doing:
bool foundSequenceDiag1 = true;
if (height == width) {
for (int i = 0; i < 3; i++) {
if (map[i][i] != player) {
foundSequenceDiag1 = false;
}
}
}
First, you say "the player has won" foundSequenceDiag1=true;. Then you say, "was the move on a diagonal?", and only then do you run code that can set foundSequenceDiag1 to false.
If the player makes a move that isn't on the diagonal, the check won't run.
to fix:
bool foundSequenceDiag1 = (height==width); // true if the player played on diagonal
if (foundSequenceDiag1) { // loop code now only executes if player played on diagonal
for (int i = 0; i < 3; i++) {
if (map[i][i] != player) {
foundSequenceDiag1 = false;
}
}
}
when you've found something, stop looking.
If I were writing your checks, I'd make use of the break keyword to stop looking once I found an answer.
for (int i = 0; i < 3; i++) {
if (map[i][i] != player) {
foundSequenceDiag1 = false;
break; // can't be true now, so stop checking.
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have recently coded Connect 4 in C++. I would like to know if there are any improvements that could be made to the code.
connect4.cpp:
#include <iostream>
#include <stdlib.h>
char grid[6][7];
void setup_grid();
void display_grid();
void player_turn(char);
bool four_in_a_row(char);
bool grid_is_full();
int main()
{
char player = '1';
setup_grid();
system("cls");
while(true)
{
display_grid();
player_turn(player);
if(four_in_a_row(player))
{
system("cls");
display_grid();
std::cout << "Player " << player << " has won!" << std::endl;
goto end;
}
else if(grid_is_full())
{
system("cls");
display_grid();
std::cout << "It is a draw." << std::endl;
goto end;
}
if(player == '1')
player = '2';
else if(player == '2')
player = '1';
system("cls");
}
end:
std::cin.get();
std::cin.get();
return 0;
}
void setup_grid()
{
for(int i = 0; i < 6; i++)
for(int j = 0; j < 7; j++)
grid[i][j] = '0';
}
void display_grid()
{
std::cout << std::endl;
std::cout << "Enter a column number (1-7) to put a piece into that column." << std::endl;
std::cout << std::endl;
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 7; j++)
std::cout << grid[i][j] << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
}
void player_turn(char player)
{
int column_number;
bool valid;
do
{
valid = true;
std::cout << "Player " << player << ": ";
std::cin >> column_number;
column_number--;
if((column_number < 0) || (column_number > 6))
{
std::cout << "That number was not between 1 and 7" << std::endl;
valid = false;
continue;
}
if(grid[0][column_number] != '0')
{
std::cout << "Column is full." << std::endl;
valid = false;
}
}
while(!valid);
for(int i = 0; i < 6; i++)
{
if(grid[i + 1][column_number] != '0')
{
grid[i][column_number] = player;
break;
}
else if(i == 6)
{
grid[i][column_number] = player;
break;
}
}
}
bool four_in_a_row(char player)
{
// Horizontal check:
for(int i = 0; i < 6; i++)
for(int j = 0; j < 4; j++)
if(grid[i][j] == player && grid[i][j+1] == player)
if(grid[i][j+2] == player && grid[i][j+3] == player)
return true;
// Vertical check:
for(int i = 0; i < 3; i++)
for(int j = 0; j < 7; j++)
if(grid[i][j] == player && grid[i+1][j] == player)
if(grid[i+2][j] == player && grid[i+3][j] == player)
return true;
// Diagonal check:
for(int y = 0; y < 3; y++)
{
for(int x = 0; x < 7; x++)
{
if(grid[y][x] == player)
{
// Diagonally left:
if(grid[y+1][x-1] == player)
{
if(grid[y+2][x-2] == player)
if(grid[y+3][x-3] == player)
return true;
}
// Diagonally right: (There is an error here)
if(grid[y+1][x+1] == player)
{
if(grid[y+2][x+2] == player)
if(grid[y+3][x+3] == player)
return true;
}
}
}
}
return false;
}
bool grid_is_full()
{
for(int y = 0; y < 6; y++)
{
for(int x = 0; x < 7; x++)
{
if(grid[y][x] == '0')
return false;
}
}
return true;
}
I know the goto statement (line 36) is bad programming practice but it seemed appropriate to the situation.
Should I use camelCase or snake_case?
On lines 48 and 49, why do I have to type std::cin.get() twice to get one input?
1) Put the I/J size in a #define instead of multiple use of 6 & 7.
2) Every time when a player place an entry reduce 1 from 6*7 count variable. When count variable reaches 0 grid_is_full.
I want to input alphabet to binary code, and output the alphabet from generated binary code.
Example
1 --> a
01 --> b
001 --> c
0001 --> d
00001 --> e
000001 --> f
a => 1
b => 01
c => 001
d => 0001
e => 00001
-------------Encode.cpp--------------------
#include "Encode.h"
Encode::Encode()
{
}
Encode::~Encode()
{
}
void Encode::inputWord()
{
cout << "Input word: ";
cin.getline(word, 255);
return;
}// User input a word
char * Encode::getBuf(void)
{
return buffer;
}// return buffer to Decode::setBuf(char* buf)
void Encode::printEncResult()
{
int size = strlen(word);
int buffersize = 0;
cout << "Encoding result" << endl; // print similar binary
for (int i = 0; i < size; i++)
{
if (word[i] == 'z')
{
for (int j = 0; j < 25; j++)
{
cout<<buffer[buffersize++];
}
}
else
{
int len = (int)word[i] - (int)'a';
for (int j = 0; j < len; j++)
{
cout<<buffer[buffersize++];
}
cout << buffer[buffersize++];
}
}
}// output similar binary
int Encode::encodeWord(void)
{
int buffersize = 0;
int size = strlen(word);
for (int i = 0; i < size; i++)
{
if (word[i] == 'z')
{
for (int j = 0; j < 25; j++)
{
buffer[buffersize++] = '0';
}
}
else
{
int len = (int)word[i] - (int)'a';
for (int j = 0; j < len; j++)
{
buffer[buffersize++] = '0';
}
buffer[buffersize++] = '1';
}
}
return 0;
}// change word to similar binary
--------Decode.cpp-------------
#include "Decode.h"
Decode::Decode()
{
}
Decode::~Decode()
{
}
void Decode::setBuf(char * buf)
{
int i = 0;
int size = 0;
while (*(buf + i) == '1' || *(buf + i) == '0')
{
i++;
}
size = i;
for(int i = 0; i < size; i++)
{
buffer[i] = buf[i];
}
return;
}// set buffer from Encode::getBuf(void)
void Decode::printWord() // print similar binary
{
int i = 0;
int size = 0;
int check = 1;
while (check)
{
if (word[i] >= 'a' && (int)word[i] <= 'z')
{
i++;
size = i;
}
else
check = 0;
}
cout << "Decoding result" << endl;
for (int i = 0; i < size; i++)
{
if (word[i] >= 'a' && (int)word[i] <= 'z') // **this part is also strange** I can not shoten the code.
cout<<word[i];
}
cout << endl;
}
int Decode::decodebin(vector<char> buffer)
{
int buffersize = 0;
int check = 0;
int size = 0;
int i = 0;
char printval = 'a';
while (buffer[i] == '1' || buffer[i] == '0')
{
i++;
}
size = i;
for (int j = 0; j < size; j++) // nested loop does not work. I want save words in order
{
for (i = 0; i < size; i++)
{
if (buffer[i] == '0')
++printval;
else
{
word[j] = printval; // In this part, word[0] does not have any value.
printval = 'a';
}
}
}
return 0;
}
In this code, I want save values in order, but word[0] does not have any value. Moreover, If I input 'bb' then, 'bbbb' saved ins word array.
There are some problems and consideration you need to take care of:
as Fei Xiang said in the comments don't use magic numbers, use characters since you have a character array.
int printWord function you actually get the word and print the same word, there is no conversion as your problem statement. your didn't take buffer into account.
you are using some data validation to get your array size, this could end up a disaster(UB). you need to pass your array size to your function or use std::vector(Recommended).
in this statement if ((int)word[i] >= 97 || (int)word[i] <= 122) as I said don't use magic number and || should be change to && otherwise you end up in an infinity loop.
Anyway by keeping your approach(using array) and function signature here's what you can do :
int Decode::decodebin(void)
{
int buffersize = 0;
int check = 0;
int size = 0;
int i = 0;
char printval = 'a';
while(buffer[i] == '1' || buffer[i] == '0')
{
i++;
size = i;
}
for(int i = 0; i < size; i++)
{
if(buffer[i] == '0')
++printval;
else
{
cout << printval;
printval = 'a';
}
}
return 0;
}
void Decode::printWord()
{
int i = 0;
int size = 0;
int check = 1;
while(check)
{
if(word[i] >= 'a' && word[i] <= 'z')
{
i++;
size = i;
}
else
check = 0;
}
cout << "Decoding result" << endl;
for(int i = 0; i < size; i++)
{
int distance = word[i] - 'a';
for(int j = 0; j < distance; ++j)
cout << '0';
cout << '1';
}
cout << endl;
}
EDIT BASED ON OP REQUIREMENT IN COMMENTS:
using std::vector you can implement your needs like this :
#include <iostream>
#include <vector>
class Decode
{
public:
void decodebin(std::vector<char> buffer)
{
char printval = 'a';
for(unsigned int i = 0; i < buffer.size(); i++)
{
if(buffer[i] == '0')
++printval;
else
{
word.push_back(printval);
printval = 'a';
}
}
}
void printWord(void)
{
for(auto iter = word.begin(); iter != word.end(); ++iter)
std::cout << *iter;
std::cout << std::endl;
}
private:
std::vector<char> word;
};
int main()
{
Decode decoder;
std::vector<char> buffer = {'0', '1', '0', '0', '0', '0', '1', '0', '0', '0', '1'};
decoder.decodebin(buffer);
decoder.printWord();
return 0;
}
Here decodebin stores the given input into word member variable of Decode class. Then printWord function print word values on the screen.
std::vector has all the power of C-style array and it's nicer and easier to use. You can retrieve it's size whenever you want and you don't have to worry about the memory it's allocating.