Snake console game in C++

I reviewed this question to a snake game console implementation: My first C++ game (snake console game)

I enjoyed refactoring this code and presenting a solution using more C++ features / classes. I ended up rewriting this project from scratch.

My aim was to make the code easy and maintenable to read. Also i tried to seperate the IO with the console from the logic because maybe I want to use the logic to port the game from console to QT-GUI as another excercise later.

I wonder what can be still be improved in the code?

Is the code easy to read for you / easy to follow?

Are there any bad practices?

Things which can possible be improved:

  • Currently we are not portable. ConsoleOperations.cpp uses Windows specified header. Is there a easy way to enable linux/mac aswell?

main.cpp

#include "Game.h"  #include <iostream>  int main()  try {     snakeGame::runGame();     return 0; } catch (...) {     std::wcerr << "unknown error " << "\n";     std::wcin.get(); } 

Game.h

#pragma once  namespace snakeGame {      void runGame(); }  namespace snakeGame::impl {      class Board; // fwd delaration      bool askUserToEndGame();      void pauseUntilPauseKeyPressedAgain();      void printBoardWithStats(const Board& board, long long score, int delay);      void waitFor(int milliseconds);      void printGameOverWithScore(int score);  } 

Game.cpp

#include "Game.h"  #include "Snake.h" #include "Board.h" #include "ConsoleOperations.h" #include "SnakeDirection.h"  #include <chrono> #include <iostream> #include <thread>  namespace snakeGame {      using namespace impl;      void runGame()     {         for (;;) {              if (askUserToEndGame()) {                 return;             }              constexpr auto fieldWidth = 40;             constexpr auto fieldHeight = 15;              Board board{ fieldWidth, fieldHeight };             board.updateSnakePosition();             board.placeFood();             SnakeDirection snakeDirection = SnakeDirection::right;              long long score{ 0 };             long long points{ 100 };             auto delay(300);              bool wasPausedInLastLoop{ false };             for (;;) {                 putCursorToStartOfConsole();                 printBoardWithStats(board, score, delay);                  if (wasPausedInLastLoop) {                     // If we don't do this and print pause to the console by                      // pressing p during the game the pause statement will                      // still be printed because  during the game the pause                      // statement will still be printed because during the game                      // the pause statement will still be printed because                      // during the game the pause statement will still be                      // printed because we start printing from the beginning of                     // the console and now the total string printed to the                      // console would be one row lower.                     std::wcout << L"                                     \n";                     wasPausedInLastLoop = false;                 }                  if (keyWasPressed()) {                     auto key = getKey();                      if (key == 'p') {                         wasPausedInLastLoop = true;                         std::wcout << L"#####PAUSED#####\n";                         pauseUntilPauseKeyPressedAgain();                     }                     else {                         snakeDirection = updateDirection(key, snakeDirection);                     }                 }                  board.moveSnake(snakeDirection);                  if (board.snakeHitFood()) {                     board.eatFood();                     board.growSnake();                     board.placeFood();                     score += points;                     points *= 2;                     delay -= 5;                 }                 else if (board.snakeHitWall() || board.snakeHitSnake()) {                     break;                 }                 board.updateSnakePosition();                  std::this_thread::sleep_for(std::chrono::milliseconds{ delay });             }              printGameOverWithScore(score);         }     } }  namespace snakeGame::impl {      bool askUserToEndGame()     {         clearScreen();         while (true) {              auto choice{ 0 };             std::wcout << L"1. Play\n";             std::wcout << L"2. Quit\n";             std::wcin >> choice;              if (choice == 1) {                 return false;             }              else if (choice == 2) {                 return true;             }              else {                 std::wcout << L"Invalid input!";                 std::wcin.get();                 clearScreen();             }         }     }      void pauseUntilPauseKeyPressedAgain()     {         for (;;) {             if (keyWasPressed) {                  auto key = getKey();                  if (key == 'p') {                     return;                 }             }         }     }      void printBoardWithStats(const Board& board, long long score, int delay)     {         std::wcout << L"Score:" << score << '\n';         std::wcout << L"Delay:" << delay << "ms  \n";         std::wcout << board;         std::wcout << L"Use 'w, a, s, d' to change directions\n";     }      void waitFor(int milliseconds)     {         std::this_thread::sleep_for(std::chrono::milliseconds{ milliseconds });     }      void printGameOverWithScore(int score)     {         clearScreen();         std::wcout << L"Game over!\n";         std::wcout << L"Score: " << score << '\n';         std::wcin.clear();         std::wcin.ignore(120, '\n');         std::wcin.get();     } } 

