Last active
October 11, 2016 10:00
-
-
Save henkman/af791e8b28e155a18d4e87a226516c68 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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