diff --git a/games/Makefile b/games/Makefile index e6df444d..7b0fb823 100644 --- a/games/Makefile +++ b/games/Makefile @@ -6,6 +6,7 @@ INITRDDIR:=../initrd LOCALBINARIES:=\ pong \ conway \ +snake \ BINARIES:=$(addprefix $(INITRDDIR)/,$(LOCALBINARIES)) diff --git a/games/snake.cpp b/games/snake.cpp new file mode 100644 index 00000000..d9d8059a --- /dev/null +++ b/games/snake.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include + +using namespace Maxsi; +using namespace Maxsi::Keyboard; + +const int width = 80; +const int height = 25; + +const int buffersize = height * width; + +System::VGA::Frame* frame; + +int posx; +int posy; +int velx; +int vely; +int tailx; +int taily; +int taillen; +int tailmax; +int animalx; +int animaly; + +char direction[buffersize]; + +uint16_t animal = '%' | (COLOR8_RED<<8); +uint16_t snake = ' ' | (COLOR8_GREEN<<12); + +// HACK: Sortix has no random number generator yet! +int random_seed=1337; +int rand(int max) +{ + int tmpmax=max; + random_seed = random_seed + 37 * 1103515245 + 12345; + return (unsigned int) (random_seed / 65536) % tmpmax; +} + +void Clear() +{ + // Reset the game data. + for ( int i = 0; i < buffersize; i++ ) { frame->text[i] = 0; direction[i] = -1; } +} + +void Reset() +{ + Clear(); + tailx = posx = width/2; + taily = posy = height/2; + switch ( rand(4) ) + { + case 0: velx = -1; vely = 0; break; + case 1: velx = 1; vely = 0; break; + case 2: velx = 0; vely = -1; break; + case 3: velx = 0; vely = -1; break; + } + + animalx = 2 + rand(width-4); + animaly = 2 + rand(height-4); + + taillen = 0; + tailmax = 3; + + frame->text[animaly * width + animalx] = animal; +} + +int Init() +{ + // Create a VGA frame we can render onto. + frame = System::VGA::CreateFrame(); + if ( frame == NULL ) + { + Print("Could not create VGA frame\n"); + return -1; + } + + System::VGA::ChangeFrame(frame->fd); + + Reset(); + + return 0; +} + +void Update() +{ + int newvelx = velx; + int newvely = vely; + + // Read the keyboard input from the user. + unsigned method = System::Keyboard::POLL; + uint32_t codepoint; + while ( (codepoint = System::Keyboard::ReceieveKeystroke(method) ) != 0 ) + { + bool keyup = codepoint & DEPRESSED; + if ( keyup ) { continue; } + codepoint &= ~DEPRESSED; + + if ( codepoint == '\n' ) { Reset(); return; } + if ( codepoint == 'w' || codepoint == 'W' ) { newvelx = 0; newvely = -1; } + if ( codepoint == 'a' || codepoint == 'A' ) { newvelx = -1; newvely = 0; } + if ( codepoint == 's' || codepoint == 'S' ) { newvelx = 0; newvely = 1; } + if ( codepoint == 'd' || codepoint == 'D' ) { newvelx = 1; newvely = 0; } + } + + // Make sure we don't do a 180. + if ( !(velx == -1 && newvelx == 1) && + !(velx == 1 && newvelx == -1) && + !(vely == -1 && newvely == 1) && + !(vely == 1 && newvely == -1) ) + { + velx = newvelx; vely = newvely; + } + + // Don't collide with the border! + if ( posx + velx < 0 || width <= posx + velx || + posy + vely < 0 || height <= posy + vely ) { Reset(); return; } + + int newx = posx + velx; + int newy = posy + vely; + + // Move the tail, if needed. + if ( taillen == tailmax ) + { + frame->text[taily * width + tailx] = 0; taillen--; + switch ( direction[taily * width + tailx] ) + { + case 0: tailx--; break; + case 1: tailx++; break; + case 2: taily--; break; + case 3: taily++; break; + } + } + + // Check for collision. + if ( frame->text[newy * width + newx] == snake ) { Reset(); return; } + + // Check for food. + if ( newx == animalx && newy == animaly ) + { + tailmax++; + animalx = 2 + rand(width-4); + animaly = 2 + rand(height-4); + } + + frame->text[animaly * width + animalx] = animal; + + // Remember where we are going. + int dir = 0; + if ( velx < 0 ) { dir = 0; } + if ( velx > 0 ) { dir = 1; } + if ( vely < 0 ) { dir = 2; } + if ( vely > 0 ) { dir = 3; } + direction[posy * width + posx] = dir; + + // Move the head. + posx = newx; + posy = newy; + frame->text[posy * width + posx] = snake; taillen++; +} + +int main(int argc, char* argv[]) +{ + int result = Init(); + if ( result != 0 ) { return result; } + + // Update the game every 300th milisecond. + while ( true ) + { + const int sleepms = 75; + Thread::USleep(sleepms * 1000); + Update(); + } + + return 0; +}