snake.cpp (2612B)
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 }