Blob Blame Raw
#include <stdlib.h>
#include <time.h>
#include <gtk/gtk.h>

#define COLS 10
#define ROWS 20

const int size = 30;
const int colors_count = 3;
const double colors[][3] = {
  { 1, 1, 1 },
  { 1, 1, 0 },
  { 1, 0, 0 },
  { 0, 0, 1 },
  { 0.66, 0.66, 0.66 },
  { 0.33, 0.33, 0.33 } };

int board[COLS][ROWS];


void new_game() {
  srand(time(NULL));
  for(int x = 0; x < COLS; ++x)
    for(int y = 0; y < ROWS; ++y)
      board[x][y] = 1 + rand()%colors_count;
}

int get_block(int x, int y) {
  if (x < 0 || y < 0 || x >= COLS || y >= ROWS)
    return -1;
  return board[x][y];
}

void check(int x, int y) {
  int color = get_block(x, y);
  if (color > 0) {
    if (get_block(x-1, y) == color) {
      board[x][y] = 0;
      check(x-1, y);
      board[x-1][y] = 0;
    }
    if (get_block(x+1, y) == color) {
      board[x][y] = 0;
      check(x+1, y);
      board[x+1][y] = 0;
    }
    if (get_block(x, y-1) == color) {
      board[x][y] = 0;
      check(x, y-1);
      board[x][y-1] = 0;
    }
    if (get_block(x, y+1) == color) {
      board[x][y] = 0;
      check(x, y+1);
      board[x][y+1] = 0;
    }
  }
}

void fall() {
  int dx = 0;
  for(int x = 0; x < COLS; ++x) {
    int dy = 0;
    for(int y = 0; y < ROWS; ++y) {
      if (board[x][y] != 0) {
        if (dx > 0 || dy > 0) {
          board[x-dx][y-dy] = board[x][y];
          board[x][y] = 0;
        }
      } else {
        ++dy;
      }
    }
    if (dy == ROWS) ++dx;
  }
}

gboolean button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
  if (event->button == 1) {
    check((int)(event->x)/size, ROWS - 1 - (int)(event->y)/size);
    fall();
  } else
  if (event->button == 3) {
    new_game();
  }
  gtk_widget_queue_draw(widget);
  return TRUE;
}

gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
  for(int x = 0; x < COLS; ++x) {
    for(int y = 0; y < ROWS; ++y) {
      int c = board[x][ROWS - 1 - y];
      cairo_rectangle(cr, x*size, y*size, size, size);
      cairo_set_source_rgb(cr, colors[c][0], colors[c][1], colors[c][2]);
      cairo_fill(cr);
    }
  }
  return TRUE;
}

void activate(GtkApplication* app, gpointer data) {
  GtkWidget *window = gtk_application_window_new (app);
  g_signal_connect(window, "draw", G_CALLBACK(draw), NULL);
  g_signal_connect(window, "button-press-event", G_CALLBACK(button_press), NULL);
  gtk_window_set_default_size(GTK_WINDOW(window), size*COLS, size*ROWS);
  gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
  gtk_widget_show_all(window);

  new_game();
}

int main(int argc, char **argv) {
  GtkApplication *application = gtk_application_new(NULL, 0);
  g_signal_connect(application, "activate", G_CALLBACK(activate), NULL);
  int status = g_application_run(G_APPLICATION(application), argc, argv);
  g_object_unref(application);
  return status;
}