Trädvy Permalänk
Medlem
Registrerad
Jan 2013

Tic tac toe-problem i C++

Hej, jag har gjort ett tic tac toe spel där jag nu lagt till funktionen att storleken och antalet tecken i rad för att vinna kan bestämmas av användaren. Det fungerar upp till 3x3 men med större planer beter sig spelet konstigt. T.ex. så säger den inte att en viss spelare har vunnit när det har 4 tecken i rad på en 5x5 stor spelplan. Jag är väl medveten om att koden ser rätt smutsig ut och att allt ligger i main, men det kommer jag fixa sedan. Det går heller inte att vinna diagonalt än dom två som är i mitten, men det kommer jag också fixa sedan. Det jag just nu undrar mest är varför det inte fungerar det som jag beskrev ovan. Här är koden. Alla for-loopar är bara till för att kolla om en spelare vunnit. För att underlätta eventuellt testande så har jag gjort att det bara är samma spelare som för lägga tecken på planen.

#include <iostream> #include <string> #include <cstdlib> #include <ctime> using namespace std; enum TicTacToeCases { PLAYER_ONE = 'O', PLAYER_TWO = 'X', NEUTRAL = '*' }; int main(){ srand(time(NULL)); int decide = rand(); bool over = false; int boardSize = 3; int toWin = 3; char ticTacToe[20][20]; cout<< "Choose the size of the board: "; cin>> boardSize; cout<< "Choose the amount of character in a row in order to win: "; cin>> toWin; for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ ticTacToe[i][j] = static_cast<char>(NEUTRAL); } } //PRINTS THE GAME for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ cout<< ticTacToe[i][j]<< " "; } cout<< "\n\n"; } while (!over){ int counter = 0; int diagonal = 0; int otherDiagonal = boardSize - 1; int *forTheDiagonal = &diagonal; int *forTheOtherDiagonal = &otherDiagonal; if (decide % 2 == 0){ int i; int j; bool valid = false; while (!valid){ cout<< "Player one decide position\n"; cin>> i; cin>> j; if (ticTacToe[i-1][j-1] == '*'){ valid = true; } else{ cout<< "This position is already taken\n"; } } cout<< "\n"; ticTacToe[i-1][j-1] = static_cast<char>(PLAYER_ONE); for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ cout<< ticTacToe[i][j]<< " "; } cout<< "\n\n"; } for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ if (ticTacToe[i][j] == 'O'){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player one wins!\n"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ if (ticTacToe[j][i] == 'O'){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player one wins!\n"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ if (ticTacToe[i][diagonal] == 'O'){ counter++; (*forTheDiagonal)++; } else{ *forTheDiagonal = 0; } if (counter == toWin){ cout<< "Player one wins!\n"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ if (ticTacToe[i][otherDiagonal] == 'O'){ counter++; (*forTheOtherDiagonal)--; } else{ *forTheOtherDiagonal = boardSize - 1; } if (counter == toWin){ cout<< "Player one wins!\n"; over = true; } } counter = 0; } else{ int i; int j; bool valid = false; while (!valid){ cout<< "Player two decide position\n"; cin>> i; cin>> j; if (ticTacToe[i-1][j-1] == '*'){ valid = true; } else{ cout<< "This position is already taken\n"; } } cout<< "\n"; ticTacToe[i-1][j-1] = static_cast<char>(PLAYER_TWO); for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ cout<< ticTacToe[i][j]<< " "; } cout<< "\n\n"; } for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ if (ticTacToe[i][j] == 'X'){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player two wins!\n"; cout<< "1"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ if (ticTacToe[j][i] == 'X'){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player two wins!\n"; cout<< "2"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ if (ticTacToe[i][diagonal] == 'X'){ counter++; (*forTheDiagonal)++; } else{ *forTheDiagonal = 0; } if (counter == toWin){ cout<< "Player two wins!\n"; cout<< "3"; over = true; } } counter = 0; for (int i = 0; i < boardSize; i++){ if (ticTacToe[i][otherDiagonal] == 'X'){ counter++; (*forTheOtherDiagonal)--; } else{ *forTheOtherDiagonal = boardSize - 1; } if (counter == toWin){ cout<< "Player two wins!\n"; cout<< "4"; over = true; } } counter = 0; } decide+=2; } }

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Okt 2003

Jag ser två buggar i alla fall. För det första bör du testa om counter >= toWin. Om det behövs tre för att vinna kan man ju ända få exempelvis fem i rad, genom att sätta en plupp mellan två grupper av två.

För det andra nollställer du inte räknaren när du byter rad. Det är ju dels en bugg i sig och dels kan det vara en anledning till varför counter blir för hög och triggar bugg 1.

Men skriv nu en enkel funktion som ersätter de där åtta separate testerna!

Trädvy Permalänk
Medlem
Registrerad
Jan 2013
Skrivet av Gubbjekeln:

Jag ser två buggar i alla fall. För det första bör du testa om counter >= toWin. Om det behövs tre för att vinna kan man ju ända få exempelvis fem i rad, genom att sätta en plupp mellan två grupper av två.

För det andra nollställer du inte räknaren när du byter rad. Det är ju dels en bugg i sig och dels kan det vara en anledning till varför counter blir för hög och triggar bugg 1.

Men skriv nu en enkel funktion som ersätter de där åtta separate testerna!

Tack för uppmärksammade problem!
Har uppdaterat koden med det första problemet samt det andra, dock på ett annat sätt än det du visade. Har även dammsugit den så att main är ren och fin. Problemet beskrivet i trådstarten består dock. Här är uppdateringen:

