Simple Console Snake game C++Sprite animation handlerSnake console gameSnake-like console gameSnake game for Windows consoleSimple console snake game in PythonSimple console Snake game following GRASPSimple Snake GameConsole Based Snake GameSnake game for Windows text consoleConsole snake game in C#
How to make healing in an exploration game interesting
What is Thermal Runaway Protection?
What is a good source for large tables on the properties of water?
Co-worker team leader wants to inject his friend's awful software into our development. What should I say to our common boss?
Why do Australian milk farmers need to protest supermarkets' milk price?
Making a sword in the stone, in a medieval world without magic
An Accountant Seeks the Help of a Mathematician
Why are the outputs of printf and std::cout different
How to answer questions about my characters?
Brexit - No Deal Rejection
Is having access to past exams cheating and, if yes, could it be proven just by a good grade?
Sword in the Stone story where the sword was held in place by electromagnets
Employee lack of ownership
Does this AnyDice function accurately calculate the number of ogres you make unconcious with three 4th-level castings of Sleep?
Ban on all campaign finance?
Identifying the interval from A♭ to D♯
Instead of Universal Basic Income, why not Universal Basic NEEDS?
Check this translation of Amores 1.3.26
Do I need life insurance if I can cover my own funeral costs?
Provisioning profile doesn't include the application-identifier and keychain-access-groups entitlements
How to deal with a cynical class?
Informing my boss about remarks from a nasty colleague
SQL Server Primary Login Restrictions
Bastion server: use TCP forwarding VS placing private key on server
Simple Console Snake game C++
Sprite animation handlerSnake console gameSnake-like console gameSnake game for Windows consoleSimple console snake game in PythonSimple console Snake game following GRASPSimple Snake GameConsole Based Snake GameSnake game for Windows text consoleConsole snake game in C#
$begingroup$
I recently started learning C++ and have made a very simple Console-based Snake Game, I would like to have some feedback on improvements.
You might notice the obvious delay in clearing and printing of the screen, as I did not use system("cls") since it was stated as 'evil' and 'bad'.
I printed a bunch of newlines instead as suggested in a forum that I had read.
(Didn't use NCurses since it was an overkill for my simple snake game)
#include <iostream>
#include <string>
#include <limits>
#include <conio.h>
#include <thread>
#include <chrono>
enum Direction2D
UNDEFINED = 0,
LEFT,
RIGHT,
UP,
DOWN
;
bool IsOppositeOf(const Direction2D& first, const Direction2D& second)
// Feedback for a more elegant approach, thanks.
bool isOpposite = false;
if (first == LEFT && second == RIGHT)
isOpposite = true;
else if (first == RIGHT && second == LEFT)
isOpposite = true;
else if (first == UP && second == DOWN)
isOpposite = true;
else if (first == DOWN && second == UP)
isOpposite = true;
return isOpposite;
struct Vector2D
int x;
int y;
;
// Since we are printing downwards, 'up' would technically be down.
Vector2D const Up = 0, -1 ;
Vector2D const Down = 0, 1 ;
Vector2D const Left = -1, 0 ;
Vector2D const Right = 1, 0 ;
Vector2D const Zero = 0, 0 ;
#pragma region Vector2D_Operators
bool operator ==(const Vector2D& first, const Vector2D& second)
return (first.x == second.x) && (first.y == second.y);
Vector2D operator +(const Vector2D& first, const Vector2D& second)
return (first.x + second.x), (first.y + second.y) ;
Vector2D operator -(const Vector2D& first, const Vector2D& second)
return (first.x - second.x), (first.y - second.y) ;
#pragma endregion
bool gameOver;
int playerScore;
int width;
int height;
Vector2D snakeHeadPosition;
Vector2D currentFruitPosition;
Direction2D currentSnakeMovingDirection;
// I'm assuming the length of the tail doesn't go beyond 256.
// Accepting feedback on how I could do this more elegantly.
Vector2D tailPositions[256];
int tailLength;
#pragma region Util
void ClearCinInput()
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
template <typename T>
void RequestForValidInputValue(T &receivingArg, std::string errorMsg)
// Ask for input while the input is not of the correct type.
while (!(std::cin >> receivingArg))
std::cout << errorMsg << std::endl;
ClearCinInput();
#pragma region Request_For_YesNo
void PrintRespectiveYesNoTextByFirstRun(bool firstRun)
if (firstRun)
std::cout << "(Y/N)" << std::endl;
else
std::cout << "Please input either 'Y' or 'N'." << std::endl;
bool CheckIfValidYesNoInput(std::string input) input == "N");
bool AskUserForYesNo()
std::string userInput = "";
bool loopFirstRun = true;
// Ask for input again while the input was not a confirmation.
do
PrintRespectiveYesNoTextByFirstRun(loopFirstRun);
RequestForValidInputValue(userInput, "ERROR: Please input 'Y' or 'N' ");
loopFirstRun = false;
while (!CheckIfValidYesNoInput(userInput));
return userInput == "Y";
#pragma endregion
void ClearScreen()
// SLOW
std::cout << std::string(100, 'n');
void PlaceFruitRandomlyInPlayingField()
currentFruitPosition = rand() % width, rand() % height ;
#pragma endregion
void HandleFruitEating()
++tailLength;
++playerScore;
PlaceFruitRandomlyInPlayingField();
bool SnakeEatingFruit()
return snakeHeadPosition == currentFruitPosition;
bool SnakeHeadTouchedTail()
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == snakeHeadPosition)
touchedTail = true;
break;
return touchedTail;
bool SnakeHeadTouchedBorder() x < 0
void UpdateSnakePositionByCurrentMoveDirection()
switch (currentSnakeMovingDirection)
case LEFT:
snakeHeadPosition = snakeHeadPosition + Left;
break;
case RIGHT:
snakeHeadPosition = snakeHeadPosition + Right;
break;
case UP:
snakeHeadPosition = snakeHeadPosition + Up;
break;
case DOWN:
snakeHeadPosition = snakeHeadPosition + Down;
break;
default:
break;
void UpdateSnakeTailPositions()
Vector2D prevPosition = tailPositions[0];
Vector2D temp;
tailPositions[0] = snakeHeadPosition;
for (int i = 1; i < tailLength; ++i)
temp = tailPositions[i];
tailPositions[i] = prevPosition;
prevPosition = temp;
void UpdateGameLogic()
#pragma region Handling_Inputs
void MoveSnakeIfValid(Direction2D newDirection)
if (tailLength > 0)
// To prevent suicidal acts by moving backwards into a tail.
if (!IsOppositeOf(newDirection, currentSnakeMovingDirection))
currentSnakeMovingDirection = newDirection;
else
currentSnakeMovingDirection = newDirection;
void MoveSnakeByUserInput(char inputValue)
Direction2D newMoveDirection;
switch (inputValue)
case 'a':
newMoveDirection = LEFT;
break;
case 'd':
newMoveDirection = RIGHT;
break;
case 'w':
newMoveDirection = UP;
break;
case 's':
newMoveDirection = DOWN;
break;
default:
newMoveDirection = UNDEFINED;
break;
if (newMoveDirection != UNDEFINED)
MoveSnakeIfValid(newMoveDirection);
bool GetKeyPressInputIfExists(char &keyPressValue)
if (_kbhit())
keyPressValue = _getch();
return true;
else
return false;
#pragma endregion
void HandleInput()
char keyPressValue;
if (GetKeyPressInputIfExists(keyPressValue))
MoveSnakeByUserInput(keyPressValue);
#pragma region Drawing_PlayField
bool PrintTailOnPositionIfNeeded(Vector2D position)
bool tailPrinted = false;
for (int i = 0; i < tailLength; ++i)
if (position == tailPositions[i])
std::cout << "o";
tailPrinted = true;
break;
return tailPrinted;
void PrintFruitOrSnakeOrEmptyByPosition(Vector2D position)
if (snakeHeadPosition == position)
std::cout << "O";
else if (currentFruitPosition == position)
std::cout << "X";
else if (!PrintTailOnPositionIfNeeded(position))
std::cout << " ";
void DrawHorizontalBorderByWidth()
for (int i = 0; i < width + 2; ++i)
std::cout << "#";
std::cout << std::endl;
void DrawMiddleSection()
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
if (j == 0)
std::cout << "#";
PrintFruitOrSnakeOrEmptyByPosition( j, i );
if (j == width - 1)
std::cout << "#";
std::cout << std::endl;
#pragma endregion
void DrawPlayingField()
// system("cls");
ClearScreen();
// Top
DrawHorizontalBorderByWidth();
DrawMiddleSection();
// Bottom
DrawHorizontalBorderByWidth();
void UpdateGame()
DrawPlayingField();
HandleInput();
UpdateGameLogic();
#pragma region Request_PlayField_Width_And_Height_From_User
#pragma region Request_For_Valid_Play_Field_Size
bool PlayingFieldSizeIsValid()
return (width >= 10) && (height >= 10);
void RequestForValidPlayingFieldSize()
bool loopFirstRun = true;
// Keep asking for width and height while the given playing field is not of valid size.
do
if (!loopFirstRun)
std::cout << "The width and height of the playing field must be at least 10 or more!";
std::cout << "Enter the gamearea's width: " << std::endl;
RequestForValidInputValue(width, "ERROR: width must be an integer!");
std::cout << "Enter the gamearea's height: " << std::endl;
RequestForValidInputValue(height, "ERROR: Height must be an integer!");
loopFirstRun = false;
while (!PlayingFieldSizeIsValid());
#pragma endregion
void RequestForPlayingFieldSize()
bool confirmed = false;
do
RequestForValidPlayingFieldSize();
std::cout << "Your game area will be (" << width << ", " << height << "), Confirm?" << std::endl;
confirmed = AskUserForYesNo();
while (!confirmed);
#pragma endregion
void ClearAndInitalizeVariables()
tailLength = 0;
playerScore = 0;
gameOver = false;
currentSnakeMovingDirection = UNDEFINED;
void InitializeGame()
ClearScreen();
ClearAndInitalizeVariables();
RequestForPlayingFieldSize();
// Start in the center
snakeHeadPosition = (width / 2), (height / 2) ;
tailPositions[0] = snakeHeadPosition;
PlaceFruitRandomlyInPlayingField();
int main()
// Play the game while the user wants to play again.
do
InitializeGame();
while (!gameOver)
UpdateGame();
std::this_thread::sleep_for(std::chrono::milliseconds(400));
std::cout << "GAMEOVER, Your Score: " << playerScore << std::endl;
std::cout << "Play again? ";
while (AskUserForYesNo());
return 0;
Also, would anyone give me any directions on how to properly overload and make a += operator for Vector2D?
Currently I'm doing addition as Vector1 = Vector1 + Vector2, as I tried to do a += operator but the implementation I did had issues.
c++ game console snake-game
$endgroup$
bumped to the homepage by Community♦ 1 hour ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
$begingroup$
I recently started learning C++ and have made a very simple Console-based Snake Game, I would like to have some feedback on improvements.
You might notice the obvious delay in clearing and printing of the screen, as I did not use system("cls") since it was stated as 'evil' and 'bad'.
I printed a bunch of newlines instead as suggested in a forum that I had read.
(Didn't use NCurses since it was an overkill for my simple snake game)
#include <iostream>
#include <string>
#include <limits>
#include <conio.h>
#include <thread>
#include <chrono>
enum Direction2D
UNDEFINED = 0,
LEFT,
RIGHT,
UP,
DOWN
;
bool IsOppositeOf(const Direction2D& first, const Direction2D& second)
// Feedback for a more elegant approach, thanks.
bool isOpposite = false;
if (first == LEFT && second == RIGHT)
isOpposite = true;
else if (first == RIGHT && second == LEFT)
isOpposite = true;
else if (first == UP && second == DOWN)
isOpposite = true;
else if (first == DOWN && second == UP)
isOpposite = true;
return isOpposite;
struct Vector2D
int x;
int y;
;
// Since we are printing downwards, 'up' would technically be down.
Vector2D const Up = 0, -1 ;
Vector2D const Down = 0, 1 ;
Vector2D const Left = -1, 0 ;
Vector2D const Right = 1, 0 ;
Vector2D const Zero = 0, 0 ;
#pragma region Vector2D_Operators
bool operator ==(const Vector2D& first, const Vector2D& second)
return (first.x == second.x) && (first.y == second.y);
Vector2D operator +(const Vector2D& first, const Vector2D& second)
return (first.x + second.x), (first.y + second.y) ;
Vector2D operator -(const Vector2D& first, const Vector2D& second)
return (first.x - second.x), (first.y - second.y) ;
#pragma endregion
bool gameOver;
int playerScore;
int width;
int height;
Vector2D snakeHeadPosition;
Vector2D currentFruitPosition;
Direction2D currentSnakeMovingDirection;
// I'm assuming the length of the tail doesn't go beyond 256.
// Accepting feedback on how I could do this more elegantly.
Vector2D tailPositions[256];
int tailLength;
#pragma region Util
void ClearCinInput()
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
template <typename T>
void RequestForValidInputValue(T &receivingArg, std::string errorMsg)
// Ask for input while the input is not of the correct type.
while (!(std::cin >> receivingArg))
std::cout << errorMsg << std::endl;
ClearCinInput();
#pragma region Request_For_YesNo
void PrintRespectiveYesNoTextByFirstRun(bool firstRun)
if (firstRun)
std::cout << "(Y/N)" << std::endl;
else
std::cout << "Please input either 'Y' or 'N'." << std::endl;
bool CheckIfValidYesNoInput(std::string input) input == "N");
bool AskUserForYesNo()
std::string userInput = "";
bool loopFirstRun = true;
// Ask for input again while the input was not a confirmation.
do
PrintRespectiveYesNoTextByFirstRun(loopFirstRun);
RequestForValidInputValue(userInput, "ERROR: Please input 'Y' or 'N' ");
loopFirstRun = false;
while (!CheckIfValidYesNoInput(userInput));
return userInput == "Y";
#pragma endregion
void ClearScreen()
// SLOW
std::cout << std::string(100, 'n');
void PlaceFruitRandomlyInPlayingField()
currentFruitPosition = rand() % width, rand() % height ;
#pragma endregion
void HandleFruitEating()
++tailLength;
++playerScore;
PlaceFruitRandomlyInPlayingField();
bool SnakeEatingFruit()
return snakeHeadPosition == currentFruitPosition;
bool SnakeHeadTouchedTail()
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == snakeHeadPosition)
touchedTail = true;
break;
return touchedTail;
bool SnakeHeadTouchedBorder() x < 0
void UpdateSnakePositionByCurrentMoveDirection()
switch (currentSnakeMovingDirection)
case LEFT:
snakeHeadPosition = snakeHeadPosition + Left;
break;
case RIGHT:
snakeHeadPosition = snakeHeadPosition + Right;
break;
case UP:
snakeHeadPosition = snakeHeadPosition + Up;
break;
case DOWN:
snakeHeadPosition = snakeHeadPosition + Down;
break;
default:
break;
void UpdateSnakeTailPositions()
Vector2D prevPosition = tailPositions[0];
Vector2D temp;
tailPositions[0] = snakeHeadPosition;
for (int i = 1; i < tailLength; ++i)
temp = tailPositions[i];
tailPositions[i] = prevPosition;
prevPosition = temp;
void UpdateGameLogic()
#pragma region Handling_Inputs
void MoveSnakeIfValid(Direction2D newDirection)
if (tailLength > 0)
// To prevent suicidal acts by moving backwards into a tail.
if (!IsOppositeOf(newDirection, currentSnakeMovingDirection))
currentSnakeMovingDirection = newDirection;
else
currentSnakeMovingDirection = newDirection;
void MoveSnakeByUserInput(char inputValue)
Direction2D newMoveDirection;
switch (inputValue)
case 'a':
newMoveDirection = LEFT;
break;
case 'd':
newMoveDirection = RIGHT;
break;
case 'w':
newMoveDirection = UP;
break;
case 's':
newMoveDirection = DOWN;
break;
default:
newMoveDirection = UNDEFINED;
break;
if (newMoveDirection != UNDEFINED)
MoveSnakeIfValid(newMoveDirection);
bool GetKeyPressInputIfExists(char &keyPressValue)
if (_kbhit())
keyPressValue = _getch();
return true;
else
return false;
#pragma endregion
void HandleInput()
char keyPressValue;
if (GetKeyPressInputIfExists(keyPressValue))
MoveSnakeByUserInput(keyPressValue);
#pragma region Drawing_PlayField
bool PrintTailOnPositionIfNeeded(Vector2D position)
bool tailPrinted = false;
for (int i = 0; i < tailLength; ++i)
if (position == tailPositions[i])
std::cout << "o";
tailPrinted = true;
break;
return tailPrinted;
void PrintFruitOrSnakeOrEmptyByPosition(Vector2D position)
if (snakeHeadPosition == position)
std::cout << "O";
else if (currentFruitPosition == position)
std::cout << "X";
else if (!PrintTailOnPositionIfNeeded(position))
std::cout << " ";
void DrawHorizontalBorderByWidth()
for (int i = 0; i < width + 2; ++i)
std::cout << "#";
std::cout << std::endl;
void DrawMiddleSection()
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
if (j == 0)
std::cout << "#";
PrintFruitOrSnakeOrEmptyByPosition( j, i );
if (j == width - 1)
std::cout << "#";
std::cout << std::endl;
#pragma endregion
void DrawPlayingField()
// system("cls");
ClearScreen();
// Top
DrawHorizontalBorderByWidth();
DrawMiddleSection();
// Bottom
DrawHorizontalBorderByWidth();
void UpdateGame()
DrawPlayingField();
HandleInput();
UpdateGameLogic();
#pragma region Request_PlayField_Width_And_Height_From_User
#pragma region Request_For_Valid_Play_Field_Size
bool PlayingFieldSizeIsValid()
return (width >= 10) && (height >= 10);
void RequestForValidPlayingFieldSize()
bool loopFirstRun = true;
// Keep asking for width and height while the given playing field is not of valid size.
do
if (!loopFirstRun)
std::cout << "The width and height of the playing field must be at least 10 or more!";
std::cout << "Enter the gamearea's width: " << std::endl;
RequestForValidInputValue(width, "ERROR: width must be an integer!");
std::cout << "Enter the gamearea's height: " << std::endl;
RequestForValidInputValue(height, "ERROR: Height must be an integer!");
loopFirstRun = false;
while (!PlayingFieldSizeIsValid());
#pragma endregion
void RequestForPlayingFieldSize()
bool confirmed = false;
do
RequestForValidPlayingFieldSize();
std::cout << "Your game area will be (" << width << ", " << height << "), Confirm?" << std::endl;
confirmed = AskUserForYesNo();
while (!confirmed);
#pragma endregion
void ClearAndInitalizeVariables()
tailLength = 0;
playerScore = 0;
gameOver = false;
currentSnakeMovingDirection = UNDEFINED;
void InitializeGame()
ClearScreen();
ClearAndInitalizeVariables();
RequestForPlayingFieldSize();
// Start in the center
snakeHeadPosition = (width / 2), (height / 2) ;
tailPositions[0] = snakeHeadPosition;
PlaceFruitRandomlyInPlayingField();
int main()
// Play the game while the user wants to play again.
do
InitializeGame();
while (!gameOver)
UpdateGame();
std::this_thread::sleep_for(std::chrono::milliseconds(400));
std::cout << "GAMEOVER, Your Score: " << playerScore << std::endl;
std::cout << "Play again? ";
while (AskUserForYesNo());
return 0;
Also, would anyone give me any directions on how to properly overload and make a += operator for Vector2D?
Currently I'm doing addition as Vector1 = Vector1 + Vector2, as I tried to do a += operator but the implementation I did had issues.
c++ game console snake-game
$endgroup$
bumped to the homepage by Community♦ 1 hour ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
$begingroup$
I recently started learning C++ and have made a very simple Console-based Snake Game, I would like to have some feedback on improvements.
You might notice the obvious delay in clearing and printing of the screen, as I did not use system("cls") since it was stated as 'evil' and 'bad'.
I printed a bunch of newlines instead as suggested in a forum that I had read.
(Didn't use NCurses since it was an overkill for my simple snake game)
#include <iostream>
#include <string>
#include <limits>
#include <conio.h>
#include <thread>
#include <chrono>
enum Direction2D
UNDEFINED = 0,
LEFT,
RIGHT,
UP,
DOWN
;
bool IsOppositeOf(const Direction2D& first, const Direction2D& second)
// Feedback for a more elegant approach, thanks.
bool isOpposite = false;
if (first == LEFT && second == RIGHT)
isOpposite = true;
else if (first == RIGHT && second == LEFT)
isOpposite = true;
else if (first == UP && second == DOWN)
isOpposite = true;
else if (first == DOWN && second == UP)
isOpposite = true;
return isOpposite;
struct Vector2D
int x;
int y;
;
// Since we are printing downwards, 'up' would technically be down.
Vector2D const Up = 0, -1 ;
Vector2D const Down = 0, 1 ;
Vector2D const Left = -1, 0 ;
Vector2D const Right = 1, 0 ;
Vector2D const Zero = 0, 0 ;
#pragma region Vector2D_Operators
bool operator ==(const Vector2D& first, const Vector2D& second)
return (first.x == second.x) && (first.y == second.y);
Vector2D operator +(const Vector2D& first, const Vector2D& second)
return (first.x + second.x), (first.y + second.y) ;
Vector2D operator -(const Vector2D& first, const Vector2D& second)
return (first.x - second.x), (first.y - second.y) ;
#pragma endregion
bool gameOver;
int playerScore;
int width;
int height;
Vector2D snakeHeadPosition;
Vector2D currentFruitPosition;
Direction2D currentSnakeMovingDirection;
// I'm assuming the length of the tail doesn't go beyond 256.
// Accepting feedback on how I could do this more elegantly.
Vector2D tailPositions[256];
int tailLength;
#pragma region Util
void ClearCinInput()
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
template <typename T>
void RequestForValidInputValue(T &receivingArg, std::string errorMsg)
// Ask for input while the input is not of the correct type.
while (!(std::cin >> receivingArg))
std::cout << errorMsg << std::endl;
ClearCinInput();
#pragma region Request_For_YesNo
void PrintRespectiveYesNoTextByFirstRun(bool firstRun)
if (firstRun)
std::cout << "(Y/N)" << std::endl;
else
std::cout << "Please input either 'Y' or 'N'." << std::endl;
bool CheckIfValidYesNoInput(std::string input) input == "N");
bool AskUserForYesNo()
std::string userInput = "";
bool loopFirstRun = true;
// Ask for input again while the input was not a confirmation.
do
PrintRespectiveYesNoTextByFirstRun(loopFirstRun);
RequestForValidInputValue(userInput, "ERROR: Please input 'Y' or 'N' ");
loopFirstRun = false;
while (!CheckIfValidYesNoInput(userInput));
return userInput == "Y";
#pragma endregion
void ClearScreen()
// SLOW
std::cout << std::string(100, 'n');
void PlaceFruitRandomlyInPlayingField()
currentFruitPosition = rand() % width, rand() % height ;
#pragma endregion
void HandleFruitEating()
++tailLength;
++playerScore;
PlaceFruitRandomlyInPlayingField();
bool SnakeEatingFruit()
return snakeHeadPosition == currentFruitPosition;
bool SnakeHeadTouchedTail()
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == snakeHeadPosition)
touchedTail = true;
break;
return touchedTail;
bool SnakeHeadTouchedBorder() x < 0
void UpdateSnakePositionByCurrentMoveDirection()
switch (currentSnakeMovingDirection)
case LEFT:
snakeHeadPosition = snakeHeadPosition + Left;
break;
case RIGHT:
snakeHeadPosition = snakeHeadPosition + Right;
break;
case UP:
snakeHeadPosition = snakeHeadPosition + Up;
break;
case DOWN:
snakeHeadPosition = snakeHeadPosition + Down;
break;
default:
break;
void UpdateSnakeTailPositions()
Vector2D prevPosition = tailPositions[0];
Vector2D temp;
tailPositions[0] = snakeHeadPosition;
for (int i = 1; i < tailLength; ++i)
temp = tailPositions[i];
tailPositions[i] = prevPosition;
prevPosition = temp;
void UpdateGameLogic()
#pragma region Handling_Inputs
void MoveSnakeIfValid(Direction2D newDirection)
if (tailLength > 0)
// To prevent suicidal acts by moving backwards into a tail.
if (!IsOppositeOf(newDirection, currentSnakeMovingDirection))
currentSnakeMovingDirection = newDirection;
else
currentSnakeMovingDirection = newDirection;
void MoveSnakeByUserInput(char inputValue)
Direction2D newMoveDirection;
switch (inputValue)
case 'a':
newMoveDirection = LEFT;
break;
case 'd':
newMoveDirection = RIGHT;
break;
case 'w':
newMoveDirection = UP;
break;
case 's':
newMoveDirection = DOWN;
break;
default:
newMoveDirection = UNDEFINED;
break;
if (newMoveDirection != UNDEFINED)
MoveSnakeIfValid(newMoveDirection);
bool GetKeyPressInputIfExists(char &keyPressValue)
if (_kbhit())
keyPressValue = _getch();
return true;
else
return false;
#pragma endregion
void HandleInput()
char keyPressValue;
if (GetKeyPressInputIfExists(keyPressValue))
MoveSnakeByUserInput(keyPressValue);
#pragma region Drawing_PlayField
bool PrintTailOnPositionIfNeeded(Vector2D position)
bool tailPrinted = false;
for (int i = 0; i < tailLength; ++i)
if (position == tailPositions[i])
std::cout << "o";
tailPrinted = true;
break;
return tailPrinted;
void PrintFruitOrSnakeOrEmptyByPosition(Vector2D position)
if (snakeHeadPosition == position)
std::cout << "O";
else if (currentFruitPosition == position)
std::cout << "X";
else if (!PrintTailOnPositionIfNeeded(position))
std::cout << " ";
void DrawHorizontalBorderByWidth()
for (int i = 0; i < width + 2; ++i)
std::cout << "#";
std::cout << std::endl;
void DrawMiddleSection()
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
if (j == 0)
std::cout << "#";
PrintFruitOrSnakeOrEmptyByPosition( j, i );
if (j == width - 1)
std::cout << "#";
std::cout << std::endl;
#pragma endregion
void DrawPlayingField()
// system("cls");
ClearScreen();
// Top
DrawHorizontalBorderByWidth();
DrawMiddleSection();
// Bottom
DrawHorizontalBorderByWidth();
void UpdateGame()
DrawPlayingField();
HandleInput();
UpdateGameLogic();
#pragma region Request_PlayField_Width_And_Height_From_User
#pragma region Request_For_Valid_Play_Field_Size
bool PlayingFieldSizeIsValid()
return (width >= 10) && (height >= 10);
void RequestForValidPlayingFieldSize()
bool loopFirstRun = true;
// Keep asking for width and height while the given playing field is not of valid size.
do
if (!loopFirstRun)
std::cout << "The width and height of the playing field must be at least 10 or more!";
std::cout << "Enter the gamearea's width: " << std::endl;
RequestForValidInputValue(width, "ERROR: width must be an integer!");
std::cout << "Enter the gamearea's height: " << std::endl;
RequestForValidInputValue(height, "ERROR: Height must be an integer!");
loopFirstRun = false;
while (!PlayingFieldSizeIsValid());
#pragma endregion
void RequestForPlayingFieldSize()
bool confirmed = false;
do
RequestForValidPlayingFieldSize();
std::cout << "Your game area will be (" << width << ", " << height << "), Confirm?" << std::endl;
confirmed = AskUserForYesNo();
while (!confirmed);
#pragma endregion
void ClearAndInitalizeVariables()
tailLength = 0;
playerScore = 0;
gameOver = false;
currentSnakeMovingDirection = UNDEFINED;
void InitializeGame()
ClearScreen();
ClearAndInitalizeVariables();
RequestForPlayingFieldSize();
// Start in the center
snakeHeadPosition = (width / 2), (height / 2) ;
tailPositions[0] = snakeHeadPosition;
PlaceFruitRandomlyInPlayingField();
int main()
// Play the game while the user wants to play again.
do
InitializeGame();
while (!gameOver)
UpdateGame();
std::this_thread::sleep_for(std::chrono::milliseconds(400));
std::cout << "GAMEOVER, Your Score: " << playerScore << std::endl;
std::cout << "Play again? ";
while (AskUserForYesNo());
return 0;
Also, would anyone give me any directions on how to properly overload and make a += operator for Vector2D?
Currently I'm doing addition as Vector1 = Vector1 + Vector2, as I tried to do a += operator but the implementation I did had issues.
c++ game console snake-game
$endgroup$
I recently started learning C++ and have made a very simple Console-based Snake Game, I would like to have some feedback on improvements.
You might notice the obvious delay in clearing and printing of the screen, as I did not use system("cls") since it was stated as 'evil' and 'bad'.
I printed a bunch of newlines instead as suggested in a forum that I had read.
(Didn't use NCurses since it was an overkill for my simple snake game)
#include <iostream>
#include <string>
#include <limits>
#include <conio.h>
#include <thread>
#include <chrono>
enum Direction2D
UNDEFINED = 0,
LEFT,
RIGHT,
UP,
DOWN
;
bool IsOppositeOf(const Direction2D& first, const Direction2D& second)
// Feedback for a more elegant approach, thanks.
bool isOpposite = false;
if (first == LEFT && second == RIGHT)
isOpposite = true;
else if (first == RIGHT && second == LEFT)
isOpposite = true;
else if (first == UP && second == DOWN)
isOpposite = true;
else if (first == DOWN && second == UP)
isOpposite = true;
return isOpposite;
struct Vector2D
int x;
int y;
;
// Since we are printing downwards, 'up' would technically be down.
Vector2D const Up = 0, -1 ;
Vector2D const Down = 0, 1 ;
Vector2D const Left = -1, 0 ;
Vector2D const Right = 1, 0 ;
Vector2D const Zero = 0, 0 ;
#pragma region Vector2D_Operators
bool operator ==(const Vector2D& first, const Vector2D& second)
return (first.x == second.x) && (first.y == second.y);
Vector2D operator +(const Vector2D& first, const Vector2D& second)
return (first.x + second.x), (first.y + second.y) ;
Vector2D operator -(const Vector2D& first, const Vector2D& second)
return (first.x - second.x), (first.y - second.y) ;
#pragma endregion
bool gameOver;
int playerScore;
int width;
int height;
Vector2D snakeHeadPosition;
Vector2D currentFruitPosition;
Direction2D currentSnakeMovingDirection;
// I'm assuming the length of the tail doesn't go beyond 256.
// Accepting feedback on how I could do this more elegantly.
Vector2D tailPositions[256];
int tailLength;
#pragma region Util
void ClearCinInput()
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
template <typename T>
void RequestForValidInputValue(T &receivingArg, std::string errorMsg)
// Ask for input while the input is not of the correct type.
while (!(std::cin >> receivingArg))
std::cout << errorMsg << std::endl;
ClearCinInput();
#pragma region Request_For_YesNo
void PrintRespectiveYesNoTextByFirstRun(bool firstRun)
if (firstRun)
std::cout << "(Y/N)" << std::endl;
else
std::cout << "Please input either 'Y' or 'N'." << std::endl;
bool CheckIfValidYesNoInput(std::string input) input == "N");
bool AskUserForYesNo()
std::string userInput = "";
bool loopFirstRun = true;
// Ask for input again while the input was not a confirmation.
do
PrintRespectiveYesNoTextByFirstRun(loopFirstRun);
RequestForValidInputValue(userInput, "ERROR: Please input 'Y' or 'N' ");
loopFirstRun = false;
while (!CheckIfValidYesNoInput(userInput));
return userInput == "Y";
#pragma endregion
void ClearScreen()
// SLOW
std::cout << std::string(100, 'n');
void PlaceFruitRandomlyInPlayingField()
currentFruitPosition = rand() % width, rand() % height ;
#pragma endregion
void HandleFruitEating()
++tailLength;
++playerScore;
PlaceFruitRandomlyInPlayingField();
bool SnakeEatingFruit()
return snakeHeadPosition == currentFruitPosition;
bool SnakeHeadTouchedTail()
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == snakeHeadPosition)
touchedTail = true;
break;
return touchedTail;
bool SnakeHeadTouchedBorder() x < 0
void UpdateSnakePositionByCurrentMoveDirection()
switch (currentSnakeMovingDirection)
case LEFT:
snakeHeadPosition = snakeHeadPosition + Left;
break;
case RIGHT:
snakeHeadPosition = snakeHeadPosition + Right;
break;
case UP:
snakeHeadPosition = snakeHeadPosition + Up;
break;
case DOWN:
snakeHeadPosition = snakeHeadPosition + Down;
break;
default:
break;
void UpdateSnakeTailPositions()
Vector2D prevPosition = tailPositions[0];
Vector2D temp;
tailPositions[0] = snakeHeadPosition;
for (int i = 1; i < tailLength; ++i)
temp = tailPositions[i];
tailPositions[i] = prevPosition;
prevPosition = temp;
void UpdateGameLogic()
#pragma region Handling_Inputs
void MoveSnakeIfValid(Direction2D newDirection)
if (tailLength > 0)
// To prevent suicidal acts by moving backwards into a tail.
if (!IsOppositeOf(newDirection, currentSnakeMovingDirection))
currentSnakeMovingDirection = newDirection;
else
currentSnakeMovingDirection = newDirection;
void MoveSnakeByUserInput(char inputValue)
Direction2D newMoveDirection;
switch (inputValue)
case 'a':
newMoveDirection = LEFT;
break;
case 'd':
newMoveDirection = RIGHT;
break;
case 'w':
newMoveDirection = UP;
break;
case 's':
newMoveDirection = DOWN;
break;
default:
newMoveDirection = UNDEFINED;
break;
if (newMoveDirection != UNDEFINED)
MoveSnakeIfValid(newMoveDirection);
bool GetKeyPressInputIfExists(char &keyPressValue)
if (_kbhit())
keyPressValue = _getch();
return true;
else
return false;
#pragma endregion
void HandleInput()
char keyPressValue;
if (GetKeyPressInputIfExists(keyPressValue))
MoveSnakeByUserInput(keyPressValue);
#pragma region Drawing_PlayField
bool PrintTailOnPositionIfNeeded(Vector2D position)
bool tailPrinted = false;
for (int i = 0; i < tailLength; ++i)
if (position == tailPositions[i])
std::cout << "o";
tailPrinted = true;
break;
return tailPrinted;
void PrintFruitOrSnakeOrEmptyByPosition(Vector2D position)
if (snakeHeadPosition == position)
std::cout << "O";
else if (currentFruitPosition == position)
std::cout << "X";
else if (!PrintTailOnPositionIfNeeded(position))
std::cout << " ";
void DrawHorizontalBorderByWidth()
for (int i = 0; i < width + 2; ++i)
std::cout << "#";
std::cout << std::endl;
void DrawMiddleSection()
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
if (j == 0)
std::cout << "#";
PrintFruitOrSnakeOrEmptyByPosition( j, i );
if (j == width - 1)
std::cout << "#";
std::cout << std::endl;
#pragma endregion
void DrawPlayingField()
// system("cls");
ClearScreen();
// Top
DrawHorizontalBorderByWidth();
DrawMiddleSection();
// Bottom
DrawHorizontalBorderByWidth();
void UpdateGame()
DrawPlayingField();
HandleInput();
UpdateGameLogic();
#pragma region Request_PlayField_Width_And_Height_From_User
#pragma region Request_For_Valid_Play_Field_Size
bool PlayingFieldSizeIsValid()
return (width >= 10) && (height >= 10);
void RequestForValidPlayingFieldSize()
bool loopFirstRun = true;
// Keep asking for width and height while the given playing field is not of valid size.
do
if (!loopFirstRun)
std::cout << "The width and height of the playing field must be at least 10 or more!";
std::cout << "Enter the gamearea's width: " << std::endl;
RequestForValidInputValue(width, "ERROR: width must be an integer!");
std::cout << "Enter the gamearea's height: " << std::endl;
RequestForValidInputValue(height, "ERROR: Height must be an integer!");
loopFirstRun = false;
while (!PlayingFieldSizeIsValid());
#pragma endregion
void RequestForPlayingFieldSize()
bool confirmed = false;
do
RequestForValidPlayingFieldSize();
std::cout << "Your game area will be (" << width << ", " << height << "), Confirm?" << std::endl;
confirmed = AskUserForYesNo();
while (!confirmed);
#pragma endregion
void ClearAndInitalizeVariables()
tailLength = 0;
playerScore = 0;
gameOver = false;
currentSnakeMovingDirection = UNDEFINED;
void InitializeGame()
ClearScreen();
ClearAndInitalizeVariables();
RequestForPlayingFieldSize();
// Start in the center
snakeHeadPosition = (width / 2), (height / 2) ;
tailPositions[0] = snakeHeadPosition;
PlaceFruitRandomlyInPlayingField();
int main()
// Play the game while the user wants to play again.
do
InitializeGame();
while (!gameOver)
UpdateGame();
std::this_thread::sleep_for(std::chrono::milliseconds(400));
std::cout << "GAMEOVER, Your Score: " << playerScore << std::endl;
std::cout << "Play again? ";
while (AskUserForYesNo());
return 0;
Also, would anyone give me any directions on how to properly overload and make a += operator for Vector2D?
Currently I'm doing addition as Vector1 = Vector1 + Vector2, as I tried to do a += operator but the implementation I did had issues.
c++ game console snake-game
c++ game console snake-game
asked Feb 12 at 18:56
KaynnKaynn
1438
1438
bumped to the homepage by Community♦ 1 hour ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
bumped to the homepage by Community♦ 1 hour ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Small Bug Fix
Noticed a small bug in my game, where the fruit might have a chance to spawn inside the snake.
Did a quick fix for it:
Renamed PlaceFruitRandomlyInPlayingField into PlaceFruitInPlayingField, added and changed codes:
bool ValidPositionForFruit(Vector2D position)
bool isValidPosForFruit = true;
if (position == snakeHeadPosition)
isValidPosForFruit = false;
else if (PositionIsTouchingTail(position))
isValidPosForFruit = false;
return isValidPosForFruit;
void PlaceFruitInPlayingField()
// Change the fruit position while the fruit's current position is not valid.
do
currentFruitPosition = rand() % width, rand() % height ;
while (!ValidPositionForFruit(currentFruitPosition));
Finally, I renamed and refactored SnakeHeadTouchedTail into PositionIsTouchingTail(Vector2D) since my I do need to check if my new fruit's position would touch the head, and I didn't want to repeat myself:
bool PositionIsTouchingTail(Vector2D position)
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == position)
touchedTail = true;
break;
return touchedTail;
And I placed inside the #pragma region Util since C++ is picky about function placements.
(The region should be near the top)
Also, in UpdateGameLogic() function, as you might have guessed, I'm doing PositionIsTouchingTail(snakeHeadPosition) instead of SnakeHeadTouchedTail() to check if the snake's head had touched the tail.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213324%2fsimple-console-snake-game-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Small Bug Fix
Noticed a small bug in my game, where the fruit might have a chance to spawn inside the snake.
Did a quick fix for it:
Renamed PlaceFruitRandomlyInPlayingField into PlaceFruitInPlayingField, added and changed codes:
bool ValidPositionForFruit(Vector2D position)
bool isValidPosForFruit = true;
if (position == snakeHeadPosition)
isValidPosForFruit = false;
else if (PositionIsTouchingTail(position))
isValidPosForFruit = false;
return isValidPosForFruit;
void PlaceFruitInPlayingField()
// Change the fruit position while the fruit's current position is not valid.
do
currentFruitPosition = rand() % width, rand() % height ;
while (!ValidPositionForFruit(currentFruitPosition));
Finally, I renamed and refactored SnakeHeadTouchedTail into PositionIsTouchingTail(Vector2D) since my I do need to check if my new fruit's position would touch the head, and I didn't want to repeat myself:
bool PositionIsTouchingTail(Vector2D position)
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == position)
touchedTail = true;
break;
return touchedTail;
And I placed inside the #pragma region Util since C++ is picky about function placements.
(The region should be near the top)
Also, in UpdateGameLogic() function, as you might have guessed, I'm doing PositionIsTouchingTail(snakeHeadPosition) instead of SnakeHeadTouchedTail() to check if the snake's head had touched the tail.
$endgroup$
add a comment |
$begingroup$
Small Bug Fix
Noticed a small bug in my game, where the fruit might have a chance to spawn inside the snake.
Did a quick fix for it:
Renamed PlaceFruitRandomlyInPlayingField into PlaceFruitInPlayingField, added and changed codes:
bool ValidPositionForFruit(Vector2D position)
bool isValidPosForFruit = true;
if (position == snakeHeadPosition)
isValidPosForFruit = false;
else if (PositionIsTouchingTail(position))
isValidPosForFruit = false;
return isValidPosForFruit;
void PlaceFruitInPlayingField()
// Change the fruit position while the fruit's current position is not valid.
do
currentFruitPosition = rand() % width, rand() % height ;
while (!ValidPositionForFruit(currentFruitPosition));
Finally, I renamed and refactored SnakeHeadTouchedTail into PositionIsTouchingTail(Vector2D) since my I do need to check if my new fruit's position would touch the head, and I didn't want to repeat myself:
bool PositionIsTouchingTail(Vector2D position)
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == position)
touchedTail = true;
break;
return touchedTail;
And I placed inside the #pragma region Util since C++ is picky about function placements.
(The region should be near the top)
Also, in UpdateGameLogic() function, as you might have guessed, I'm doing PositionIsTouchingTail(snakeHeadPosition) instead of SnakeHeadTouchedTail() to check if the snake's head had touched the tail.
$endgroup$
add a comment |
$begingroup$
Small Bug Fix
Noticed a small bug in my game, where the fruit might have a chance to spawn inside the snake.
Did a quick fix for it:
Renamed PlaceFruitRandomlyInPlayingField into PlaceFruitInPlayingField, added and changed codes:
bool ValidPositionForFruit(Vector2D position)
bool isValidPosForFruit = true;
if (position == snakeHeadPosition)
isValidPosForFruit = false;
else if (PositionIsTouchingTail(position))
isValidPosForFruit = false;
return isValidPosForFruit;
void PlaceFruitInPlayingField()
// Change the fruit position while the fruit's current position is not valid.
do
currentFruitPosition = rand() % width, rand() % height ;
while (!ValidPositionForFruit(currentFruitPosition));
Finally, I renamed and refactored SnakeHeadTouchedTail into PositionIsTouchingTail(Vector2D) since my I do need to check if my new fruit's position would touch the head, and I didn't want to repeat myself:
bool PositionIsTouchingTail(Vector2D position)
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == position)
touchedTail = true;
break;
return touchedTail;
And I placed inside the #pragma region Util since C++ is picky about function placements.
(The region should be near the top)
Also, in UpdateGameLogic() function, as you might have guessed, I'm doing PositionIsTouchingTail(snakeHeadPosition) instead of SnakeHeadTouchedTail() to check if the snake's head had touched the tail.
$endgroup$
Small Bug Fix
Noticed a small bug in my game, where the fruit might have a chance to spawn inside the snake.
Did a quick fix for it:
Renamed PlaceFruitRandomlyInPlayingField into PlaceFruitInPlayingField, added and changed codes:
bool ValidPositionForFruit(Vector2D position)
bool isValidPosForFruit = true;
if (position == snakeHeadPosition)
isValidPosForFruit = false;
else if (PositionIsTouchingTail(position))
isValidPosForFruit = false;
return isValidPosForFruit;
void PlaceFruitInPlayingField()
// Change the fruit position while the fruit's current position is not valid.
do
currentFruitPosition = rand() % width, rand() % height ;
while (!ValidPositionForFruit(currentFruitPosition));
Finally, I renamed and refactored SnakeHeadTouchedTail into PositionIsTouchingTail(Vector2D) since my I do need to check if my new fruit's position would touch the head, and I didn't want to repeat myself:
bool PositionIsTouchingTail(Vector2D position)
bool touchedTail = false;
for (int i = 0; i < tailLength; ++i)
if (tailPositions[i] == position)
touchedTail = true;
break;
return touchedTail;
And I placed inside the #pragma region Util since C++ is picky about function placements.
(The region should be near the top)
Also, in UpdateGameLogic() function, as you might have guessed, I'm doing PositionIsTouchingTail(snakeHeadPosition) instead of SnakeHeadTouchedTail() to check if the snake's head had touched the tail.
answered Feb 12 at 19:26
KaynnKaynn
1438
1438
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213324%2fsimple-console-snake-game-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown