Connect 4 PVP Function - c++

I can't seem to find something that specifically answers my question. I am looking for a solution to my problem. The connect 4 player versus player seems to just ask the first player to drop then the second player to drop, but the first if statement is no longer true so it continues to ask the second player to drop. I am using eclipse for mac osx although the game is programmed for ASCII character set.
display();
int hold;
int hold2 = 0;
int charsPlaced = 0;
bool gamewon = false;
char player = 15;
string r;
while (!gamewon)
{
if (hold2 != -1)
{
if (player == 15)
{
cout << ax << " what column would you like to drop in?";
player = 178;
}
else
{
cout << bx << " what column would you like to drop in?";
player = 176;
}
}

You need to switch the players' turn after each action. If P1 took an action, you need to update the "turn" so that the next time the code loops it will ask for P2. Then, after you've done the stuff you need to do for P2, you need to update the "turn" so that the next time it loops it will ask for P1 action.
Here's a different approach on your code by using an enum. You can use a bool type variable which is false for P1 and true for P2, or an int that's 1 or 2, but that's a bit harder to understand from the outisde.
// omitted code
enum PlayerTurn { ePlayer1 = 0, ePlayer2 };
// omitted code
PlayerTurn plTurn = ePlayer1;
while (!gamewon)
{
if (pTurn == ePlayer1)
{
cout << ax << " what column would you like to drop in?";
// TODO: stuff to do for Player #1
}
else
{
cout << bx << " what column would you like to drop in?";
// TODO: stuff to do for Player #2
}
// TODO: decide if game has been won, mechanics etc.
// move to the next player without overflowing the 2 possible values (0 and 1)
plTurn = (plTurn + 1) % 2;
}
Then, on your display() function, you can show any ASCII character you wish.

Related

Is there a way to run a statement when a condition in a loop is met at least once?

I am currently doing games on my free time and am currently working on a hangman game. However, I have stumbled upon a problem and I think I could solve it if there was a way to run a statement if a condition inside a loop is met at least once, and if the condition isn't met even once, it'll do another thing. Is it possible to do? Does anyone have any ideas?
I appreaciate any suggestions.
I tried doing something like this:
for (){
if (string [i] == letter that the player inputed){
// replace underscores with the letter guessed
// and also turn a bool statement true
}
else {
// turn the bool statement false
}
}
if (!bool variable){
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
However I noticed that it doesn't work because the loop will run and if the last letter that it checks is not in the answer, the bool will turn false, thus printing that the letter was not in the answer and substracting one from the score. (It's also my first time posting here, and I don't know if that's how I'm supposed to write a code, so I apologize beforehand if I'm not doing it correctly)
`
You should approach this problem from the different angle:
for( ... ) {
if( your condition is met ) {
do_whatever_you_have_to();
break; // <<--- exit the loop, so it's done only once
}
}
You don't have to put flag guessed off if the comparation fails
string s;
bool guessed = false;
char inputted_letter; // comes from somewhere
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == inputted_letter) {
// replace underscores with the letter guessed
guessed = true;
}
}
if (!guessed) {
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
You don't have to set false in the loop:
bool has_found = false;
for (auto& c : word_to_guess)
{
if (input_letter == c) {
// replace _ by current letter...
has_found = true;
}
}
if (!has_found){
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
But I suggest that your loop does only one thing at a time:
bool contains(const std::string& word_to_guess, char input_letter)
{
return std::any_of(word_to_guess.begin(),
word_to_guess.end(),
[&](char c){ return input_letter == c; })
/*
for (auto& c : word_to_guess)
{
if (input_letter == c) {
return true;
}
}
return false;
*/
}
if (contains(word_to_guess, input_letter)
{
// show current letter...
for (std::size_t i = 0; i != hangman_word.size(); ++i) {
if (word_to_guess[i] == input_letter) {
hangman_word[i] = word_to_guess[i];
}
}
} else {
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
Can you do what you are asking; possibly, however you stated you were making the game Hangman in C++ and I think you are going about this with the wrong approach, therefore, choosing or implementing the wrong algorithms. You are trying to traverse through two strings with possible different lengths from the back end which if it isn't done correctly can lead to issues, will tend to be hard to track especially if their comparisons determine loop conditions, exit or return statements.
I have implemented my version of "Hangman", now albeit the formatting isn't the prettiest, nor are the level dictionaries being generated from a large pool of random words. I express this in the comments of the code that these would generally be read in from a text file and saved into these structures. For simplicity's sake, I initialized them with random words directly in the code.
Take a look to see what I've done:
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <random>
class Game;
int main() {
using namespace util;
try {
Game game("Hangman");
game.start();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
class Game {
private:
std::string title_;
bool is_running_{ false };
std::string answer_;
std::string guessed_;
std::map<unsigned, std::vector<std::string>> dictionary_; // unsigned represents difficulty level of word
unsigned choosen_difficulty_;
std::string guessed_characters_{"\n"};
public:
Game(const std::string& title) : title_{ title }, choosen_difficulty_{ 0 } {
initialize();
start_over();
}
void start() {
is_running_ = true;
// the player has as many attempts as twice the length of hidden answer's word length.
int number_tries = answer_.size() * 2;
while (is_running_ || number_tries > 0) {
displayGuessedWord();
displayGuessedCharacters();
// ask the player to guess a character;
char guess;
// get a character and make sure it is a valid alphabet character
do {
std::cout << "Guess a character ";
std::cin >> guess;
// Note: I'm using ascii characters in this case
// but for demonstration purposes only!
if ((guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z')) {
std::cout << "invalid entry ";
}
} while ( (guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z') );
// test character and update guessed word and number of tries.
test_character(guess);
update_guessed_characters(guess);
number_tries--;
// failed condition
if (number_tries <= 0 && guessed_ != answer_) {
std::cout << "\nGame Over!\n";
is_running_ = try_again(number_tries);
// winning condition
} else if (number_tries > 0 && guessed_ == answer_) {
std::cout << "\nCongratulations!\n";
is_running_ = try_again(number_tries);
}
if (!is_running_) break;
}
}
private:
void displayGuessedWord() {
std::cout << '\n' << guessed_ << '\n';
}
void displayGuessedCharacters() {
std::cout << guessed_characters_ << '\n';
}
void initialize() {
// Normally this would be read in from a file upon game initialization
// but for demonstration purpose, I'll generate a few small vectors of strings
// and associate them to their difficulty level
// levels are based on 3 factors, the length of the word, the repetitive occurance
// of common characters, and the amount of less commonly used characters.
std::vector<std::string> level_1{ "ate", "cat", "dog", "coat", "coal", "does" };
std::vector<std::string> level_2{ "able", "believe", "balloon", "better", "funny", "happy" };
std::vector<std::string> level_3{ "ability", "carpenter", "dogmatic", "hilarious", "generosity", "hostility" };
// ... etc. I'll use just these here for simplicty where each vector has six entries, however,
// with random number generators, this can be done generically for any size
// or number of elements in each of the different vectors.
// create generate the map:
dictionary_[1] = level_1;
dictionary_[2] = level_2;
dictionary_[3] = level_3;
}
std::string getWordFromDictionary(unsigned difficulty, std::map<unsigned, std::vector<std::string>>& dict) {
auto level = dict[difficulty]; // extract the vector based on difficulty level
auto size = level.size(); // get the size of that vector
std::random_device dev; // create a random device
std::mt19937 rng(dev()); // create a pseudo random generator
// create a uniform int distribution type with the range from 0 to size-1
std::uniform_int_distribution<std::mt19937::result_type> dist(0, size - 1);
return level[dist(rng)]; // return a random string from this level.
}
void start_over() {
system("cls"); // Note: I'm running visual studio on Windows!
std::cout << "Welcome to " << title_ << '\n';
// We can use a random generator to pick a word from the given difficulty
// but first we need to get user input for the chosen level.
do {
std::cout << "Choose your difficulty [1-3]\n";
std::cin >> choosen_difficulty_;
if (choosen_difficulty_ < 1 || choosen_difficulty_ > 3) {
std::cout << "Invalid entry:\n";
}
} while (choosen_difficulty_ < 1 || choosen_difficulty_ > 3);
answer_ = getWordFromDictionary(choosen_difficulty_, dictionary_);
// clear and resize guessed word to be that of answer_ and add bunch of hypens.
guessed_.clear();
guessed_.resize(answer_.size(), '-');
// also reset the guessed_characters
guessed_characters_ = std::string("\n");
}
bool try_again(int& tries) {
std::cout << "Would you like to try again?\n";
char c;
std::cin >> c;
if (c == 'y' || c == 'Y') {
start_over();
// don't forget to update this so that the loop can repeat
tries = answer_.size() * 2;
return true;
}
else {
std::cout << "Thank you for playing " << title_ << '\n';
return false;
}
}
void test_character(const char c) {
// here is where you would use the standard library for taking the character
// passed into this function, updating the guessed_characters
// get all indexes
std::vector<unsigned> locations;
for (unsigned i = 0; i < answer_.size(); i++)
if (answer_[i] == c)
locations.push_back(i);
// now update the guessed word
if ( locations.size() > 0 )
for (size_t n = 0; n < locations.size(); n++)
guessed_[locations[n]] = c;
}
void update_guessed_characters(const char c) {
guessed_characters_.insert(0, &c); // just push to the front
}
};
If you noticed how I structured the game class above; I am using while and do-while loops in conjunction with for-loops and if-statements and a single boolean flag to determine the state of the game. The game state is also determined from the update to the guessed characters and guessed word. Then I compare that to the answer. Depending on certain conditions the loop will continue seeking input from the user or will exit.
I am not guaranteeing that this code is 100% bug-free for I didn't do any rigorous testing or checking corner cases or special cases but the code has run without error and I've tested all primary game state cases. It appears to be working fine.
I know that there could be many improvements and simplifications made if I had chosen to use some of the standard library functions for working with strings, but I wanted to illustrate the individual steps that are involved in the design or thinking process of making a game with states and their transitions. I could of also put the game class declaration into its own header file with its implementation in a cpp file, but I left that as a single class that is shown in main.cpp for easy copy and paste and compilation.
With this particular game, I did not use a switch and case statements, I just stuck with some while and do-while loops, a few for loops, and if statements since there are only a few game states and transitions to worry about. This implementation also demonstrates the algorithms that are involved and shows how they interconnect with each other. I hope this helps to give you a better understanding of the design process.
When making a game that has different states with a bit of complexity to it, you should start by making your state table first and list all of its transitions before you even write any code. Then you should list your starting, continuing, winning, failing and exiting states or cases. Then you need to draw up how you would transition from one state to another by their required conditions. This will help you in the long run!
Once you have the game state and its transitions laid out properly, then you can start to make your required functions for those states and begin to connect them together. After that is when you would write the internal of the functions or their implementation of what they would do.
Finally, after you have that down is where you want to do some debugging and unit and case testing and if everything appears to be okay, then it would be safe to improve your current algorithms or choosing better ones for peak or most efficient performance.

Is there a way to implement AI to the computer in TicTacToe?

I have this program that runs the game of Tictactoe, but i'd like to add AI to the computer function so it can be more difficult in order to play with
I tried by rand(); but it just make the computer put the decision in whatever slot is available.
void ia_turn(){
while (true){
int ia_tu = (rand() % 9) +1;
int ia_op = ia_tu - 1;
int row = ia_op / 3;
int column = ia_op % 3;
char matrix_pos = matrix[row][column];
if (matrix_pos == 'X' || matrix_pos == 'O'){
continue;
}else{
cout << "The AI selected the position: "<<ia_tu<<endl;
matrix[row][column] = 'O';
break;
}
}
}
I expect the movements of the ComputerAI to block my movements, but it can't be done with the rand() function.
This is the checking for wins function that i have
void checking_for_wins(){
const char* wins_possibilities[8] = {"123","456","789","159","753","147","258","369"};
for (int i =0;i<8;i++){
bool win = true;
char prev_op = '0';
const char* win_possibility = wins_possibilities[i]; //funciona como puntero en caso de que se cumpla uno de las wins_possibilities[]
for (int rcl = 0;rcl<dim_m;rcl++){
char alphaChar = win_possibility[rcl];
int intr_number = alphaChar - '0';
int op_sp = intr_number - 1;
int row = op_sp / dim_m; //busca la posiciĆ³n de la fila
int column = op_sp % dim_m; //busca la posiciĆ³n de la columna
char current_op = matrix[row][column];
if (prev_op == '0'){
prev_op = current_op;
}else if (prev_op == current_op){
continue;
}else{
win = false;
break;
}
}
if (win){
cout << "Felicidades, ganaste!! \n";
cout << "El jugador "<<prev_op<<" gana, felicidades! \n";
exit(0);
break;
}
}
}
The best way to start is to write a function which looks for possible victories (instead of looking to see if there are three in a row, check to see if there are two in a row instead). Then have the function return the space that would be a victory and have the AI move there instead. Ex: If the matrix looks like
X X _
_ _ _
_ O O
Have the function return 0,2 and 2,0.
Then have your AI pick from that randomly.
After that you can modify that function to return who's possible victory it is, and then have your AI always prefer to go where it would win.
Implementation can look something like this:
#include <vector> // Vector comes from this
#include <utility> // Pair comes from this
std::vector<std::pair<bool, Point>> GetPossibleVictories()
{
std::vector<std::pair<bool, Point>> retVal;
// Check for two in a row Horitzontally, Vertically, and Diagonally.
{
if (/*IsPossibleWin*/)
{
retVal.push_back(std::pair<bool, Point>(isAIsVictory, Point{ X, Y }));
}
}
return retVal;
}
In addition I would also investigate more modern C++ constructs which can help you such as containers (std::vector, std::list, std::set, and etc) which can help you store your matrix in a easier to manipulate way.
In the example above I'm using a custom type (Point) which in its simplest way can be programmed like this:
struct Point
{
int X = 0;
int Y = 0;
};
By using a struct (or a class where every member is public by default) you can store coordinates for your matrix in a single object. In addition I'm using a vector which acts like a automatically resizing array. You can go through each thing in the vector like this:
for(const auto& possibleWin : possibleWins) // possibleWins is the vector returned from the previous example.
{
// possibleWin in this block will be the same value as if you used a for loop and did possibleWins[x]
}
Finally the example above uses Pair, which just holds two different types of things. It can be used as follows:
std::pair<bool, Point> myPair;
myPair.first = true;
myPair.second = Point{0, 2};
For more reading (Scroll to the bottom for examples on how to use them):
Vector
Pair
Hopefully this can give you some ideas on how to start making your AI a little smarter.

whitecards (lowercase) skips other players in PlayerVector but the first - why?

I have tried for several days to find a solution to this but I am at a loss.
I am creating a Cards Against Humanity game that makes use of a Player class. This player class has functions to add white cards, retrieve a white card, get rid of a white card, get name, set name, and others.
The program goes:
Main menu (goes to gameplay, how to play, credits, and quit)
Chooses number of players.
Creates vector of players
Sets player names.
Assigns eight cards to each player's whitecards vector.
Begins game.
The main issue I have is with the assigning eight cards to each player's whitecards vector.
This is the code for the part of the program that distributes cards.
for (i = 0; i < playercount; i++) /* Adds eight white cards to each player's vector of cards */
{
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
PlayerVector.at(i).addwhitecard();
}
This is the section of Player.cpp that assigns a white card.
bool Player::addwhitecard()`{
whitecard_ptr = fopen("WhiteCards.txt", "r");
if (whitecard_ptr != NULL)
{
std::cout << "This Part Worked" << std::endl;
if (maxwhitecardcount >= whitecards.size())
{
std::cout << "Yes Continue Pls" << std::endl;
srand(time(0));
randomnumber = rand() % 398;
randomnumber2 = rand() % 398;
randomnumber3 = rand() % 398;
randomnumber4 = rand() % 398;
randomnumber5 = rand() % 398;
randomnumber6 = rand() % 398;
randomnumber7 = rand() % 398;
randomnumber8 = rand() % 398;
while (getline(WhiteCards, line))
{
++LineNo;
if (LineNo == randomnumber || LineNo == randomnumber2 || LineNo == randomnumber3 || LineNo == randomnumber4 || LineNo == randomnumber5 || LineNo == randomnumber6 || LineNo == randomnumber7 || LineNo == randomnumber8)
{
whitecards.push_back(line);
std::cout << "Yes! This size is: " << whitecards.size() << std::endl;
return true;
}
}
}
else
{
std::cout << name << "has too many white cards!";
return false;
}
}
}
This is the constructor for the player class.
Player::Player(std::string name, int points)
{
this->points = 0;
this->name = "PlayerName";
this->whitecards;
}
And this is the player class itself in the header file
class Player
{
public:
Player();
Player(std::string name, int points);
void drawwhitecard();
std::string getwhitecard();
void ridwhitecard();
void addpoint();
int getpoints();
bool addwhitecard();
void namechar();
bool showwhitecards();
bool setname();
std::string getname();
protected:
int points;
std::vector<std::string> whitecards;
std::string name;
int whitecardcount;
int maxwhitecardcount = 8;
int whitecardchoicenumber = 0;
};
I tried to put the whitecards vector as an argument in player, but I wasn't able to use the vector in the arguments list when creating a player object in the main code.
Can someone tell me where I went wrong? Whether I do actually need to put the vector in the arguments and how to use it in an arguments list.
Thanks in advance.
I found a solution to this, though it's somewhat long.
I had to add 56 other randomnumber variables that all the other players can use.
Sorry I couldn't provide a MCVE due to time constraints.

Weird Behaviour in C++ Snake School Assignment

So over the last few weeks we've been coding snake in c++ step by step. Right now we have to implement the snake actually growing. (All of this happens in the console)
We realize the growth by saving the head and the tail of the snake, as well as the Direction the Head went on a given field and then moving the tail into that saved direction from the field the tail is on.
Theoretically skipping this tail movement once when we eat a fruit should let our snake grow.
However, my Snake either doesnt grow at all, or grows infinitely until I pass the Field on which the fruit was again, or ,in this current iteration, grows mostly correct but only in the direction which I was facing when eating the fruit. Also in this Iteration the size of the snake changes, if I comment out the GenerateFruit() Command (Even when that command is completely empty).
I'm clueless as to what im doing wrong. I've had different behaviour just by having a literally empty if statement.
Heres the main part of the code:
bool MoveSnake(SnakeDataT snakeData){
//Collision detection: If the new x/y Coordinate hits the walls we have a collision.
if (snakeData.Head.x + snakeData.dx == WIDTH - 1 || snakeData.Head.x + snakeData.dx == 0 || snakeData.Head.y + snakeData.dy == HEIGHT + 1 || snakeData.Head.y + snakeData.dy == 0)
{
SetCursor(WIDTH, HEIGHT);
cout << "\n";
cout << "\n";
cout << "\n";
cout << "Game Over" << endl;
return false;
}
//Save current Movement Direction in current coordinate
snakeData.Field[snakeData.Head.x][snakeData.Head.y].dx = snakeData.dx;
snakeData.Field[snakeData.Head.x][snakeData.Head.y].dy = snakeData.dy;
//Fruit Collision:
if (snakeData.Head.x == snakeData.Fruit.x && snakeData.Head.y == snakeData.Fruit.y)
{
//GenerateFruit(snakeData); <- If I leave this out it literally changes behaviour?!
}
else if (!(snakeData.Head.x == snakeData.Fruit.x && snakeData.Head.y == snakeData.Fruit.y))
{
//Delete at Tail Position
SetCursor(snakeData.Tail.x, snakeData.Tail.y);
cout << ' ';
//Move Tail by saved Direction. I did try this with the Tail coordinates first, but after many different iterations this showed the weirdest results.
snakeData.Tail.x += snakeData.Field[snakeData.Head.x][snakeData.Head.y].dx;
snakeData.Tail.y += snakeData.Field[snakeData.Head.x][snakeData.Head.y].dy;
}
//Move Head
snakeData.Head.x += snakeData.dx;
snakeData.Head.y += snakeData.dy;
//Draw Head
SetCursor(snakeData.Head.x, snakeData.Head.y);
cout << "\xCE";
return true;
Here are my structs:
#define WIDTH 30
#define HEIGHT 30
enum FieldTypeT
{
empty,
Snake
};
struct FieldT
{
FieldTypeT fieldType;
int dx;
int dy;
};
struct PointT
{
int &x;
int &y;
};
struct SnakeDataT
{
PointT Head;
PointT Fruit;
int &dx;
int &dy;
PointT Tail;
FieldT Field[WIDTH][HEIGHT];
};
If you need more Insight I'll add what you need.
Bear with me though, the Teacher is asking for questionable practices.

Variable not being set to correct value

I am making a Tic Tac Toe game. At the end of the game if one of the two human players wins, it is supposed to say "Player [1 or 2] has won!" It does this by checking what value ('X' or 'O') the winning row/column/diagonal is and corresponds it to what player it is (player 1 chooses X or O as their symbol). However, it ALWAYS thinks that player 1 has won regardless of who actually won.
Weird thing is, I can have the program cout both playerwon and BSTAT.getsquarestatus("A1") and player_won will ALWAYS output 'X' and BSTAT.getsquarestatus("A1") will output the correct answer, whether it's X or O.
Question: Why is player_won always being set to X? It is supposed to be set to the value of the player who won, but for some reason it is always set to X even if the winning player's value is 'O'.
If you need more information, please let me know. Thanks for your help!
char player1_mark;
char player_won;
class Boardstatus
{
char A1;
public:
char getsquarestatus( string square )
{
// enumerator basically changes A1-C3 to a number 1-9
// not an actual enumerator, just a function
int squarenumber = enumerator( square );
switch ( squarenumber )
{
case 1:
return A1;
break;
}
}
private:
//This function acts similar to an enumerator, but instead returns a number 1-9 based
//on what string x is entered so that the switch cases in get and setsquarestatus will
//function properly (they require int or char to work)
int enumerator( string x )
{
if ( x == "A1" )
{
return 1;
}
};
bool checkwin( Boardstatus& BSTAT)
{
//Row 'A' checkwin
if (BSTAT.getsquarestatus("A1")!= ' ' && BSTAT.getsquarestatus("A1")==BSTAT.getsquarestatus("A2") && BSTAT.getsquarestatus("A2")==BSTAT.getsquarestatus("A3"))
{
//****This is where something is wrong****
player_won = BSTAT.getsquarestatus("A1");
return true;
}
}
int main()
{
Boardstatus BSTAT;
if ( player_won = player1_mark )
{
cout << "Player 1 has won!";
}
else
{
cout << "Player 2 has won!";
}
}
This: if ( player_won = player1_mark ) is setting the value of player_won
You need == for comparison, not assignment.