wm: dino

ref: 796572b18e177f129778b68460a2618de881a624
dir: /dino.c/

View raw version
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <time.h>

#include <errno.h>
#include <fcntl.h>
#include <local/colors.h>
#include <signal.h>
#include <sys/ioctl.h>

#define DINASOUR_HEIGHT 15
#define DINASOUR_WIDTH 15
#define SUN_HEIGHT 5
#define SUN_WIDTH 5
#define DELAY 60000
#define TREE_HEIGHT 7
#define TREE_WIDTH 7
void die(const char *msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}
char *colors[] = {

    // black_fg,
    red_fg,
    // green_fg ,
    yellow_fg,
    // blue_fg   ,
    // magenta_fg,
    // cyan_fg   ,
    // white_fg  ,
};

char *fbuffer = NULL; // should be point_t* buffer
uint64_t fbuffer_size = 0;
static volatile int cursor = 0;
int max_y;
int max_x;
static volatile bool resize = false;
typedef struct {
  bool *matrix;
  int height;
  int width;
  int x;
  int y;
  bool visible;
} shape_t;
// a hash tables suits better no?
// keys will be memory address of shapes.
// and vals will be the number of times they collided
// and um, we also need to store coordinates of collisions?
// maybe we can use an observer pattern here!\
// each shape subscribes to collisions,...
typedef struct collision_t {
  shape_t *shape;
  struct collision_t *next;
} collision_t;

typedef struct {
  char *escapes;
  char charachter;
  // collision_t collisions; // it's actually better to have a global collisions
  // (hash table or linked list and update it every tflush()).
  int x;
  int y;
  bool written;
} point_t;
void alloc_fbuf();

void gotoxy(int x, int y) {
  if (x >= max_x || y >= max_y)
    return;
  int new_cursor = (max_x * y) + x;
  cursor = (max_x * y) + x;
}
void _gotoxy(int x, int y) { printf("%c[%d;%df", 0x1B, y, x); }
void max_xy(int signo) {
  (void)signo;
  struct winsize w;
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

  max_x = w.ws_col;
  max_y = w.ws_row;
  resize = true;
  // alloc_fbuf();
}

void tprint(const char c) {
  if (cursor >= fbuffer_size || cursor < 0)
    return;
  fbuffer[cursor++] = c;
}


void draw_line(point_t a, point_t b) {
  // int slope = (a.y - b.y) / (a.x - b.x);
  int dy = b.y - a.y;
  int dx = b.x - a.x;

  while (true) {
    int newx = a.x + dx;
    int newy = a.y + dy;

    if (newx == b.x && newy == b.y)
      break;
    gotoxy(a.x + dx, a.y + dy);
    tprint('*');
  }
}

void draw_shape(shape_t *shape, const char *color) {
  if (shape->visible) { // FIXME : idk why this happens.
    return;
  }
  bool print_newline = false;
  // gotoxy(shape->x, shape->y);

  for (int i = 0; i < shape->height; i++) {
    gotoxy(shape->x, shape->y + i);
    for (int j = 0; j < shape->width; j++) {
      if (shape->matrix[i * shape->height + j]) {
        print_newline = true;
        // printf("%s%s%s", inverse_off ,  color, " " reset );
        tprint('*');
      } else {
        // printf(" ");
        tprint(' ');
      }
    }
    if (print_newline)
      printf("\r");
    // fbuffer[cursor] = '\n'
    tprint('\n');
  }
}

shape_t *init_shape(int width, int height) {
  shape_t *ret = calloc(width * height, sizeof(bool));
  return ret;
}

void free_shape(shape_t *shape) { free(shape); }

void tflush() {
  for (uint64_t row = 0; row < max_y; ++row) {
    printf("\n");
    for (uint64_t col = 0; col < max_x; ++col) {
      if (fbuffer[row * max_x + col] == '*') {
        _gotoxy(col, row);
        // printf("%s%s %s",inverse, colors[rand() %
        // sizeof(colors)/sizeof(*colors)], reset);
        printf("%s%c%s", reset inverse, /*fbuffer[row * max_x + col]*/ ' ',
               reset);

      } else
        printf(reset " " reset);
    }
  }
  // write(STDOUT_FILENO, fbuffer, max_x * max_y); // drawing will be very
  // smooth this way.
}

void alloc_fbuf() {
  if (max_x * max_y > fbuffer_size) {
    fbuffer_size = max_y * max_x; //* sizeof(char);
    fbuffer = realloc(fbuffer, fbuffer_size);
    assert(fbuffer);
  }
}

bool dinasour_frame1[DINASOUR_WIDTH][DINASOUR_HEIGHT] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0},
    {1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0},
    {1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0},
    {1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0},
};

bool dinasour_frame2[DINASOUR_WIDTH][DINASOUR_HEIGHT] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0},
    {1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0},
    {1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0},
    {1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
};

bool dinasour_frame3[DINASOUR_WIDTH][DINASOUR_HEIGHT] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0},
    {1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0},
    {1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0},
    {1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
};

bool tree_1[TREE_WIDTH][TREE_HEIGHT] = {
    {1, 1, 1, 0, 0, 1, 1}, {1, 0, 1, 0, 1, 0, 1}, {1, 0, 0, 1, 0, 0, 1},
    {0, 1, 0, 0, 0, 1, 0}, {0, 0, 1, 0, 1, 0, 0}, {0, 0, 1, 0, 1, 0, 0},
    {0, 0, 1, 1, 1, 0, 0},
};

void clear_screen() {
  memset(fbuffer, 0, fbuffer_size);
  printf("\033c");
}

int main(int argc, char *argv[]) {
  max_xy(0);
  alloc_fbuf();
  shape_t dinasour_f1 = {.matrix = &dinasour_frame1[0][0],
                         .width = DINASOUR_WIDTH,
                         .height = DINASOUR_HEIGHT,
                         .x = 10,
                         .y = 10};

  shape_t dinasour_f2 = {.matrix = &dinasour_frame2[0][0],
                         .height = DINASOUR_HEIGHT,
                         .width = DINASOUR_WIDTH,
                         .x = 10,
                         .y = 10};

  shape_t dinasour_f3 = {
      .matrix = &dinasour_frame3[0][0],
      .height = DINASOUR_HEIGHT,
      .width = DINASOUR_WIDTH,
      .x = 10,
      .y = 10,
  };

  shape_t dinasour2_f1 = {.matrix = &dinasour_frame1[0][0],
                          .width = DINASOUR_WIDTH,
                          .height = DINASOUR_HEIGHT,
                          .x = 10,
                          .y = 10,
                          .visible = true};

  shape_t dinasour2_f2 = {.matrix = &dinasour_frame2[0][0],
                          .height = DINASOUR_HEIGHT,
                          .width = DINASOUR_WIDTH,
                          .x = 10,
                          .y = 10,
                          .visible = true};

  shape_t dinasour2_f3 = {.matrix = &dinasour_frame3[0][0],
                          .height = DINASOUR_HEIGHT,
                          .width = DINASOUR_WIDTH,
                          .x = 10,
                          .y = 10 + DINASOUR_HEIGHT + 2,
                          .visible = true};

  bool sun_matrix[SUN_HEIGHT][SUN_WIDTH] = {
      {0, 0, 1, 0, 0}, {0, 1, 0, 1, 0}, {1, 0, 0, 0, 1},
      {0, 1, 0, 1, 0}, {0, 0, 1, 0, 0},
  };
  shape_t sun = {.matrix = &sun_matrix[0][0],
                 .height = SUN_HEIGHT,
                 .width = SUN_WIDTH,
                 .x = (float)max_x / 2,
                 .y = 10};
  shape_t tree = {.matrix = &tree_1[0][0],
                  .height = TREE_HEIGHT,
                  .width = TREE_WIDTH,
                  .x = 50,
                  .y = 10 + DINASOUR_HEIGHT - TREE_HEIGHT};
  struct sigaction sa;
  sa.sa_handler = max_xy;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  // sigaction(SIGWINCH, &sa, NULL);

  int randx = 0;
  int randy = 0;
  clear_screen();
  shape_t *arr[3] = {&dinasour_f1, &dinasour_f2, &dinasour_f3};
  shape_t *arr2[3] = {&dinasour2_f1, &dinasour2_f2, &dinasour2_f3};
  unsigned int index = 0;
  srand(time(NULL));
  unsigned int t = 1;

  shape_t *current_tree = malloc(sizeof(shape_t));
  assert(current_tree);
  current_tree = malloc(sizeof(shape_t));
  current_tree->matrix = &tree_1[0][0];
  current_tree->x = max_x;
  current_tree->y = 10 + DINASOUR_HEIGHT - TREE_HEIGHT;
  current_tree->height = TREE_HEIGHT;
  current_tree->width = TREE_WIDTH;
  current_tree->visible = false;
  shape_t *next_tree = NULL;
  while (true) {
    shape_t *ptr = arr[++index % 3];
    draw_shape(ptr, white_bg);
    if (current_tree)
      draw_shape(current_tree, white_bg);
    if (next_tree) {
      draw_shape(next_tree, white_bg);
    }

    // printf("\nptr->x = %d, ptr->y = %d\n", ptr->x, ptr->y);
    // printf("max_x = %d, max_y = %d\n", max_x, max_y);
    // printf("fbuffer = %#X, fbuffer_size=%PRlu64\n", (unsigned int)fbuffer,
    // fbuffer_size); printf("fbuffer = %#X, fbuffer_size=%llu, cursor = %d\n",
    // fbuffer, fbuffer_size, cursor); draw_shape(&sun, yellow_bg);
    // draw_shape(ptr2, yellow_bg);
    tflush();
    usleep(DELAY);
    /*for (int i = 0; i < 3; ++i) {

      arr[i]->x = (arr[i]->x + rand()) % max_x;
      arr2[i]->x = (arr[i]->x + rand()) % max_x;
      //arr[i]->y = (arr[i]->x - 1) % (max_y - DINASOUR_HEIGHT);
      arr[i]->y = rand() % (max_y - DINASOUR_HEIGHT);

          arr2[i]->x = (arr[i]->x + rand()) % (max_x - DINASOUR_HEIGHT);
          arr2[i]->y = (arr[i]->y + rand()) % (max_y - DINASOUR_HEIGHT);
        } */

    /*for (int i = 0; i < 3; i++) {
            arr[i]->x = (arr[i]->x + 1) % max_x;
    }*/
    if (next_tree)
      --next_tree->x;
    if (current_tree && --current_tree->x == max_x / 2) {
      // tree.visible = true;
      // free(current_tree);
      // current_tree = NULL;
      // current_tree = next_tree;
      next_tree = malloc(sizeof(shape_t));
      assert(next_tree);
      next_tree->matrix = &tree_1[0][0];
      next_tree->x = max_x - TREE_WIDTH;
      next_tree->y = 10 + DINASOUR_HEIGHT - TREE_HEIGHT;
      next_tree->height = TREE_HEIGHT;
      next_tree->width = TREE_WIDTH;
      next_tree->visible = false;
      
    }
    if (current_tree && current_tree->x == 10) {
      free(current_tree);
      current_tree = next_tree;
      next_tree = NULL;
    }

    // collisions();
    assert(cursor <= fbuffer_size + 1);
    /*if (resize) {
      alloc_fbuf();
      resize = false;
    }*/
    clear_screen();
  }
  
  free(fbuffer);
  return 0;
}