So i'm trying to make a game inspired by a youtube tutorial but a bit more complex , i had the snake created in the setup function but i moved it since i couldn't acces it's members from other functions and with it being global i can't acces it at all , how can i fix it ?
in the stuff.h header i have colio.h and iostream
bool gameOver;
std::array<std::array<int, 20>, 20> grid;
snake jerry(15, 9);
class object
{
protected:
int m_x, m_y;
object(int y, int x) :m_x(x), m_y(y) {};
public:
const int getX() { return m_x; };
const int getY() { return m_y; };
};
class snake:public object
{
private:
enum direction
{
STOP,
LEFT,
RIGHT,
UP,
DOWN,
};
direction dir;
public:
snake(int y, int x) :object(y, x) {};
const void moveSnake(char c)
{
if (c == 'a') { dir = LEFT; };
if (c == 'd') { dir = RIGHT; };
if (c == 's') { dir = DOWN; };
if (c == 'w') { dir = UP; }
};
const void changeCoords(int y,int x) { m_x = x, m_y = y; };
};
class fruit :public object
{
private:
public:
fruit(int y, int x) :object(y,x) {};
};
void setup()
{
for (int j = 0; j < 20; ++j)
{
for (int i = 0; i < 20; ++i)
{
if (j == 0 || j == 19 || i == 0 || i == 19) // 0=space , 1=# , 2=snake, 3= fruit , 4= snake tail
{
grid[j][i] = 1;
}
else
{
grid[j][i] = 0;
}
}
}
grid[jerry.getY()][jerry.getX]=2;
fruit fr(rand() % 20, rand() % 20);
grid[fr.getY()][fr.getX()] = 3;
}
void draw()
{
for (int j = 0; j < 20; ++j)
{
for (int i = 0; i < 20; ++i)
{
if (grid[j][i]==1)
{
std::cout << "#";
}
else if (grid[j][i]==0)
{
std::cout << " ";
}
else if (grid[j][i] == 2)
{
std::cout << "O";
}
else if (grid[j][i] == 3)
{
std::cout << "F";
}
}
std::cout << std::endl;
}
system("cls");
}
void input()
{
if (_kbhit())
{
jerry.moveSnake(_getch);
}
}
void logic()
{
}
int main()
{
setup();
while (gameOver==false)
{
draw();
input();
logic();
}
return 0;
}
Related
New to C++. Here is my code:
#include <string>
#include <cstdlib>
#include <time.h>
using namespace std;
const int Gardensize = 20;//Garden size, a 20X20 2d array
const int initialants = 100;//100 initial ants
const int initialdoodlebug = 5;//5 intial bug
const int antType = 1;//
const int doodleType = 2;//
const char antchar = 'O';//ant will display'O'in the window
const char bugchar = 'X';//
class Garden;
class Organism;
class Ant;
class Doodlebug;
class Garden {
friend class Organism;
friend class Ant;
friend class Doodlebug;
public:
Garden();
~Garden();
int checkType(int x, int y);//check the element type (ant or bug)in the grid
void Display();
private:
Organism grid[Gardensize][Gardensize]; //C2079 'Garden::grid' uses undefined class 'Organism' I have already define the class Organism in advance,have no ideal how to fix this error.
};
Garden::Garden() { //initialize the garden, set all elements in grid to "NULL"
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
grid[i][j] = NULL; //error:subscript requires array or pointer
}
}
}
Garden::~Garden() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j] != NULL) {
grid[i][j] = NULL;
}
}
}
}
void Garden::Display() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j].getType == antType) {
cout << antchar;
}
else if (grid[i][j].getType == NULL) {
cout << ".";
}
else if (grid[i][j].getType == doodleType) {
cout << bugchar;
}
}
cout << endl;
}
}
int Garden::checkType(int x, int y) {
return grid[x][y].getType();
}
class Organism {
friend class Garden;
public:
virtual int getType() {}; //
virtual void breed() {};
virtual bool starve() {};
virtual int move( int &breedtoken) {};
protected:
int x = -1; //initial xy place
int y = -1;
Garden garden;
bool moved; //used to define whether org has moved or not
int breedtoken = 0; //used to define whether org need to breed
};
class Ant : public Organism {
public:
Ant() {}; //
Ant(int x, int y, Garden* g)//initial a ant object by define the xy place in the gardene
{
this->x = x;
this->y = y;
garden = *g;
}
~Ant() {};
virtual int getType() {
return antType;
}
virtual int move(int &breedtoken);
virtual void breed() {};
virtual bool starve() { return false; };// ant wont starve
};
int Ant::move(int& breedtoken) {
int dir = rand() % 4;// randomly select direction
switch (dir) {
case 0 :// 0move upwards
if( this->x > 0 && garden.grid[x - 1][y] == NULL ){
garden.grid[x-1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x--;
}
break;
case 1:// 1 move downwards
if (this->x < Gardensize - 1 && garden.grid[x + 1][y] == NULL) {
garden.grid[x + 1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x++;
}
break;
case 2: // 2 move leftwards
if (this->y > 0 && garden.grid[x][y-1] == NULL) {
garden.grid[x][y-1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y--;
}
break;
case 3: // 3 move to right
if (this->y < Gardensize- 1 && garden.grid[x][y + 1] == NULL) {
garden.grid[x][y + 1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y++;
}
break;
this->breedtoken += 1;
return breedtoken;
}
}
class Doodlebug :public Organism {
public:
Doodlebug() {};
Doodlebug(int x, int y, Garden* g)
{
this->x = x;
this->y = y;
garden = *g;
}
virtual int getType() {
return doodleType;
}
};
int main()
{
srand(time(NULL));//
Garden garden;
int antCount = 0; //Ant counter, used to intilize 100 ants
int DoodleCount = 0;
Ant antarray[initialants];
Doodlebug doodlebugarray[initialdoodlebug];
while (antCount < initialants) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
antarray[antCount] = Ant(x, y, &garden); //initilize 100 ants
antCount++;
}
}
while (DoodleCount < initialdoodlebug) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
doodlebugarray[DoodleCount] = Doodlebug(x, y, &garden); //用数组的模式创建100只蚂蚁
DoodleCount++;
}
}
garden.Display();//display
}
The project is not finished yet. Right now, the code can initialize 100ants and 5 bugs. It can run properly but keep showing"subscript requires array or pointer " wherever I write grid[i][j] in the for loop. and " 'Garden::grid' uses undefined class 'Organism'" when I define the "Organism grid[][]" in the Garden class. I wonder to know how can i fix these 2 errors, and what's wrong with my 2d array grid?
The problem with the 2d array is caused, because you try to create an array of Organisms, which are up to that point only declared, not defined, and so the compiler doesn't know their size and can't create an array of them. This can b fixed by reordering your classes, or by putting the class declarations in headers. You can also just replace the array with a dynamic array (double pointer), and initialize it after they have been declared.
The other error is just a consequence of the first, fix it and they will both disapear.
You should try reading some book about c or c++ first, and learn a bit about pointers, and design and structure of c++ programs
Visual studio said I got no issue but, every time I try to run my code I get an assertion failure error, and the error says that vector subscript is out of range, what should I do to fix this, I dont really know what I am doing wrong.
#include <iostream>
#include <ctime>
#include <windows.h>
#include <conio.h>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
class Human
{
private:
int ap;
int hp;
public:
Human()
{
srand(time(NULL));
ap = rand() % 3 + 8;
hp = rand() % 2 + 9;
}
int getAp() { return ap; }
int getHp() { return hp; }
void dmg(int x) { hp -= x; }
};
class Skeleton
{
private:
int ap;
int hp;
public:
Skeleton()
{
srand(time(NULL));
ap = rand() % 3 + 3;
hp = rand() % 2 + 4;
}
int getAp() { return ap; }
int getHp() { return hp; }
void dmg(int x) { hp -= x; }
};
class game
{
private:
std::vector<Human*> hum;
std::vector<Skeleton*> ske;
bool adv;
int sC;
int hC;
public:
game(int h, int s)
{
srand(time(NULL));
adv = rand() % 2;
sC = s;
hC = h;
for (int i = 0; i < h; i++) { hum.push_back( new Human()); }
for (int i = 0; i < h; i++) { ske.push_back(new Skeleton()); }
}
~game()
{
for (int i = 0; i < hum.size(); i++)
{
Human* current = hum.back();
hum.pop_back();
delete current;
}
for (int i = 0; i < ske.size(); i++)
{
Skeleton* current = ske.back();
ske.pop_back();
delete current;
}
}
void start()
{
int x = hC-1;
int y = sC-1;
bool quit = false;
while (!quit)
{
if (adv)
{
ske[y]->dmg(hum[x]->getAp());
if (ske[y]->getHp() <= 0) { y--; ske.pop_back();}
adv = 0;
}
if (!adv)
{
hum[x]->dmg(ske[y]->getAp());
if (hum[x]->getHp() <= 0) { x--; hum.pop_back(); }
adv = 1;
}
if (hum.size() == 0 || ske.size() == 0)
{
cout << "human left : " << hum.size() << "skeleton left : " << ske.size();
quit = true;
}
}
}
};
int main()
{
game g1(10, 5);
g1.start();
return 0;
}
I always get this error box.
this is the error message i got no idea what are they talkin about.
I also get this, what is this?
this
ive fixed it thx to all of ur comments,
this is the completed code, it may look like garbage but it runs
#include <iostream>
#include <ctime>
#include <windows.h>
#include <conio.h>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
class Human
{
private:
int ap;
int hp;
public:
Human()
{
ap = rand() % 3 + 8;
hp = rand() % 2 + 9;
}
int getAp() { return ap; }
int getHp() { return hp; }
void dmg(int x) { hp -= x; }
};
class Skeleton
{
private:
int ap;
int hp;
public:
Skeleton()
{
ap = rand() % 3 + 3;
hp = rand() % 2 + 4;
}
int getAp() { return ap; }
int getHp() { return hp; }
void dmg(int x) { hp -= x; }
};
class game
{
private:
std::vector<Human*> hum;
std::vector<Skeleton*> ske;
bool adv;
int sC;
int hC;
public:
game(int h, int s)
{
srand(time(NULL));
adv = rand() % 2;
sC = s;
hC = h;
for (int i = 0; i < h; i++) { hum.push_back( new Human()); }
for (int i = 0; i < s; i++) { ske.push_back(new Skeleton()); }
}
~game()
{
for (int i = 0; i < hum.size(); i++)
{
Human* current = hum.back();
hum.pop_back();
delete current;
}
for (int i = 0; i < ske.size(); i++)
{
Skeleton* current = ske.back();
ske.pop_back();
delete current;
}
}
void start()
{
int x = hum.size()-1;
int y = ske.size()-1;
bool quit = false;
while (!quit)
{
if (hum.size() == 0 || ske.size() == 0)
{
cout << "human left : " << hum.size() << "skeleton left : " << ske.size();
quit = true;
break;
}
if (adv)
{
ske.at(y)->dmg(hum.at(x)->getAp());
if (ske.at(y)->getHp() <= 0) { y--; ske.pop_back();}
adv = 0;
}
else if (!adv)
{
hum.at(x)->dmg(ske.at(y)->getAp());
if (hum.at(x)->getHp() <= 0) { x--; hum.pop_back(); }
adv = 1;
}
}
}
};
int main()
{
game g1(8, 20);
g1.start();
return 0;
}
Your final code is somewhat complex than it should be, I have simplified it by:
Remove the windows related header files, they are not used
Use member initializer lists
Modify dmg to return the latest hp
Remove the unnecessary index in start, to use back
Remove the vector of pointers, it's Ok to use objects here
Move the srand call into main(Actually we can use std::random here)
Simplify the while loop in start
#include <ctime>
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
class Human {
private:
int ap;
int hp;
public:
Human() : ap(rand() % 3 + 8), hp(rand() % 2 + 9) {}
int getAp() { return ap; }
int getHp() { return hp; }
int dmg(int x) { return hp -= x; }
};
class Skeleton {
private:
int ap;
int hp;
public:
Skeleton() : ap(rand() % 3 + 3), hp(rand() % 2 + 4) {}
int getAp() { return ap; }
int getHp() { return hp; }
int dmg(int x) { return hp -= x; }
};
class game {
private:
bool adv;
int sC;
int hC;
std::vector<Human> hum;
std::vector<Skeleton> ske;
public:
game(int h, int s) : adv(rand() % 2), sC(s), hC(h), hum(h), ske(s) {}
void start() {
while (!hum.empty() && !ske.empty()) {
if (adv) {
if (ske.back().dmg(hum.back().getAp()) <= 0) {
ske.pop_back();
}
} else {
if (hum.back().dmg(ske.back().getAp()) <= 0) {
hum.pop_back();
}
}
adv = !adv;
}
cout << "human left : " << hum.size() << ", skeleton left : " << ske.size();
}
};
int main() {
srand(time(NULL));
game g1(8, 20);
g1.start();
return 0;
}
Online demo
In function start, ske[y] is accessed with a negative index. std::vector does not like negative indexes, this needs to be fixed.
I am creating an minimax player for a game called Specker in c++.
The rules are simple:
There are p players (0 to p - 1) and n heaps (0 to n - 1)
Starting with player 0 each player takes k > 0 coins from a heap x and places m coins (0 <= m < k) on heap y
The winning player is the one which plays last when all coins from all heaps are removed
So I have created the game and some player classes (GreedyPlayer, SpartanPlayer etc.) but they all are a little bit predictable on what they will do. They aren't clever.
so i am creating a player who plays according to minimax (pt18a038)code compiles fine but the program stops responding on execution.
the clever player class:
class pt18a038 : public Player {
private:
string player_type;
public:
pt18a038(const string &n) : Player(n) {
player_type = "Asder aka theRunner";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int sum = 0;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
Move m(source_heap, source_coins, target_heap, target_coins);
sum = minimax(s, 3, 0, m);
cout << "Play:" << source_heap << "," << source_coins << "," << target_heap << ","
<< target_coins << ":" << sum << endl;
}
}
}
}
cout << sum << endl;
// ///////////// for debbuging only until minimax is working...
source_heap = 0;
source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
// /////////////
}
static int minimax(State s, const int &players, int depth, const Move move) {
if (s.winning()) {
cout << "game end!" << endl;
return 1000;
if (depth % players == 0) return 1000; //Maximazing player
else return -1000; //Minimazing player
}
if (depth > 4) {
//cout<<"optimazing"<<endl;
return 0;
}
//cout << s << endl;
s.next(move);
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int max = -100000;
int min = 100000;
int result;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
//cout << "Move:" << source_heap << "," << source_coins << "," << target_heap << ","<< target_coins << endl;
Move m(source_heap, source_coins, target_heap, target_coins);
result = minimax(s, players, depth + 1, m);
if (depth % players == 0) {
max = result ? (result > max) : result;
} else {
min = result ? (result < min) : result;
}
}
}
}
}
return max ? (depth % players == 0) : min;
}
};
Here is my code for the rest of the game(it's tested and works fine)
#include <iostream>
#include <stdexcept>
using namespace std;
class Move {
private:
int source_heap, source_coins, target_heap, target_coins;
public:
Move(int sh, int sc, int th, int tc) {
source_heap = sh;
source_coins = sc;
target_heap = th;
target_coins = tc;
}
int getSource() const {
return source_heap;
}
int getSourceCoins() const {
return source_coins;
}
int getTarget() const {
return target_heap;
}
int getTargetCoins() const {
return target_coins;
}
// Let's do some operator overloading
friend ostream &operator<<(ostream &out, const Move &move) {
if (move.getTargetCoins()) {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts " << move.getTargetCoins()
<< " coins to heap " << move.getTarget();
} else {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts nothing";
}
}
};
class State {
// State with h heaps, where the i-th heap starts with c[i] coins.
private:
int heaps, *heap_coins;
public:
State(int h, const int c[]) {
heaps = h;
heap_coins = new int[heaps];
for (int i = 0; i < heaps; i++)
heap_coins[i] = c[i];
}
~State() {
delete[] heap_coins;
return;
}
int getCoins(int h) const throw(logic_error) {
if (h < 0 || h > heaps) {
throw logic_error(
"Invalid heap number, enter a number between 1 and heaps!");
return 1;
} else {
return heap_coins[h];
}
}
void next(const Move &move) throw(logic_error) {
if ((move.getSource() < 0) || (move.getSource() > heaps) ||
(move.getTarget() < 0) || (move.getTarget() > heaps)) {
throw logic_error("Invalid Heap!");
return;
} else if (
(move.getSourceCoins() < 1) || (move.getTargetCoins() < 0) ||
(move.getSourceCoins() <= move.getTargetCoins()) ||
(move.getSourceCoins() > getCoins(move.getSource()))) {
throw logic_error("Invalid Coin number!");
} else {
heap_coins[move.getSource()] -= move.getSourceCoins();
heap_coins[move.getTarget()] += move.getTargetCoins();
}
}
bool winning() const {
int s = 0;
for (int i = 0; i < heaps; i++)
s += getCoins(i);
return not s; // yeah i know how booleans work :P
}
int getHeaps() const {
return heaps;
}
friend ostream &operator<<(ostream &out, const State &state) {
for (int i = 0; i < state.getHeaps(); i++) {
out << state.heap_coins[i];
if (i != state.getHeaps() - 1)
out << ", ";
}
return out;
}
};
class Player {
public:
Player(const string &n);
virtual ~Player();
virtual const string &getType() const = 0;
virtual Move play(const State &s) = 0;
friend ostream &operator<<(ostream &out, const Player &player);
protected:
string player_name;
};
class GreedyPlayer : public Player {
private:
string player_type;
public:
GreedyPlayer(const string &n) : Player(n) {
player_type = "Greedy";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move GreedyObject(source_heap, source_coins, 0, 0);
return GreedyObject;
}
};
class SpartanPlayer : public Player {
public:
SpartanPlayer(const string &n) : Player(n) {
player_type = "Spartan";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
}
private:
string player_type;
};
class SneakyPlayer : public Player {
public:
SneakyPlayer(const string &n) : Player(n) {
player_type = "Sneaky";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int j = 0;
while (s.getCoins(j) == 0) {
j++;
}
int source_heap = j;
int source_coins = s.getCoins(j);
for (int i = j + 1; i < s.getHeaps(); i++) {
if ((s.getCoins(i) < source_coins) && (s.getCoins(i) > 0)) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SneakyObject(source_heap, source_coins, 0, 0);
return SneakyObject;
}
private:
string player_type;
};
class RighteousPlayer : public Player {
public:
RighteousPlayer(const string &n) : Player(n) {
player_type = "Righteous";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int target_heap = 0;
int source_heap = 0;
int source_coins = s.getCoins(0);
int target_coins = source_coins;
for (int i = 1; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
} else if (s.getCoins(i) < target_coins) {
target_heap = i;
target_coins = s.getCoins(i);
}
}
source_coins -= source_coins / 2;
Move RighteousObject(
source_heap, source_coins, target_heap, source_coins - 1);
return RighteousObject;
}
private:
string player_type;
};
Player::Player(const string &n) {
player_name = n;
}
Player::~Player() {
player_name.clear();
}
ostream &operator<<(ostream &out, const Player &player) {
out << player.getType() << " player " << player.player_name;
return out;
}
class Game {
private:
int game_heaps, game_players, current_heap, current_player;
int *heap_coins;
Player **players_list;
public:
Game(int heaps, int players) {
heap_coins= new int [heaps];
game_heaps = heaps;
game_players = players;
current_heap = 0;
current_player = 0;
players_list = new Player*[players];
}
~Game() {
delete[] heap_coins;
delete[] players_list;
}
void addHeap(int coins) throw(logic_error) {
if (current_heap > game_heaps)
throw logic_error("All heaps are full with coins!");
else if (coins < 0)
throw logic_error("Coins must be a positive number!");
else {
heap_coins[current_heap++] = coins;
}
}
void addPlayer(Player *player) throw(logic_error) {
if (current_player > game_players)
throw logic_error("All players are added!");
else {
players_list[current_player++] = player;
}
}
void play(ostream &out) throw(logic_error) {
if ((current_player != game_players) && (current_heap != game_heaps)) {
throw logic_error("Have you added all heaps and players?");
} else {
int i = 0;
State currentState(game_heaps, heap_coins);
while (!currentState.winning()) {
out << "State: " << currentState << endl;
out << *players_list[i % game_players] << " "
<< players_list[i % game_players]->play(currentState) << endl;
currentState.next(
players_list[i % game_players]->play(currentState));
i++;
}
out << "State: " << currentState << endl;
i--;
out << *players_list[i % game_players] << " wins" << endl;
}
}
};
int main() {
Game specker(6, 5);
specker.addHeap(10);
specker.addHeap(20);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addPlayer(new GreedyPlayer("Alan"));
specker.addPlayer(new SneakyPlayer("Tom"));
specker.addPlayer(new SpartanPlayer("Mary"));
specker.addPlayer(new RighteousPlayer("Robin"));
specker.addPlayer(new pt18a038("Stavros"));
specker.play(cout);
}
Updated
I see a couple of issues in your minimax program, some are serious in nature :
1) Use Alpha Beta pruning to reduce the size of the search tree.
2) There is no proper boundary condition (if depth >5 return score or something) in the minimax recursive call ( see my code snippet for details), the CPU may hang while calling.
3)Your leaf node evaluation is weak, so the evaluated moves , in spite of using minimax algorithm, is not likely to be intelligent ones.
4)To increase the search speed, you may use multi-threading only at the top level branch.
5) If a leaf node gives a winning move while maximizing, you may skip further evaluation by returning a high score.
6) Once your code is functional, refer it at code-review with 'ai' tag , rather than at SO, for more detailed analysis.
int EvaluateLeafNode(State s, const int &players)
{
//TODO analyze here
return score;
}
int minimax(State s, const int &players, int depth , const Move move, int alpha, int beta)
{
if( depth >= 5) return EvaluateLeafNode(s,players); // this was missing in your code
//don't analyze here
//rest of minimax recursive code
}
I know there has been tons of questions like that, but unfortunately after hours of googling and browsing through all of them, none of the answers I read helped. Therefore I am making my own version of my question. The error message I get is: "error: invalid use of incomplete type ‘std::iterator_traits::value_type {aka class Cell}’" My code:
cell.h
#ifndef CELL_H
#define CELL_H
#include <QPushButton>
#include <QMouseEvent>
#include <vector>
class Padding;
class Cell : public QPushButton
{
Q_OBJECT
public:
friend class Padding;
Cell(int x, int y, Padding* padding, QWidget* parent = 0) : QPushButton(parent), x(x), y(y),
padding(padding)
{
setFixedSize(20, 20);
}
Cell(const Cell& object) : QPushButton(), x(object.x), y(object.y), padding(object.padding)
{
setFixedSize(20, 20);
}
int getX() { return x; };
int getY() { return y; };
bool hasMine() { return mine; };
void setHasMine(bool mine) { this -> mine = mine; };
bool isFlagged() { return flagged; };
bool didExplode() { return exploded; };
bool getHasBeenClicked() { return hasBeenClicked; };
void clicked();
~Cell() {};
Cell operator=(const Cell& object)
{
if(&object == this)
{
return *this;
}
padding = object.padding;
x = object.x;
y = object.y;
mine = object.mine;
flagged = object.flagged;
exploded = object.exploded;
hasBeenClicked = object.hasBeenClicked;
setFixedSize(20, 20);
return *this;
}
private:
Padding* padding;
int x;
int y;
bool mine = false;
bool flagged = false;
bool exploded = false;
bool hasBeenClicked = false;
void mousePressEvent(QMouseEvent* e);
void rightClicked();
};
#endif // CELL_H
cell.cpp
#include "cell.h"
#include "padding.h"
void Cell::mousePressEvent(QMouseEvent* event)
{
if(event -> button() == Qt::LeftButton)
{
clicked();
}
else if(event -> button() == Qt::RightButton)
{
rightClicked();
}
}
void Cell::clicked()
{
hasBeenClicked = true;
// TODO: Set the button frame to flat. DONE.
setFlat(true);
// TODO: Make the button not click able. DONE.
setEnabled(false);
// TODO: Display appropriate number on the button, or mine and end the game. DONE.
if(mine)
{
// TODO: Send game over signal and end the game.
//setIcon(QIcon("mine_clicked.png"));
setText("/");
exploded = true;
padding -> gameOver();
}
else
{
setText(QString::number(padding -> countMinesAround(this)));
}
if(padding -> countMinesAround(this) == 0)
{
// Trigger chain reaction; uncover many neighboring cells, if they are not mines.
padding -> triggerChainReactionAround(this);
}
}
void Cell::rightClicked()
{
if(text() != "f")
{
setText("f");
(padding -> minesLeft)--;
}
else
{
setText("");
(padding -> minesLeft)++;
}
flagged = !flagged;
}
padding.h
#ifndef PADDING_H
#define PADDING_H
#include <QWidget>
#include <QGridLayout>
#include <vector>
class Cell;
class Padding : public QWidget
{
Q_OBJECT
public:
friend class Cell;
enum class Difficulty
{
Beginner,
Intermediate,
Advanced,
Custom
};
Padding(QWidget* parent = 0);
void newGame();
void gameOver();
void setLevel(Padding::Difficulty difficulty) { this -> difficulty = difficulty; };
void setPaddingHeight(int height) { paddingHeight = height; };
void setPaddingWidth(int width) { paddingWidth = width; };
void setMines(int mines) { this -> mines = mines; };
int getMinesLeft() { return minesLeft; };
~Padding() {};
private:
struct DifficultyLevelsProperties
{
struct BeginnerProperties
{
const int PADDING_HEIGHT = 9;
const int PADDING_WIDTH = 9;
const int MINES = 10;
} Beginner;
struct IntermediateProperties
{
const int PADDING_HEIGHT = 16;
const int PADDING_WIDTH = 16;
const int MINES = 40;
} Intermediate;
struct AdvancedProperties
{
const int PADDING_HEIGHT = 16;
const int PADDING_WIDTH = 40;
const int MINES = 99;
} Advanced;
} LevelProperties;
Difficulty difficulty = Difficulty::Beginner;
int paddingHeight;
int paddingWidth;
int mines;
// Mines that are not flagged.
int minesLeft;
// Time in seconds since the game was started.
int secondsSinceStart;
std::vector<Cell> cells;
QGridLayout* paddingLayout;
const int CELLS_HEIGHT = 20;
const int CELLS_WIDTH = 20;
int countMinesAround(Cell*);
void triggerChainReactionAround(Cell*);
void updateSecondsSinceStart();
};
#endif // PADDING_H
padding.cpp
#include "padding.h"
#include <QGridLayout>
#include <QTimer>
#include <QTime>
#include <QDebug>
#include "cell.h"
Padding::Padding(QWidget* parent) : QWidget(parent)
{
newGame();
paddingLayout = new QGridLayout(this);
paddingLayout -> setSpacing(0);
}
void Padding::newGame()
{
if(difficulty == Padding::Difficulty::Beginner)
{
paddingHeight = LevelProperties.Beginner.PADDING_HEIGHT;
paddingWidth = LevelProperties.Beginner.PADDING_WIDTH;
mines = LevelProperties.Beginner.MINES;
}
else if(difficulty == Padding::Difficulty::Intermediate)
{
paddingHeight = LevelProperties.Intermediate.PADDING_HEIGHT;
paddingWidth = LevelProperties.Intermediate.PADDING_WIDTH;
mines = LevelProperties.Intermediate.MINES;
}
else if(difficulty == Padding::Difficulty::Advanced)
{
paddingHeight = LevelProperties.Advanced.PADDING_HEIGHT;
paddingWidth = LevelProperties.Advanced.PADDING_WIDTH;
mines = LevelProperties.Advanced.MINES;
}
minesLeft = mines;
cells.clear();
for(int i = 0; i < paddingHeight; i++)
{
for(int j = 0; j < paddingWidth; j++)
{
// TODO: Use smart pointers instead of raw pointers.
Cell* cell = new Cell(j + 1, i + 1, this);
cells.push_back(*cell);
delete cell;
}
}
qsrand(QTime::currentTime().msec());
for(int i = 0; i < mines; i++)
{
// TODO: Fix the randomness of the numbers. DONE.
cells[qrand() % (paddingHeight * paddingWidth) + 1].setHasMine(true);
}
for(int i = 0; i < cells.size(); i++)
{
paddingLayout -> addWidget(&cells[i], cells[i].getY(), cells[i].getX());
}
}
void Padding::gameOver()
{
for(int i = 0; i < cells.size(); i++)
{
cells[i].setEnabled(false);
if((cells[i].hasMine()) && (!cells[i].getHasBeenClicked()))
{
cells[i].clicked();
}
}
}
int Padding::countMinesAround(Cell*)
{
int minesCounter = 0;
for(int i = 0; i < cells.size(); i++)
{
qDebug() << QString::number(cells[i].getX());
if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
(cells[i].hasMine()))
{
minesCounter++;
}
}
return minesCounter;
}
void Padding::triggerChainReactionAround(Cell*)
{
for(int i = 0; i < cells.size(); i++)
{
if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
(!cells[i].getHasBeenClicked()))
{
cells[i].clicked();
}
}
}
Sorry for how long the whole thing, but I could not shorten it as I can't locate what causes the error. Also please ignore any TODO's or any lines that are commented out and I forgot to delete them. Please help!
When you forward declare a type, you can only use pointers or references to that type objects, so this line in padding.h is pretty much not compiling:
std::vector<Cell> cells;
I suppose the compiler complaint comes from where it is trying to decide how to build/destroy a Cell object in a vector. To do that, it needs information about the type, generally from the type declaration (i.e. the header file).
I attended a class of C++, not like all my students, I bought a Mac using xcode to run and edit my files. But recently there is a piece of code, that can be well ran in Ubuntu system, but in my mac, it kept giving me error.
the error appears in this line: char (*maze)[width] = reinterpret_cast (m_maze);
and there are 3 lines with the same above content. if you use the code in Ubuntu, it runs successfully, but in mac, it terminates and report 3 same errors.
the warn said: can not initialize a type of type 'char()[width]' with an rvalue of 'char()[width] '
Plz help
the code is about a mouse in a MAZE.
here are the codes:
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <cstdio>
using namespace std;
const char MOUSE = '*';
const char WAY = ' ';
const char WALL = '#';
const char PASS = '.';
const char IMPASS = 'X';
typedef enum tag_Direction {
EDIR_RIGHT,
EDIR_DOWN,
EDIR_LEFT,
EDIR_UP
} EDIR;
class Stack {
public:
Stack (void) : m_top (NULL) {}
~Stack (void) {
for (Node* next; m_top; m_top = next) {
next = m_top -> m_next;
delete m_top;
}
}
void push (EDIR dir) {
m_top = new Node (dir, m_top);
}
EDIR pop (void) {
if (! m_top)
throw underflow_error ("Underflow of Stack!");
EDIR dir = m_top -> m_dir;
Node* next = m_top -> m_next;
delete m_top;
m_top = next;
return dir;
}
private:
class Node {
public:
Node (EDIR dir, Node* next) : m_dir (dir),
m_next (next) {}
EDIR m_dir;
Node* m_next;
};
Node* m_top;
};
class Mouse {
public:
Mouse (size_t x, size_t y) : m_x (x), m_y (y),
m_total (0), m_valid (0) {}
size_t getx (void) const {
return m_x;
}
size_t gety (void) const {
return m_y;
}
size_t gettotal (void) const {
return m_total;
}
size_t getvalid (void) const {
return m_valid;
}
void stepright (void) {
m_x++;
remember (EDIR_RIGHT);
}
void stepdown (void) {
m_y++;
remember (EDIR_DOWN);
}
void stepleft (void) {
m_x--;
remember (EDIR_LEFT);
}
void stepup (void) {
m_y--;
remember (EDIR_UP);
}
void stepback (void) {
switch (recall ()) {
case EDIR_RIGHT:
m_x--;
break;
case EDIR_DOWN:
m_y--;
break;
case EDIR_LEFT:
m_x++;
break;
case EDIR_UP:
m_y++;
break;
}
}
private:
void remember (EDIR dir) {
m_brain.push (dir);
m_total++;
m_valid++;
}
EDIR recall (void) {
EDIR dir = m_brain.pop ();
m_total++;
m_valid--;
return dir;
}
size_t m_x;
size_t m_y;
size_t m_total;
size_t m_valid;
Stack m_brain;
};
class Game {
public:
Game (size_t width, size_t height) :
m_width (width), m_height (height),
m_maze (new char[width * height]),
m_mouse (0, 1) {
if (height < 3)
throw invalid_argument ("The maze is too small!");
srand (time (NULL));
char (*maze)[width] = reinterpret_cast<char (*)[width]> (m_maze);**
for (size_t i = 0; i < height; i++)
for (size_t j = 0; j < width; j++)
if (i == m_mouse.gety () &&
j == m_mouse.getx ())
maze[i][j] = MOUSE;
else
if ((i == 1 && j < 4) ||
(i == height - 2 && j >width-5))
maze[i][j] = WAY;
else
if (i == 0 || i == height - 1 ||
j == 0 || j == width - 1)
maze[i][j] = WALL;
else
maze[i][j] =
rand () % 4 ? WAY : WALL;
}
~Game (void) {
if (m_maze) {
delete[] m_maze;
m_maze = NULL;
}
}
void run (void) {
for (show (); ! quit () && step (););
}
private:
void show (void) {
char (*maze)[m_width] = reinterpret_cast<char (*)[m_width]> (m_maze);
for (size_t i = 0; i < m_height; i++) {
for (size_t j = 0; j < m_width; j++)
cout << maze[i][j];
cout << endl;
}
cout << "Total steps:" << m_mouse.gettotal ()
<< ",Valid steps:" << m_mouse.getvalid ()
<< endl;
}
bool quit (void) {
cout << "Press<Q>to exit,Other keys to continue..."<<flush;
int ch = getchar ();
cout << endl;
return ch == 'Q' || ch == 'q';
}
bool step (void) {
char (*maze)[m_width] = reinterpret_cast<char (*)[m_width]> (m_maze);
size_t x = m_mouse.getx ();
size_t y = m_mouse.gety ();
if (x + 1 <= m_width - 1 && maze[y][x + 1] == WAY) {
maze[y][x] = PASS;
m_mouse.stepright ();
}
else
if (y + 1 <= m_height - 1 &&
maze[y + 1][x] == WAY) {
maze[y][x] = PASS;
m_mouse.stepdown ();
}
else
if (x - 1 >= 0 &&
maze[y][x - 1] == WAY) {
maze[y][x] = PASS;
m_mouse.stepleft ();
}
else
if (y - 1 >= 0 &&
maze[y - 1][x] == WAY) {
maze[y][x] = PASS;
m_mouse.stepup ();
}
else {
maze[y][x] = IMPASS;
m_mouse.stepback ();
}
x = m_mouse.getx ();
y = m_mouse.gety ();
maze[y][x] = MOUSE;
show ();
if (x == 0 && y == 1) {
cout << "I can't get out!cry~~~~" << endl;
return false;
}
if (x == m_width - 1 && y == m_height - 2) {
cout << "I am OUT!!!" << endl;
return false;
}
return true;
}
size_t m_width;
size_t m_height;
char* m_maze;
Mouse m_mouse;
};
int main (int argc, char* argv[]) {
if (argc < 3) {
cerr << "Method:" << argv[0] << " <width> <height>"
<< endl;
return -1;
}
try {
Game game (atoi (argv[1]), atoi (argv[2]));
game.run ();
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}
char (*maze)[width] = reinterpret_cast<char (*)[width]> (m_maze);
is not standard: warning: ISO C++ forbids variable length array 'maze' [-Wvla].
You have to use
m_maze[y * width + x]
instead of
maze[y][x]