Skip to content

Instantly share code, notes, and snippets.

@henkman
Last active October 11, 2016 10:00
Show Gist options
  • Select an option

  • Save henkman/af791e8b28e155a18d4e87a226516c68 to your computer and use it in GitHub Desktop.

Select an option

Save henkman/af791e8b28e155a18d4e87a226516c68 to your computer and use it in GitHub Desktop.
// unixoid:
// g++ -fno-ident -Wall -std=c++11 -s -O2 -o snake snake.cc $(sdl2-config --libs)
// win:
// windres snake.rc -O coff snake.res && g++ -fno-ident -Wall -std=c++11 -s -O2 -o snake snake.cc snake.res -static $(sdl2-config --static-libs)
#include <SDL2/SDL.h>
const auto WIDTH = 320, HEIGHT = 240, BLOCK = 16;
constexpr auto MAX_SEGS = ((WIDTH / BLOCK) * (HEIGHT / BLOCK));
constexpr auto MAX_DOTS = (MAX_SEGS / 100);
template <typename T, unsigned N>
struct Array {
T v[N];
unsigned n;
inline T& operator[](unsigned i) { return v[i]; }
void del(unsigned i)
{
if (i == n - 1) {
n--;
return;
}
for (; i < (n - 1); i++) {
v[i] = v[i + 1];
}
n--;
}
};
struct Vec2 {
float x, y;
inline Vec2 operator+(Vec2 o) { return (Vec2){ x + o.x, y + o.y }; }
inline Vec2 operator*(float f) { return (Vec2){ x * f, y * f }; }
inline bool operator==(Vec2 o) { return x == o.x && y == o.y; }
};
struct Snake {
Array<Vec2, MAX_SEGS> segs;
Vec2 dir, ldir;
bool addseg;
inline void reset()
{
dir = ldir = (Vec2){ -1, 0 };
segs[0] = (Vec2){ ((WIDTH / 2) / BLOCK) * BLOCK,
((HEIGHT / 2) / BLOCK) * BLOCK };
segs.n = 1;
addseg = false;
}
inline Vec2& head() { return segs[0]; }
inline Vec2& tail() { return segs[segs.n - 1]; }
inline unsigned len() { return segs.n; }
};
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO);
auto win = SDL_CreateWindow("snake", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, 0);
auto rend = SDL_CreateRenderer(
win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
Array<Vec2, MAX_DOTS> dots;
Snake snek;
unsigned lt, ct, movt, ssegs;
SDL_Event e;
srand(SDL_GetTicks());
game:
movt = 0;
dots.n = 0;
snek.reset();
ssegs = 3;
lt = SDL_GetTicks();
for (;;) {
ct = SDL_GetTicks();
while (SDL_PollEvent(&e))
if (e.type == SDL_QUIT
|| (e.type == SDL_KEYUP
&& e.key.keysym.scancode == SDL_SCANCODE_ESCAPE))
goto end;
auto kb = SDL_GetKeyboardState(NULL);
Vec2 ndir = { 0, 0 };
if (kb[SDL_SCANCODE_UP])
ndir.y = -1;
else if (kb[SDL_SCANCODE_DOWN])
ndir.y = 1;
if (kb[SDL_SCANCODE_LEFT])
ndir.x = -1;
else if (kb[SDL_SCANCODE_RIGHT])
ndir.x = 1;
if (!(ndir.y == snek.ldir.y * -1 || ndir.x == snek.ldir.x * -1)
&& !(ndir.x && ndir.y))
snek.dir = ndir;
movt += ct - lt;
if (movt > 120) {
movt = 0;
snek.ldir = snek.dir;
if (ssegs) {
ssegs--;
snek.addseg = true;
} else {
if (dots.n < MAX_DOTS && (rand() % 6) == 0) {
Vec2 dot
= (Vec2){ (float)(rand() % (WIDTH / BLOCK) * BLOCK),
(float)(rand() % (HEIGHT / BLOCK) * BLOCK) };
bool occ = false;
for (unsigned i = 0; i < snek.len(); i++) {
if (dot == snek.segs[i]) {
occ = true;
break;
}
}
if (!occ) {
for (unsigned i = 0; i < dots.n; i++) {
if (dot == dots[i]) {
occ = true;
break;
}
}
if (!occ) {
dots[dots.n] = dot;
dots.n++;
}
}
}
}
auto nhead = snek.head() + (snek.dir * BLOCK);
if (nhead.x < 0 || nhead.x >= WIDTH || nhead.y < 0
|| nhead.y >= HEIGHT)
goto game;
Vec2 oldtail = snek.tail();
for (unsigned i = snek.len() - 1; i >= 1; --i) {
Vec2& s = snek.segs[i];
if (nhead == s)
goto game;
s = snek.segs[i - 1];
}
snek.head() = nhead;
if (!snek.addseg) {
for (unsigned i = 0; i < dots.n; i++) {
if (snek.head() == dots[i]) {
snek.addseg = true;
dots.del(i);
break;
}
}
}
if (snek.addseg) {
snek.addseg = false;
snek.segs.n++;
snek.tail() = oldtail;
}
}
SDL_SetRenderDrawColor(rend, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(rend);
SDL_Rect r[MAX_SEGS];
{
for (unsigned i = 0; i < snek.len(); i++) {
auto s = snek.segs[i];
r[i] = (SDL_Rect){ (int)s.x, (int)s.y, BLOCK, BLOCK };
}
SDL_SetRenderDrawColor(rend, 0xFF, 0x44, 0x00, 0xFF);
SDL_RenderFillRect(rend, &r[0]);
SDL_SetRenderDrawColor(rend, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderFillRects(rend, &r[1], snek.len() - 1);
}
if (dots.n) {
for (unsigned i = 0; i < dots.n; i++) {
auto d = dots[i];
r[i] = (SDL_Rect){ (int)(d.x + (BLOCK / 4)),
(int)(d.y + (BLOCK / 4)), BLOCK / 2, BLOCK / 2 };
}
SDL_SetRenderDrawColor(rend, 0xFF, 0x00, 0xFF, 0xFF);
SDL_RenderFillRects(rend, r, dots.n);
}
SDL_RenderPresent(rend);
lt = ct;
}
end:
SDL_DestroyRenderer(rend);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment