diff --git a/OneLoneCoder_Snake.cpp b/OneLoneCoder_Snake.cpp new file mode 100644 index 0000000..a1095fe --- /dev/null +++ b/OneLoneCoder_Snake.cpp @@ -0,0 +1,180 @@ +/* +OneLoneCoder.com - Command Line Snake +"Give me a break, I'm on holiday..." - @Javidx9 + +Disclaimer +~~~~~~~~~~ +I don't care what you use this for. It's intended to be educational, and perhaps +to the oddly minded - a little bit of fun. Please hack this, change it and use it +in any way you see fit. BUT, you acknowledge that I am not responsible for anything +bad that happens as a result of your actions. However, if good stuff happens, I +would appreciate a shout out, or at least give the blog some publicity for me. +Cheers! + +Background +~~~~~~~~~~ +Classic Snake! Controls are Arrow keys Left & Right, eat food, grow larger, avoid self! + + +Author +~~~~~~ +Twitter: @javidx9 +Blog: www.onelonecoder.com + +Video: +~~~~~~ +https://youtu.be/e8lYLYlrGLg + +Last Updated: 24/06/2017 +*/ + +#include +#include +#include +using namespace std; + +#include + +int nScreenWidth = 120; +int nScreenHeight = 30; + +struct sSnakeSegment +{ + int x; + int y; +}; + +int main() +{ + // Create Screen Buffer + wchar_t *screen = new wchar_t[nScreenWidth*nScreenHeight]; + for (int i = 0; i < nScreenWidth*nScreenHeight; i++) screen[i] = L' '; + HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + SetConsoleActiveScreenBuffer(hConsole); + DWORD dwBytesWritten = 0; + + while(1) + { + // Reset to known state + list snake = { {60,15},{61,15},{62,15},{63,15},{64,15},{65,15},{66,15},{67,15},{68,15},{69,15} }; + int nFoodX = 30; + int nFoodY = 15; + int nScore = 0; + int nSnakeDirection = 3; + bool bDead = false; + bool bKeyLeft = false, bKeyRight = false, bKeyLeftOld = false, bKeyRightOld = false; + + while (!bDead) + { + // Frame Timing, compensate for aspect ratio of command line + auto t1 = chrono::system_clock::now(); + while ((chrono::system_clock::now() - t1) < ((nSnakeDirection % 2 == 1) ? 120ms : 200ms)) + { + // Get Input, + bKeyRight = (0x8000 & GetAsyncKeyState((unsigned char)('\x27'))) != 0; + bKeyLeft = (0x8000 & GetAsyncKeyState((unsigned char)('\x25'))) != 0; + + if (bKeyRight && !bKeyRightOld) + { + nSnakeDirection++; + if (nSnakeDirection == 4) nSnakeDirection = 0; + } + + if (bKeyLeft && !bKeyLeftOld) + { + nSnakeDirection--; + if (nSnakeDirection == -1) nSnakeDirection = 3; + } + + bKeyRightOld = bKeyRight; + bKeyLeftOld = bKeyLeft; + } + + // ==== Logic + + // Update Snake Position, place a new head at the front of the list in + // the right direction + switch (nSnakeDirection) + { + case 0: // UP + snake.push_front({ snake.front().x, snake.front().y - 1 }); + break; + case 1: // RIGHT + snake.push_front({ snake.front().x + 1, snake.front().y }); + break; + case 2: // DOWN + snake.push_front({ snake.front().x, snake.front().y + 1 }); + break; + case 3: // LEFT + snake.push_front({ snake.front().x - 1, snake.front().y }); + break; + } + + // Collision Detect Snake V Food + if (snake.front().x == nFoodX && snake.front().y == nFoodY) + { + nScore++; + while (screen[nFoodY * nScreenWidth + nFoodX] != L' ') + { + nFoodX = rand() % nScreenWidth; + nFoodY = (rand() % (nScreenHeight-3))+3; + } + + for (int i = 0; i < 5; i++) + snake.push_back({ snake.back().x, snake.back().y }); + } + + // Collision Detect Snake V World + if (snake.front().x < 0 || snake.front().x >= nScreenWidth) + bDead = true; + if (snake.front().y < 3 || snake.front().y >= nScreenHeight) + bDead = true; + + // Collision Detect Snake V Snake + for (list::iterator i = snake.begin(); i != snake.end(); i++) + if (i != snake.begin() && i->x == snake.front().x && i->y == snake.front().y) + bDead = true; + + // Chop off Snakes tail :-/ + snake.pop_back(); + + // ==== Presentation + + // Clear Screen + for (int i = 0; i < nScreenWidth*nScreenHeight; i++) screen[i] = L' '; + + // Draw Stats & Border + for (int i = 0; i < nScreenWidth; i++) + { + screen[i] = L'='; + screen[2 * nScreenWidth + i] = L'='; + } + wsprintf(&screen[nScreenWidth + 5], L"www.OneLoneCoder.com - S N A K E ! ! SCORE: %d", nScore); + + + // Draw Snake Body + for (auto s : snake) + screen[s.y * nScreenWidth + s.x] = bDead ? L'+' : L'O'; + + // Draw Snake Head + screen[snake.front().y * nScreenWidth + snake.front().x] = bDead ? L'X' : L'@'; + + // Draw Food + screen[nFoodY * nScreenWidth + nFoodX] = L'%'; + + if (bDead) + wsprintf(&screen[15 * nScreenWidth + 40], L" PRESS 'SPACE' TO PLAY AGAIN "); + + // Display Frame + WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten); + } + + // Wait for space + while ((0x8000 & GetAsyncKeyState((unsigned char)('\x20'))) == 0); + } + + return 0; +} + + +