简体   繁体   中英

How to use std::multimap to map integer key to two integer values that serve as multidimensional array coordinates (for Tic Tac Toe)?

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.

(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 eg 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

Ie 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 int s. 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.

但是我怎样才能创建整数和整数对的多重映射??非常感谢 Cpp 解决方案

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM