Day 47 — What? Snek is evolving! Congratulations! Your snek evolved into Curlyboi!

Recently I found this snake game by Julia Evans and thought that it might be fun to go through it to learn more about large-ish C projects and ncurses! I also paired with Edith (who is writing her own text editor from scratch!) to walk through the code and understand how pointers and malloc work!

I'm not yet sure of other ways to write a terminal game, but from what I understood from the snake code and ncurses docs, we need to:

  1. Initialize game state
  2. Get ahold of the terminal
  3. Update the game state with some input
  4. Clear the terminal and print new game state
  5. Go back to 3!

I've known about curlyboi since the last two PyCon AUs. So I thought that it might be fun to extend the snake game Julia wrote into curlyboi!

First step, get colors! ncurses lets us define color pairs, and give them a number, which we can refer to later to print colored text.


  start_color();
  init_pair(1, COLOR_GREEN, COLOR_BLACK);
  init_pair(2, COLOR_YELLOW, COLOR_BLACK);
  init_pair(3, COLOR_MAGENTA, COLOR_BLACK);
  init_pair(4, COLOR_RED, COLOR_BLACK);
  init_pair(5, COLOR_BLUE, COLOR_BLACK);

All these 5 colors are in the curlyboi color order, except magenta in place of orange, because curses.h does not define a COLOR_ORANGE :(

I also found these unicode half-ish blocks which look similar to curlyboi's curls!

And added this while loop to print these curls alternatingly based on their x and y position, and on the direction in which curlyboi is going, to simulate a slither!


  int pos = 0;
  const wchar_t* symbol = L"▛";

  while (snake) {
      switch (dir) {
          case UP:
              symbol = snake->y % 2 == 0 ? L"▟" : L"▙";
              break;
          case DOWN:
              symbol = snake->y % 2 == 0 ? L"▜" : L"▛";
              break;
          case LEFT:
              symbol = snake->x % 2 == 0 ? L"▜" : L"▟";
              break;
          case RIGHT:
              symbol = snake->x % 2 == 0 ? L"▛" : L"▙";
              break;
      }
      attron(COLOR_PAIR((pos % 5) + 1));
      mvaddwstr(snake->y, snake->x, symbol);

      pos = pos + 1;
      snake = snake->next;
  }

attron(COLOR_PAIR((pos % 5) + 1)) applies one of the color pairs we defined above to each curl based on its position in curlyboi!

And since I was doing unicode, I added food emojis (over a 100 of them)!


  const int NUM_FOODS = 113;
  wchar_t* FOODS[113] = {
      L"🍇",
      L"🍈",
      L"🍉",
      L"🍊",
      L"🍋",
      L"🍌",
      L"🍍",
      L"🥭",
      L"🍎",
      ...
  }

I had to add a data variable to struct Point which holds the value of this food whenever it is initialized:


  struct Point {
      int x;
      int y;
      wchar_t* data;
      struct Point *next;
  };

Finally, while compiling the game, I had to link to ncursesw (the wide unicode version) instead of ncurses. It looks like this:

curlyboi

You can check out the code here!