Board.h

#pragma once  #include "Snake.h"  #include <vector> #include <random> #include <iosfwd>  namespace snakeGame::impl {      enum class SnakeDirection;      struct Element {         bool hasSnakeSegment{ false };         bool hasSnakeHead{ false };         bool hasWall{ false };         bool hasFood{ false };     };      class Board     {     public:         Board(int width, int height);          void placeFood();         void updateSnakePosition();         bool snakeHitFood() const;         void eatFood();         void growSnake();         bool snakeHitWall() const;         bool snakeHitSnake() const;         void moveSnake(SnakeDirection snakeDirection);          void debugPrintSnakeCoordinates();     private:         std::vector<std::vector<Element>> initFieldWithWalls(int width, int height);         void removeOldSnakePosition(const std::vector<SnakeSegment>& body);         void addNewSnakePosition(const std::vector<SnakeSegment>& body);          Snake mSnake;         std::vector<std::vector<Element>> mField;          std::random_device mRandomDevice;         std::default_random_engine mGenerator;         std::uniform_int_distribution<int> mWidthDistribution;         std::uniform_int_distribution<int> mHeightDistribution;          friend std::wostream& operator<<(std::wostream& os, const Board& obj);     };      std::wostream& operator<<(std::wostream& os, const Board& obj);  } 

Board.cpp

#include "Board.h"  #include "SnakeDirection.h"  #include <algorithm> #include <iostream>;  namespace snakeGame::impl {      Board::Board(int width, int height)         : mSnake{ width, height },         mField{ initFieldWithWalls(width, height) },         mRandomDevice{},         mGenerator{ mRandomDevice() },         mWidthDistribution{ 1, width - 2 },         mHeightDistribution{ 1, height - 2 }     {     }      void Board::updateSnakePosition()     {         auto snakeBody = mSnake.getBody();          removeOldSnakePosition(snakeBody);         addNewSnakePosition(snakeBody);     }      bool Board::snakeHitFood() const     {         auto pos = mSnake.getBody()[0].pos;         return mField[pos.y][pos.x].hasFood;     }      void Board::eatFood()     {         auto pos = mSnake.getBody()[0].pos;         mField[pos.y][pos.x].hasFood = false;     }      void Board::growSnake()     {         mSnake.grow();     }      bool Board::snakeHitWall() const     {         auto pos = mSnake.getBody()[0].pos;         return mField[pos.y][pos.x].hasWall;     }      bool Board::snakeHitSnake() const     {         auto pos = mSnake.getBody()[0].pos;         return mField[pos.y][pos.x].hasSnakeSegment;     }      void Board::moveSnake(SnakeDirection snakeDirection)     {         switch (snakeDirection) {         case SnakeDirection::right:             mSnake.moveRight();             break;          case SnakeDirection::down:             mSnake.moveDown();             break;          case SnakeDirection::left:             mSnake.moveLeft();             break;          case SnakeDirection::up:             mSnake.moveUp();             break;         }     }      void Board::debugPrintSnakeCoordinates()     {         auto body = mSnake.getBody();          for (auto i = 0; i < body.size(); ++i) {              auto pos = body[i].pos;              std::wcout << "nr:" << i << "x:" << pos.x << "\t" << "y:" << pos.y << "\t";              auto field = mField[pos.y][pos.x];              if (field.hasSnakeHead) {                 std::wcout << L"Head\t";             }             else {                 std::wcout << L"    \t";             }             if (field.hasSnakeSegment) {                 std::wcout << L"Body\n";             }             else {                 std::wcout << L"    \n";             }         }     }      void Board::placeFood()     {         for (;;) {             auto x = mWidthDistribution(mGenerator);             auto y = mHeightDistribution(mGenerator);              if (!mField[y][x].hasSnakeHead &&                 !mField[y][x].hasSnakeSegment) {                 mField[y][x].hasFood = true;                 break;             }         }     }      std::vector<std::vector<Element>> Board::initFieldWithWalls(int width, int height)     {         std::vector<Element> row(width, Element{});         std::vector<std::vector<Element>> field(height, row);          Element wall{ false, false, true, false };          std::fill(field[0].begin(), field[0].end(), wall);         std::fill(field[field.size() - 1].begin(), field[field.size() - 1].end(), wall);          for (auto it_row = field.begin() + 1; it_row < field.end() - 1; ++it_row) {             (*it_row)[0] = wall;             (*it_row)[it_row->size() - 1] = wall;         }         return field;     }      void Board::removeOldSnakePosition(const std::vector<SnakeSegment>& body)     {         auto first{ true };         for (const auto& snakeSegment : body) {             auto prev = snakeSegment.prev;              if (first) {                 mField[prev.y][prev.x].hasSnakeHead = false;                 first = false;             }             else {                 mField[prev.y][prev.x].hasSnakeSegment = false;             }         }     }      void Board::addNewSnakePosition(const std::vector<SnakeSegment>& body)     {         auto first{ true };         for (const auto& snakeSegment : body) {             auto pos = snakeSegment.pos;              if (first) {                 mField[pos.y][pos.x].hasSnakeHead = true;                 first = false;             }             else {                 mField[pos.y][pos.x].hasSnakeSegment = true;             }         }     }       std::wostream& operator<<(std::wostream& os, const Board& obj)     {         for (const auto& row : obj.mField) {             for (const auto& element : row) {                 if (element.hasSnakeSegment) {                     os << L'o';                 }                 else if (element.hasSnakeHead) {                     os << L'@';                 }                 else if (element.hasWall) {                     os << L'#';                 }                 else if (element.hasFood) {                     os << L'*';                 }                 else {                     os << L' ';                 }             }             os << '\n';         }         return os;     }  } 

