0

我目前正在尝试创建一个井字游戏,由玩家共享的棋盘对象上的玩家类创建的两个玩家对象交替播放。据我所知,我已经完成了该程序,但是当我尝试构建时,我得到了这些错误并且似乎找不到原因。我对面向对象编程比较陌生。这是我得到的错误:

 1>Player.obj : error LNK2005: "public: __thiscall Player::Player(class Board *,char)" (??0Player@@QAE@PAVBoard@@D@Z) already defined in Connect_Four_Game.obj
 1>fatal error LNK1169: one or more multiply defined symbols found

以下是代码:

#ifndef ___PLAYER_H___
#define ___PLAYER_H___


#include <iostream>
#include "Board.h"
using namespace std;
class Player {
private:
    Board * sharedboard;
    char player_char;
public:

    Player(Board *shared_board, const char player_char);

    bool play(int &choice);
    bool wins();
    bool columnFull(int&choice);

};
Player:: Player(Board *shared_board,const char player_char)
    : player_char(player_char), sharedboard(shared_board)
{}

#endif

板子头文件:

#ifndef ___BOARD_H___
#define ___BOARD_H___


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

class Board {

public:
    vector<vector<char>> holder;
    void displayBoard();
    bool isBoardFull();
    Board()
    {
        vector<vector<char>>holder(7, vector<char>(7, 'A'));
    }
};


#endif

播放器cpp文件:

#include <iostream>
#include "Player.h"

using namespace std;


bool Player::columnFull(int &choice)//DONE
{
    for (int i = 6; i >= 0; i--)
    {
        if(sharedboard->holder[i][choice]=='A')//if the choice is not full
        {
            sharedboard->holder[i][choice] = player_char;//put the players character(X or O here)
            return false;
        }
        else//if the choive is full
        {

            return true;
        }
    }
}

bool Player::play(int &choice)//DONE
{ 
    if(choice < 0 )
    {
        cout << "Choice is not valid." << endl;
        return false;
    }
    else if(choice > 6)
    {
        cout << "Choice is not valid." << endl;
        return false;
    }
    else if(columnFull( choice))//if its true then its full
    {
        cout << "Choice is not valid." << endl;
        return false;
    }
    else
    {
        sharedboard->displayBoard();//if previous ones were false, then the place was empty, and filled, therefore the board will be displayed
    }
}

bool Player::wins()//if the player wins
{

        int o = 0;
        int x = 0;

        for (int i = 0; i < 7; i++)//HORIZONTAL
        {
            for (int j = 0; j < 7; j++)
            {
                if (sharedboard->holder[i][j] == 'O')
                {
                    o++;
                }
                else if (sharedboard->holder[i][j] == 'X')
                {
                    x++;
                }
                if (o == 4)//if O is four horizantily
                {
                    cout << "Player2 wins!" << endl;
                    sharedboard->displayBoard();
                    return true;
                }
                else if (x == 4)//if X is four horizantily
                {
                    cout << "Player1 wins!" << endl;
                    sharedboard->displayBoard();
                    return true;
                }
            }
        }//HORIZONTAL
        o = 0;
        x = 0;
        for (int i = 0; i < 7; i++)//VERTICALLY
        {
            for (int j = 0; j < 7; j++)
            {
                if (sharedboard->holder[j][i] == 'O')
                {
                    o++;
                }
                else if (sharedboard->holder[j][i] == 'X')
                {
                    x++;
                }
                if (o == 4)//if O is four vertically
                {
                    cout << "Player2 wins!" << endl;
                    sharedboard->displayBoard();
                    return true;
                }
                else if (x == 4)//if X is four vertically
                {
                    cout << "Player1 wins!" << endl;
                    sharedboard->displayBoard();
                    return true;
                }
            }
        }//VERTICALLY
}

板子cpp文件:

#include "Board.h"
#include<iostream>

using namespace std;

void Board::displayBoard()//DONE
{
    for (int i = 0; i < 7; i++)
    {
        for (int j = 0; j < 7; j++)
        {
            cout << holder[i][j] << " ";
        }
        cout << endl;
    }
}
bool Board::isBoardFull()//DONE-CORRECTED
{
    for (int i = 0; i < 7; i++)
    {
        for (int j = 0; j < 7; j++)
        {
            if (holder[i][j] == 'A')
            {
                return false;//game continues
            }
            else if(((i==6)&&(j==6)))
            {
                return true;//ends in tie
            }
        }
        cout << endl;
    }
}

主要源文件:

#include<iostream>
#include<string>
#include "Board.h"
#include "Player.h"

using namespace std;

