Edit #2: Ok, I did another *.cpp to check if the codes for Arrow Keys were right. Doing that, I noticed keyPressed variable in detectKeyPressing() had the wrong type of variable, so I changed it from char to int and changed the codes.
Once I did that, it worked. Now I have put the limits, so the Player cannot go outside the square. But I have another problem, the movement is too tough and if you press the keys too fast, the instructions run with a annoying delay. I know I should use either Sleep(ms) or Delay(ms), but I don't know when I should use it.
This is the new code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing() {
// 0: Escape
// 1: Enter
//2: Up
// 3: Left
// 4: Down
// 5: Right
int keyPressed = 0;
while (keyPressed != 27) {
if (keyPressed == 0 || keyPressed == 224) {
keyPressed = _getch(); //First value of _getch() when any of the arrow keys are pressed is "224", the next one is the code depending of which arrow you pressed
}
else if (keyPressed == 13) {
return 1;
}
else {
switch (keyPressed) {
//Up
case 72:
return 2;
break;
//Left
case 75:
return 3;
break;
//Down
case 80:
return 4;
break;
//Right
case 77:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu() {
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY) {
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main() {
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 1;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); // Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
switch (pressedKey) {
//Up
case 2:
Sleep(200);
if (Player.y == Player.speed) {
Player.y = Player.speed; //Top Limit
}
else {
Player.y -= Player.speed;
}
break;
//Left
case 3:
Sleep(200);
if (Player.x == Player.speed) {
Player.x = Player.speed; //Left Limit
}
else {
Player.x -= Player.speed;
}
break;
//Down
case 4:
Sleep(200);
if (Player.y == 30 - Player.speed) {
Player.y = 30 - Player.speed; //Bottom Limit
}
else {
Player.y += Player.speed;
}
break;
//Right
case 5:
Sleep(200);
if (Player.x == 78 - Player.speed) {
Player.x = 78 - Player.speed; //Right Limit
}
else {
Player.x += Player.speed;
}
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x or Player.y modified
};
};
};
return 0;
};
Edit #1: I fixed the mistakes you told me, here's the main function modified. It isn't working though.
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = FALSE; //Changed "TRUE" to "FALSE"
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); //Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
cout << "There's no problem in Else If statement"; //Couts made for testing
switch (pressedKey) {
cout << "There's no problem in Switch statement";
//Up
case 2:
Player.y -= Player.speed;
cout << "You moved Up";
break;
//Left
case 3:
Player.x -= Player.speed; //Fixed Left movement
cout << "You moved Left";
break;
//Down
case 4:
Player.y += Player.speed;
cout << "You moved Down";
break;
//Right
case 5:
Player.x += Player.speed;
cout << "You moved Right";
break;
};
//system("cls"); //Erase all
//draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
Initial Post: I'm trying to do something like an Undertale normal fight and now I'm doing the "dodging attacks" part, but I'm stuck at making the player move (Yep, that "a") because it didn't update when I press an arrow key (for movement). It is supposed to draw, and put the Player in Player.x and Player.y, so I did something in main() to edit these variables depending on the arrow key you pressed, and then erase and re-draw with the Player.x or Player.y modified.
Here's the code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing(){
// 0: Escape
// 1: Enter
// 2: Up
// 3: Left
// 4: Down
// 5: Right
char keyPressed = 0;
while (keyPressed != 27){
if(keyPressed == 0){
keyPressed = _getch();
}
else if(keyPressed == 13){
return 1;
}
else{
switch (keyPressed) {
//Up
case 65:
return 2;
break;
//Left
case 68:
return 3;
break;
//Down
case 66:
return 4;
break;
//Right
case 67:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu(){
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY){
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = TRUE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (detectKeyPressing() == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (detectKeyPressing() > 1 && detectKeyPressing() < 6) {
switch (detectKeyPressing()) {
//Up
case 2:
Player.y -= Player.speed;
break;
//Left
case 3:
Player.x += Player.speed;
break;
//Down
case 4:
Player.y += Player.speed;
break;
//Right
case 5:
Player.x += Player.speed;
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
I did a few tests and it seems that the else if in "//If any of the Arrow Keys is Pressed" part isn't running but I don't know why.
I would really appreciate any help you can provide. Sorry if anything isn't well written, I'm not a native english speaker.
Where you have this comment
//Draw if proyectile is moving - not yet add a variable to save your pressed key, something like
int pressedKey = detectKeyPressing();
Then, use that variable to check which condition is met within your if-else.
What’s happening is that you’re calling your function, thus asking/waiting for an input each time a condition is being checked.
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
http://pastebin.com/bjwFDLgj
player_q_learning.h
http://pastebin.com/zUrnvdsL
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.