Trying to make 2048 in c++ and i just added a function in Game.cpp that checks gamestate of the 4x4 grid and either shows the game is still in play or ends based on win or loss,
not sure what is going on, but i get this error from the compiler about multiple declarations or multiple definitions but im so confused about where the error is, if someone could either solve it, or explain how to understand the compilers error so im able to solve it myself ( aka where the error is, what lines its pointing to etc ) i would be grateful.
file for compiling is at the bottom ( it was provided by my uni )
This is the error in console
compiling main.cpp
In file included from main.cpp:15:
In file included from ./Grid.h:4:
In file included from ../../include/graphics.h:28:
In file included from ../../include/graphics_internal.h:18:
In file included from ../../include/juce/JuceHeader.h:23:
In file included from ../../3rdparty/JUCE/modules/juce_cryptography/juce_cryptography.h:60:
../../3rdparty/JUCE/modules/juce_cryptography/encryption/juce_BlowFish.h:100:10: warning:
mangled name of 'apply' will change in C++17 due to non-throwing exception
specification in function signature [-Wc++17-compat-mangling]
bool apply (void*, size_t, void (BlowFish::*op) (uint32&, uint32&) const noexc...
^
1 warning generated.
linking build/main.o
build/Game.o:(.bss+0x4): multiple definition of `grid'
build/main.o:(.bss+0x4): first defined here
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)
Makefile:33: recipe for target 'build/2048' failed
make: *** [build/2048] Error 1
and these are my files
Main.cpp
/**
* File: main.cpp
* Author: nice try ;)
* Date: 20-11-2019
* Desc:
* Copyright: University of West of England 2017
*/
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
// include the UFCFGL301's standard library
#include <ufcfgl-30-1.h>
#include <iostream>
#include <time.h>
#include "Grid.h"
#include "Game.h"
// uncomment if you want to use the graphics library
#include <graphics.h>
using namespace std;
using namespace uwe;
/**
* main routine, implements ...
* @return success
*/
int main(void) {
int c = 0;
srand(time(0));
Grid grid = Grid();
Game game = Game();
cout << "\033[2J"; // this clears the terminal
cout << "Player Score : " << grid.totalScore << "\n";
grid.addValue();
grid.drawGrid();
initialiseGraphics(600,400);
loop (
[&](){},
[&](keyPress keyPress){
// w a s d are also inputted into an integer as their respective ascii value
// so this allows the use of w a s d and also the arrow keys in controlling
// the moves of the player
int kpVal = keyPress.getKeyCode();
if ( kpVal == 'q' ){
return true;
}
if ( kpVal == 'w' || kpVal == keyPress::upKey){
grid.shiftUp();
grid.setScore(grid.score);
cout << "\033[2J"; // this clears the terminal
cout << "Player Score : " << grid.totalScore << "\n";
grid.drawGrid();
game.checkGameState();
}
if ( kpVal == 'a' || kpVal == keyPress::leftKey){
grid.shiftLeft();
grid.setScore(grid.score);
cout << "\033[2J";
cout << "Player Score : " << grid.totalScore << "\n";
grid.drawGrid();
game.checkGameState();
}
if ( kpVal == 's' || kpVal == keyPress::downKey){
grid.shiftDown();
grid.setScore(grid.score);
cout << "\033[2J";
cout << "Player Score : " << grid.totalScore << "\n";
grid.drawGrid();
game.checkGameState();
}
if ( kpVal == 'd' || kpVal == keyPress::rightKey){
grid.shiftRight();
grid.setScore(grid.score);
cout << "\033[2J";
cout << "Player Score : " << grid.totalScore << "\n";
grid.drawGrid();
game.checkGameState();
}
return false;
}
);
}
Grid.cpp
#include "Grid.h"
#include <iostream>
#include <cstdio>
#include <string>
#include <graphics.h>
// this empties the board from left to right and top to bottom
// and sets each value to 0
Grid::Grid(){
for(int x = 0; x < tilesWide; x++){
for(int y = 0; y < tilesHigh; y++){
grid[x][y] = emptyCell;
didMove = true;
}
}
}
// draws the current grid with lines inbetween ( ascii 4x4 grid essentially )
void Grid::drawGrid(){
std::cout << "--------------------" << '\n';
for(int y = 0; y < tilesWide ; y++){
for(int x = 0;x < tilesHigh; x++){
std::cout << "| " << grid[x][y] << " |";
}
std::cout << '\n' << "--------------------" << '\n';
}
}
// function to set the score
void Grid::setScore(int score){
totalScore = totalScore + score;
}
// this function adds a 2 or a 4 to a random empty tile
void Grid::addValue(){
int value = Grid::randValue();
while(true){
int valX = rand() % tilesWide;
int valY = rand() % tilesHigh;
if (grid[valX][valY] == 0) {
// this if statement checking a boolean is so that a tile is only added if
// a tile has been moved or merged, so that if you press a key and nothing
// happened, it will not add a tile causing you to choose a different direction
// to move
if(didMove == true){
grid[valX][valY] = value;
didMove = false;
break;
}
else{
printf("DID NOT MOVE \n");
break;
}
}
}
}
// this function generates a 2 or a 4 and returns it to the addValue function
int Grid::randValue(){
int randVal = rand() % 10;
// 90% chance of spawning a 2, same probability as the original source code
if(randVal < 9){
return 2;
}
else{
return 4;
}
}
// this function is so that the value of grid[x][y] can be checked in another
// source file ( in this case in game.cpp for game state check) as using
// grid[x][y] was not recognised
int Grid::gridValue(int x, int y){
return grid[x][y];
}
//-----------------------------TILE MOVEMENT----------------------------------//
// this packs and merges all the tiles up to the top of the board if there is
// space
// up // down // left // right // order of functions
void Grid::shiftUp(){
moveUp();
mergeUp();
moveUp();
addValue();
}
void Grid::shiftDown(){
moveDown();
mergeDown();
moveDown();
addValue();
}
void Grid::shiftLeft(){
moveLeft();
mergeLeft();
moveLeft();
addValue();
}
void Grid::shiftRight(){
moveRight();
mergeRight();
moveRight();
addValue();
}
// functions to move and merge upwards
void Grid::moveUp(){
for(int x = 0; x < tilesWide; x++){
for(int y = 0; y < tilesHigh; y++){
if( grid[x][y] == emptyCell){
for(int t = y+1; t < tilesWide; t++){
if(grid[x][t] != emptyCell){
grid[x][y] = grid[x][t];
grid[x][t] = emptyCell;
didMove = true;
break;
}
}
}
}
}
}
void Grid::mergeUp(){
for(int x = 0; x < tilesWide; x++){
for(int y = 0; y < tilesHigh-1; y++){
if(grid[x][y] == grid[x][y+1]){
grid[x][y] = ( grid[x][y] *2);
grid[x][y+1] = emptyCell;
setScore(grid[x][y]);
didMove = true;
}
}
}
}
// functions to move and merge downwards
void Grid::moveDown(){
for(int x = 0; x < tilesWide; x++){
for(int y = tilesHigh - 1; y > 0 ; y--){
if( grid[x][y] == emptyCell){
for(int t = y-1; t >= 0; t--){
if(grid[x][t] != emptyCell){
grid[x][y] = grid[x][t];
grid[x][t] = emptyCell;
didMove = true;
break;
}
}
}
}
}
}
void Grid::mergeDown(){
for(int x = 0; x < tilesWide; x++){
for(int y = tilesHigh-1; y > 0; y--){
if(grid[x][y] == grid[x][y-1]){
grid[x][y] = (grid[x][y] *2);
grid[x][y-1] = emptyCell;
setScore(grid[x][y]);
didMove = true;
}
}
}
}
// functions to move and merge to the left
void Grid::moveLeft(){
for(int x = 0; x < tilesWide; x++){
for(int y = 0; y < tilesHigh; y++){
if( grid[x][y] == emptyCell){
for(int t = x+1; t < tilesHigh; t++){
if(grid[t][y] != emptyCell){
grid[x][y] = grid[t][y];
grid[t][y] = emptyCell;
didMove = true;
break;
}
}
}
}
}
}
void Grid::mergeLeft(){
for(int x = 0; x < tilesWide-1; x++){
for(int y = 0; y < tilesHigh; y++){
if(grid[x][y] == grid[x+1][y]){
grid[x][y] = (grid[x][y] *2);
grid[x+1][y] = emptyCell;
setScore(grid[x][y]);
didMove = true;
}
}
}
}
// functions to move and merge to the right
void Grid::moveRight(){
for(int x = tilesWide - 1; x >= 0; x--){
for(int y = 0; y < tilesHigh; y++){
if( grid[x][y] == emptyCell){
for(int t = x-1; t >= 0; t--){
if(grid[t][y] != emptyCell){
grid[x][y] = grid[t][y];
grid[t][y] = emptyCell;
didMove = true;
break;
}
}
}
}
}
}
void Grid::mergeRight(){
for(int x = tilesWide - 1; x > 0; x--){
for(int y = 0; y < tilesHigh; y++){
if(grid[x][y] == grid[x-1][y]){
grid[x][y] = (grid[x][y] *2);
grid[x-1][y] = emptyCell;
setScore(grid[x][y]);
didMove = true;
}
}
}
}
Grid.h
#pragma once
#include <cstdio>
#include <string>
#include <graphics.h>
class Grid {
public:
Grid();
// defining functions for processing user input into various moves on the board
void drawGrid();
int randValue();
void addValue();
void moveLeft();
void mergeLeft();
void moveRight();
void mergeRight();
void moveUp();
void mergeUp();
void moveDown();
void mergeDown();
void shiftUp();
void shiftDown();
void shiftLeft();
void shiftRight();
int gridValue(int x, int y);
static const int tilesWide = 4;
static const int tilesHigh = 4;
bool didMove;
int grid[tilesWide][tilesHigh];
int score = 0;
int totalScore = 0;
void setScore(int score);
static const int emptyCell = 0;
private :
};
Game.cpp
#include "Game.h"
#include <iostream>
#include <cstdio>
#include <string>
#include <graphics.h>
Game::Game(){}
bool canMove(){
bool canMove = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; x++){
if (grid.gridValue(x,y) == Grid::emptyCell) {
canMove = true;
return canMove;
}
else if(grid.gridValue(x,y) == grid.gridValue(x,y+1) ||
grid.gridValue(x,y) == grid.gridValue(x+1,y) ) {
canMove = true;
return canMove;
}
}
}
return canMove;
}
bool checkWin(){
bool win = false;
for(int x = 0; x < Grid::tilesWide; x++){
for(int y = 0; y < Grid::tilesHigh; x++){
if(grid.gridValue(x,y) == 2048){
win = true;
}
}
}
return win;
}
bool checkLoss(){
bool loss = false;
if(canMove() == false ){
loss = true;
}
return loss;
}
void checkGameState(){
if(checkWin() == true) {
std::cout << "YOU WIN";
exit(1);
}
else if(checkLoss() == true) {
std::cout << "YOU LOSE";
exit(1);
}
}
Game.h
#pragma once
#include "Grid.h"
#include <cstdio>
#include <string>
#include <graphics.h>
Grid grid;
class Game{
public:
Game();
bool canMove();
bool checkWin();
bool checkLoss();
void checkGameState();
private:
};
MakeFile
# File: Makefile
# Author: again, nice try ;)
# Date: 20-11-2019
#
# Copyright: University of West of England 2017
#
ifeq ($(origin ROOTDIR), undefined)
ROOTDIR=../..
endif
include $(ROOTDIR)/MakefileDefs.inc
# Build path
BUILD_DIR = build
TARGET = 2048
CPP_SOURCES = main.cpp Grid.cpp Game.cpp
#######################################
# build the application
#######################################
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(CPP_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CPP_SOURCES)))
CFLAGS += -I$(INCDIR) -I$(JUCEINSTALL)/modules
LIBS = $(LIBDIR)/libgraphics.a $(JUCELIB) $(LIBDIR)/libufcfgl-30-1.a
$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR)
$(ECHO) compiling $<
$(CC) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET): $(OBJECTS) $(LIBS) Makefile
$(ECHO) linking $<
$(CC) $(OBJECTS) $(LIBS) $(LINUXLIBFALGS) $(LDFLAGS) -o $@
$(ECHO) success
$(BUILD_DIR):
mkdir -p $@
#######################################
# install
#######################################
install:
#######################################
# clean up
#######################################
clean:
-rm -fR .dep $(BUILD_DIR)
#######################################
# dependencies
#######################################
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
.PHONY: clean all