#include <iostream> #include <string> #include <cstdlib> #include <ctime> using namespace std; enum TicTacToeCases { PLAYER_ONE = 'O', PLAYER_TWO = 'X', NEUTRAL = '*' }; void printGame(char [][20], int); void makeMove(char [][20], int, char); bool checkIfGameOver(char [][20], char, int, int); int main(){ srand(time(NULL)); int decide = rand(); bool over = false; int boardSize = 3; int toWin = 3; char player; char ticTacToe[20][20]; cout<< "Choose the size of the board: "; cin>> boardSize; cout<< "Choose the amount of character in a row in order to win: "; cin>> toWin; for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ ticTacToe[i][j] = static_cast<char>(NEUTRAL); } } printGame(ticTacToe, boardSize); while (!over){ if (decide % 2 == 0){ player = static_cast<char>(PLAYER_ONE); makeMove(ticTacToe, boardSize, player); printGame(ticTacToe, boardSize); over = checkIfGameOver(ticTacToe, player, boardSize, toWin); } else{ player = static_cast<char>(PLAYER_TWO); makeMove(ticTacToe, boardSize, player); printGame(ticTacToe, boardSize); over = checkIfGameOver(ticTacToe, player, boardSize, toWin); } decide+=2; } } void printGame(char ticTacToe[][20], int boardSize){ for (int i = 0; i < boardSize; i++){ for (int j = 0; j < boardSize; j++){ cout<< ticTacToe[i][j]<< " "; } cout<< "\n\n"; } } void makeMove(char ticTacToe[][20], int boardSize, char player){ int i; int j; bool valid = false; while (!valid){ cout<< "Player one decide position\n"; cin>> i; cin>> j; if (ticTacToe[i-1][j-1] == '*'){ valid = true; } else{ cout<< "This position is already taken\n"; } } cout<< "\n"; ticTacToe[i-1][j-1] = static_cast<char>(player); } bool checkIfGameOver(char ticTacToe[][20], char player, int boardSize, int toWin){ int counter = 0; int diagonal = 0; int otherDiagonal = boardSize - 1; int *forTheDiagonal = &diagonal; int *forTheOtherDiagonal = &otherDiagonal; for (int i = 0; i < boardSize; i++){ counter = 0; for (int j = 0; j < boardSize; j++){ if (ticTacToe[i][j] == player){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player one wins!\n"; return true; } } counter = 0; for (int i = 0; i < boardSize; i++){ counter = 0; for (int j = 0; j < boardSize; j++){ if (ticTacToe[j][i] == player){ counter++; } else{ counter = 0; } } if (counter == toWin){ cout<< "Player one wins!\n"; return true; } } counter = 0; for (int i = 0; i < boardSize; i++){ counter = 0; if (ticTacToe[i][diagonal] == player){ counter++; (*forTheDiagonal)++; } else{ *forTheDiagonal = 0; } if (counter == toWin){ cout<< "Player one wins!\n"; return true; } } counter = 0; for (int i = 0; i < boardSize; i++){ counter = 0; if (ticTacToe[i][otherDiagonal] == player){ counter++; (*forTheOtherDiagonal)--; } else{ *forTheOtherDiagonal = boardSize - 1; } if (counter == toWin){ cout<< "Player one wins!\n"; return true; } } counter = 0; return false; }

Trädvy Permalänk
Medlem
Registrerad
Mar 2013

Du kanske redan har fått programmet att funka men vad jag såg när jag tittade igenom det var att du testar "counter == toWin" först när raden är klar. Detta funkar så länge boardSize och toWin är lika, men är boardSize större än toWin så fungerar det bara så länge "vinnande rad" är i slutet på raden. Tänk dig en plan som är 5x5 och det behövs 4 för att vinna, befinner sig de fyra tecknen i början på raden så kommer "counter" att nollställas av det femte tecknet på raden och vinnande rad kommer inte att detekteras.

Antingen får du hålla reda på max på raden eller också flyttar du upp "if (counter == toWin)" till strax efter uppräkningen av "counter".

PS. Om du inte gör kollen vid varje uppräkning av "counter" så bör du använda "if (counter >= toWin)" som @Gubbjekeln redan nämnt. DS.

Trädvy Permalänk
Medlem
Registrerad
Jan 2013
Skrivet av ByteBitten:

Du kanske redan har fått programmet att funka men vad jag såg när jag tittade igenom det var att du testar "counter == toWin" först när raden är klar. Detta funkar så länge boardSize och toWin är lika, men är boardSize större än toWin så fungerar det bara så länge "vinnande rad" är i slutet på raden. Tänk dig en plan som är 5x5 och det behövs 4 för att vinna, befinner sig de fyra tecknen i början på raden så kommer "counter" att nollställas av det femte tecknet på raden och vinnande rad kommer inte att detekteras.

Antingen får du hålla reda på max på raden eller också flyttar du upp "if (counter == toWin)" till strax efter uppräkningen av "counter".

PS. Om du inte gör kollen vid varje uppräkning av "counter" så bör du använda "if (counter >= toWin)" som @Gubbjekeln redan nämnt. DS.

Tack så mycket!! Det var precis det som du nämnde som var problemet. Hade lagt kollen utanför den inre for-loopen, vilket medförde felet. Dock så kan man vinna på en 5x5 plan om dom tre sista i spelet är ifyllda