int main()
{
    Board myBoard = Board();


    /* 
       //Create your player objects based on your choice of approach to share an object.
       //The parameters "..." are left for you to set.
       Player player1 = Player(...); 
       Player player2 = Player(...);
    */
    Player player1(&myBoard, 'X');
    Player player2(&myBoard, 'O');


    int col, turn = 0;
    bool continueGame = true;
    bool validMove = false;

    while(continueGame)
    {
        myBoard.displayBoard();
        if(turn == 0)
        {
            cout << "Player 1 turn: " << endl;
            cin >> col;
            validMove = player1.play(col);

            if(player1.wins())
            {
                continueGame = false;
                cout << "Player1 won the game!" << endl;
            }
        }
        else if(turn == 1)
        {
            cout << "Player 2 turn: " << endl;
            cin >> col;
            validMove = player2.play(col);

            if(player2.wins())
            {
                continueGame = false;
                cout << "Player2 won the game!" << endl;
            }
        }

        if(continueGame) {
            //If a valid move has been done, change the turn
            if(validMove) {
                turn = (turn + 1) % 2;      
            }

            if(myBoard.isBoardFull())
            {
                continueGame = false;
                cout << "Noone won the game!" << endl;
            }
        }
    }   

    cout << "Game is over!" << endl;
    cout << "Final state of the board: " << endl;
    myBoard.displayBoard();

    return 0;
}

我没有发布整个播放器 cpp 文件,因为它大约有 600 行,并且只有对角搜索的重复,没有别的。现在谢谢你。

4

1 回答 1

1

该错误表示您定义了多个符号。很可能,您将 Player.cpp 文件(而不是 Player.h)多次(直接或间接)包含在其他一些文件中(您没有共享 Connect_Four_Game 文件)。

我建议你做一些研究:如果你包含 .cpp 文件会发生什么?阅读有关声明、定义、多重包含,...。这也可能很有用: 已经在 .obj 中定义 - 没有双重包含

我和你一样开始,问不好的问题(我想每个人都这样做)。下次,您应该尝试检测链接器错误发生的位置,并知道链接器错误是什么。

我清楚地记得我开始使用 C++ 的日子。由于您显然已经在此代码中付出了努力,因此请允许我给您一些与您发布的代码相关的建议。

设计

在编码之前,请正确进行设计。玩家之间可以共享棋盘。你也可以有一个玩家订阅的板。无论哪种方式:

董事会应该知道自己的一切。即:玩家不应访问棋盘的属性“持有人”来查看方格是否被占用。玩家应该只问棋盘:那个方格是空的吗?

同样, columnFull 不应该是Player的方法。

代码

您应该尝试使用现代 C++。我重写了你的一些代码。

播放器构造函数:使用智能指针

Player(const std::shared_ptr<Board>& board, std::string&& name) : 
    m_name(std::move(name)), m_board(board)
{}

您的主文件现在将如下所示:

std::shared_ptr<Board> myBoard = std::make_shared<Board>();
Player me(myBoard,"Me");
Player you(myBoard,"You");

参考内置类型:

bool play(const int choice) // no reference to built-in types unless needed

尽可能使用 const :

bool wins() const // should be const, you don't want to modify "this"

使用私有成员、字符串而不是 char 和智能指针

private:
    std::shared_ptr<Board> m_board; // use smart pointers
    std::string m_name; // not playerChar -> it's obvious its about the player

看看现代 C++ 有多好:

void display() const // use const if you don't modify this
{
    // you had hardcoded numbers here (7)... try to avoid that, keep the code generic
    for (const auto& v : m_holder) // you do have access to C++11 I hope?
    {
        for (const auto& h : v)
            std::cout << h << std::endl;
    }
}

使用标准库:

bool isFull() const // try to use the wonderful standard library, your code will be much more readable
{
    for (const auto& v : m_holder)
    {
        auto it = std::find_if(v.begin(),v.end(),[](const std::string& h){ return h.empty(); });
        if (it==v.end())
            return false;
    }
    return true;
    // cout << endl shouldn't be in this function which checks if the board is full...
}

也许一些 typedef 来保持代码干净?此外,使用 _ 或 m_ 作为属性。尽可能将属性保密。

private: // try to keep members in private so you control who changes them
    // maybe use typedef? you use that type multiple times
    typedef std::vector<std::vector<std::string>> HolderType;
    HolderType m_holder; // for members, use _ or m_

全面的

  1. 在编码之前专注于设计。
  2. 使用现代 C++、标准库、...
  3. 使用智能指针。
  4. 了解何时使用 const、引用、...
  5. 保持代码干净。

这当然是一个非常不完整的建议列表。但这些是您的代码的主要缺陷。

我希望这可以帮到你。

于 2018-03-28T15:16:34.087 回答