2

As an exercise, I am trying to create a TicTacToe game in Visual Studio as a console application. First, I created the 3x3 grid with a multidimensional array. I thought an intuitive way to "write" an 'X' or an 'O' in a particular square of the grid would be by having the player input a number 1-9 and that number would map to a particular square. Below is how the numbers would be correspond to the spots in the grid:

1   2   3

4   5   6

7   8   9

Thus, I used std::multimap to map the player input to a square in the grid to practice using maps and multimaps. Since I am new to std::multimap I guess I messed up somewhere: there is no error, the game compiles, but the input does not seem to be mapping correctly to the right square.

I do not know how to fix the bug because I am unfamiliar with maps and multimaps.

*If someone could tell me how to fix the problem using the mapping method I have chosen that would be great!

*I'm also welcoming other and better ideas as to how to approach mapping player input to specific squares!

Sorry for the long code; I don't think I could cut anything more. Thanks for taking the time!

#include <iostream>
#include <map>
using namespace std;


class TTTClass
{
private:
    static const int GRID_LENGTH = 3;
    char Grid[GRID_LENGTH][GRID_LENGTH] = {' '};

    int POInput;
    int PXInput;
    bool IsInputValid = false;

public:
    TTTClass()
{
    POInput = 1;
    PXInput = 1;
}


void EmptyGrid()
{
    for (int RowCounter = 0; RowCounter < GRID_LENGTH; RowCounter++)
    {
        for (int ColumnCounter = 0; ColumnCounter < GRID_LENGTH; ColumnCounter++)
        {
            Grid[RowCounter][ColumnCounter] = ' ';
        }
    }
}


void DisplayGrid()
{
    for (int RowCounter = 0; RowCounter < GRID_LENGTH; RowCounter++)
    {
        std::cout << "  ";
        for (int ColumnCounter = 0; ColumnCounter < GRID_LENGTH; ColumnCounter++)
        {
            std::cout << Grid[RowCounter][ColumnCounter];
            if (ColumnCounter != GRID_LENGTH - 1) {std::cout << " | ";}         
        }
        if (RowCounter != GRID_LENGTH - 1)
        {
            std::cout << "\n  __|___|__ \n    |   |\n";
        }
    }
    std::cout << "\n\n";
}


void POTurn()
{
    std::multimap<int, int> Gridmm;

    Gridmm.insert(std::make_pair(1, 0)); Gridmm.insert(std::make_pair(1, 0));
    Gridmm.insert(std::make_pair(2, 0)); Gridmm.insert(std::make_pair(2, 1));
    Gridmm.insert(std::make_pair(3, 0)); Gridmm.insert(std::make_pair(3, 2));
    Gridmm.insert(std::make_pair(4, 1)); Gridmm.insert(std::make_pair(4, 0));
    Gridmm.insert(std::make_pair(5, 1)); Gridmm.insert(std::make_pair(5, 1));
    Gridmm.insert(std::make_pair(6, 1)); Gridmm.insert(std::make_pair(6, 2));
    Gridmm.insert(std::make_pair(7, 2)); Gridmm.insert(std::make_pair(7, 0));
    Gridmm.insert(std::make_pair(8, 2)); Gridmm.insert(std::make_pair(8, 1));
    Gridmm.insert(std::make_pair(9, 2)); Gridmm.insert(std::make_pair(9, 2));

    do
    {
        std::cout << "PlayerO, select a square: ";
        std::cin >> POInput;
        if (POInput < 1 || POInput > 9)
            IsInputValid = false;
        else
        {
            std::pair<std::multimap<int, int>::iterator, std::multimap<int, int>::iterator> RepeaterIterator;
            RepeaterIterator = Gridmm.equal_range(POInput);

            std::multimap<int, int>::iterator itr1 = RepeaterIterator.first;
            std::multimap<int, int>::iterator itr2 = RepeaterIterator.second;

            Grid[itr1->second][itr2->second] = 'O';
            std::cout << "Value at square " << POInput << "/ Coord. " << itr1->second << ", " << itr2->second;
            std::cout << " is: " << Grid[itr1->second][itr2->second] << "\n";
            IsInputValid = true;
        }       
    } while (IsInputValid == false);
}

void PXTurn()
{
    std::multimap<int, int> Gridmm;

    Gridmm.insert(std::make_pair(1, 0)); Gridmm.insert(std::make_pair(1, 0));
    Gridmm.insert(std::make_pair(2, 0)); Gridmm.insert(std::make_pair(2, 1));
    Gridmm.insert(std::make_pair(3, 0)); Gridmm.insert(std::make_pair(3, 2));
    Gridmm.insert(std::make_pair(4, 1)); Gridmm.insert(std::make_pair(4, 0));
    Gridmm.insert(std::make_pair(5, 1)); Gridmm.insert(std::make_pair(5, 1));
    Gridmm.insert(std::make_pair(6, 1)); Gridmm.insert(std::make_pair(6, 2));
    Gridmm.insert(std::make_pair(7, 2)); Gridmm.insert(std::make_pair(7, 0));
    Gridmm.insert(std::make_pair(8, 2)); Gridmm.insert(std::make_pair(8, 1));
    Gridmm.insert(std::make_pair(9, 2)); Gridmm.insert(std::make_pair(9, 2));

    do
    {
        std::cout << "PlayerX, select a square: ";
        std::cin >> PXInput;
        if (PXInput < 1 || PXInput > 9)
            IsInputValid = false;
        else
        {
            std::pair<std::multimap<int, int>::iterator, std::multimap<int, int>::iterator> RepeaterIterator;
            RepeaterIterator = Gridmm.equal_range(PXInput);

            std::multimap<int, int>::iterator itr1 = RepeaterIterator.first;
            std::multimap<int, int>::iterator itr2 = RepeaterIterator.second;

            Grid[itr1->second][itr2->second] = 'X';
            std::cout << "Value at square " << POInput << "/ Coord. " << itr1->second << ", " << itr2->second;
            std::cout << " is: " << Grid[itr1->second][itr2->second] << "\n";
            IsInputValid = true;
        }
    } while (IsInputValid == false);
}   
};

