Console RPG in DEV C++ / Map - c++

Im trying to make a Dev C++ RPG game. Im stuck at the map, its a twodimesnional array with the dimensions measured with how many chars can fit before "breaking" a line. The map prints out just fine, but i want to make the player move with the arrow keys.
Heres what ive got so far (doesnt work):
#include <iostream>
#include <string>
#include <conio.h>
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
void MapPrint(int StartX, int StartY){
int Map[12][80]={0};
Map[StartX][StartY]=1;
for (int x=0; x<12; x++)
{
for (int y=0; y<80; y++)
{
if(Map[x][y]==0){
std::cout<<"=";
}
if (y==80){
std::cout<<"\n";
continue;
}
if (Map[x][y]==1){
std::cout<<"#";
continue;
}
}
}
}
int main(){
int Map[12][80]={0};
int StartX,StartY;
Map[StartX][StartY]=1;
int c = 0;
StartX=6;
StartY=40;
MapPrint(StartX,StartY);
while(1)
{
c=0;
switch((c=getch())) {
case KEY_UP:
system("CLS");
Map[StartX][StartY]=0;
Map[StartX][StartY+1]=1;
std::cout<<StartY; //remains of a fix attempt
MapPrint(StartX,StartY);
case KEY_DOWN:
system("CLS");
Map[StartX][StartY]=0;
Map[StartX][StartY-1]=1;
MapPrint(StartX,StartY);
case KEY_LEFT:
system("CLS");
Map[StartX][StartY]=0;
Map[StartX-1][StartY]=1;
MapPrint(StartX,StartY);
case KEY_RIGHT:
system("CLS");
Map[StartX][StartY]=0;
Map[StartX+1][StartY]=1;
MapPrint(StartX,StartY);
}
}
return 0;
}`

I've modify your code and I made it better. If you have anything to ask, leave a comment below.
#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#define XSIZE 80
#define YSIZE 20
using namespace std;
int c_x=XSIZE/2,c_y=YSIZE/2; //the player will be in the middle of the map
int direction=1;//direction of the player
bool gameOver=false;
int tim=2000,tt;//that's how we set "speed"
void MapPrint(int newX, int newY)
{
//if the new position of the player if out of the map
//the game if over
if(c_x<0 || c_x>XSIZE || c_y<0 ||c_y>YSIZE)
{
system("CLS");
cout<<"GAME OVER!";
gameOver=true;
return;
}
//printing the map, without using an twodimesnional array
for (int y=0; y<YSIZE; y++)
{
for (int x=0; x<XSIZE; x++)
{
if(newX==x && newY==y)cout<<'#';
else cout<<' ';
}
cout<<'\n';
}
}
int main()
{
char c;
MapPrint(c_x,c_y);
while(!gameOver)
{
//_kbhit() tell us if any key is pressed
if(_kbhit())
{
c=_getch();
//setting the direction according to key pressed
if(c=='w')direction=1;
else if(c=='d')direction=2;
else if(c=='s')direction=3;
else if(c=='a')direction=4;
}
tt++;
if(tt>=tim)
{
if(direction==1)
{
system("CLS");
c_y--; // we go up, so y position of the player decrements
MapPrint(c_x,c_y);
}
else if(direction==3)
{
system("CLS");
c_y++; // we go down, so y position of the player increments
MapPrint(c_x,c_y);
}
else if(direction==4)
{
system("CLS");
c_x--; // we go to the left, so x position of the player decrements
MapPrint(c_x,c_y);
}
else if(direction==2)
{
system("CLS");
c_x++; // we go to the right, so x position of the player increments
MapPrint(c_x,c_y);
}
tt=0;
}
}
return 0;
}

Related

Segmentation fault, while running a Monte-Carlo-random-walk simulation in c++

I am trying to simulate a random walk of 2000 particles, while the one boundary has the ability to make particles bound on that and merely perform a biased step.
There are of course probabilities for binding unbinding etc...
Below I have the whole code.
However I get segfault error.
I put some print statements in the code to see where the issue lies. But nothing. What I found strange though, is that although seed is fixed, the length of the output statement determined the loop, where code crushed.
I am totally inexperienced in these issues, so if you have any idea on what I could do, would be appreciated.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
using namespace std;
const int pi=6;
const int epsilon=10;
const int X=3000;
const int Y=30; //length
const int time_steps=100000;
const int N=2000; // number of molecules
int kinesins[N][3]={0};//[X,Y,bound or not]
int grid[X][Y][2]={0};
void place_kinesins(){
for (int i=0; i<N;i++){
int x= rand()%X;
int y= (rand()%(Y-2))+2;
if (grid[x][y][0]==0){
kinesins[i][0]=x;
kinesins[i][1]=y;
kinesins[i][2]=0;
grid[x][y][0]=1;
}else{i--;}
}
}
void create_boundaries(){
for(int i=0;i<Y;i++){
grid[0][i][1]=-1;
grid[X-1][i][1]=-3;
}
for (int i=0; i<X; i++){
grid[i][Y-1][1]=-2;
}
}
void create_filament(){ //in order to create binding affinity.
for(int i=0; i<X;i++){
grid[i][1][1]=pi;
}
}
void step(int kinesin, int x_step, int y_step){
int x=kinesins[kinesin][0];
int y=kinesins[kinesin][1];
int x_end=x+x_step;
int y_end=y+y_step;
if (grid[x_end][y_end][0]==0){
grid[x][y][0]=0;
kinesins[kinesin][0]=x_end;
kinesins[kinesin][1]=y_end;
grid[x_end][y_end][0]=1;
}
}
void bound(int kinesin){
int roll=rand()%10000 ;
if (roll<epsilon){
kinesins[kinesin][2]=0;
step(kinesin,0,1);
}else{
if (roll%63==0){ //controls the binding rate speed
step(kinesin, 1,0);
};
}
}
void unbound(int kinesin){
cout<<"1";
int x= kinesins[kinesin][0];
int y= kinesins[kinesin][1];
int type= grid[x][y][1];
switch(type){
case 0:{
cout<<"2";
int roll=rand()%4;
switch(roll){
case 0:
step(kinesin,-1,0);
break;
case 1:
step(kinesin,1,0);
break;
case 2:
step(kinesin,0,1);
break;
case 3:
step(kinesin,0,-1);
break;
}
break;
}
case -1:
step(kinesin,1,0);
break;
case -2:
step(kinesin,0,-1);
break;
case -3:
step(kinesin,-1,0);
break;
default:
int roll=rand()%10000;
if(roll<grid[x][y][1]){kinesins[kinesin][2]=1;}
else{ if(roll%2==0){step(kinesin,0,1);}}
}
}
void kinesin_move(int kinesin){
cout<<" "<<kinesins[kinesin][0]<<kinesins[kinesin][1];
if (kinesins[kinesin][2]==0){
unbound(kinesin);
}else{
cout<<"3";
bound(kinesin);
}
}
void simulation(){
for(int j=7000; j<time_steps;j++){
cout<<endl<< j<<" "<<endl;
for (int kin=0; kin<N; kin++){
cout<<kin;
kinesin_move(kin);
cout<<"E " ;
}
}
}
void programm(){
srand(1);
create_boundaries();
create_filament();
cout<<"Filament done"<<endl;
place_kinesins();
cout<<"Kines placed"<<endl;
simulation();
}
int main(){
programm();
return 0;
}
Problem:
In the function step you're accessing the array grid out of its bonds, which produces Undefined Behaviour and the segmentation fault.
This can be proven adding an assert before if (grid[x_end][y_end][0]==0):
if(!(x_end < X && x_end >= 0))
std::cerr << x_end << std::endl;
assert(x_end < X && x_end >= 0);
if (grid[x_end][y_end][0]==0){
grid[x][y][0]=0;
kinesins[kinesin][0]=x_end;
kinesins[kinesin][1]=y_end;
grid[x_end][y_end][0]=1;
}
Output:
3000
Assertion failed: x_end < X && x_end >= 0 main.cpp line 57
This application has requested the Runtime to terminate it in an unusual way.
Solution:
You will have to check the arguments for step won't make it go out of bonds before each call.
Additional information:
using namespace std; is considered a bad practice (More info here).
rand is not uniformly distributed. You may want use the <random> library instead (More info here).
Global variables are bad (More info here).
You may want to use std::array instead of raw, C-style arrays.

How to allow user to choose when to stop each of three columns from rotating

I'm writing a simple fruit machine slot in console. I have managed to create 3 separate arrays to simulate 'wheels' of the machine. Each array contains of 6 random generated characters which then 'move' upwards by swapping characters in the array. I would like to ask you for some sort of hint, how would you solve this problem. Thanks in advance.
I think the problem might be in the way I've done the 'wheels'. When I have while loop; wheels are spinning but I cannot figure out how to stop each wheel. Iv'e tried to use if statements with "GetAsyncKeyState(VK_SPACE))" inside the while loop, but once space was released it kept spinning again and this was solving only part of my problem because I have three wheels.
#include <iostream>
#include <windows.h>
#include <cstdlib> // system cls
#include <time.h>
#include <conio.h>
using namespace std;
void SetCursorPosition(int x, int y);
char printRandomChar(int n);
void wheel0();
void assignWheel0Char();
int const arraySize = 6;
int coursor_x = 1;
int coursor_y = 1;
char wheelArray[arraySize];
int main()
{
srand(time(NULL));
assignWheel0Char();
bool playing_game = true;
while (playing_game)
{
wheel0();
Sleep(500);
}
std::cin.get();
}
void SetCursorPosition(int x, int y)
{
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
COORD position = { x,y };
SetConsoleCursorPosition(output, position);
}
void wheel0()
{
for (int i = 0; i < 3; i++)
{
SetCursorPosition(coursor_x, coursor_y);
cout << wheelArray[i];
coursor_y++;
}
char temp;
temp = wheelArray[0];
wheelArray[0] = wheelArray[1];
wheelArray[1] = wheelArray[2];
wheelArray[2] = wheelArray[3];
wheelArray[3] = wheelArray[4];
wheelArray[4] = temp;
coursor_y = 1;
}
void assignWheel0Char()
{
for (int i = 0; i < arraySize; i++)
{
wheelArray[i] = printRandomChar(1);
}
}
char printRandomChar(int n)
{
char alphabet[6] = { 'J', 'Q', 'K', 'W', 'L', 'D' };
char res{};
for (int i = 0; i < n; i++)
res = res + alphabet[rand() % 6];
return res;
}
I want to allow user to stop each wheel by using space bar so it looks like this:
1.Game starts wheels are spinning, user presses space bar, wheel1 stops ,
but other two wheels keeps spinning.
2. Another space bar press, now wheel1 is stoped and wheel2 stops while
wheel 3 keeps spinning.
3. Last space bar press stops wheel3.
4. Score is displayed if symbols match
5. User is asked if he wants to play again
I want to allow user to stop each wheel by using space bar so it looks
like this:
1.Game starts wheels are spinning, user presses space bar, wheel1 stops , but other two wheels keeps spinning. 2. Another space bar
press, now wheel1 is stoped and wheel2 stops while wheel 3 keeps
spinning. 3. Last space bar press stops wheel3. 4. Score is displayed
if symbols match 5. User is asked if he wants to play again
The following is an example implementation you can refer to:
#include <iostream>
#include <windows.h>
#include <cstdlib> // system cls
#include <time.h>
#include <conio.h>
using namespace std;
#define MAX_COLUMN_POSITION 3
#define SCORE_COLUMN_POSITION (MAX_COLUMN_POSITION + 1)
#define FINAL_COLUMN_POSITION (SCORE_COLUMN_POSITION + 1)
void SetCursorPosition(SHORT y, SHORT x = 1);
char printRandomChar(int n);
void wheel0();
void assignWheel0Char();
int const arraySize = 6;
char wheelArray[arraySize];
int spaceCnt = 0;
bool playing_game = true;
DWORD WINAPI GetUserInput(LPVOID lpThreadParameter)
{
while (playing_game)
{
char c = _getch();
switch (c)
{
case ' ':
{
spaceCnt++;
if (spaceCnt >= MAX_COLUMN_POSITION)
{
SetCursorPosition(SCORE_COLUMN_POSITION);
cout << "\n Score: ";
}
}
break;
case 'y':
case 'Y':
{
spaceCnt = 0;
}
break;
case 'n':
case 'N':
{
playing_game = FALSE;
}
break;
default:
break;
}
}
return 0;
}
int main()
{
srand(time(NULL));
assignWheel0Char();
CreateThread(NULL, 0, GetUserInput, NULL, 0, NULL);
cout << "Enter SPACE key to stop one wheel. Enter Y(Yes) to play again, enter N (No) to exit. \n";
while (playing_game)
{
wheel0();
Sleep(500);
}
SetCursorPosition(FINAL_COLUMN_POSITION);
cout << "\n Exiting...";
std::cin.get();
}
void SetCursorPosition(SHORT y, SHORT x)
{
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
COORD position = { x,y };
SetConsoleCursorPosition(output, position);
}
void wheel0()
{
for (SHORT i = 0, coursor_y = 1; i < MAX_COLUMN_POSITION; i++, coursor_y++)
{
if (spaceCnt > 0 && spaceCnt >= coursor_y)
continue;
SetCursorPosition(coursor_y);
cout << wheelArray[i];
}
char temp;
temp = wheelArray[0];
wheelArray[0] = wheelArray[1];
wheelArray[1] = wheelArray[2];
wheelArray[2] = wheelArray[3];
wheelArray[3] = wheelArray[4];
wheelArray[4] = temp;
}
void assignWheel0Char()
{
for (int i = 0; i < arraySize; i++)
{
wheelArray[i] = printRandomChar(1);
}
}
char printRandomChar(int n)
{
char alphabet[6] = { 'J', 'Q', 'K', 'W', 'L', 'D' };
char res{};
for (int i = 0; i < n; i++)
res = res + alphabet[rand() % 6];
return res;
}

Trying to make a primitive console snake game. 0 warnings/erros. Why does my program crash? (C++)

Thank you for reading this thread. I am a beginning programmer and am trying to make a simple snake game with C++. It isn't finished yet, but I think I got a nice start to it. However, when I try to run the program it instantly crashes. (The compiler says there are 0 warnings and errors. I am using the Code::Blocks IDE. Does anyone know why my program isn't working? I think it may have something to do with the "vector coordHistory", but I can't tell for sure. At least that is the last thing I added to the program.
This is my code:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <windows.h>
#include <conio.h>
#include <vector>
#define MAXX 156 //Number of columns that fits on my screen
#define MAXY 62 //Number of rows that fits on my screen
using namespace std;
// This function clears the console window
void clearConsole()
{
system("cls"); //empties console window
};
// This function returns the x position of the cursor
int getcursorX()
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
return csbi.dwCursorPosition.X;
}
};
// This function returns the y position of the cursor
int getcursorY()
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
return csbi.dwCursorPosition.Y;
}
};
// This function sets the x position of the cursor
void setcursorX(int x)
{
COORD coord = {x, getcursorY()};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
// This function sets the y position of the cursor
void setcursorY(int y)
{
COORD coord = {getcursorX(), y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
// The snake class contains the coordinates of the snake and direction in which it is moving
class Snake
{
private:
bool isAlive;
int snakexCoord;
int snakeyCoord;
char snakeDirection;
int snakeLength;
public:
//getters
int getsnakexCoord() { return snakexCoord; };
int getsnakeyCoord() { return snakeyCoord; };
char getsnakeDirection() { return snakeDirection; };
bool getisAlive() { return isAlive; };
int getsnakeLength() { return snakeLength; };
//setters
void setsnakexCoord(int newsnakexCoord) { snakexCoord = newsnakexCoord;};
void setsnakeyCoord(int newsnakeyCoord) { snakeyCoord = newsnakeyCoord;};
void setsnakeDirection(char newsnakeDirection) { snakeDirection = newsnakeDirection;};
void setisAlive(bool newisAlive) { isAlive = newisAlive; };
void setsnakeLength(int newsnakeLength) { snakeLength = newsnakeLength; };
//constructor
Snake()
{
snakexCoord = MAXX / 2;
snakeyCoord = MAXY / 2;
snakeDirection = 'E';
isAlive = true;
snakeLength = 1;
};
//destructor
~Snake(){};
};
int main()
{
int i; //iterator
system("mode 650"); //makes console window full-screen
Snake snake; //initializes Snake object snake
char c; //char that stores user input to change snake direction
vector<int[2]> coordHistory; //vector of arrays that stores previous locations of snake
while (snake.getisAlive())
{
//Adds snake coordinates to coordHistory
coordHistory[coordHistory.size()][0] = snake.getsnakexCoord();
coordHistory[coordHistory.size()-1][1] = snake.getsnakeyCoord();
//Iterates backwards through coordHistory and draws an "O" until the snake is as long as it should be
for(i = coordHistory.size() - 1; i > coordHistory.size() - 1 - snake.getsnakeLength(); i--)
{
setcursorX(coordHistory[i][0]);
setcursorY(coordHistory[i][1]);
cout << "O";
}
//Allows user to change snake direction
c = _getch();
switch (c){
case 'w':
snake.setsnakeDirection('N');
break;
case 'd':
snake.setsnakeDirection('E');
break;
case 's':
snake.setsnakeDirection('S');
break;
case 'a':
snake.setsnakeDirection('W');
break;
}
//Checks in which direction snake is going and changes coordinates accordingly
switch (snake.getsnakeDirection())
{
case 'N':
snake.setsnakeyCoord(snake.getsnakeyCoord()-1);
break;
case 'E':
snake.setsnakexCoord(snake.getsnakexCoord()+1);
break;
case 'S':
snake.setsnakeyCoord(snake.getsnakeyCoord()+1);
break;
case 'W':
snake.setsnakexCoord(snake.getsnakexCoord()-1);
break;
}
//Checks if snake goes out of boundaries
if ((snake.getsnakexCoord() > MAXX) || (snake.getsnakexCoord() < 0) || (snake.getsnakeyCoord() > MAXY) || (snake.getsnakeyCoord() < 0))
{
snake.setisAlive(false);
}
//Sleep(200); Ignore WIP
clearConsole();
}
return 0;
}
Your vector usage is wrong.
coordHistory[coordHistory.size()][0] = snake.getsnakexCoord();
coordHistory[coordHistory.size()-1][1] = snake.getsnakeyCoord();
You appear to assume that vector[n-1] will automatically create as many elements as needed to result in a vector of size n. It doesn't.
You are twice accessing the first element of vector coordHistory, a vector which is actually empty.
To add elements, in general use the member function push_back or emplace_back. You're really going to struggle with a vector of arrays, though, since arrays are neither assignable nor copyable. That's why I can't use push_back here; I have to explicitly resize the vector then access the newly-created elements as you were doing before:
coordHistory.resize(1);
coordHistory[0][0] = snake.getsnakexCoord();
coordHistory[0][1] = snake.getsnakeyCoord();
This is pretty awkward. why don't you instead store a nice delicious class type with x and y members?
std::vector<deliciousClassType> coordHistory;
coordHistory.emplace_back(
snake.getsnakexCoord(),
snake.getsnakeyCoord()
);

(C++) Does not stop on std::cin and goes into infinity loop?

I have a wird problem. Im using Visual Studio 2012, thats my code: (something is in polish but i hope you will understand how it works).
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
using namespace std;
#pragma warning (disable: 4996);
struct strona
{
int zawartosc;
int gdzie;
};
void Wyswietl(int tab[], int dlugosc)
{
cout<<"Tablica wyglada tak"<<endl;
for(int i=0;i<dlugosc;i++)
{
cout<<tab[i]<<"\t";
}
cout<<endl;
}
int main()
{
int ileStron=3;
int *tablicaStron, *tablicaBitowOdniesienia;
tablicaStron=new int[ileStron];
tablicaBitowOdniesienia=new int[ileStron];
queue <strona> kolejka;
char opcja='a';
while(opcja!='k')
{
cout<<"(D)odawac (K)oniec (W)yswietl";
cin>>opcja;//DONT STOP THE PROGRAM!
if(opcja=='D'|opcja=='d')
{
strona tymczas;
cout<<"Podaj co dodać do kolejki";
cin>>tymczas.zawartosc;
int licznik=0;
if(kolejka.size()<ileStron)
{
tymczas.gdzie=kolejka.size();
kolejka.push(tymczas);
tablicaStron[tymczas.gdzie]=tymczas.zawartosc;
}
else if(kolejka.size()==ileStron)
{
cout<<"bang bang";
int czyJest=0;
int licznikfora=0;
for(int i=0;i<ileStron;i++)//sprawdza czy wpisywana strona nie istnieje przypadkiem w tablicy stron
{
if(tablicaStron[i]==tymczas.zawartosc)
{
czyJest=1;
}
licznikfora++;
}
cout<<"czyJest ma wartosc "<<czyJest<<" a licznik fora "<<licznikfora<<endl;
if(czyJest==0)
{
tymczas.gdzie=kolejka.front().gdzie;
kolejka.pop();//TUTAJ SIE BEDZIE ZAPISYWAC DO PAMIECI WIRTUALNEJ
kolejka.push(tymczas);
tablicaStron[tymczas.gdzie]=tymczas.zawartosc;
}
else if(czyJest==1)
{
cout<<"to co chcesz dodac juz jest w pamieci";
}
}
else
{
cout<<"rozmiar kolejki sie nie zgadza";
}
}
else if(opcja=='W'|opcja=='w')
{
Wyswietl(tablicaStron,ileStron);
cout<<endl;
cout<<"pierwszy element w kol: "<<kolejka.front().zawartosc<<"|"<<kolejka.front().gdzie<<" "
<<"ostatni element w kol: "<<kolejka.back().zawartosc<<"|"<<kolejka.back().gdzie<<endl;
}
}
system("pause");
return 0;
}
The problem is that after choosing option (d) - just type d and press enter, then type any few letters and the program should show you
(D)odawac (K)oniec (W)yswietl
but it is starting to loop to infinity...
What is the problem?
I think problem is with this statement:
cin>>tymczas.zawartosc;
At this point if you give a char or string input, program blows up.
to make your program work properly:
start the program and give only one input d, let the control hit this point : cin>>tymczas.zawartosc;
now input a number here, as it is int type. now control hits first cin.
The problem is with using cin to read int but user inputs a char or string. Behaviour is undefined in this case.
This link should resolve confusion: C++ character to int

Linking/Integration Issue. I need a direction of where to go?

So I have a 2 games running side by side.
proj2/main.cpp (main that gets run that then can call either game)
proj2/spades/display.cpp
proj2/spades/gameplay.cpp
proj2/spades/otherFiles.cpp
proj2/hearts/display.cpp (this is the same display class as in the spades game with the same functions just sightly altered.)
proj2/hearts/hearts.cpp
proj2/hearts/otherFiles.cpp
What basically happened is I am trying to integrate 2 games, 1 I created and another that uses the same display.cpp and display.h files slightly altered. In order to do this I created 2 seperate namespaces, hearts and spades. Everything I have compiles fine but a few of the .cpp files do not link correctly and I get errors such as the following.
./gamePlay.o: In function `__static_initialization_and_destruction_0(int, int)':
gamePlay.cpp:(.text+0x396): undefined reference to `spades::display::display()'
./gamePlay.o: In function `__tcf_3':
gamePlay.cpp:(.text+0x480): undefined reference to `spades::display::~display()'
./gamePlay.o: In function `spades::gamePlay::storeBid(std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&)':
gamePlay.cpp:(.text+0x1507): undefined reference to `spades::display::captureInput()'
What am I doing wrong here?
Below are some of the files I am using. Let me know if there are anymore I should add. (Dont want to bloat this post anymore than I have to)
gameplay.cpp
#include <iostream>
#include <sys/ioctl.h>
#include <cstdio>
#include <unistd.h>
#include <locale.h>
#include <ncursesw/ncurses.h>
#include <fstream>
#include "gamePlay.h"
#include <cstdlib>
#include <sstream>
#include <ctime>
namespace spades {
vector <spades::player> players(4);
vector <spades::card> deck(52);
spades::display monitor;
spades::card center[4];
vector <spades::card> gamePlay::getDeck(){return deck;}
vector <spades::player> gamePlay::getplayers(){return players;}
//sorts the cards in the players hand into diamonds, clubs, hearts, spades
void gamePlay::handSort(){
int spades[13];
int hearts[13];
int clubs[13];
int diamonds[13];
int index;
int i;
for(i=0; i<13; i++){ //determines the card number and places them into corresponding indexes
index = (players.at(0).hand.at(i).getCardNum()+11)%13; //cause the cards to be placed based on their number with 2 being index 0 and 1(ace) being index 12
switch(players.at(0).hand.at(i).getSuit())
{
case 1: spades[index] = 1;
break;
case 2: hearts[index] = 1;
break;
case 3: clubs[index] = 1;
break;
case 4: diamonds[index] = 1;
break;
default: mvprintw(3,2,"!!!!!!!we have a problem!!!!!!!!!!");
break;
}
}
i = 0;
while(i<13){ //being placing the ordered cards back into the players hand
int j = 0;
while(j < 13){
if(diamonds[j] == 1){ //if a card has been placed in this index for the diamonds only array
if(j+2 == 14) //if the card is an ace
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2); //add 2 to each index to get the card number
players.at(0).hand.at(i).setSuit(4);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(clubs[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(3);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(hearts[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(2);
i++;
}
j++;
}
j = 0;
while(j < 13){
if(spades[j] == 1){
if(j+2 == 14)
players.at(0).hand.at(i).setCardNum(1);
else
players.at(0).hand.at(i).setCardNum(j+2);
players.at(0).hand.at(i).setSuit(1);
i++;
}
j++;
}
}
}
//compares the center pile of 4 played cards to determine who wins the trick
int gamePlay::compareCenter(int leadplayer){
int highest = center[leadplayer].getCardNum();
if(center[leadplayer].getCardNum() == 1)
highest = 14;
int suit = center[leadplayer].getSuit();
int player = leadplayer;
for(int i = leadplayer+1; i < leadplayer+4; i++)
{
if(center[i%4].getSuit() == 1)
setSpadesBroken(true);
if((suit != 1) && (center[i%4].getSuit() == 1))
{
player = i%4;
suit = 1;
highest = center[i%4].getCardNum();
}
if(suit == center[i%4].getSuit()){
if(center[i%4].getCardNum() == 1){
player = i % 4;
highest = 14;
}
if(highest < center[i%4].getCardNum())
{
player = i%4;
highest = center[i%4].getCardNum();
}
}
}
players.at(player).setTricksTaken(players.at(player).getTricksTaken()+1); //increments the trick count of the winning player
return player; //return the player who won to determine who goes first next turn
}
//Create the deck of 52 cards by setting the suit and number of each card to a nonzero integer
void gamePlay::createDeck() {
for(int j = 0; j < 52; j++)
{
deck.at(j).setCardNum((j%13)+1);
deck.at(j).setSuit((j/13)+1);
}
random_shuffle(deck.begin(), deck.end());
}
//deal out 13 cards to each player by setting the
void gamePlay::deal(vector <spades::card> &newdeck, vector <spades::player> &newplayers){
for(int i = 0; i<52; i++){
newplayers.at(i/13).addCard(newdeck.at(i));
newdeck.at(i).setSuit(0);
newdeck.at(i).setCardNum(0);
}
}
//determines if the player still has a card of the same suit in their hand as the leading card played
bool gamePlay::containSuit(spades::card lead, spades::player players){
bool suit = false;
for(int i = 0; i < players.getHand().size(); i++){
if(lead.getSuit() == players.getHand().at(i).getSuit())
suit = true;
}
return suit;
}
//determines if the player has only spades cards left in their hand
bool gamePlay::onlySpade(spades::player play){
for(int i = 0; i<play.getHand().size(); i++){
if(play.getHand().at(i).getSuit()!=1)
return false;
}
return true;
}
//determines if the position the player is clicking on the screen actually points to a playable card
//and then returns the position of that card based on the player's hand vector of type <card>
int gamePlay::handCheck(int xevent, int yevent, vector <spades::player> players, int trickStart){
int i = xevent/6;
//first check to find the card on the display
if(i>=0 && i<players.at(0).getHand().size() && yevent>17 && yevent<23 &&
players.at(0).getHand().at(i).getSuit() != 0 &&
players.at(0).getHand().at(i).getCardNum() != 0)
{
spades::card playedCard = players.at(0).getHand().at(i);
//check to see if leading the current round or not and if spades are "broken"
if(trickStart==0 && !getSpadesBroken()){
if(onlySpade(players.at(0)))
return i;
else if(playedCard.getSuit() != 1)
return i;
else
return (-1);
}
if(trickStart == 0 && getSpadesBroken())
return i;
//if not leading, then call the containsuit method to see if your hand contains one of similar suit
if(trickStart > 0 && containSuit(center[trickStart],players.at(0))){
if(playedCard.getSuit()==center[trickStart].getSuit())
return i;
}
if(trickStart > 0 && !containSuit(center[trickStart],players.at(0)))
return i;
else
return (-1);
}
mvprintw(4,3,"invalid card");
return (-1);
}
//draws the cards in the player's hand if it contains a valid card, erase the card otherwise if invalid
void gamePlay::displayHand(){
int offset = 0;
for(int i =0; i<players.at(0).getHand().size(); i++){
if(players.at(0).getHand().at(i).getSuit() != 0)
monitor.displayCard(offset, 17, players.at(0).getHand().at(i).getSuit(), players.at(0).getHand().at(i).getCardNum(), 0);
else
monitor.eraseBox(offset, 17, 6, 5);
offset+=6;
}
}
void gamePlay::displayAdd(){
vector <string> lines;
int count12 = 0;
string line;
ifstream myfile ("advertisement.txt");
if ( myfile.is_open() )
{
while ( ! myfile.eof() )
{
getline (myfile, line);
lines.push_back(line);
count12++;
}
myfile.close();
int random1 = rand() % 6;
monitor.bannerBottom(lines.at(random1));
}
else{
monitor.bannerBottom("Unable to open Advertisement file.");
}
}
//determins the position of a mouse click and sends that to handcheck(), and then sends the card to the center pile array to be scored
void gamePlay::humanPlay(int trickStart){
int xevent, yevent;
for(;;){
mvprintw(3,2,"Please choose a card to play.");
int key = monitor.captureInput();
// if a mouse click occurred
if (key == -1) {
xevent = monitor.getMouseEventX();
yevent = monitor.getMouseEventY();
int handCh = handCheck(xevent, yevent, players, trickStart);
if(handCh != (-1)){ //if the card is valid
spades::card played = players.at(0).getHand().at(handCh);
players.at(0).hand.at(handCh).setCardNum(0);
players.at(0).hand.at(handCh).setSuit(0);
center[0]= played;
monitor.displayCard(39, 12, center[0].getSuit(), center[0].getCardNum(), 0);
displayHand();
//playedCards++; //Update Global Variable---- NEED TO HAVE THIS INITIATED GLOBALLY.
break;
}
else
mvprintw(4,3,"invalid card");
}
}
}
//loops through a computer players hand and checks to see if the random card is playable within the rules of the game
void gamePlay::CPUplay(int trickStart, int CPU){
bool goodCard = false;
spades::card playedCard =players.at(CPU).getHand().at(0);
int i;
for(i = 0; i < players.at(CPU).getHand().size(); i++){
if(players.at(CPU).getHand().at(i).getSuit() != 0 &&
players.at(CPU).getHand().at(i).getCardNum() != 0){
playedCard = players.at(CPU).getHand().at(i);
//check to see if leading or not
if(trickStart==CPU && !getSpadesBroken()){
if(onlySpade(players.at(CPU)))
break;
if(playedCard.getSuit()!=1)
break;
}
if(trickStart == CPU && getSpadesBroken())
break;
//if not leading use contains suit function
if(trickStart != CPU && containSuit(center[trickStart], players.at(CPU)))
if(playedCard.getSuit()==center[trickStart].getSuit())
break;
if(trickStart != CPU && !containSuit(center[trickStart], players.at(CPU)))
break;
}
}
players.at(CPU).hand.at(i).setCardNum(0);
players.at(CPU).hand.at(i).setSuit(0);
center[CPU]= playedCard;
if(CPU==1)
monitor.displayCard(29, 7, center[CPU].getSuit(), center[CPU].getCardNum(), 0);
if(CPU==2)
monitor.displayCard(39, 2, center[CPU].getSuit(), center[CPU].getCardNum(), 0);
if(CPU==3)
monitor.displayCard(49, 7, center[CPU].getSuit(), center[CPU].getCardNum(), 0);
}
//scores each team with the player being teamed with CPU 2 and the other team being CPU 1 and CPU 3
void gamePlay::score(spades::player &play, spades::player &play2){
int trickOver = play.getTricksTaken()-play.getBid(); // Calculate the difference between bid and actually taken.
if(play.getBid() == NULL)
trickOver = 0;
int trickOver2 = play2.getTricksTaken()-play2.getBid(); // Calculate the difference between bid and actually taken.
int totalBid = play.getBid()+play2.getBid();
int totalTrick = trickOver+trickOver2;
//Bidding Double Nil (if gets it 200 points other wise -200 points)
if(play.getDoubleNil()){
if(play.getTricksTaken()==0) //player did get Double Nil successfully
play.setScore(play.getScore()+200); // add 200 points
else
play.setScore(play.getScore()-200);
}
else if(play.getBid()==0){ //Bidding Nil (if gets it 100 points other wise -100 points)
if(play.getTricksTaken()==0) //player did get Nil successfully
play.setScore(play.getScore()+100); //add 100 points
else //player didnt get Nil
play.setScore(play.getScore()-100); //take away 100 points
}
if(totalTrick < 0){ //player bids more than number of tricks won
play.setScore(play.getScore()+(totalBid*(-10))); //decrease score by 10 poitns for every overtrick
}
else if(totalTrick >= 0){ //player bids less then number of tricks won
play.setSandBag(play.getSandBag() + totalTrick); //increase sandbag by 1
play.setScore(play.getScore()+totalTrick+(10*totalBid)); //increase 10 points per trick bid on and 1 point per trick over
}
if(play.getSandBag()>10){ //check for sandbagging
play.setScore(play.getScore()-100);
play.setSandBag(play.getSandBag()-10);
}
play.setBid(NULL); //reset players bid to NULL
play2.setBid(NULL); //reset players bid to NULL
play.setTricksTaken(0);
play2.setTricksTaken(0);
play.setDoubleNil(false); //Player has not yet bid double NILL.
}
//loops infinitely until a mouse click or key input is detected, then sets bid accordingly
void gamePlay::storeBid(stringstream &msg){
int xevent;
int yevent;
for(;;){
mvprintw(3,2,"Click the box bid Double Nil or type out your bid now. \n Use the keys 1-9, a for 10, b for 11, c for 12, and d for 13.");
int key = monitor.captureInput();
monitor.drawBox(2, 5, 3, 2, 0);
xevent = monitor.getMouseEventX();
yevent = monitor.getMouseEventY();
if (key == -1)
if((xevent>=2 && xevent<4)&&(yevent>=5 && yevent <7)){
msg.str("");
msg << "Your bid: double nil";
monitor.bannerTop(msg.str());
players.at(0).setDoubleNil(true);
break;
}
else{
msg.str("");
msg << "Your bid is horrible. Bid again!!!!";
monitor.bannerTop(msg.str());
}
if ((key-48) >= 0 && (key-48) <= 9){
msg.str("");
msg << "Your bid: " << (key-48);
monitor.bannerTop(msg.str());
players.at(0).setBid(key-48);
break;
}
else if(key>=97 && key<=100){
msg.str("");
msg << "Your bid: " << (key-87);
monitor.bannerTop(msg.str());
players.at(0).setBid(key-87);
break;
}
else if(key!=0 && key!=-1){
msg.str("");
msg << "Your bid is horrible. Bid again!!!!";
monitor.bannerTop(msg.str());
}
}
monitor.eraseBox(1, 1, 62, 16);
}
//main function that runs the entire game
void gamePlay::runGame(){
double startTime = clock();
stringstream messageString;
srand(time(NULL));
int count;
int handStart = 0;
int trickStart;
while(players.at(0).getScore()<500 && players.at(1).getScore()<500)
{
createDeck();
deal(deck, players); //deal out 13 cards to each player
handSort(); // sort the human players hand
displayHand();
storeBid(messageString); //asks for bid
//sets the bid randomly between 2-4 for each computer player
players.at(1).setBid(rand()%3+2);
players.at(2).setBid(rand()%3+2);
players.at(3).setBid(rand()%3+2);
//displays the current bid and scores of each team
messageString << " Partner: " << (players.at(2).getBid())
<< " CPU 1: " << players.at(1).getBid()
<< " CPU 3: " << players.at(3).getBid()
<< " Team Score = " << players.at(0).getScore()
<< " Enemy Score = " << players.at(1).getScore();
monitor.bannerTop(messageString.str());
displayAdd();
trickStart = handStart;
count = 0;
setSpadesBroken(false);
while(count<13){ // simulates the different cases where the human player plays 1st, 2nd, 3rd, last
bool success = true;
switch (trickStart)
{
case 0: humanPlay(trickStart);
CPUplay(trickStart,1);
CPUplay(trickStart,2);
CPUplay(trickStart,3);
break;
case 3: CPUplay(trickStart,3);
humanPlay(trickStart);
CPUplay(trickStart,1);
CPUplay(trickStart,2);
break;
case 2: CPUplay(trickStart,2);
CPUplay(trickStart,3);
humanPlay(trickStart);
CPUplay(trickStart,1);
break;
case 1: CPUplay(trickStart,1);
CPUplay(trickStart,2);
CPUplay(trickStart,3);
humanPlay(trickStart);
break;
default: mvprintw(3,2,"!!!!we have a problem!!!!");
success = false;
break;
}
monitor.eraseBox(3, 2, 20, 2);
for(;;){//pause to wait for an acknowledgment mouse click
int key = monitor.captureInput();
monitor.eraseBox(3, 2, 30, 4);
mvprintw(3,2,"click anywhere to continue");
if(key == -1){
break;
}
}
//if no errors appear, display the tricks taken
if(success){
monitor.eraseBox(1, 1, 62, 16);
trickStart = compareCenter(trickStart);
messageString.str("");
messageString << "Your Tricks= " << players.at(0).getTricksTaken()
<< " Partner= " << players.at(2).getTricksTaken()
<< " CPU 1= " << players.at(1).getTricksTaken()
<< " CPU 3= " << players.at(3).getTricksTaken();
displayAdd();
monitor.bannerAboveBottom(messageString.str());
count++;
}
}
//score the round and tally up for each team
for(int n =0; n<2;n++)
score(players.at(n),players.at(n+2));
messageString.str("");
monitor.bannerTop(messageString.str());
messageString << "Your Tricks = " << players.at(0).getTricksTaken()
<< " Partner = " << players.at(2).getTricksTaken()
<< " CPU 1 = " << players.at(1).getTricksTaken()
<< " CPU 3 = " << players.at(3).getTricksTaken();
handStart = (handStart +1) % 4;
}
double endTime = clock();
}
}
gameplay.h
#include "player.h"
#include "display.h"
#ifndef gamePlay_H
#define gamePlay_H
namespace spades {
using namespace std;
class gamePlay{
bool spadesBroken;
public:
vector <spades::card> getDeck();
vector <spades::player>getplayers();
bool getSpadesBroken() {return spadesBroken;}
void setSpadesBroken(bool b){spadesBroken = b;}
int compareCenter(int leadplayer);
void createDeck();
void deal(vector <spades::card> &deck, vector <spades::player> &players);
void handSort();
bool containSuit(spades::card lead, spades::player players);
bool onlySpade(spades::player play);
int handCheck(int xevent, int yevent, vector <spades::player> players, int trickStart);
void displayHand();
void displayAdd();
void humanPlay(int trickStart);
void CPUplay(int trickStart, int CPU);
void score(spades::player &play, spades::player &play2);
void storeBid(stringstream &msg);
void runGame();
};
}
#endif
player.h
#include <iostream> // Stream declarations
#include <vector> //Vectors used to store deck and players hands
#include <string> //String declarations
#include <algorithm> //Shuffle Method
#include "card.h"
#ifndef PLAYER_H
#define PLAYER_H
namespace spades {
using namespace std;
class player {
int score; //total score
int bid; //bid for that round
int tricksTaken; //score for thast round
int sandBag; //the number of points you win, more than what you bid, every 10th bag = -100
bool doubleNil;
//vector <card> hand;
public:
player();
vector <card> hand;
int getSandBag(){return sandBag;}
bool getDoubleNil() {return doubleNil;}
int getScore() {return score;}
int getBid() {return bid;}
int getTricksTaken() {return tricksTaken;}
vector<card> getHand() {return hand;}
void setSandBag(int i) {sandBag = i;}
void setBid(int i) {bid = i;}
void setTricksTaken(int i) {tricksTaken=i;}
void setScore(int i) {score = i;}
void setDoubleNil(bool i) {doubleNil = i;}
//add card to end of vector
void addCard(card b);
void removeCard(card a);
};
}
#endif
player.cpp
#include <iostream> // Stream declarations
#include <vector> //Vectors used to store deck and players hands
#include <string> //String declarations
#include <algorithm> //Shuffle Method
#include <sys/ioctl.h>
#include <cstdio>
#include <unistd.h>
#include <locale.h>
#include <ncursesw/ncurses.h>
#include "player.h"
namespace spades {
using namespace std;
player::player() {
score =0; //total score
bid = NULL; //bid for that round
tricksTaken = 0; //score for thast round
sandBag = 0; //the number of points you win, more than what you bid, every 10th bag = -100
doubleNil = false;
for(int i=0; i<13; i++)
hand.push_back(card());
}
void player::addCard(spades::card b){
for (int i=0; i<hand.size(); i++){
//compare card being played to the ones in your hand to search and determine which one to erase
if((hand.at(i).getCardNum() == 0) &&
(hand.at(i).getSuit() == 0))
{
hand.at(i).setCardNum(b.getCardNum());
hand.at(i).setSuit(b.getSuit());
return;
}
}
}
void player::removeCard(spades::card a) {
for (int i=0; i<hand.size(); i++){
//compare card being played to the ones in your hand to search and determine which one to erase
if((hand.at(i).getCardNum() == a.getCardNum()) &&
(hand.at(i).getSuit() == a.getSuit()))
{
hand.at(i).setCardNum(0);
hand.at(i).setSuit(0);
return;
}
}
}
}
What does your link line look like? It looks like when you're linking, you're missing spades.o?
If that's not it, use the nm command to see what symbols spades.o is providing - it's always possible
you've typo'd a namespace name or something:
nm -C spades.o | grep 'display::.*display'
(The -C option should put nm into C++/demangled mode - if it doesn't for your nm, add a "c++filt" or "dem" step to the pipe chain before grep).