parent
cb2401e72c
commit
3c2d01859a
@ -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 <iostream> |
||||||
|
#include <list> |
||||||
|
#include <thread> |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
|
||||||
|
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<sSnakeSegment> 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<sSnakeSegment>::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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in new issue