I wanted to expand on an older Tic Tac Toe game I made where two players can play versus each other. I want to give the user the option of playing against a difficult AI. The issue is that the AI won't pick the best move all the time. For instance, it will always pick spot 1 if going first. If the user picks spot 2, it will pick spot 4. After this, no matter what the user picks (besides spot 7) the AI won't pick spot 7. Victory for the AI is far from inevitable (the user can still win the game at this point), so that's not the problem.
Any help is appreciated. Thanks!
I'm positive the problem is with my minimax or bestmove functions. It may just be that I haven't properly implemented by minimax function, but I can't spot the issue.
#include <iostream>
#include <iomanip>
#include <string>
#include <array>
// This is a program to play a single game of tic-tac-toe
// between either two human (non-AI) players or an AI.
using namespace std;
void PrintBoard(array <char, 9>);
int programprogress();
int checkwin(array <char, 9>);
int minimax(array <char, 9>, int, int, bool);
int bestMove(array <char, 9>, int);
int Opposite(int);
char PlayerSymbol(int);
const int SIZE = 9;
array <char, SIZE> Pos = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
int player_number = 1;
int k = -11, result;
bool AI = false, first;
// Global variables used by 2 or more functions.
// Array had to be initialized with numbers instead of blank spaces
// because the check win function wouldn't work properly.
int main()
{
string userinp;
cout << "This is tic tac toe! Here's your board!" << endl;
PrintBoard(Pos);
cout << "Would you like to play versus an AI? (Y/N)" << endl;
cin >> userinp;
if (userinp[0] == 'Y')
{
cout << "Excellent! Would you like to start first, or second? (F/S)" << endl;
cin >> userinp;
if (userinp[0] == 'F')
{
cout << "You will start first!" << endl;
first = false;
player_number = 2;
}
else
{
cout << "The AI will start first!" << endl;
first = true;
}
AI = true;
}
else
{
cout << "Excellent! Your game will start soon." << endl;
}
result = programprogress();
player_number--;
PrintBoard(Pos);
if (result == 1)
cout << endl << "Player " << player_number << " has won!!!\n";
else if (result == 10)
cout << endl << "The AI has won! Better luck next time!\n";
else if (result = -10)
cout << endl << "You beat the world's best AI! Congratulations!\n";
else
cout << endl << "The game has been drawn!" << endl;
return 0;
}
void PrintBoard(array <char, 9> Pos)
{
system("cls");
cout << setw(6) << "|" << setw(6) << "|" << endl << setw(3) << Pos[0] << setw(3) << "|" << setw(3) << Pos[1] << setw(3) << "|" << setw(3) << Pos[2] << " TIC TOE" << endl;
cout << "_____|_____|_____" << endl;
cout << setw(6) << "|" << setw(6) << "|" << endl << setw(3) << Pos[3] << setw(3) << "|" << setw(3) << Pos[4] << setw(3) << "|" << setw(3) << Pos[5] << " TAC " << endl;
cout << "_____|_____|_____" << endl;
cout << setw(6) << "|" << setw(6) << "|" << endl << setw(3) << Pos[6] << setw(3) << "|" << setw(3) << Pos[7] << setw(3) << "|" << setw(3) << Pos[8] << " TIC TOE " << endl;
cout << " | |" << endl;
}
int programprogress()
{
while (k == -11 && AI)
{
bool InvalidChoice = false;
char letter;
//player_number = (player_number % 2) ? 1 : 2;
int PlayerChoice;
if (player_number == 2)
{
cout << endl << "What is your move?" << endl;
cin >> PlayerChoice;
while ((PlayerChoice < 1) || (PlayerChoice > 9))
{
cout << "That's an invalid choice! Please choose a number that is 1-9!" << endl;
cin >> PlayerChoice;
}
PlayerChoice--;
letter = (!first) ? 'X' : 'O';
if (Pos[PlayerChoice] == '1' || Pos[PlayerChoice] == '2' || Pos[PlayerChoice] == '3' || Pos[PlayerChoice] == '4' || Pos[PlayerChoice] == '5' || Pos[PlayerChoice] == '6' || Pos[PlayerChoice] == '7' || Pos[PlayerChoice] == '8' || Pos[PlayerChoice] == '9')
{
Pos[PlayerChoice] = letter;
PrintBoard(Pos);
}
/*else
{
cout << "That space is already taken!" << endl;
player_number--;
}*/
k = checkwin(Pos);
if (k != -11)
k = k * -10;
player_number = 1;
}
else
{
cout << endl << "The computer has made its move!" << endl;
letter = (first) ? 'X' : 'O';
if (first)
PlayerChoice = bestMove(Pos, 1);
else
PlayerChoice = bestMove(Pos, 2);
Pos[PlayerChoice] = letter;
PrintBoard(Pos);
k = checkwin(Pos);
if (k != -11)
k = k * 10;
player_number = 2;
}
}
while (k == -11 && !AI)
{
bool InvalidChoice = false;
char letter;
player_number = (player_number % 2) ? 1 : 2;
int PlayerChoice;
cout << endl << "What's player " << player_number << "'s move?" << endl;
cin >> PlayerChoice;
while ((PlayerChoice < 1) || (PlayerChoice > 9))
{
cout << "That's an invalid choice! Please choose a number that is 1-9!" << endl;
cin >> PlayerChoice;
}
PlayerChoice--;
letter = (player_number == 1) ? 'X' : 'O';
if (Pos[PlayerChoice] == '1' || Pos[PlayerChoice] == '2' || Pos[PlayerChoice] == '3' || Pos[PlayerChoice] == '4' || Pos[PlayerChoice] == '5' || Pos[PlayerChoice] == '6' || Pos[PlayerChoice] == '7' || Pos[PlayerChoice] == '8' || Pos[PlayerChoice] == '9')
{
Pos[PlayerChoice] = letter;
PrintBoard(Pos);
}
else
{
cout << "That space is already taken!" << endl;
player_number--;
}
k = checkwin(Pos);
player_number++;
}
return k;
}
int checkwin(array <char, SIZE> Pos)
{
if (Pos[0] == Pos[1] && Pos[1] == Pos[2])
return 1;
else if (Pos[3] == Pos[4] && Pos[4] == Pos[5])
return 1;
else if (Pos[6] == Pos[7] && Pos[7] == Pos[8])
return 1;
else if (Pos[0] == Pos[3] && Pos[3] == Pos[6])
return 1;
else if (Pos[1] == Pos[4] && Pos[4] == Pos[7])
return 1;
else if (Pos[2] == Pos[5] && Pos[5] == Pos[8])
return 1;
else if (Pos[0] == Pos[4] && Pos[4] == Pos[8])
return 1;
else if (Pos[2] == Pos[4] && Pos[4] == Pos[6])
return 1;
else if (Pos[0] != '1' && Pos[1] != '2' && Pos[2] != '3'
&& Pos[3] != '4' && Pos[4] != '5' && Pos[5] != '6'
&& Pos[6] != '7' && Pos[7] != '8' && Pos[8] != '9')
return 0;
else
return -11;
}
int minimax(array <char, SIZE> newpos, int depth, int player, bool opp)
{
int scale = 0;
if ((player == 1 && first) || (player == 2 && !first))
scale = 10;
else
scale = -10;
//cout << scale;
int score = scale*checkwin(newpos);
if (score < 0)
score += depth;
else if (score > 0)
score -= depth;
if (score == -10 || score == 10 || score == 0)
return score;
if (opp)
{
int best = -1000;
for (int i = 0; i < SIZE; i++)
{
if (newpos[i] != 'X' && newpos[i] != 'O')
{
char temp = newpos[i];
newpos[i] = PlayerSymbol(player);
best = max(best, minimax(newpos, depth + 1, Opposite(player), !opp));
newpos[i] = temp;
}
}
return best;
}
else
{
int best = 1000;
for (int i = 0; i < SIZE; i++)
{
if (newpos[i] != 'X' && newpos[i] != 'O')
{
char temp = newpos[i];
newpos[i] = PlayerSymbol(player);
best = min(best, minimax(newpos, depth + 1, Opposite(player), !opp));
newpos[i] = temp;
}
}
return best;
}
}
int bestMove(array <char, SIZE> newpos, int player)
{
int best = -1000;
int bestpos = -1;
for (int i = 0; i < SIZE; i++)
{
if (newpos[i] != 'X' && newpos[i] != 'O')
{
char temp = newpos[i];
newpos[i] = PlayerSymbol(player);
int move = minimax(newpos, 0, player, !first);
newpos[i] = temp;
if (move > best)
{
//cout << "I like pineapple on pizza" << endl;
bestpos = i;
best = move;
}
/*if (move == best)
{
cout << "I like pineapple on pizza" << endl;
}*/
}
}
cout << bestpos;
return bestpos;
}
int Opposite(int x)
{
if (x == 1)
return 2;
else
return 1;
}
char PlayerSymbol(int x)
{
if (x == 1)
return 'X';
else
return 'O';
}
An out of bounds error due to the -1 value of bestpos. I'm not sure how to change this, though.
There are 4 issues that I could find. Solving them seems to lead to the intended behavior.
Firstly, when you call minimax(newpos, 0, player, !first); from inside the bestMove function, you pass player rather than Opposite(player), indicating that the first minimax step will be performed by the same player as the bestMove step. In other words: The AI makes two successive moves for itself. Therefore player needs to be changed to Opposite(player).
Secondly, minimax has a bool variable named opp that seems to indicate whether it is the AI or its opponent making the move. For the first minimax step, opp is set to !first, indicating that only if the AI goes first, the opponent will make a move after the AI. That is incorrect. It is always the opponent making a move after the AI. So bestMove should call minimax with true rather than !first. As an aside, opp is redundant, because you can use (player == 1 && first) || (player == 2 && !first) to check whether it's the AI or its opponent making the move.
Thirdly, the scale is set the wrong way around. With (player == 1 && first) || (player == 2 && !first) you check whether its the AI making a move. But you do that in the next minimax step, after the potentially winning move. So if the AI is making a move and the game is already won, then the opponent made the winning move, not the AI. Ergo, the scale should be
if ((player == 1 && first) || (player == 2 && !first))
scale = -10;
else
scale = 10;
instead.
Lastly, you check whether the score is 10 or -10 after adding the depth. If depth is not 0, then this check will always fail. So beyond depth 0, the AI can only see a draw, never a win. You could instead write
if (score == -10 || score == 10 || score == 0)
{
if (score < 0)
score += depth;
else if (score > 0)
score -= depth;
return score;
}
Hope this answers your question fully.
Related
I'm working on a little poker application and i've run into the first problem I just can't seem to comprehend.
while (allplayersGood != 1) { //round table till all decided
cout << "TOP OF WHILE LOOP";
for (int i = 0; i < PLAYER_COUNT; i++) { //for loop for decisions from non button or blinds
int player_decision = 1;
char choice;
if ((players[i].playerhand.card1.value != 'F') && (players[i].playerhand.card1.value != 'C')) {
if ((players[i].blind != 1 && players[i].blind != 2) && players[i].button != true) {
cout << "\n\n";
cout << " POT: " << playerTable->currentPot;
cout << "\n";
for (int i = 0; i < PLAYER_COUNT; i++) {
cout << "Player " << players[i].playernumber;
cout << " (" << players[i].chip_amount << ") ";
}
while (player_decision == 1) {
if (playerTable->currentBet > players[i].currentBet) {
cout << "\n\nPlayer " << players[i].playernumber << " ("; players[i].playerhand.printhand(); cout << ") " << "Type F for Fold, B for Call, R for Raise: ";
cin >> choice;
players[i].choice = choice;
if (choice == 'F') {
player_decision = 0;
players[i].fold();
}
if (choice == 'R') {
player_decision = 0;
players[i].bet(playerTable);
}
if (choice == 'B') {
player_decision = 0;
players[i].call(playerTable);
}
}
if ((playerTable->currentBet == players[i].currentBet) && player_decision != 0) { //big blind after round table
cout << "\n\nPlayer " << players[i].playernumber << " ("; players[i].playerhand.printhand(); cout << ") " << "Type C for Check, R for Raise: ";
cin >> choice;
players[i].choice = choice;
if (choice == 'B') {
player_decision = 0;
players[i].bet(playerTable);
}
if (choice == 'C') {
if (players[i].check(playerTable) == true) {
player_decision = 0;
}
}
}
}
}
else if (players[i].blind == 1 || players[i].blind == 2) {
if (players[i].blind == 1) {
players[i].chip_amount -= sblind;
playerTable->currentPot += sblind;
players[i].blind = 0;
players[i].currentBet = sblind;
}
if (players[i].blind == 2) {
players[i].chip_amount -= bblind;
playerTable->currentPot += bblind;
players[i].blind = 0;
players[i].currentBet = bblind;
}
}
}
}
for (int i = 0; i < PLAYER_COUNT; i++) { //seperate loop for button and blinds that were ignored in loop above
int player_decision = 1;
char choice;
if (players[i].button == true || players[i].blind == 1) { //button and small blind
cout << "\n\n";
cout << " POT: " << playerTable->currentPot;
cout << "\n";
for (int i = 0; i < PLAYER_COUNT; i++) {
cout << "Player " << players[i].playernumber;
cout << " (" << players[i].chip_amount << ") ";
}
while (player_decision == 1) {
cout << "\n\nPlayer " << players[i].playernumber << " ("; players[i].playerhand.printhand(); cout << ") " << "Type F for Fold, B for Call, R for Raise: ";
cin >> choice;
players[i].choice = choice;
if (choice == 'F') {
player_decision = 0;
players[i].fold();
}
if (choice == 'R') {
player_decision = 0;
players[i].bet(playerTable);
}
if (choice == 'B') {
player_decision = 0;
players[i].call(playerTable);
}
}
}
cout << i;
if (players[i].blind == 2) { //big blind
cout << "\n\n";
cout << " POT: " << playerTable->currentPot;
cout << "\n";
for (int i = 0; i < PLAYER_COUNT; i++) {
cout << "Player " << players[i].playernumber;
cout << " (" << players[i].chip_amount << ") ";
}
while (player_decision == 1) {
cout << "\n\nPlayer " << players[i].playernumber << " ("; players[i].playerhand.printhand(); cout << ") " << "C for Check, R for Raise: ";
cin >> choice;
players[i].choice = choice;
if (choice == 'C') {
if (players[i].check(playerTable) == true) {
player_decision = 0;
}
}
if (choice == 'R') {
player_decision = 0;
players[i].bet(playerTable);
}
}
}
}
int playersBetting = 0;
int playersGood = 0;
int playersChecked = 0;
int playersNot = 0;
for (int i = 0; i < PLAYER_COUNT; i++) {
if (players[i].playerhand.card1.value != 'F') {
playersBetting++;
if (players[i].currentBet == playerTable->currentBet) {
playersGood++;
}
}
}
for (int i = 0; i < PLAYER_COUNT; i++) {
if (players[i].playerhand.card1.value != 'F') {
if (players[i].isChecked == true) {
playersChecked++;
}
else {
playersNot++;
}
}
}
cout << playersBetting << playersGood;
if ((playersBetting == playersGood) || (playersNot == 0)) {
cout << "NEXT ROUND STARTED";
}
}
The issue is, during the second for loop with comment "seperate loop for button and blinds that were ignored in loop above" after the first if statement succeeds because players[0] has button equal to true, the player will make the terminal input as a decision, and the program will exit the for loop and go down to the end with the playersBetting and playersGood loops, then return back to the for loop at index 1 correctly.
I'm sorry if this is a little complicated to understand there is a lot of code that I probably didn't put into context very well, if you need any extra information please let me know.
Thank you.
You seem to have different loops inside one another. This is possible, but in that case, you need to use another loop variable (j instead of i), let me show you what happens:
for i ...
for j ...
This causes the following values to be taken for i and j:
i j
1 1
1 2
1 ...
1 n
2 1
2 2
2 ...
2 n
...
n 1
n 2
...
n n
... and here it stops.
If you keep using i in the inner loop, this is what you get:
i (outside loop) i (inside loop)
1 1
2 2 // indeed: changing i inside also changes i outside
... ...
n n
So you jump out of the outside loop, even after just having looped the inside loop one time.
I figured it out, it was unrelated to the actual loop and actually had to do with a value I changed upstream. Thank you for the few who tried to help with such little context haha
Have a good one
vector<char>teikums(count);
Having problems when trying to erase a element from vector.
For Example i input:
a b c d e f
and when trying to erase a element
teikums.erase(teikums.begin() + 3);
it will output
a b d e e f
Been trying to figure out why it doesn't output
a b c d f
Code:
int main() {
system("cls"); // Notira Ekranu
patsk = 0; // Pieskir vertibu
cout << "Ievadi Massiva lielumu: ";
cin >> count;
vector<char>teikums(count);
cout << "Vai aizpildit burtus automatiski (Y/Cits): ";
cin >> aizp;
srand(time(NULL));
cout << "\n";
if (aizp == 'y' || aizp == 'Y') {
for (int i = 1; i <= count; i++) {
teikums[i] = (rand() % 26) + 'a';
cout << teikums[i] << " ";
}
}
else {
do {
cout << "Ievadi " << count << " burtus vienu pa vienam\n";
for (i = 1; i <= count; i++) {
cin >> teikums[i];
if (!((teikums[i] >= 'a' && teikums[i] <= 'z') || (teikums[i] >=
'A' && teikums[i] <= 'Z'))) {
cout << "Kluda! Ievadiet tikai burtus\n";
i = i - 1;
}
}
}
while (i <= count);
}
teikums.erase(teikums.begin() + 3);
do {
cout << "\n";
cout << "\n1.Izpildit individualo uzdevumu";
cout << "\n2.Pievienot jaunu elementu vektoram";
cout << "\n3.Dzest elementu no vektroa";
cout << "\n4.Sakt programmu no jauna";
cout << "\n5.Beigt Darbu";
cout << "\nIevadi izveli : ";
cin >> opcijas;
switch (opcijas) {
case 1:
izpildit_uzdevumu(teikums);
break;
case 2:
pievienot_elementu(teikums, count);
break;
case 3:
dzest_elementu(teikums);
break;
case 4:
no_jauna();
break;
case 5:
return 0;
}
}
while (opcijas != 4);
getch();
}
void izpildit_uzdevumu(vector<char>& teikums) {
patskani = 0;
for (i = 0; i <= count; i++) {
cout << " " << teikums[i];
}
cout << "\nIzmantotie Patskani:";
for (i = 1; i < count; i = i + 2) {
if (teikums[i] == 'a' || teikums[i] == 'e' || teikums[i] == 'i' ||
teikums[i] == 'o' || teikums[i] == 'u' || teikums[i] == 'A' ||
teikums[i] == 'E' || teikums[i] == 'I' || teikums[i] == 'O' ||
teikums[i] == 'U') {
patskani = patskani + 1;
cout << teikums[i];
}
}
cout << "\nPatskanu Skaits: " << patskani;
}
When you erase the element, you should also decrease count, or use teikums.size() to monitor the size of your vector.
You had 6 elements, you did:
teikums.erase(teikums.begin() + 3);
which erases the 4th element, thus now the vector has 5 elements in number.
Check the example in the ref too.
I have 2 things that aren't working with this code. The first thing is that in my second do-while loop in main, when I input 'g' or 'G' and I put in coordinates and select if it is left or right it loops continuously.
My second thing that doesn't work right is that when I shoot my laser, a baffle should turn it and make it go a different direction. This works but it doesn't turn the laser until the box after the baffle is located. I am so stuck with this, any help would be great, and anything that you also see that I should fix would be greatly appreciated.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using namespace std;
struct velocity
{
int X = 0, Y = 0;
};
struct position
{
int X = 0, Y = 0;
void addVelocity(velocity V)
{
X += V.X;
Y += V.Y;
}
};
int gameBoard[10][10];
int guessBoard[10][10];
int random(int);
void laser(int&);
int boxNum(position, velocity);
position calcExitPos(velocity&, int&);
position moveLaser(position&, velocity V);
velocity checkPos(position, velocity&);
bool checkWall(position, velocity);
int main()
{
char level, action;
int num = 0;
int score = 0, guess = 0, shots = 0, LorR = 0;
int X = 0, Y = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
gameBoard[i][j] = 0;
}
}
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
guessBoard[i][j] = 0;
}
}
cout << "Welcome to the Baffle Game." << endl;
cout << " 10 11 12 13 14 15 16 17 18 19" << endl;
cout << "9|___|___|___|___|___|___|___|___|___|___|20" << endl;
cout << "8|___|___|___|___|___|___|___|___|___|___|21" << endl;
cout << "7|___|___|___|___|___|___|___|___|___|___|22" << endl;
cout << "6|___|___|___|___|___|___|___|___|___|___|23" << endl;
cout << "5|___|___|___|___|___|___|___|___|___|___|24" << endl;
cout << "4|___|___|___|___|___|___|___|___|___|___|25" << endl;
cout << "3|___|___|___|___|___|___|___|___|___|___|26" << endl;
cout << "2|___|___|___|___|___|___|___|___|___|___|27" << endl;
cout << "1|___|___|___|___|___|___|___|___|___|___|28" << endl;
cout << "0|___|___|___|___|___|___|___|___|___|___|29" << endl;
cout << " 39 38 37 36 35 34 33 32 31 30" << endl << endl;
cout << "This is the game board, you will shoot lasers and try to find all the baffles. " << endl << endl;
//cout << "For beginner there are 4 baffles, for intermediate there are 7 baffles and for advanced there are 10 baffles." << endl;
//cout << "Please type B for beginner, I for intermediate, and A for advanced" << endl;
do
{
cout << "For beginner there are 4 baffles, for intermediate there are 7 baffles" << endl;
cout << "and for advanced there are 10 baffles." << endl;
cout << "Please type B for beginner, I for intermediate, and A for advanced" << endl;
cin >> level;
} while (level != 'b' && level != 'B' && level != 'i' && level != 'I' && level != 'a' && level != 'A');
if (level == 'B' || level == 'b')
{
//Baffles equals 4
num = random(4); // function returns to num
}
else if(level == 'I' || level == 'i')
{
//Baffles equals 7
num = random(7);
}
else
{
//Baffles equals 10
num = random(10);
}
cout << "We will begin the game now." << endl;
cout << "Here are some commands that you will need to know to play." << endl;
cout << "L: Laser shot, then pick a number on the board to shoot the laser from." << endl;
cout << "G: Guess the location of one baffle with coordinance and L or R to choose a left or right baffle." << endl;
cout << "S: When you want me to print the score that you have." << endl;
cout << "P: Print the board showing the baffles that you have already found." << endl;
cout << "Q: Quit the game at any time" << endl;
cout << "C: This shows you the board with all the baffles and which direction they are." << endl;
do
{
cout << "Please type in your command." << endl;
cin >> action;
if (action == 'L' || action == 'l')
{
laser(shots);
}
else if (action == 'G' || action == 'g')
{
cout << "We will guess where the baffle is." << endl;
cout << "Please enter the X coordinate." << endl;
cin >> X;
cout << "Please enter the Y coordinate." << endl;
cin >> Y;
//cout << gameBoard[X][Y] << endl;
cout << "Please enter L and R for Left and Right Baffles." << endl;
cin >> LorR;
//cout << gameBoard[X][Y];
if (gameBoard[X][Y] == 1)//Right
{
//cout << "1" << endl;
if (LorR == 'R' || LorR == 'r')
{
cout << "Good job you got it correct." << endl;
guessBoard[X][Y] = 'R';
//points++
}
else
cout << "Wrong!" << endl;
}
else if (gameBoard[X][Y] == 2)//Left
{
//cout << "2" << endl;
if (LorR == 'L' || LorR == 'l')
{
cout << "Good job you got it correct." << endl;
guessBoard[X][Y] = 'L';
//points++
}
else
cout << "Wrong!" << endl;
}
else if (gameBoard[X][Y] == 0)
{
cout << "Your are wrong!" << endl;
}
}
else if (action == 'S' || action == 's')
{
cout << "Number of shots: " << shots << endl;
cout << "Number of guesses: " << guess << endl;
cout << "Current score: " << endl;//Get score
}
else if (action == 'P' || action == 'p')
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << setw(2) << guessBoard[i][j] << " ";
}
cout << endl;
}
}
else if (action == 'C' || action == 'c')
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << setw(2) << gameBoard[i][j] << " ";
}
cout << endl;
}
}
else if (action == 'q' || action == 'Q')
{
}
else if (action != 'q' && action != 'Q')
{
cout << "*** Illegal command - Try again ***" << endl;
}
cout << "loop" << endl;
}
while (action == 'q' || action == 'Q' || action == 'L' || action == 'l' || action == 'G' || action == 'g' ||
action == 'S' || action == 's' || action == 'P' || action == 'p' || action == 'C' || action == 'c');
}
//This function finds a random number for the find a random index
// in the array.
int random(int randnum)
{
unsigned seed = time(0); //get the system time.
srand(seed); //seed the random number generator.
int x, y, randomNum = 0;
int count;
for (count = 0; count < randnum; count++)
{
do
{
x = (rand() % (9 - 0 + 1)) + 0;
y = (rand() % (9 - 0 + 1)) + 0;
} while (gameBoard[x][y] != 0);
cout << "(" << x << "," << y << ")" << endl;
randomNum = rand();
gameBoard[x][y] = (randomNum % 2) + 1;
cout << gameBoard[x][y] << endl;
//2 = Left baffle
//1 = right baffle
}
return gameBoard[x][y];
}
void laser(int &shots) //Shoots a laser where user asks it to
{
int shoot;
cout << "Please input what number you want to shoot the laser from." << endl;
cin >> shoot;
shots++;
velocity V;
position P = calcExitPos(V,shoot);
//checkPos(P, V);
//cout << "1" << endl;
do
{
checkPos(P, V);
moveLaser(P, V);
//cout << "1" << endl;
} while (checkWall(P, V) == false);
cout << "Laser shot #" << shots << " exited the box at " << boxNum(P, V) << endl;
}
int boxNum(position P, velocity V) //Figures out what number the laser exits
{
if (P.X == 0 && V.X == -1)
{
return 9 - P.Y;
}
else if (P.Y == 0 && V.Y == -1)
{
return 10 + P.X;
}
else if (P.X == 9 && V.X == 1)
{
return P.Y + 20;
}
else if (P.Y == 9 && V.Y == 1)
{
return 39 - P.X;
}
}
position calcExitPos(velocity &V, int &box)//Figures out where the laser shoots from by the number the user inputs
{
position P1;
if (box >= 0 && box <= 9)
{
V.X = 1;
V.Y = 0;
P1.X = 0;
P1.Y = (9 - box);
}
else if (box >= 10 && box <= 19)
{
V.X = 0;
V.Y = 1;
P1.X = (box - 10);
P1.Y = 0;
}
else if (box >= 20 && box <= 29)
{
V.X = -1;
V.Y = 0;
P1.X = 9;
P1.Y = (box - 20);
}
else if (box >= 30 && box <= 39)
{
V.X = 0;
V.Y = -1;
P1.X = (39 - box);
P1.Y = 9;
}
return P1;
}
position moveLaser(position &P, velocity V)
{
int baffletype = gameBoard[P.X][P.Y];
if (baffletype == 1)//Right
{
if (V.X == 1)
{
V.Y = -1;
V.X = 0;
P.Y--;
}
else if (V.X == -1)
{
V.Y = 1;
V.X = 0;
P.Y++;
}
else if (V.Y == 1)
{
V.X = -1;
V.Y = 0;
P.X--;
}
else if (V.Y == -1)
{
V.X = 1;
V.Y = 0;
P.X++;
}
}
else if (baffletype == 2)//Left
{
if (V.X == 1)
{
V.Y = 1;
V.X = 0;
P.Y++;
}
else if (V.X == -1)
{
V.Y = -1;
V.X = 0;
P.Y--;
}
else if (V.Y == 1)
{
V.X = 1;
V.Y = 0;
P.X++;
}
else if (V.Y == -1)
{
V.X = -1;
V.Y = 0;
P.X--;
}
}
else if (baffletype == 0)
{
if (V.X == 1)
{
V.Y = 0;
V.X = 1;
P.X++;
}
else if (V.X == -1)
{
V.Y = 0;
V.X = -1;
P.X--;
}
else if (V.Y == 1)
{
V.X = 0;
V.Y = 1;
P.Y++;
}
else if (V.Y == -1)
{
V.X = 0;
V.Y = -1;
P.Y--;
}
}
cout << "(" << P.X << ","<< P.Y << ")" << endl;
return P;
}
velocity checkPos(position P, velocity &V) //Directs the laser when the laser hits a baffle
{
int baffletype = gameBoard[P.X][P.Y];
if (baffletype == 1)//Right
{
if (V.X == 1)
{
V.Y = -1;
V.X = 0;
}
else if (V.X == -1)
{
V.Y = 1;
V.X = 0;
}
else if (V.Y == 1)
{
V.X = -1;
V.Y = 0;
}
else if (V.Y == -1)
{
V.X = 1;
V.Y = 0;
}
}
else if (baffletype == 2)//Left
{
if (V.X == 1)
{
V.Y = 1;
V.X = 0;
}
else if (V.X == -1)
{
V.Y = -1;
V.X = 0;
}
else if (V.Y == 1)
{
V.X = 1;
V.Y = 0;
}
else if (V.Y == -1)
{
V.X = -1;
V.Y = 0;
}
}
else if (baffletype == 0)
{
if (V.X == 1)
{
V.Y = 0;
V.X = 1;
P.X++;
}
else if (V.X == -1)
{
V.Y = 0;
V.X = -1;
P.X--;
}
else if (V.Y == 1)
{
V.X = 0;
V.Y = 1;
P.Y++;
}
else if (V.Y == -1)
{
V.X = 0;
V.Y = -1;
P.Y--;
}
}
//cout << "( " << P.X << ", " << P.Y << ")" << endl;
return V;
}
bool checkWall(position P, velocity V) //Checks to see if the laser hits the wall
{
//cout << "2" << endl;
P.addVelocity(V);
return (P.X > 9 || P.X < 0 || P.Y > 9 || P.Y < 0); //Checks to see if the next position is out of bounds
}
I don't have a complete solution for you but a couple of things.
You should make your while loop test simpler.
How about this (pseudocode):
bool done = false;
while (!done) {
// Process action loop
cin >> action;
action = toupper(action); // Make everything upper case
processTheAction(action);
done = areWeDoneYet(action);
}
Break up the complex "are we done yet" task and other things into functions. (Divide and conquer)
bool areWeDoneYet(action) {
switch (action) {
case A:
case B:
... (cases where we are not done)
return false;
case E:
case F:
... (cases where we are done)
return true;
}
}
Make your "event loop" simple. Have it call a complex function
"ProcessAction" That way you can tell if you are busy processing when you have an issue, or if your having an issue with the event loop.
void processTheAction( action ) {
switch (action) {
case A:
case a: // Optional method if you don't do topper on Action
// Code for action 'A' goes here
// If a *lot* of code make a function like "ProcessActionA()"
break;
case B:
case b: // not needed if you do topper
// Code for action 'B' goes here
break;
default:
printf("I'm hosed cause I forgot to manage action [%c]\n",
action);
}
}
Don't know if this helps, but it might help you to break down the problem.
Im currently making a one-armed bandit game and this is what it's supposed to do:
The user should be able to put money into the machine, 50, 100 or 500
The user should be able to bet money for each game
After the user have betted money symbols should be randomized in a field like this:
[ o ] [ p ] [ x ]
[ x ] [ x ] [ x ]
[ x ] [ o ] [ x ]
(1 columns/ lines wins 2x money, 2 columns/ lines wins 4x money etc.)
This field should each time be randomized with letters , also a two-dimensional array should be used to represent the gamearea.
I've ran into some problems, basically after I bet some money the game closes and I cant see any errors etc, any help that clarifies this problem would be greatly appreciated, aswell as any improvements I could do to my code etc.
This is my code:
#include <iostream>
#include <ctime>
using namespace std;
int main(int args, const char* argv[])
{
int svar = 0;
int bokstav = 0;
int insert;
int build;
int bet;
int credit;
int array;
int jackpot;
int tal;
int spin_1x = 0;
int spin_1y = 0;
int spin_2x = 0;
int spin_2y = 0;
cout << "Welcome to the one-armed bandit!" << endl;
cout << endl;
cout << "To play start by betting some money!" << endl;
cout << endl;
cout << "Insert 50/ 100/ 500 kr to your account!" << endl;
cout << endl;
cin >> insert;
while (insert < 50 || insert > 500)
{
cout << "You either inserted to little or to much" << endl;
cin >> insert;
}
cout << "You inserted" << insert;
cout << endl;
while (insert > 50)
{
cout << "Bet some money to play!" << endl;
cout << endl;
cin >> bet;
cout << endl;
while (bet !=50 && bet !=100 && bet !=500)
{
if (bet == 50) return 1;
{
cout << "You have betted 50 kr!" << endl;
}
{
if (bet == 100) return 2;
{
cout << "You have betted 100 kr!" << endl;
}
{
if (bet == 500)
{
cout << "You have betted 500 kr!" << endl;
}
char a = '£';
char b = '$';
char c = '*';
char build [4][4] = {
{ ' ', 'A', 'B', 'C',},
{ '1', ' ', ' ', ' ',},
{ '2', ' ', ' ', ' ',},
{ '3', ' ', ' ', ' ',},
};
int array();
cout << build[0][1] << " " << build[0][2] <<" "<< build[0][3] <<" " << endl;
cout << build[1][0] <<"|_|" <<"|_|" << "|_|" << endl
<< build[2][0] <<"|_|" <<"|_|" << "|_|" << endl
<< build[3][0] <<"|_|" <<"|_|" << "|_|" << endl;
return 0;
srand(time(0));
spin_1x=rand() % 4 + 1;
spin_1y=rand() % 4 + 1;
spin_2x=rand() % 4 + 1;
spin_2y=rand() % 4 + 1;
int y = 0;
int x = 0;
if (x == spin_1x && y == spin_1y)
{
build[x][y]='0';
cout << "Congrats you won!" << endl;
}
else if (x == spin_2x && y == spin_2y)
cout << "Congrats you won!" << endl;
cout << endl;
cout << "JACKPOT!" << endl;
{
if (insert <= 0)
{
cout << "You dont have any money left! Game's over!" << endl;
}
int insert;
if ((a == 7 && b == 7 && c == 7))
{
cout << "You have won x2 your bet!($" << ( bet*2) << ")" << endl;
credit = credit + (bet*2);
}
else if ((a == b == c) && ! (a == 7 && b == 7 && c == 7))
{
cout << "You have won x4 your bet!($" << (bet*4) << ")" << endl;
credit = credit + (bet*4);
}
else if ((a == b || a == c || b == c) && !(a == b == c) && !(a == 7 && b == 7 && c == 7))
{
credit = credit + (bet*8);
cout << "You have won x8 your bet!($" << (bet*8) << ")" << endl;
}
else if ((a == b || a == c || b == c) && ! (a == b == c) && ! (a == 7 && b == 7 && c == 7))
{
credit = credit + (bet*16);
cout << "You have won x16 your bet!($" << (bet*16) << ")" << endl;
}
else if (( a == b || a == c || b == c) && ! (a == b == c) && ! (a == 7 && b == 7 && c == 7))
{
credit = credit + (bet*128);
cout << "You have won x128 your bet!($" << (bet*128) << ")" << endl;
}
else
{
cout << "You have lost your betting!($-" << bet << ")" << endl;
credit = credit - bet;
}
return credit;
}
}
return 0;
}
}
}
}
The issue, as others stated, is that you are returning from your main which terminates the program. My suggestion:
Move your game logic into a separate method(s)
Place the logic call inside a while loop in the main that checks if the player wants to play again
Only return from main when the player wants to stop
Example partial code (you should get the idea):
void printWelcome( )
{
std::cout << "Welcome to the One-Armed Bandit!" << std::endl;
// etc.
}
int getBet( )
{
int betAmount;
std::cout << "To play start by betting some money!\n"
<< "Insert 50/ 100/ 500 kr to your account!" << std::endl;
std::cin >> betAmount;
return betAmount;
}
void playGame( )
{
// All of your game logic in here
}
bool wantsToPlay( )
{
std::cout << "Do you want to play again? (y/n)" << std::endl;
char response;
std::cin >> response;
if( response == 'y' )
{
return true;
}
else
{
return false;
}
}
int main( int argc, char** argv )
{
int betAmount = 0;
printWelcome( );
do
{
betAmount = getBet( );
if( betAmount != 50 && betAmount != 100 && betAmount != 150 )
{
// Restart the game loop (ask for bet again)
continue;
}
playGame( );
} while( wantsToPlay( ) );
std::cout << "Thank you for playing!" << std::endl;
return 0;
}
Your console is closing because the program is terminated when the main function hits a return , put a cin before each return. That will "pause" the application just before it terminates letting you see your traces.
Run your program by yourself instead of computer and you will see why its closing so fast. Remember that return in main() means "close program now".
The title kind of says it all. I'm not sure exactly why the Tic Tac Toe program is not detecting a tie. I've attached the main function, additional functions, etc.. I'm not sure what im doing wrong. Any help is greatly appreciated.
#include <string>
#include <iostream>
#include <cstdlib>
using namespace std;
string displayBoard(string board[9]); // displays tic tac toe board
bool isGameOver(string board[9]); // checks if game is over
void displayGameWelcome(); // displays welcome message
int main()
{
string board[9]; // tic tac toe, top row 0 thru 2, middle row 3 thru 5, bottom row 6 thru 8
int position = 0; // player's position
bool gameOver = false; // flag variable to mark end of the game
bool validMove = false; // determines if move is valid or not
displayGameWelcome();
// initializing board with blank spaces
for (int i = 0; i < 9; i++)
{
board[i] = " ";
}
while (!gameOver)
{
// player #1's turn **************************
validMove = false;
while (!validMove)
{
cout << "Enter your position: ";
cin >> position;
if (position >= 0 && position <= 8 && board[position] == " ")
{
validMove = true;
board[position] = "x"; // placing x in desired board location
}
else
{
cout << "That position is already occupied." << endl;
cout << displayBoard(board) << endl;
}
}
cout << displayBoard(board) << endl;
if (isGameOver(board))
{
gameOver = true;
}
// player #2's turn **********************************
validMove = false;
while (!validMove)
{
cout << "Enter your position: ";
cin >> position;
if (position >= 0 && position <= 8 && board[position] == " ")
{
validMove = true;
board[position] = "o"; // placing o in desired board position
}
else
{
cout << "That position is already occupied." << endl;
cout << displayBoard(board) << endl;
}
}
cout << displayBoard(board) << endl;
if (isGameOver(board))
{
gameOver = true;
}
}// end of validMove while loop
system("pause");
return 0;
}// end of main
// ************************** functions *************************
void displayGameWelcome()
{
cout << "Welcome to Tic Tac Toe v3.2" << endl;\
cout << "by Brett Singley & Nick Canarelli" << endl;
cout << "****************************\n\n\n";
}// end of displayGameWelcome
// checks if game is over
bool isGameOver(string board[9])
{
if (board[0] == "x" && board[1] == "x" && board[2] == "x")
{
cout << endl << "The game is over - x wins" << endl;
return true;
}
else if (board[0] == "o" && board[1] == "o" && board[2] == "o")
{
cout << endl << "The game is over - o wins" << endl;
return true;
}
else if (board[3]=="x" && board[4]=="x" && board[5]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[3]=="o" && board[4]=="o" && board[5]=="o")
{
cout <<endl << "The game is over - o wins" <<endl;
}
else if (board[0]=="x" && board[3]=="x" && board[6]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[0]=="o" && board[3]=="o" && board[6]=="o")
{
cout <<endl << "The game is over - o wins" <<endl;
}
else if (board[6]=="x" && board[7]=="x" && board[8]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[6]=="o" && board[7]=="o" && board[8]=="o")
{
cout <<endl << "The game is over - O wins" <<endl;
}
else if (board[1]=="x" && board[4]=="x" && board[7]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[1]=="o" && board[4]=="o" && board[7]=="o")
{
cout <<endl << "The game is over - O wins" <<endl;
}
else if (board[2]=="x" && board[5]=="x" && board[8]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[2]=="o" && board[5]=="o" && board[8]=="o")
{
cout <<endl << "The game is over - o wins" <<endl;
}
else if (board[0]=="x" && board[4]=="x" && board[8]=="x")
{
cout <<endl << "The game is over - X wins" << endl;
}
else if (board[0]=="o" && board[4]=="o" && board[8]=="o")
{
cout <<endl << "The game is over - o wins" <<endl;
}
else if (board[2]=="x" && board[4]=="x" && board[6]=="x")
{
cout <<endl << "The game is over - X wins" <<endl;
}
else if (board[2]=="o" && board[4]=="o" && board[6]=="o")
{
cout <<endl << "The game is over - o wins" <<endl;
}
else
{
cout << "WOAH!!!!! Tie Game" <<endl;
}
// more to do here (don't forget to check for draw)
return false;
}// end of isGameOver
// displays tic tac toe board in the format
// |0 1 2|
// |3 4 5|
// |6 7 8|
string displayBoard(string board[9])
{
string str = "";
for (int i = 0; i < 9; i++)
{
if (i == 0)
{
str = str + "|" + board[i];
}
else if (i == 2 || i == 5)
{
str = str + board[i] + "|\n|";
}
else if (i == 8)
{
str = str + board[i] + "|\n";
}
else
{
str = str + board[i];
}
}
return str;
}// end of displayBoard
You can simplify checking for a winner by using for loops and realizing that the value in the three spaces are equal (to something other than the initial value). Also, since there are 3 rows and 3 columns, the rows and columns can be checked inside the same for loop:
const char initial_value = ' ';
const unsigned int max_rows_or_columns = 3;
bool Is_Game_Over(int board[9], char& winner)
{
for (unsigned int i = 0; i < max_rows_or_columns; ++i)
{
// Check the row
if ( (board[(i * 3) + 0] == board[(i * 3) + 1])
&& (board[(i * 3) + 1) == board[(i * 3) + 2]))
{
// By transitive property, board[(i * 3) + 0] == board[(i * 3) + 2]
winner = board[(i * 3) + 0];
if (winner != initial_value)
{
break;
}
}
else // Check the columns
{
if ( (board[(0 * 3) + i] == board[(1 * 3) + i])
&& (board[(1 * 3) + i] == board[(2 * 3) + i]))
{
winner = board[(0 * 3) + i];
if (winner != initial_value)
{
break;
}
}
}
bool winner_found = true;
if (i >= max_rows_or_columns)
{
winner_found = false;
}
return winner_found;
}
The checking of the diagonals is left as an exercise for the reader.