int main()
{
    TTTClass MyGame;

    MyGame.EmptyGrid();
    MyGame.DisplayGrid();

    MyGame.PXTurn();
    MyGame.DisplayGrid();

    MyGame.POTurn();
    MyGame.DisplayGrid();

    return 0;
}

BTW, I know the game only runs through two turns, but problem shows up regardless.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • *there is no error, the game compiles* -- All that means is that there are no syntax errors. It has nothing to do with whether your program has logical errors. There are no bonus points for having a program that just compiles with no errors. – PaulMcKenzie Jul 20 '19 at 04:35
  • 2
    Off-topic, but you have unnecessary code duplication going on in a major way. The two functions that denote the turns are identical, with the only difference being one is 'X' and the other is 'O' – PaulMcKenzie Jul 20 '19 at 04:40
  • 2
    Why do you need MULTImap? I didn't get the idea why you need duplicates. – Dmitry Kuzminov Jul 20 '19 at 04:46
  • I used multimap because one user input needs to map to two integers that are used to access a specific square in the multidimensional array used to make the grid. For example, if the user input 5, the multimap would output 1 and 1 (for Row 1, Column 1). I thought this approach would be most intuitive, but I'm open to suggestions! – Nicolas Cancio Jul 20 '19 at 06:43

1 Answers1

1

(Too long for a comment and, may be, actually an answer.)

I believe, OP missed the point that the required mapping is intint × int.

Either the value type has to be e.g. std::pair<int, int> or there are two mappings needed – one to map input to rows and one to map input to columns.

However, there is a very simple linear relation between input index and grid coordinates:

 1 -> 0, 0 | 2 -> 0, 1 | 3 -> 0, 2
 ----------+-----------+----------
 4 -> 1, 0 | 5 -> 1, 1 | 6 -> 1, 2
 ----------+-----------+----------
 7 -> 2, 0 | 8 -> 2, 1 | 9 -> 2, 2

I.e. for input int i: int col = (i - 1) % 3, row = (i - 1) / 3;.

This aside: If OP really wants to use a map, then std::map<int, std::pair<int, int> > makes more sense than multimap.

A std::map is a sorted associative container that contains key-value pairs with unique keys. (which you have). Each input index maps to exactly one grid cell and there are no duplicated keys.

It is irrelevant that the value is a pair of ints. It can be rather any object with a minimal requirement of properties:

A std::multimap is an associative container that contains a sorted list of key-value pairs, while permitting multiple entries with the same key. (which you don't need as your keys are unique).


in OPs code:

std::cin >> i;
if (i >= 1 && i <= 9) {
  Grid[/* row: */(i - 1) / 3, /* col: */(i - 1) % 3] = mark;
} else {
  // harass user
}

Thereby, char mark could have 'X' or 'O' to consider the hint of PaulMcKenzie about code duplication.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56