Task: Honeycombs

C: 










#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<gtk/gtk.h>

static GdkPixbuf*create_pixbuf(const gchar*filename) {
  GdkPixbuf*pixbuf;
  GError*error = NULL;
  pixbuf = gdk_pixbuf_new_from_file(filename, &error);
  if(!pixbuf) {
    fprintf(stderr,"\n%s\n", error->message);
    g_error_free(error);
  }
  return pixbuf;
}

#define NGON struct ngon
NGON {
  double Cx,Cy, r;
  int sides, selected;
  char c;
};

GRand*random_numbers = NULL;

#define R 20
#define TAU (2*M_PI)	   
  if ((broken = (NULL == random_numbers)))
    random_numbers = g_rand_new();
  for (i = 'A'; i <= 'Z'; ++i)
    g_queue_push_head(shuffler,GINT_TO_POINTER(i));
  memset(hs,0,n*(sizeof(NGON)));
  hs[n-1].sides = -1;		
  for (h = hs; !h->sides; ++h) {
    int div = (h-hs)/4, mod = (h-hs)%4;
    h->sides = 6;
    h->c = GPOINTER_TO_INT(
	     g_queue_pop_nth(
	       shuffler,
	       g_rand_int_range(
		 random_numbers,
		 (gint32)0,
		 (gint32)g_queue_get_length(shuffler))));
    fputc(h->c,stderr);
    h->r = R;
    h->Cx = R*(2+div*OFFSET_X), h->Cy = R*(2*(1+mod*OFFSET_Y)+ODD(div)*OFFSET_Y);
    fprintf(stderr,"(%g,%g)\n",h->Cx,h->Cy);
  }
  fputc('\n',stderr);
  g_queue_free(shuffler);
  if (broken)
    g_rand_free(random_numbers);  
}

static void add_loop(cairo_t*cr,NGON*hs,int select) {
  NGON*h;
  double r,Cx,Cy,x,y;
  int i, sides;
  for (h = hs; 0 < (sides = h->sides); ++h)
    if ((select && h->selected) || (select == h->selected)) {
      r = h->r, Cx = h->Cx, Cy = h->Cy;
      i = 0;
      x = Cx+r*cos(TAU*i/sides), y = Cy+r*sin(TAU*i/sides), cairo_move_to(cr,x,y);
      for (i = 1; i < sides; ++i)
        x = Cx+r*cos(TAU*i/sides), y = Cy+r*sin(TAU*i/sides), cairo_line_to(cr,x,y);
      cairo_close_path(cr);
    }
}

static int make_labels(cairo_t*cr,NGON*hs,int select) {
  NGON*h;
  int i = 0;
  char text[2];
  text[1] = 0;
  for (h = hs; 0 < h->sides; ++h)
    if ((select && h->selected) || (select == h->selected))
      
      *text = h->c, cairo_move_to(cr,h->Cx,h->Cy), cairo_show_text(cr,text), ++i;
  return i;
}

static int archive(int a) {
  static GQueue*q = NULL;
  if ((NULL == q) && (NULL == (q = g_queue_new()))) {
    fputs("\ncannot allocate archival queue.  quitting!\n",stderr);
    exit(EXIT_FAILURE);
  }
  if (a < -1)			
    return g_queue_free(q), q = NULL, 0;
  if (-1 == a)			
    return g_queue_is_empty(q) ? 0 : GPOINTER_TO_INT(g_queue_pop_tail(q));
  if (!a)			
    return g_queue_is_empty(q) ? 0 : GPOINTER_TO_INT(g_queue_peek_head(q));
  g_queue_push_head(q,GINT_TO_POINTER(a)); 
  return a;
}


static gboolean draw(GtkWidget*widget,cairo_t*cr,gpointer data) {

  
  cairo_set_source_rgba(cr,0.8,0.8,0,1),
  add_loop(cr,(NGON*)data,0);
  cairo_fill(cr);

  
  cairo_set_source_rgba(cr,0.8,0,0.8,1);
  add_loop(cr,(NGON*)data,1);
  cairo_fill_preserve(cr);

  
  cairo_set_line_width (cr, 3.0);
  cairo_set_source_rgba(cr,0.7,0.7,0.7,0.7); 
  add_loop(cr,(NGON*)data,0);
  cairo_stroke(cr);

  
  cairo_set_source_rgba(cr,0,1,0,1);
  make_labels(cr,(NGON*)data,1);
  cairo_stroke(cr);

  
  cairo_set_source_rgba(cr,1,0,0,1);
  
  if (!make_labels(cr,(NGON*)data,0)) {
    int c;
    putchar('\n');
    while ((c = archive(-1)))
      putchar(c);
    puts("\nfinished");
    archive(-2);
    exit(EXIT_SUCCESS);
  }
  cairo_stroke(cr);

  return TRUE;
}


static gboolean button_press_event(GtkWidget*widget,const GdkEvent*event,gpointer data) {
  NGON*h,*hs = (NGON*)data;
  gdouble x_win, y_win;
  if (!gdk_event_get_coords(event,&x_win,&y_win))
    fputs("\nBUTTON, gdk_event_get_coords(event,&x_win,&y_win)) failed\n",stderr);
  else {
    fprintf(stderr,"x_win=%g y_win=%g\n",(double)x_win,(double)y_win);
    for (h = hs; 0 < h->sides; ++h) 
      
      
      if ((pow((x_win-h->Cx),2)+pow((y_win-h->Cy),2)) < pow((h->r*cos(TAU/(180/h->sides))),2)) {
	++h->selected;
	archive(h->c);
	
	gdk_window_invalidate_rect(gtk_widget_get_window(widget),(const GdkRectangle*)NULL,TRUE);
	break;
      }
  }
  return TRUE;
}

static gboolean key_press_event(GtkWidget*widget,const GdkEvent*event,gpointer data) {
  NGON*h,*hs = (NGON*)data;
  guint keyval;
  int unicode;
  if (!gdk_event_get_keyval(event,&keyval))
    fputs("\nKEY!  gdk_event_get_keyval(event,&keyval)) failed.\n",stderr);
  else {
    unicode = (int)gdk_keyval_to_unicode(gdk_keyval_to_upper(keyval));
    fprintf(stderr,"key with unicode value: %d\n",unicode);
    for (h = hs; 0 < h->sides; ++h) 
      if (h->c == unicode) {
	++(h->selected);
	archive(h->c);
	
	gdk_window_invalidate_rect(gtk_widget_get_window(widget),(const GdkRectangle*)NULL,TRUE);
	break;
      }
  }
  return TRUE;
}

int main(int argc,char*argv[]) {
  GtkWidget *window, *vbox,  *drawing_area;
  NGON ngons[21];	   

  
  
  gtk_init(&argc, &argv);

  
  fprintf(stderr,"GTK VERSION %d.%d.%d\n",GTK_MAJOR_VERSION,GTK_MINOR_VERSION,GTK_MICRO_VERSION);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  

  
  
  gtk_window_set_title(GTK_WINDOW(window), "Rosetta Code Honeycomb, C with GTK");
  gtk_window_set_default_size(GTK_WINDOW(window), 308, 308+12+8); 
  
  
  g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);

  
  gtk_window_set_icon(GTK_WINDOW(window),create_pixbuf("/tmp/favicon.ico"));

  vbox = gtk_vbox_new(TRUE,1);
  gtk_container_add(GTK_CONTAINER(window),vbox);

  
  
  
  
#if 0
  label = gtk_label_new("None Selected");
  gtk_widget_set_size_request(label,308,20);
  gtk_box_pack_end(GTK_BOX(vbox),label,FALSE,TRUE,4);
#endif

  drawing_area = gtk_drawing_area_new();
  gtk_widget_set_events(drawing_area,GDK_BUTTON_PRESS_MASK|GDK_KEY_PRESS_MASK|GDK_EXPOSURE_MASK);

  random_numbers = g_rand_new();
  initialize_hexagons(ngons,G_N_ELEMENTS(ngons));
  
  g_signal_connect(G_OBJECT(drawing_area),"draw",G_CALLBACK(draw),(gpointer)ngons);

  g_signal_connect(G_OBJECT(drawing_area),"button-press-event",G_CALLBACK(button_press_event),(gpointer)ngons);
  g_signal_connect(G_OBJECT(drawing_area),"key-press-event",G_CALLBACK(key_press_event),(gpointer)ngons);
  gtk_widget_set_size_request(drawing_area, 308, 308); 
  gtk_box_pack_start(GTK_BOX(vbox),drawing_area,TRUE,TRUE,4);

  
  gtk_widget_set_can_focus(drawing_area,TRUE);

  
  gtk_widget_show_all(window);
  gtk_main();
  g_rand_free(random_numbers);
  return EXIT_SUCCESS;
}





Java: import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Honeycombs extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new Honeycombs();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);
        });
    }

    public Honeycombs() {
        add(new HoneycombsPanel(), BorderLayout.CENTER);
        setTitle("Honeycombs");
        setResizable(false);
        pack();
        setLocationRelativeTo(null);
    }
}

class HoneycombsPanel extends JPanel {

    Hexagon[] comb;

    public HoneycombsPanel() {
        setPreferredSize(new Dimension(600, 500));
        setBackground(Color.white);
        setFocusable(true);

        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                for (Hexagon hex : comb)
                    if (hex.contains(e.getX(), e.getY())) {
                        hex.setSelected();
                        break;
                    }
                repaint();
            }
        });

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                for (Hexagon hex : comb)
                    if (hex.letter == Character.toUpperCase(e.getKeyChar())) {
                        hex.setSelected();
                        break;
                    }
                repaint();
            }
        });

        char[] letters = "LRDGITPFBVOKANUYCESM".toCharArray();
        comb = new Hexagon[20];

        int x1 = 150, y1 = 100, x2 = 225, y2 = 143, w = 150, h = 87;
        for (int i = 0; i < comb.length; i++) {
            int x, y;
            if (i < 12) {
                x = x1 + (i % 3) * w;
                y = y1 + (i / 3) * h;
            } else {
                x = x2 + (i % 2) * w;
                y = y2 + ((i - 12) / 2) * h;
            }
            comb[i] = new Hexagon(x, y, w / 3, letters[i]);
        }

        requestFocus();
    }

    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        g.setFont(new Font("SansSerif", Font.BOLD, 30));
        g.setStroke(new BasicStroke(3));

        for (Hexagon hex : comb)
            hex.draw(g);
    }
}

class Hexagon extends Polygon {
    final Color baseColor = Color.yellow;
    final Color selectedColor = Color.magenta;
    final char letter;

    private boolean hasBeenSelected;

    Hexagon(int x, int y, int halfWidth, char c) {
        letter = c;
        for (int i = 0; i < 6; i++)
            addPoint((int) (x + halfWidth * Math.cos(i * Math.PI / 3)),
                     (int) (y + halfWidth * Math.sin(i * Math.PI / 3)));
        getBounds();
    }

    void setSelected() {
        hasBeenSelected = true;
    }

    void draw(Graphics2D g) {
        g.setColor(hasBeenSelected ? selectedColor : baseColor);
        g.fillPolygon(this);

        g.setColor(Color.black);
        g.drawPolygon(this);

        g.setColor(hasBeenSelected ? Color.black : Color.red);
        drawCenteredString(g, String.valueOf(letter));
    }

    void drawCenteredString(Graphics2D g, String s) {
        FontMetrics fm = g.getFontMetrics();
        int asc = fm.getAscent();
        int dec = fm.getDescent();

        int x = bounds.x + (bounds.width - fm.stringWidth(s)) / 2;
        int y = bounds.y + (asc + (bounds.height - (asc + dec)) / 2);

        g.drawString(s, x, y);
    }
}