1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00
sortix--sortix/games/snake.cpp

227 lines
5.3 KiB
C++
Raw Normal View History

/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
snake.cpp
Single-player snake.
*******************************************************************************/
2011-09-07 06:20:28 -04:00
#include <libmaxsi/platform.h>
#include <libmaxsi/sortix-vga.h>
#include <sys/keycodes.h>
#include <sys/termmode.h>
#include <stdio.h>
2011-11-10 06:27:31 -05:00
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <error.h>
#include <string.h>
2011-09-07 06:20:28 -04:00
const int width = 80;
const int height = 25;
const int buffersize = height * width;
int vgafd;
uint16_t frame[width*height];
2011-09-07 06:20:28 -04:00
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);
const int defaultspeed = 75;
const int speedincrease = -5;
const int maxspeed = 40;
volatile int speed;
bool tabhack = false;
2011-09-07 06:20:28 -04:00
void Clear()
{
// Reset the game data.
for ( int i = 0; i < buffersize; i++ ) { frame[i] = ' '; direction[i] = -1; }
2011-09-07 06:20:28 -04:00
}
void Reset()
{
Clear();
tailx = posx = width/2;
taily = posy = height/2;
2011-11-10 06:27:31 -05:00
switch ( rand() % 4 )
2011-09-07 06:20:28 -04:00
{
case 0: velx = -1; vely = 0; break;
case 1: velx = 1; vely = 0; break;
2011-09-07 06:20:28 -04:00
case 2: velx = 0; vely = -1; break;
case 3: velx = 0; vely = -1; break;
}
animalx = 2 + (rand() % (width-4));
animaly = 2 + (rand() % (height-4));
2011-09-07 06:20:28 -04:00
taillen = 0;
tailmax = 3;
frame[animaly * width + animalx] = animal;
speed = defaultspeed;
2011-09-07 06:20:28 -04:00
}
bool FlushVGA()
2011-09-07 06:20:28 -04:00
{
2012-03-24 10:34:30 -04:00
return writeall(vgafd, frame, sizeof(frame)) < sizeof(frame);
}
2011-09-07 06:20:28 -04:00
int Init()
{
vgafd = open("/dev/vga", O_RDWR);
if ( vgafd < 0 ) { error(0, errno, "unable to open vga device /dev/vga"); return 1; }
2011-09-07 06:20:28 -04:00
Reset();
return 0;
}
bool tabhacking = false;
2011-09-07 06:20:28 -04:00
void Update()
{
int newvelx = velx;
int newvely = vely;
// Read the keyboard input from the user.
unsigned termmode = TERMMODE_KBKEY
| TERMMODE_UNICODE
| TERMMODE_SIGNAL
| TERMMODE_NONBLOCK;
if ( settermmode(0, termmode) ) { error(1, errno, "settermmode"); }
while ( true )
2011-09-07 06:20:28 -04:00
{
uint32_t codepoint;
ssize_t numbytes = read(0, &codepoint, sizeof(codepoint));
if ( !numbytes ) { break; }
if ( numbytes < 0 ) { break; }
int kbkey = KBKEY_DECODE(codepoint);
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
if ( tabhack && abskbkey == KBKEY_TAB ) { tabhacking = (0 < kbkey); }
if ( kbkey == KBKEY_ENTER ) { Reset(); return; }
if ( kbkey == KBKEY_W ) { newvelx = 0; newvely = -1; }
if ( kbkey == KBKEY_A ) { newvelx = -1; newvely = 0; }
if ( kbkey == KBKEY_S ) { newvelx = 0; newvely = 1; }
if ( kbkey == KBKEY_D ) { newvelx = 1; newvely = 0; }
2011-09-07 06:20:28 -04:00
}
if ( tabhack && tabhacking )
{
if ( animalx == posx && posy < animaly ) { newvelx = 0; newvely = 1; }
if ( animalx == posx && posy > animaly ) { newvelx = 0; newvely = -1; }
if ( animaly == posy && posx < animalx ) { newvelx = 1; newvely = 0; }
if ( animaly == posy && posx > animalx ) { newvelx = -1; newvely = 0; }
}
2011-09-07 06:20:28 -04:00
// 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[taily * width + tailx] = ' '; taillen--;
2011-09-07 06:20:28 -04:00
switch ( direction[taily * width + tailx] )
{
case 0: tailx--; break;
case 1: tailx++; break;
2011-09-07 06:20:28 -04:00
case 2: taily--; break;
case 3: taily++; break;
}
}
// Check for collision.
if ( frame[newy * width + newx] == snake ) { Reset(); return; }
2011-09-07 06:20:28 -04:00
// Check for food.
if ( newx == animalx && newy == animaly )
{
tailmax++;
animalx = 2 + (rand() % (width-4));
animaly = 2 + (rand() % (height-4));
ASSERT(0 <= animalx && animalx < width);
ASSERT(0 <= animaly && animaly < height);
if ( maxspeed < speed ) { speed += speedincrease; }
2011-09-07 06:20:28 -04:00
}
frame[animaly * width + animalx] = animal;
2011-09-07 06:20:28 -04:00
// 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[posy * width + posx] = snake; taillen++;
2011-09-07 06:20:28 -04:00
}
int main(int argc, char* argv[])
{
for ( int i = 1; i < argc; i++ )
{
if ( strcmp("--tabhack", argv[i]) == 0 ) { tabhack = true; }
}
2011-09-07 06:20:28 -04:00
int result = Init();
if ( result != 0 ) { return result; }
// Update the game every once in a while.
2011-09-07 06:20:28 -04:00
while ( true )
{
usleep(speed * 1000);
2011-09-07 06:20:28 -04:00
Update();
FlushVGA();
2011-09-07 06:20:28 -04:00
}
return 0;
}