summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Controllers/ConsoleController/ConsoleController.cpp45
-rw-r--r--src/Controllers/ConsoleController/ConsoleController.hpp4
-rw-r--r--src/Helpers/Keyboard.hpp1
-rw-r--r--src/Model/Game.cpp52
-rw-r--r--src/Model/Game.hpp11
-rw-r--r--src/Model/Grid.cpp355
-rw-r--r--src/Model/Grid.hpp42
-rw-r--r--src/main.cpp2
8 files changed, 344 insertions, 168 deletions
diff --git a/src/Controllers/ConsoleController/ConsoleController.cpp b/src/Controllers/ConsoleController/ConsoleController.cpp
index d91e807..1bc9b84 100644
--- a/src/Controllers/ConsoleController/ConsoleController.cpp
+++ b/src/Controllers/ConsoleController/ConsoleController.cpp
@@ -2,14 +2,22 @@
#include <SFML/Window/Keyboard.hpp>
#include "../../Helpers/Keyboard.hpp"
+
+//==================== Constructor and Destructor ====================
+
+//Constructor
ConsoleController::ConsoleController()
{
}
+//Destructor
ConsoleController::~ConsoleController()
{
}
+//==================== Helpers ====================
+
+//Run the game.
void ConsoleController::run()
{
@@ -22,6 +30,9 @@ void ConsoleController::run()
//Pop a random number on the grid
m_game.popRandomNumber();
+ //First cout stats
+ this->coutStats();
+
//First cout grid
m_game.coutGrid();
@@ -33,20 +44,27 @@ void ConsoleController::run()
keyPress=this->waitArrowKeyPress();
//Apply move
- m_game.swipe(keyPress);
+ bool moveDone=m_game.swipe(keyPress);
- //Pop a random number on the grid
- m_game.popRandomNumber();
+ //Cout stats
+ this->coutStats();
//Cout grid
m_game.coutGrid();
}
+
+ //Last cout stats
+ this->coutStats();
+
+ //Last cout grid
m_game.coutGrid();
}
+
+//Wait for keypress and return the keyPress.
kbdh::Direction ConsoleController::waitArrowKeyPress()
{
//Initialise keyPress
@@ -59,7 +77,8 @@ kbdh::Direction ConsoleController::waitArrowKeyPress()
keyPress=kbdh::Left;
while(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
- //Wait for release
+ //Wait for release and try to remove arrow printed characters
+ std::cout << "\r" << " ";
}
break;
}
@@ -68,7 +87,8 @@ kbdh::Direction ConsoleController::waitArrowKeyPress()
keyPress=kbdh::Right;
while(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
- //Wait for release
+ //Wait for release and try to remove arrow printed characters
+ std::cout << "\r" << " ";
}
break;
}
@@ -77,17 +97,18 @@ kbdh::Direction ConsoleController::waitArrowKeyPress()
keyPress=kbdh::Up;
while(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
- //Wait for release
+ //Wait for release and try to remove arrow printed characters
+ std::cout << "\r" << " ";
}
break;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
- // la touche "flèche gauche" est enfoncée : on bouge le personnage
keyPress=kbdh::Down;
while(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
- //Wait for release
+ //Wait for release and try to remove arrow printed characters
+ std::cout << "\r" << " ";
}
break;
}
@@ -95,3 +116,11 @@ kbdh::Direction ConsoleController::waitArrowKeyPress()
return keyPress;
}
+
+
+//Cout the stats of the game
+void ConsoleController::coutStats(){
+
+ std::cout << std::endl << "Score : " << m_game.getScore() << std::endl;
+ std::cout << "Nombre de coups : " << m_game.getNbMove() << std::endl;
+}
diff --git a/src/Controllers/ConsoleController/ConsoleController.hpp b/src/Controllers/ConsoleController/ConsoleController.hpp
index 8d73f79..f3e9952 100644
--- a/src/Controllers/ConsoleController/ConsoleController.hpp
+++ b/src/Controllers/ConsoleController/ConsoleController.hpp
@@ -18,9 +18,13 @@ class ConsoleController
Game m_game;
kbdh::Direction waitArrowKeyPress();
public:
+ //Constructor and Destructor
ConsoleController();
~ConsoleController();
+
+ //Helpers
void run();
+ void coutStats();
};
#endif
diff --git a/src/Helpers/Keyboard.hpp b/src/Helpers/Keyboard.hpp
index 9d2dfa3..c24c1ba 100644
--- a/src/Helpers/Keyboard.hpp
+++ b/src/Helpers/Keyboard.hpp
@@ -10,6 +10,7 @@ namespace kbdh {
//Key arrow
enum Direction { Up, Down, Left, Right };
+ //Key arrow typedef
typedef enum Direction Direction;
}
diff --git a/src/Model/Game.cpp b/src/Model/Game.cpp
index 6039bc9..284d82b 100644
--- a/src/Model/Game.cpp
+++ b/src/Model/Game.cpp
@@ -1,49 +1,85 @@
#include "Game.hpp"
+//==================== Constructor and Destructor ====================
-Game::Game() : m_grid(){
+//Constructor
+Game::Game() : m_grid(), m_score(0), m_nbMove(0){
}
+//Destructor
Game::~Game(){
}
+//==================== Helpers ====================
-
+//Swipe action
bool Game::swipe(kbdh::Direction direction){
+ bool moveDone;
+
switch(direction){
case kbdh::Left:
- m_grid.swipeLeft();
+ moveDone=m_grid.swipeLeft();
break;
case kbdh::Right:
- m_grid.swipeRight();
+ moveDone=m_grid.swipeRight();
break;
case kbdh::Up:
- m_grid.swipeUp();
+ moveDone=m_grid.swipeUp();
break;
case kbdh::Down:
- m_grid.swipeDown();
+ moveDone=m_grid.swipeDown();
break;
}
- return true;
+ if(moveDone){
+ m_score+=m_grid.getLastMoveScore();
+ m_nbMove++;
+ this->popRandomNumber();
+ }
+
+ return moveDone;
}
+//Cout the grid
void Game::coutGrid(){
std::cout << m_grid.description();
}
+//Return true if the game is lost. False else.
bool Game::isOver(){
return m_grid.isOver();
}
+//Pop a random number on the grid
void Game::popRandomNumber(){
std::tuple<int, int> coord(m_grid.getRandomEmptyCellCoord());
- int number=2;
+ int percent=rand() % 100;
+
+ int number;
+
+ if(percent <= 10){
+ number=4;
+ }
+ else{
+ number=2;
+ }
+
m_grid.setCell(coord, number);
}
+//==================== Getters and Setter ====================
+
+//Retrieve the Score
+int Game::getScore(){
+ return m_score;
+}
+
+//Retrieve the number of moves
+int Game::getNbMove(){
+ return m_nbMove;
+}
diff --git a/src/Model/Game.hpp b/src/Model/Game.hpp
index ab19340..0b2ee4d 100644
--- a/src/Model/Game.hpp
+++ b/src/Model/Game.hpp
@@ -16,16 +16,25 @@
class Game
{
private:
+ //Members
Grid m_grid;
+ int m_score;
+ int m_nbMove;
public:
+ //Constructor and Destructor
Game();
~Game();
-
+
+ //Helpers
bool swipe(kbdh::Direction direction);
void coutGrid();
void popRandomNumber();
bool isOver();
+
+ //Getters and Setters
+ int getScore();
+ int getNbMove();
};
#endif
diff --git a/src/Model/Grid.cpp b/src/Model/Grid.cpp
index 3a8a075..cc0fe60 100644
--- a/src/Model/Grid.cpp
+++ b/src/Model/Grid.cpp
@@ -1,5 +1,7 @@
#include "Grid.hpp"
+//==================== Constructor and Destructor ====================
+
//Constructor
Grid::Grid(): m_size(4), m_grid(4){
@@ -9,7 +11,6 @@ Grid::Grid(): m_size(4), m_grid(4){
m_grid.at(i).push_back(0);
}
}
-
}
//Destructor
@@ -17,109 +18,10 @@ Grid::~Grid(){
}
-std::string Grid::description(){
-
- //Init stringstream description
- std::stringstream description;
-
- //Get max str len of the grid
- int maxStrLen=this->maxStrLenInGrid();
-
- //Start to write description
- std::stringstream gridBorder;
- for(int i=0;i<(maxStrLen+2)*4+1;i++){
- gridBorder<<"-";
- }
- description << std::endl << gridBorder.str() << std::endl;
- for(int i=0;i<m_size;i++){
- for(int j=0;j<m_size;j++){
- std::stringstream spaceCol;
- for(int k=0;k<maxStrLen-std::to_string(m_grid.at(i).at(j)).size();k++){
- spaceCol << " ";
- }
- if(m_grid.at(i).at(j) == 0)
- description << "| " << " " << spaceCol.str();
- else
- description << "| " << m_grid.at(i).at(j) << spaceCol.str();
- }
- description << "|";
- description << std::endl;
- }
- description << gridBorder.str() << std::endl << std::endl;
-
- //Return description
- return description.str();
-}
-
-
-int Grid::maxStrLenInGrid(){
- int max=0;
- for(int i=0;i<m_size;i++){
- for(int j=0;j<m_size;j++){
- std::string number=std::to_string(m_grid.at(i).at(j));
- if(number.size() > max)
- max=number.size();
- }
- }
- return max;
-}
-
-bool Grid::isEmpty(int i, int j){
- if(m_grid.at(i).at(j) == 0)
- return true;
- return false;
-}
-
-std::tuple<int, int> Grid::getRandomEmptyCellCoord(){
-
- //Init list of candidate
- std::vector<std::tuple<int, int> > candidates;
-
- //Construct list of candidates
- for(int i=0;i<m_size;i++){
- for(int j=0;j<m_size;j++){
- if(this->isEmpty(i,j)){
- std::tuple<int, int> currentCandidate(i,j);
- candidates.push_back(currentCandidate);
- }
- }
- }
-
- //If no candidate available
- if(candidates.size() == 0)
- return std::tuple<int, int>(-1, -1);
-
- //Select the candidates
- int winnerIs(rand() % candidates.size());
-
- //Return the candidate
- return candidates.at(winnerIs);
-
-}
-
-
-
-//Change value of cell
-bool Grid::setCell(std::tuple<int, int> coord, int value){
- int i=std::get<0>(coord);
- int j=std::get<1>(coord);
+//==================== Merge and defragment methods ====================
- if(i>=0 && i<m_size && j>=0 && j<m_size){
- m_grid.at(i).at(j)=value;
- return true;
- }
-
- return false;
-}
-
-//Another setCell method
-bool Grid::setCell(int i, int j, int value){
- std::tuple<int, int> coord(i,j);
- return this->setCell(coord, value);
-}
-
-
-std::vector<int> Grid::defragmentLine(std::vector<int> line){
+//Defragment the line to the right
+std::vector<int> Grid::rightDefragment(std::vector<int> line){
for(int j=0; j<m_size-1;j++){
for(int i=0; i<m_size-1;i++){
int val1=line.at(i);
@@ -134,7 +36,16 @@ std::vector<int> Grid::defragmentLine(std::vector<int> line){
return line;
}
-std::vector<int> Grid::mergeLine(std::vector<int> line){
+//Defragment the line to the left using right defragmentation
+std::vector<int> Grid::leftDefragment(std::vector<int> line){
+
+ std::vector<int> reversedLine= this->reverseLine(line);
+
+ return this->reverseLine(this->rightDefragment(reversedLine));
+}
+
+//Merge line to the right
+std::vector<int> Grid::rightMerge(std::vector<int> line){
for(int i=0; i< m_size-1;i++){
int val1=line.at(i);
int val2=line.at(i+1);
@@ -142,72 +53,153 @@ std::vector<int> Grid::mergeLine(std::vector<int> line){
if(val1==val2){
line.at(i)=0;
line.at(i+1)=val1*2;
+ m_lastMoveScore+=val1*2;
i++;
}
}
return line;
}
-std::vector<int> Grid::swipeLine(std::vector<int> line){
-
- //Swipe line is :
- //- A defragmentation
- //- A merging
- //- Another defragmentation
- line=this->defragmentLine(line);
- line=this->mergeLine(line);
- line=this->defragmentLine(line);
+//Merge line to the left
+std::vector<int> Grid::leftMerge(std::vector<int> line){
+ for(int i=m_size-1; i>0;i--){
+ int val1=line.at(i);
+ int val2=line.at(i-1);
- //Return swiped line
+ if(val1==val2){
+ line.at(i)=0;
+ line.at(i-1)=val1*2;
+ m_lastMoveScore+=val1*2;
+ i--;
+ }
+ }
return line;
}
-//Swipe to right
-void Grid::swipeRight(){
+//==================== Swipe methods ====================
+
+
+//Swipe to the right
+bool Grid::swipeRight(){
+
+ m_lastMoveScore=0;
+ bool moveDone=false;
for(int i=0; i<m_size;i++){
- m_grid.at(i)=this->swipeLine(m_grid.at(i));
+ std::vector<int> swipedLine(this->rightDefragment(this->leftMerge(this->rightDefragment(m_grid.at(i)))));
+
+ if(!this->compareLines(m_grid.at(i), swipedLine)){
+ moveDone=true;
+ m_grid.at(i)=swipedLine;
+ }
}
+ return moveDone;
}
-//Swipe to right
-void Grid::swipeLeft(){
+//Swipe to the left
+bool Grid::swipeLeft(){
+ m_lastMoveScore=0;
+ bool moveDone=false;
for(int i=0; i<m_size;i++){
- m_grid.at(i)=this->reverseLine(this->swipeLine(this->reverseLine(m_grid.at(i))));
+ std::vector<int> swipedLine(this->leftDefragment(this->rightMerge(this->leftDefragment(m_grid.at(i)))));
+ if(!this->compareLines(m_grid.at(i), swipedLine)){
+ moveDone=true;
+ m_grid.at(i)=swipedLine;
+ }
}
+ return moveDone;
}
-void Grid::swipeUp(){
+//Swipe to the top
+bool Grid::swipeUp(){
+ m_lastMoveScore=0;
+ bool moveDone=false;
for(int i=0; i<m_size;i++){
std::vector<int> colVect=this->getCol(i);
- this->setCol(i,this->reverseLine(this->swipeLine(this->reverseLine(colVect))));
+
+ std::vector<int> swipedLine(this->leftDefragment(this->rightMerge(this->leftDefragment(colVect))));
+ if(!this->compareLines(colVect, swipedLine)){
+ moveDone=true;
+ this->setCol(i,swipedLine);
+ }
}
+ return moveDone;
}
-void Grid::swipeDown(){
+//Swipe to the bottom
+bool Grid::swipeDown(){
+ m_lastMoveScore=0;
+ bool moveDone=false;
for(int i=0; i<m_size;i++){
std::vector<int> colVect=this->getCol(i);
- this->setCol(i,this->swipeLine(colVect));
+
+ std::vector<int> swipedLine(this->rightDefragment(this->leftMerge(this->rightDefragment(colVect))));
+
+ if(!this->compareLines(colVect, swipedLine)){
+ moveDone=true;
+ this->setCol(i,swipedLine);
+ }
}
+ return moveDone;
}
-void Grid::setCol(int col, std::vector<int> colVect){
+//==================== Helpers ====================
+
+//Get the max len of a string of the numbers in the grid :
+// Exemple:
+// - 1 return 1
+// - 22 return 2
+// - 120 return 3
+// - 1000 return 4
+//This method help to calculate the columns size
+int Grid::maxStrLenInGrid(){
+ int max=0;
for(int i=0;i<m_size;i++){
- m_grid.at(i).at(col)=colVect.at(i);
+ for(int j=0;j<m_size;j++){
+ std::string number=std::to_string(m_grid.at(i).at(j));
+ if(number.size() > max)
+ max=number.size();
+ }
}
+ return max;
}
-std::vector<int> Grid::getCol(int col){
+//Test if the cell at (i,j) is empty
+bool Grid::isEmpty(int i, int j){
+ if(m_grid.at(i).at(j) == 0)
+ return true;
+ return false;
+}
- std::vector<int> colVect;
+//Return a tuple that contain a random empty cell
+std::tuple<int, int> Grid::getRandomEmptyCellCoord(){
+
+ //Init list of candidate
+ std::vector<std::tuple<int, int> > candidates;
+ //Construct list of candidates
for(int i=0;i<m_size;i++){
- colVect.push_back(m_grid.at(i).at(col));
+ for(int j=0;j<m_size;j++){
+ if(this->isEmpty(i,j)){
+ std::tuple<int, int> currentCandidate(i,j);
+ candidates.push_back(currentCandidate);
+ }
+ }
}
- return colVect;
+ //If no candidate available
+ if(candidates.size() == 0)
+ return std::tuple<int, int>(-1, -1);
+
+ //Select the candidates
+ int winnerIs(rand() % candidates.size());
+
+ //Return the candidate
+ return candidates.at(winnerIs);
+
}
+//Reverse a line
std::vector<int> Grid::reverseLine(std::vector<int> line){
std::vector<int> reversedLine;
@@ -218,7 +210,7 @@ std::vector<int> Grid::reverseLine(std::vector<int> line){
return reversedLine;
}
-
+//Return true if the grid is full. False else.
bool Grid::isFull(){
for(int i=0;i<m_size;i++){
@@ -227,10 +219,11 @@ bool Grid::isFull(){
return false;
}
}
-
+
return true;
}
+//Return true if the grid is full and no move can be performed. False else.
bool Grid::isOver(){
if(!this->isFull())
@@ -242,7 +235,7 @@ bool Grid::isOver(){
return false;
}
}
-
+
for(int i=0;i<m_size;i++){
std::vector<int> colVect(this->getCol(i));
@@ -256,3 +249,99 @@ bool Grid::isOver(){
}
+
+//Return true if line1 is equals to line2. False else.
+bool Grid::compareLines(std::vector<int> line1, std::vector<int> line2){
+
+ for(int i=0;i<m_size;i++){
+
+ if(line1.at(i) != line2.at(i))
+ return false;
+ }
+ return true;
+}
+
+//Return the description of the grid in a string.
+//In other terms, the grid in ASCII
+std::string Grid::description(){
+
+ //Init stringstream description
+ std::stringstream description;
+
+ //Get max str len of the grid
+ int maxStrLen=this->maxStrLenInGrid();
+
+ //Start to write description
+ std::stringstream gridBorder;
+ for(int i=0;i<(maxStrLen+1)*4+1;i++){
+ gridBorder<<"-";
+ }
+ description << std::endl << gridBorder.str() << std::endl;
+ for(int i=0;i<m_size;i++){
+ for(int j=0;j<m_size;j++){
+ std::stringstream spaceCol;
+ //Get number of space needed in cell
+ int nbSpace=maxStrLen-std::to_string(m_grid.at(i).at(j)).size();
+
+ for(int k=0;k<nbSpace;k++){
+ spaceCol << " ";
+ }
+ if(m_grid.at(i).at(j) == 0)
+ description << "|" << spaceCol.str() << " ";
+ else
+ description << "|"<< spaceCol.str() << m_grid.at(i).at(j) ;
+ }
+ description << "|";
+ description << std::endl;
+ }
+ description << gridBorder.str() << std::endl << std::endl;
+
+ //Return description
+ return description.str();
+}
+
+//==================== Getters and Setters ====================
+
+//Getter for m_lastMoveScore
+int Grid::getLastMoveScore(){
+ return m_lastMoveScore;
+}
+
+
+//Change value of cell with a tuple
+bool Grid::setCell(std::tuple<int, int> coord, int value){
+ int i=std::get<0>(coord);
+ int j=std::get<1>(coord);
+
+ if(i>=0 && i<m_size && j>=0 && j<m_size){
+ m_grid.at(i).at(j)=value;
+ return true;
+ }
+
+ return false;
+}
+
+//Change value of cell with int
+bool Grid::setCell(int i, int j, int value){
+ std::tuple<int, int> coord(i,j);
+ return this->setCell(coord, value);
+}
+
+//Assign a vector to a column.
+void Grid::setCol(int col, std::vector<int> colVect){
+ for(int i=0;i<m_size;i++){
+ m_grid.at(i).at(col)=colVect.at(i);
+ }
+}
+
+//Retrieve a specific column.
+std::vector<int> Grid::getCol(int col){
+
+ std::vector<int> colVect;
+
+ for(int i=0;i<m_size;i++){
+ colVect.push_back(m_grid.at(i).at(col));
+ }
+
+ return colVect;
+}
diff --git a/src/Model/Grid.hpp b/src/Model/Grid.hpp
index 21c653a..51168a9 100644
--- a/src/Model/Grid.hpp
+++ b/src/Model/Grid.hpp
@@ -15,38 +15,46 @@
class Grid
{
private:
+ //Members
int m_size;
std::vector<std::vector<int> > m_grid;
+ int m_lastMoveScore;
+ //Private methods
int maxStrLenInGrid();
+
public:
+ //Constructor and Destructor
Grid();
~Grid();
- std::string description();
+ //Defragment and merge methods
+ std::vector<int> rightDefragment(std::vector<int> line);
+ std::vector<int> leftDefragment(std::vector<int> line);
+ std::vector<int> rightMerge(std::vector<int> line);
+ std::vector<int> leftMerge(std::vector<int> line);
+
+ //Swipe methods
+ bool swipeRight();
+ bool swipeLeft();
+ bool swipeUp();
+ bool swipeDown();
+
+ //Helpers
+ bool isFull();
+ bool isOver();
bool isEmpty(int i, int j);
std::tuple<int, int> getRandomEmptyCellCoord();
+ bool compareLines(std::vector<int> line1, std::vector<int> line2);
+ std::vector<int> reverseLine(std::vector<int> line);
+ std::string description();
+ //Getters and Setters
bool setCell(std::tuple<int, int> coord, int value);
bool setCell(int i, int j, int value);
-
- std::vector<int> swipeLine(std::vector<int> line);
- std::vector<int> defragmentLine(std::vector<int> line);
- std::vector<int> mergeLine(std::vector<int> line);
-
std::vector<int> getCol(int col);
-
- bool isFull();
- bool isOver();
-
void setCol(int col, std::vector<int> colVect);
- std::vector<int> reverseLine(std::vector<int> line);
-
- //Moves
- void swipeRight();
- void swipeLeft();
- void swipeUp();
- void swipeDown();
+ int getLastMoveScore();
};
diff --git a/src/main.cpp b/src/main.cpp
index 49c7a20..48c1766 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -25,6 +25,6 @@ int main()
//Run the game
controller.run();
-
+ //End the application
return 0;
}