I am getting a weird error message with Qt creator which makes no sense why it is occuring at all.. I am at the moment programming an ai player for a ludo simulator, which has been written as a QT gui. I've creates a C++ class named player_q_learning
, but for some reason is moc_player_q_learning.cpp
created within the build folder, and create a multiple definition of the function which i already defined in player_q_learning
... Why am I running into this error?
/home/Vato/Desktop/ludo-gui/build-ludo-Desktop-Debug/moc_player_q_learning.cpp:116: error: multiple definition of `player_q_learning::calc_input(float*, int, int)'
ludo.pro
#-------------------------------------------------
#
# Project created by QtCreator 2016-03-15T10:40:30
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ludo
TEMPLATE = app
SOURCES += main.cpp\
dialog.cpp \
game.cpp \
ludo_player.cpp \
ludo_player_random.cpp \
player_q_learning.cpp
HEADERS += dialog.h \
game.h \
ludo_player.h \
positions_and_dice.h \
ludo_player_random.h \
player_q_learning.h
FORMS += dialog.ui
CONFIG += object_with_source
QMAKE_CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic -Wunused
main.cpp
#include "dialog.h"
#include <QApplication>
#include "game.h"
#include <vector>
#include "ludo_player.h"
#include "ludo_player_random.h"
#include "positions_and_dice.h"
Q_DECLARE_METATYPE( positions_and_dice )
using namespace std;
int main(int argc, char *argv[]){
QApplication a(argc, argv);
qRegisterMetaType<positions_and_dice>();
//instanciate the players here
ludo_player p1, p2;
ludo_player_random p3, p4;
game g;
g.setGameDelay(010); //if you want to see the game, set a delay
// Add a GUI <-- remove the '/' to uncomment block
// Dialog w;
// QObject::connect(&g,SIGNAL(update_graphics(std::vector<int>)),&w,SLOT(update_graphics(std::vector<int>)));
// QObject::connect(&g,SIGNAL(set_color(int)), &w,SLOT(get_color(int)));
// QObject::connect(&g,SIGNAL(set_dice_result(int)), &w,SLOT(get_dice_result(int)));
// QObject::connect(&g,SIGNAL(declare_winner(int)), &w,SLOT(get_winner(int)));
// w.show();
//Or don't add the GUI
//QObject::connect(&g,SIGNAL(close()),&a,SLOT(quit()));
//*/
//set up for each player
QObject::connect(&g, SIGNAL(player1_start(positions_and_dice)),&p1,SLOT(start_turn(positions_and_dice)));
QObject::connect(&p1,SIGNAL(select_piece(int)), &g, SLOT(movePiece(int)));
QObject::connect(&g, SIGNAL(player1_end(std::vector<int>)), &p1,SLOT(post_game_analysis(std::vector<int>)));
QObject::connect(&p1,SIGNAL(turn_complete(bool)), &g, SLOT(turnComplete(bool)));
QObject::connect(&g, SIGNAL(player2_start(positions_and_dice)),&p2,SLOT(start_turn(positions_and_dice)));
QObject::connect(&p2,SIGNAL(select_piece(int)), &g, SLOT(movePiece(int)));
QObject::connect(&g, SIGNAL(player2_end(std::vector<int>)), &p2,SLOT(post_game_analysis(std::vector<int>)));
QObject::connect(&p2,SIGNAL(turn_complete(bool)), &g, SLOT(turnComplete(bool)));
QObject::connect(&g, SIGNAL(player3_start(positions_and_dice)),&p3,SLOT(start_turn(positions_and_dice)));
QObject::connect(&p3,SIGNAL(select_piece(int)), &g, SLOT(movePiece(int)));
QObject::connect(&g, SIGNAL(player3_end(std::vector<int>)), &p3,SLOT(post_game_analysis(std::vector<int>)));
QObject::connect(&p3,SIGNAL(turn_complete(bool)), &g, SLOT(turnComplete(bool)));
QObject::connect(&g, SIGNAL(player4_start(positions_and_dice)),&p4,SLOT(start_turn(positions_and_dice)));
QObject::connect(&p4,SIGNAL(select_piece(int)), &g, SLOT(movePiece(int)));
QObject::connect(&g, SIGNAL(player4_end(std::vector<int>)), &p4,SLOT(post_game_analysis(std::vector<int>)));
QObject::connect(&p4,SIGNAL(turn_complete(bool)), &g, SLOT(turnComplete(bool)));
g.start();
return a.exec();
}
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->setBackgroundBrush(QBrush(QColor(240,240,239)));
diceBG = scene->addRect(0,-150,100,100,QPen(Qt::black,3,Qt::SolidLine,Qt::RoundCap, Qt::RoundJoin),QBrush(Qt::green));
diceRoll = scene->addSimpleText(QString::number(0),QFont("Courier", 72, QFont::Bold, true));
diceRoll->setPos(25,-150);
// Colors
std::vector<std::pair<QColor,QColor> >base_colors {
std::make_pair(QColor(92,170,119),QColor(185,219,125)), //G
std::make_pair(QColor(237,235,89),QColor(237,234,138)), //Y
std::make_pair(QColor(92,93,170),QColor(111,111,170)), //B
std::make_pair(QColor(237,57,60),QColor(237,114,125)) //R
};
QBrush white(Qt::white);
QPen blackPen(Qt::black);
blackPen.setWidth(1);
// Cross
scene->addRect(415,-155,160,960,blackPen,QBrush(QColor(195,195,194)));
scene->addRect(15,245,960,160,blackPen,QBrush(QColor(195,195,194)));
scene->addRect(415,245,160,160,QPen(QColor(195,195,194)),QBrush(QColor(195,195,194))); //clean center
// Goal stretch
scene->addRect(50,290,350,70,blackPen,QBrush(base_colors[0].first));
scene->addRect(460,-120,70,350,blackPen,QBrush(base_colors[1].first));
scene->addRect(590,290,350,70,blackPen,QBrush(base_colors[2].first));
scene->addRect(460,420,70,350,blackPen,QBrush(base_colors[3].first));
int x_pos = -10; //start place for green
int y_pos = 220;
int offset = 70;
int small_offset = 50;
int large_offset = 80;
//home fields
home_fields.push_back(QPointF(0,0));
home_fields.push_back(QPointF(630,-170));
home_fields.push_back(QPointF(800,445));
home_fields.push_back(QPointF(190,630));
for(size_t f = 0; f < home_fields.size(); ++f){
addHomeField(home_fields[f].x(),home_fields[f].y(),QBrush(base_colors[f].first));
}
// Playing fields
std::vector<std::pair<char,char> > directions{std::make_pair(1,-1),std::make_pair(1,1),std::make_pair(-1,1),std::make_pair(-1,-1) };
for(size_t d =0; d < directions.size(); ++d){
for(int i=0; i<5;++i){
if(d % 2 == 0)
x_pos += directions[d].first * offset;
else
y_pos += directions[d].second * offset;
fieldPos.push_back(QPointF(x_pos,y_pos));
}
x_pos += directions[d].first * small_offset;
y_pos += directions[d].second * small_offset;
for(int i=0; i<5;++i){
fieldPos.push_back(QPointF(x_pos,y_pos));
if(d % 2 == 0)
y_pos += directions[d].second * offset;
else
x_pos += directions[d].first * offset;
}
for(int i=0; i<2;++i){
fieldPos.push_back(QPointF(x_pos,y_pos));
if(d % 2 == 0)
x_pos += directions[d].first * large_offset;
else
y_pos += directions[d].second * large_offset;
}
fieldPos.push_back(QPointF(x_pos,y_pos));
}
//goal stretches
for(int x=60; x<=340; x+=offset)
fieldPos.push_back(QPointF(x,300));
for(int y=-110; y<=170; y+=offset)
fieldPos.push_back(QPointF(470,y));
for(int x=880; x>=600; x-=offset)
fieldPos.push_back(QPointF(x,300));
for(int y=710; y>=430; y-=offset)
fieldPos.push_back(QPointF(470,y));
QImage globe_img("../globe.png");//http://www.clker.com/clipart-world-black-and-white.html
QImage star_img("../star.png"); //http://www.clker.com/clipart-2568.html
// QGraphicsPixmapItem globe( QPixmap::fromImage(QImage("../globe.png")));
// QGraphicsPixmapItem star( QPixmap::fromImage(QImage("../star.png")));
for(size_t c = 0; c < base_colors.size(); ++c){
scene->addEllipse(fieldPos[0+13*c].x(),fieldPos[0+13*c].y(),50,50,QPen(base_colors[c].first),QBrush(base_colors[c].second));
for(int i=1; i < 13; ++i){
if(i == 8){
QGraphicsPixmapItem * globe = new QGraphicsPixmapItem( QPixmap::fromImage(globe_img));
globe->setPos(fieldPos[i+13*c]);
globe->setScale(0.5);
scene->addItem(globe);
} else if(i == 5 || i == 11){
QGraphicsPixmapItem * star = new QGraphicsPixmapItem( QPixmap::fromImage(star_img));
star->setPos(fieldPos[i+13*c]);
star->setScale(0.5);
scene->addItem(star);
} else {
scene->addEllipse(fieldPos[i+13*c].x(),fieldPos[i+13*c].y(),50,50,blackPen,white);
}
}
}
for(size_t g = 52; g < fieldPos.size(); ++g){
scene->addEllipse(fieldPos[g].x(),fieldPos[g].y(),50,50,blackPen,white);
}
create_graphic_players();
std::vector<int> init_pos(16,-1);
update_graphics(init_pos);
}
void Dialog::update_graphics(std::vector<int> player_positions){
QPointF p;
for(size_t i = 0; i < player_positions.size(); ++i){
if(player_positions[i] == -1){
p = home_fields[i / 4];
if(i % 4 == 0)
graphic_player[i]->setPos(p.x()+65 ,p.y()+15 );
else if(i % 4 == 1)
graphic_player[i]->setPos(p.x()+65 ,p.y()+115);
else if(i % 4 == 2)
graphic_player[i]->setPos(p.x()+15 ,p.y()+65 );
else if(i % 4 == 3)
graphic_player[i]->setPos(p.x()+115,p.y()+65 );
} else if(player_positions[i] == 99){
if(i/4 == 0){
if(i % 4 == 0) graphic_player[i]->setPos(405,300); //left
else if(i % 4 == 1) graphic_player[i]->setPos(405,270);
else if(i % 4 == 2) graphic_player[i]->setPos(405,330);
else if(i % 4 == 3) graphic_player[i]->setPos(435,300);
} else if(i/4 == 1){
if(i % 4 == 0) graphic_player[i]->setPos(470,235); //up
else if(i % 4 == 1) graphic_player[i]->setPos(440,235);
else if(i % 4 == 2) graphic_player[i]->setPos(500,235);
else if(i % 4 == 3) graphic_player[i]->setPos(470,265);
} else if(i/4 == 2){
if(i % 4 == 0) graphic_player[i]->setPos(535,300); //right
else if(i % 4 == 1) graphic_player[i]->setPos(535,270);
else if(i % 4 == 2) graphic_player[i]->setPos(535,330);
else if(i % 4 == 3) graphic_player[i]->setPos(505,300);
} else if(i/4 == 3){
if(i % 4 == 0) graphic_player[i]->setPos(470,365); //down
else if(i % 4 == 1) graphic_player[i]->setPos(440,365);
else if(i % 4 == 2) graphic_player[i]->setPos(500,365);
else if(i % 4 == 3) graphic_player[i]->setPos(470,335);
}
} else {
graphic_player[i]->setPos(fieldPos[player_positions[i]]);
}
}
ui->graphicsView->repaint();
}
void Dialog::create_graphic_players(){
graphic_player.clear();
QBrush piece;
QPen blackPen(Qt::black);
blackPen.setWidth(1);
for(int c = 0; c<4; ++c){
if(c == 0){
piece = QBrush(QColor(Qt::green));
} else if(c == 1){
piece = QBrush(QColor(Qt::yellow));
} else if(c == 2){
piece = QBrush(QColor(Qt::blue));
} else if(c == 3){
piece = QBrush(QColor(Qt::red));
}
for(int i = 0; i<4; ++i){
graphic_player.push_back(scene->addEllipse(5,5,40,40,blackPen,piece));
}
}
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::showEvent(QShowEvent *) {
ui->graphicsView->fitInView(scene->itemsBoundingRect(),Qt::KeepAspectRatio);
}
void Dialog::resizeEvent(QResizeEvent *){
ui->graphicsView->fitInView(scene->itemsBoundingRect(),Qt::KeepAspectRatio);
}
void Dialog::get_winner(int color){
scene->addRect(0,500,1000,200,QPen(Qt::black,3,Qt::SolidLine,Qt::RoundCap, Qt::RoundJoin),QBrush(active_color));
QGraphicsSimpleTextItem * win = scene->addSimpleText(QString("Winner is found!"),QFont("Courier", 72, QFont::Bold, true));
win->setPos(50,550);
}
void Dialog::get_color(int color){
switch(color){
case 0:
active_color = Qt::green;
break;
case 1:
active_color = Qt::yellow;
break;
case 2:
active_color = Qt::blue;
break;
case 3:
active_color = Qt::red;
default:
break;
}
}
void Dialog::get_dice_result(int dice){
current_dice_roll = dice;
diceBG->setBrush(active_color);
diceRoll->setText(QString::number(current_dice_roll));
ui->graphicsView->repaint();
}
void Dialog::addHomeField(int x, int y,QBrush brush){
QBrush whiteBrush(Qt::white);
QPen blackPen(Qt::black);
blackPen.setWidth(1);
scene->addEllipse(x,y,180,180,blackPen,brush);
scene->addEllipse(x+65 ,y+15 ,50,50,blackPen,whiteBrush);
scene->addEllipse(x+65 ,y+115,50,50,blackPen,whiteBrush);
scene->addEllipse(x+15 ,y+65 ,50,50,blackPen,whiteBrush);
scene->addEllipse(x+115,y+65 ,50,50,blackPen,whiteBrush);
}
game.cpp
#include "game.h"
#define DEBUG 0
game::game(){
game_delay = 1000;
game_complete = false;
turn_complete = true;
for(int i = 0; i < 16; ++i){
player_positions.push_back(-1);
}
color = 3;
}
void game::reset(){
game_complete = false;
turn_complete = true;
for(auto i : player_positions){
i = -1;
}
color = 3;
}
int game::rel_to_fixed(int relative_piece_index){
return relative_piece_index + color * 4;
}
int game::isStar(int index){
if(index == 5 ||
index == 18 ||
index == 31 ||
index == 44){
return 6;
} else if(index == 11 ||
index == 24 ||
index == 37 ||
index == 50){
return 7;
}
return 0;
}
int game::isOccupied(int index){ //returns number of people of another color
int number_of_people = 0;
if(index != 99){
for(size_t i = 0; i < player_positions.size(); ++i){
if(i < color*4 || i >= color*4 + 4){ //Disregard own players
if(player_positions[i] == index){
++number_of_people;
}
}
}
}
return number_of_people;
}
bool game::isGlobe(int index){
if(index < 52){ //check only the indexes on the board, not in the home streak
if(index % 13 == 0 || (index - 8) % 13 == 0 || isOccupied(index) > 1){ //if more people of the same team stand on the same spot it counts as globe
return true;
}
}
return false;
}
void game::send_them_home(int index){
for(size_t i = 0; i < player_positions.size(); ++i){
if(i < color*4 || i >= color*4 + 4){ //this way we don't skip one player position
if(player_positions[i] == index){
player_positions[i] = -1;
}
}
}
}
void game::move_start(int fixed_piece){
if(dice_result == 6 && player_positions[fixed_piece] < 0){
player_positions[fixed_piece] = color*13; //move me to start
send_them_home(color*13); //send pieces home if they are on our start
}
}
int game::next_turn(unsigned int delay = 0){
if(game_complete){
return 0;
}
switch(color){
case 0:
case 1:
case 2:
++color;
break;
case 3:
default:
color = 0;
break;
}
global_color = color;
rollDice();
relative.dice = getDiceRoll();
relative.pos = relativePosition();
emit set_color(color);
emit set_dice_result(dice_result);
msleep(delay);
switch(color){
case 0:
emit player1_start(relative);
break;
case 1:
emit player2_start(relative);
break;
case 2:
emit player3_start(relative);
break;
case 3:
emit player4_start(relative);
default:
break;
}
return 0;
}
void game::movePiece(int relative_piece){
int fixed_piece = rel_to_fixed(relative_piece); //index of the piece in player_positions
int modifier = color * 13;
int relative_pos = player_positions[fixed_piece];
int target_pos = 0;
if(player_positions[fixed_piece] == -1){ //if the selected piece is in the safe house, try to move it to start
move_start(fixed_piece);
} else {
//convert to relative position
if(relative_pos == 99){
std::cout << "I tought this would be it ";
} else if(relative_pos < modifier) {
relative_pos = relative_pos + 52 - modifier;
} else if( relative_pos > 50) {
relative_pos = relative_pos - color * 5 - 1;
} else {//if(relative >= modifier)
relative_pos = relative_pos - modifier;
}
if(DEBUG) std::cout << "color: " << color << " pos: " << relative_pos << " + " << dice_result << " = " << relative_pos + dice_result;
//add dice roll
relative_pos += dice_result; //this is relative position of the selected token + the dice number
int jump = isStar(relative_pos); //return 0 | 6 | 7
if(jump){
if(jump + relative_pos == 57){
relative_pos = 56;
} else {
relative_pos += jump;
}
}
//special case checks
if(relative_pos > 56 && relative_pos < 72){ // go back
target_pos = 56-(relative_pos-56) + color * 5 + 1; //If the player moves over the goal, it should move backwards
}else if(relative_pos == 56 || relative_pos >= 99){
target_pos = 99;
}else if(relative_pos > 50){ // goal stretch
target_pos = relative_pos + color * 5 + 1;
} else {
int new_pos = relative_pos + color * 13;
if(new_pos < 52){
target_pos = new_pos;
} else { //wrap around
target_pos = new_pos - 52; //this is the global position wrap around at the green entry point
}
}
//check for game stuff
if(isOccupied(target_pos)){
if(isGlobe(target_pos)){
target_pos = -1; //send me home
} else {
send_them_home(target_pos);
}
}
if(DEBUG) std::cout << " => " << target_pos << std::endl;
player_positions[fixed_piece] = target_pos;
}
std::vector<int> new_relative = relativePosition();
switch(color){
case 0:
emit player1_end(new_relative);
break;
case 1:
emit player2_end(new_relative);
break;
case 2:
emit player3_end(new_relative);
break;
case 3:
emit player4_end(new_relative);
default:
break;
}
emit update_graphics(player_positions);
}
std::vector<int> game::relativePosition(){
std::vector<int> relative_positons;
int modifier = color * 13;
//from start id to end
for(int i = color*4; i < player_positions.size(); ++i){
relative_positons.push_back(player_positions[i]);
}
//from 0 to start id
for(int i = 0; i < color*4; ++i){
relative_positons.push_back(player_positions[i]);
}
for(size_t i = 0; i < relative_positons.size(); ++i){
if(relative_positons[i] == 99 || relative_positons[i] == -1){
relative_positons[i] = (relative_positons[i]);
} else if(relative_positons[i] < modifier) {
relative_positons[i] = (relative_positons[i]+52-modifier);
} else if(relative_positons[i] > 50) {
relative_positons[i] = (relative_positons[i]-color*5-1);
} else if(relative_positons[i] > modifier) {
relative_positons[i] = (relative_positons[i]-modifier);
}
}
return std::move(relative_positons);
}
void game::turnComplete(bool win){
game_complete = win;
turn_complete = true;
if(game_complete){
std::cout << "player: " << color << " won" << std::endl;
emit declare_winner(color);
}
}
void game::run() {
if(DEBUG) std::cout << "color: relative pos => fixed\n";
while(!game_complete){
if(turn_complete){
turn_complete = false;
msleep(game_delay/4);
next_turn(game_delay - game_delay/4);
}
}
emit close();
QThread::exit();
}
ludo_player.cpp
#include "ludo_player.h"
#include <random>
ludo_player::ludo_player(){
}
int ludo_player::make_decision(){
if(dice_roll == 6){
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i]<0){
return i;
}
}
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i]>=0 && pos_start_of_turn[i] != 99){
return i;
}
}
} else {
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i]>=0 && pos_start_of_turn[i] != 99){
return i;
}
}
for(int i = 0; i < 4; ++i){ //maybe they are all locked in
if(pos_start_of_turn[i]<0){
return i;
}
}
}
return -1;
}
void ludo_player::start_turn(positions_and_dice relative){
pos_start_of_turn = relative.pos;
dice_roll = relative.dice;
int decision = make_decision();
emit select_piece(decision);
}
void ludo_player::post_game_analysis(std::vector<int> relative_pos){
pos_end_of_turn = relative_pos;
bool game_complete = true;
for(int i = 0; i < 4; ++i){
if(pos_end_of_turn[i] < 99){
game_complete = false;
}
}
emit turn_complete(game_complete);
}
ludo_player_random.cpp
#include "ludo_player_random.h"
ludo_player_random::ludo_player_random(){
}
int ludo_player_random::make_decision(){
std::vector<int> valid_moves;
if(dice_roll == 6){
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i]<0){
valid_moves.push_back(i);
}
}
}
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i]>=0 && pos_start_of_turn[i] != 99){
valid_moves.push_back(i);
}
}
if(valid_moves.size()==0){
for(int i = 0; i < 4; ++i){
if(pos_start_of_turn[i] != 99){
valid_moves.push_back(i);
}
}
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> piece(0, valid_moves.size()-1);
int select = piece(gen);
return valid_moves[select];
}
void ludo_player_random::start_turn(positions_and_dice relative){
pos_start_of_turn = relative.pos;
dice_roll = relative.dice;
int decision = make_decision();
emit select_piece(decision);
}
void ludo_player_random::post_game_analysis(std::vector<int> relative_pos){
pos_end_of_turn = relative_pos;
bool game_complete = true;
for(int i = 0; i < 4; ++i){
if(pos_end_of_turn[i] < 99){
game_complete = false;
}
}
emit turn_complete(game_complete);
}
player_q_learning.cpp
player_q_learning.h
I can't add the .h due to body character limit upto 30000 chars. I hope the .cpp gives an idea of how the .h files are constructed..
You declared calc_input
to be a signal, so you must not implement it. It's Qt that provides its implementation (in the MOC-generated file), such that when it is emitted it calls the slots that have been connected to it.
If you didn't intend it to be a signal (as it seems to me, given that you never connect
nor emit
it), move its declaration outside the signals:
section, so that it becomes a "regular" method.