Snake.h

#pragma once  #include "Point.h"  #include <vector>  namespace snakeGame::impl {      struct SnakeSegment     {         Point pos{ 0 , 0 };         Point prev{ pos };     };      class Snake     {     public:         Snake(int boardWidth, int boardHeight);          std::vector<SnakeSegment> getBody() const;          void moveRight();         void moveDown();         void moveLeft();         void moveUp();         void grow();      private:         void safeCurrentPosToLastOfFirstElement();         void moveRemainingElements();          std::vector<SnakeSegment> mBody;     };      std::vector<SnakeSegment> initSnake(int fieldWidth, int fieldHeight);  } 

Snake.cpp

#include "Snake.h"  namespace snakeGame::impl {      Snake::Snake(int fieldWidth, int fieldHeight)         :mBody{ initSnake(fieldWidth, fieldHeight) }     {     }      std::vector<SnakeSegment> Snake::getBody() const     {         return mBody;     }       void Snake::moveRight()     {         safeCurrentPosToLastOfFirstElement();         ++mBody[0].pos.x;         moveRemainingElements();     }      void Snake::moveDown()     {         safeCurrentPosToLastOfFirstElement();         ++mBody[0].pos.y;         moveRemainingElements();     }      void Snake::moveLeft()     {         safeCurrentPosToLastOfFirstElement();         --mBody[0].pos.x;         moveRemainingElements();     }      void Snake::moveUp()     {         safeCurrentPosToLastOfFirstElement();         --mBody[0].pos.y;         moveRemainingElements();     }      void Snake::grow()     {         SnakeSegment newTail;         newTail.pos.x = mBody[mBody.size() - 1].prev.x;         newTail.pos.y = mBody[mBody.size() - 1].prev.y;         mBody.push_back(newTail);     }      void Snake::safeCurrentPosToLastOfFirstElement()     {         mBody[0].prev.x = mBody[0].pos.x;         mBody[0].prev.y = mBody[0].pos.y;     }      void Snake::moveRemainingElements()     {         for (int i = 1; i < mBody.size(); ++i) {             mBody[i].prev.x = mBody[i].pos.x;             mBody[i].prev.y = mBody[i].pos.y;             mBody[i].pos.x = mBody[i - 1].prev.x;             mBody[i].pos.y = mBody[i - 1].prev.y;         }     }       std::vector<SnakeSegment> initSnake(int boardWidth, int boardHeight)     {         auto x = boardWidth / 2;         auto y = boardHeight / 2;         std::vector<SnakeSegment> body{             SnakeSegment{ x, y },             SnakeSegment{ x - 1, y },         };         return body;     }  } 

