random

:-)
git clone read: git://git.margiolis.net/random.git
Log | Files | Refs | LICENSE

snake.cpp (2620B)


      1 #include <chrono>
      2 #include <cstdlib>
      3 #include <ctime>
      4 #include <list>
      5 #include <thread>
      6 
      7 #include <curses.h>
      8 
      9 #define XMAX (getmaxx(stdscr))
     10 #define YMAX (getmaxy(stdscr))
     11 
     12 struct Snake {
     13 	struct Seg {
     14 		int x;
     15 		int y;
     16 	};
     17 	std::list<Seg> body;
     18 	int x;
     19 	int y;
     20 	int score;
     21 	bool dead;
     22 
     23 	Snake();
     24 	void update(int key);
     25 	void grow();
     26 	void draw();
     27 	bool collided();
     28 };
     29 
     30 struct Food {
     31 	int x;
     32 	int y;
     33 
     34 	Food();
     35 	void spawn();
     36 	void draw();
     37 };
     38 
     39 Snake::Snake()
     40 {
     41 	y = YMAX >> 1;
     42 	x = XMAX >> 1;
     43 	body = {{x, y}, {x + 1, y + 1}};	
     44 	score = 1;
     45 	dead = false;
     46 }
     47 
     48 void
     49 Snake::update(int key)
     50 {
     51 	switch (key) {
     52 	case KEY_UP:
     53 		y--;
     54 		body.push_front({body.front().x, body.front().y - 1});
     55 		break;
     56 	case KEY_DOWN:
     57 		y++;
     58 		body.push_front({body.front().x, body.front().y + 1});
     59 		break;
     60 	case KEY_LEFT:
     61 		x--;
     62 		body.push_front({body.front().x - 1, body.front().y});
     63 		break;
     64 	case KEY_RIGHT:
     65 		x++;
     66 		body.push_front({body.front().x + 1, body.front().y});
     67 		break;
     68 	default:
     69 		return;
     70 	}
     71 	body.pop_back();
     72 }
     73 
     74 void
     75 Snake::grow()
     76 {
     77 	for (int i = 0; i < 3; i++)
     78 		body.push_back({body.back().x, body.back().y});
     79 }
     80 
     81 void
     82 Snake::draw()
     83 {
     84 	for (const auto& b : body)
     85 		mvaddch(b.y, b.x, ACS_CKBOARD);
     86 }
     87 
     88 bool
     89 Snake::collided()
     90 {
     91 	dead = y < 2 || y > YMAX - 1 || x < 1 || x > XMAX - 1;
     92 	for (std::list<Seg>::iterator i = body.begin(); i != body.end(); i++)
     93 		if (i != body.begin()
     94 		&&  i->x == body.front().x
     95 		&&  i->y == body.front().y)
     96 			dead = true;
     97 	return (dead);
     98 }
     99 
    100 Food::Food()
    101 {
    102 	x = std::rand() % XMAX - 1;
    103 	y = std::rand() % (YMAX - 2) + 2;
    104 }
    105 
    106 void
    107 Food::spawn()
    108 {
    109 	x = std::rand() % XMAX - 1;
    110 	y = std::rand() % (YMAX - 2) + 2;
    111 }
    112 
    113 void
    114 Food::draw()
    115 {
    116 	mvaddch(y, x, 'O');
    117 }
    118 
    119 static void
    120 initcurses()
    121 {
    122 	if (!initscr())
    123 		exit(1);
    124 	cbreak();
    125 	noecho();
    126 	curs_set(0);
    127 	keypad(stdscr, true);
    128 	nodelay(stdscr, true);
    129 }
    130 
    131 static bool
    132 kbhit()
    133 {
    134 	int c;
    135 
    136 	if ((c = getch()) != ERR) {
    137 		ungetch(c);
    138 		return (true);
    139 	}
    140 	return (false);
    141 }
    142 
    143 int
    144 main(int argc, char *argv[])
    145 {
    146 	initcurses();
    147 	std::srand(std::time(nullptr));
    148 
    149 	Snake snake;
    150 	Food food;
    151 	int key, nextkey;
    152 
    153 	key = KEY_RIGHT;
    154 
    155 	for (;;) {
    156 		erase();
    157 		if (kbhit()) {
    158 			if ((nextkey = getch()) != key)
    159 				key = nextkey;
    160 			else
    161 				continue;
    162 		}
    163 
    164 		snake.update(key);
    165 		if (snake.collided() || key == 'q')
    166 			break;
    167 
    168 		if (snake.body.front().y == food.y
    169 		&&  snake.body.front().x == food.x) {
    170 			food.spawn();
    171 			snake.grow();
    172 			snake.score++;
    173 		}
    174 
    175 		food.draw();
    176 		snake.draw();
    177 
    178 		mvprintw(0, 0, "Score: %d", snake.score);
    179 		mvhline(1, 0, ACS_HLINE, XMAX);
    180 		refresh();
    181 		std::this_thread::sleep_for(std::chrono::milliseconds(60));
    182 	}
    183 
    184 	endwin();
    185 
    186 	return (0);
    187 }