Logo  

CS256 - Fundamentals of Structured Programming

Displaying ./code/snek/snek.c

#include <curses.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <string.h>

typedef enum { NONE, UP, DOWN, LEFT, RIGHT } dir_t;

#define TIMEOUT 80

int score = 0;
int tx, ty, tv;

int tailx[10000];
int taily[10000];
int tlen = 0, head = 0, tail = 0;

int R(int a, int b)
{
  int diff = (a < b? b-a : a-b)+1;
  int min = a < b? a : b;
  return min + (rand()%diff);
}


void startup(void)
{
  initscr();
  cbreak();
  nodelay(stdscr, TRUE);
  noecho();
  keypad(stdscr, TRUE);
  start_color();
  curs_set(0);

  border(ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE,
         ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER);

  srand(time(0) + getpid());
}

void shutdown(void)
{
  curs_set(1);
  echo();
  nocbreak();
  endwin();
}

void drawscore(void)
{
  mvprintw(0, 10, " Score: %d ", score);
}

void placetarget(void)
{
  chtype ch;

  do {
    tx = R(1, COLS-2);
    ty = R(1, LINES-2);
    ch = mvinch(ty,tx) & A_CHARTEXT;
  } while (ch != ' ');

  tv = R(1, 9);
  mvprintw(ty, tx, "%d", tv);
}

void addtail(int x, int y)
{
  tailx[tlen] = x;
  taily[tlen] = y;
  tlen++;
  mvaddch(y, x, 'o');
}

void eattarget(void)
{
  score = score + tv;
  drawscore();
  mvaddch(ty, tx, ' ');
  for(int i=tlen-1; i >= tail; i--) {
    tailx[i+tv] = tailx[i];
    taily[i+tv] = taily[i];
  }
  tlen = tlen + tv;
  if (head > tail) head = head + tv;
  tail = tail + tv;
  placetarget();
}

void die()
{
  char *diemsg = "You've hit something and died.";
  mvprintw(LINES/2, COLS/2 - strlen(diemsg)/2, "%s", diemsg);
  nodelay(stdscr, FALSE);
  getch();
  shutdown();
  exit(0);
}

int main(void)
{
  startup();
  int x = 9, y = LINES/2;
  dir_t dir = NONE;
  int timeout = 0;

  drawscore();

  placetarget();

  for(x=3; x < 9; x++) addtail(x, y);
  addtail(x, y);
  mvaddch(y, x, '@');
  move(y, x);
  head = tlen-1;
  tail = 0;

  while(1) {
    int ch = getch();
    if (ch != ERR) timeout = TIMEOUT;
    usleep(10000);
    timeout++;

    if (timeout > TIMEOUT) {
      if (ch == 'q' || ch == 'Q') break;
      if (ch == KEY_UP || ch == 'w') dir = UP;
      if (ch == KEY_DOWN || ch == 's') dir = DOWN;
      if (ch == KEY_LEFT || ch == 'a') dir = LEFT;
      if (ch == KEY_RIGHT || ch == 'd') dir = RIGHT;

      if (dir == NONE) continue;
      if (dir == UP) y--;
      if (dir == DOWN) y++;
      if (dir == LEFT) x--;
      if (dir == RIGHT) x++;
      timeout = 0;

      if (y == ty && x == tx) {
	eattarget();
      } else {
	chtype ch = mvinch(y,x) & A_CHARTEXT;
	if (ch != ' ' || y == 0) die();
      }
      mvaddch(y, x, '@');
      mvaddch(taily[head],tailx[head], 'o');
      mvaddch(taily[tail],tailx[tail], ' ');
      int newhead = (head + 1) % tlen;
      if (newhead == tail)
	tail = (tail + 1) % tlen;
      head = newhead;

      tailx[head] = x;
      taily[head] = y;
      move(y, x);
      refresh();
    }
  }

  shutdown();
  return 0;
}