Point.h

#pragma once  namespace snakeGame::impl {      struct Point {         int x;         int y;     };  } 

SnakeDirection.h

#pragma once  namespace snakeGame::impl {      enum class SnakeDirection {         up, right, down, left     };  } 

ConsoleOperations.h

#pragma once  // Non portable. At the moment only windows works  namespace snakeGame::impl {      enum class SnakeDirection;      void putCursorToStartOfConsole();      void clearScreen();      bool keyWasPressed();      char getKey();      SnakeDirection updateDirection(char c, SnakeDirection direction); } 

ConsoleOperations.cpp

#include "ConsoleOperations.h"  #include "SnakeDirection.h"  #include <cstdlib>  //#ifdef _WIN32 #include <conio.h> #include <Windows.h> //#else  //  //Assume POSIX //#endif  namespace snakeGame::impl {      void putCursorToStartOfConsole()     {         //#ifdef _WIN32         HANDLE hOut;         COORD Position;          hOut = GetStdHandle(STD_OUTPUT_HANDLE);          Position.X = 0;         Position.Y = 0;         SetConsoleCursorPosition(hOut, Position);         //#else          //  //Assume POSIX         //#endif     }       void clearScreen()     {         //#ifdef _WIN32         std::system("cls");         //#else         //  // Assume POSIX         //  std::system("clear");         //#endif     }      bool keyWasPressed()     {         //#ifdef _WIN32         return static_cast<bool>(_kbhit());         //#else             // Assume POSIX         //#endif     }      char getKey()     {         //#ifdef _WIN32         return _getch();         //#else             // Assume POSIX         //#endif     }      SnakeDirection updateDirection(char c, SnakeDirection direction)     {         switch (c) {         case 'a':             if (direction != SnakeDirection::right) {                 direction = SnakeDirection::left;             }             break;          case 'w':             if (direction != SnakeDirection::down) {                 direction = SnakeDirection::up;             }             break;          case 'd':             if (direction != SnakeDirection::left) {                 direction = SnakeDirection::right;             }             break;          case 's':             if (direction != SnakeDirection::up) {                 direction = SnakeDirection::down;             }             break;         }         return direction;     }  } 

Como chamar uma função dentro de outra função em ELM?

A atividade seria: 2.10 Escrever uma função que retorne o valor de um número elevado à quarta potência. Essa função deve fazer uso de uma outra que calcula o quadrado de um número qualquer. Eu poderia simplesmente fazer :

module Fe02 exposing (..)

import Html

funcExp x = x^4

main = Html.text (String.fromFloat (funcExp 2))

e assim ele me daria como resultado através de servidor localhost: 16

Mas como a questão pede uma função chamando outra função, nesse caso como eu resolveria esse problema ?

Magento 2 : We need to save product two time After generating Custom Option programmatically?

I have work on Custom Module. In Our Module I had use

<event name="catalog_product_save_after">     <observer name="add_custom_option" instance="Namespace\Modulename\Observer\AddCustomOption" /> </event> 

In observer i Had Generate Product Custom Option Programmatically

            $  product->setHasOptions(1);             $  product->setCanSaveCustomOptions(true);             foreach ($  options as $  arrayOption) {                 $  isHasOptions = $  product->getTypeInstance()->hasOptions($  product);                   $  option = \Magento\Framework\App\ObjectManager::getInstance()                         ->create('\Magento\Catalog\Model\Product\Option')                         ->setProductId($  product->getId())                         ->setStoreId($  product->getStoreId())                         ->addData($  arrayOption);                  $  this->customoptionOperation($  option, 'save');                 $  product->addOption($  option);                 //$  product->save();             } 

i have use this code for generate Product custom Option.

//$ product->save();

i had comment this code because it provide me Error

No Such Entity

After saving Product.

Product Options are generated Successfully in Product But Not Display in Front-end

I had Run All Commands

  • setup:upgrade
  • setup:static-content:deploy -f
  • indexer:reindex
  • cache:flush

But Custom Option Not Appears in Front-end

But When i have save product second time after saving product the Options are Appears in Front-end Without need Run any Commands.

I Need Solution to save Product One time and Get Product Option Front End

Is This Possible ?

Can I use an Android only SDK in my Xamarin.Forms project targeted for Android and iOS?

I have a SDK (Zebra EMDK for Android) that only targets Android.

I’d like to use it in a xamarin.forms application using dependency injection, in order to make calls to it when I run the app on iOS devices.

However my concern is that this isn’t possible since the SDK is only referenced in the Android project and the objects part of the SDK can only be instantiated from with an Android Activity.

Am I in over my head or is it actually possible to make calls to an Android SDK from my iOS project within a xamarin.forms solution?

Sorry in advanced I’m kind of new to this.

How to fix periodic ding sound on Mac Book

An irritating ding sound keeps playing which is a kind of notification or alert with out any visual guidance to figure whats going wrong. (The situation is almost like a pilot of Boeing 747 Max who doesn’t know how to turn off anti stall system. :o) )

I found some solutions mentioned here However none worked for me.

Anyone has a clue?

How does Polymorph affect procreation?

The Polymorph spell alters the body of one willing target, changing it into a different creature- Potentially from a different type.

If someone were to breed whilst under the effect of this spell, what would the result be? Would the child be born as if the polymorphed parent were truly a member of the race they turned into? Or as if they had always been their original race?

Considering that there is no way that I know of to let a single casting of polymorph last long enough to carry a pregnancy to full term: What are the effects of a woman being imregnated whilst polymorphed, or polymorphed whilst pregnant?

Upload files with REST or alternatives

I need some help with Server to Server upload. (not from the browser)

Has anyone uploaded files to sharepoint 2013, using REST, or other methods from a server (java/coldfusion/other).

I am getting a digest value … is this available only from> subdomain.sharepoint.com/sites/site1[/_api/Web/Context]

I have tried converting files to binary and uploading as body content to :

subdomain.sharepoint.com/sites/site1/subsite2/subsite3/document library/folder/{here} [ getting: [is not valid]]

I have seen documentation that says this is the only place things can be uploaded subdomain.sharepoint.com/sites/site1/document/shared documents/{here} [is not valid]

Some of my peers tried using the rest request to copy from (subdomain.com) to (subdomain.sharepoint.com) [Connection failure] This failed; firewalls.

Is the documentation flawed? Wrong?

UK Tier 4 Student Visa – Need some guidance

My daughter recently got unconditional offer for a 3 year undergraduate from a UK university. We are all US Citizens living in CA. Her start date is Oct 7th. I have few questions regarding the Visa process and clarity on the time duration between each step of the process:

  1. The Gov.uk site says that we need to apply maximum 3 months before the start of course. We have a planned family travel starting July 25th out to another country for 4 weeks which will require us to have her passport with us. Which means we have to apply after July 7th so that by July 25th she gets her passport with student visa. Due to this time constraint, I am considering to use the San Francisco Premium application center for processing. If I buy the Bronze package, will it be enough time to get the Tier 4 (Student) visa?
  2. What is the difference in processing times between the Bronze, Silver package and the regular self-managed process? Can the visa process be expedited by myself without using any of the premium packages?
  3. The requirement to apply “3 months before the course start” is considered from the time you submit the online application OR from the time you go for an actual appointment at the SF Premium center? Meaning, can I do the online paperwork in advance, so that I get the appointment as close to July 7th?
  4. How many days of wait is usually to get the appointment either at the regular support center and the Premium support center?
  5. Is there an option to apply for the Visa without having to send the original passport so that while we are in travel, the Visa process can continue?
  6. Alternative to all this that we apply for her visa after returning from our international travel in end of August. Again, the question is if that will be enough time from start to finish?
  7. Somewhere on the UK govt site, I see an option to to ask them question via email, but it has an associated charge to ask question via email. Anyone used this service?

Thanks for your help in advance.