Honeycombs

require('Tk')

class Honeycombs(
    Number size   = 36,
    Array letters = @('A' .. 'Z').shuffle.first(20),
) {

    define tk   = %S<Tk>
    has changed = Hash()

    func altitude(n) {
        sqrt(3/4) * n
    }

    method polygon_coordinates(x, y, size) {
        var alt = altitude(size)
        return (x - size,       y,
                x - size/2, y - alt,
                x + size/2, y - alt,
                x + size,       y,
                x + size/2, y + alt,
                x - size/2, y + alt,
               );
    }

    method change(canvas, id, letter_id) {
        return {
            canvas.itemconfigure(id,        '-fill' => 'magenta')
            canvas.itemconfigure(letter_id, '-fill' => 'black')
            changed{id} = true

            if (20 == changed.len) {
                say "All letters pressed."
                canvas.MainWindow.after(10, { tk.exit })
            }
        }
    }

    method comb(canvas, fromx, fromy, size, count) {
        for x,y in (
            RangeNum(fromx, 3*count*size - 1,          3*size) ~X
            RangeNum(fromy,     7.5*size - 1, 2*altitude(size))
        ) {
            var id = canvas.createPolygon(
                                  self.polygon_coordinates(x, y, size),
                                  '-outline' => 'black',
                                  '-fill'    => 'yellow',
                                  '-width'   => 2,
                                )
            var letter = letters.shift
            var letter_id = canvas.createText(x, y,
                                     '-fill' => 'red',
                                     '-text' => letter,
                                     '-font' => "{sans} #{size * 0.9}",
                                )
            canvas.MainWindow.bind('all', letter.lc,
                                      self.change(canvas, id, letter_id))
            [id, letter_id].each { |b|
                canvas.bind(b, '<Button-1>',
                                      self.change(canvas, id, letter_id))
            }
        }
    }

    method display(title) {
        {
            var mw     = %s'MainWindow'.new('-title' => title)
            var canvas = mw.Canvas('-width'  => 8*size,
                                   '-height' => 8*size).pack

            self.comb(canvas, size,       size,                  size, 3)
            self.comb(canvas, size * 2.5, size + altitude(size), size, 2)

            var btn = mw.Button('-text'      => 'Quit',
                                '-underline' => 0,
                                '-command'   => { tk.exit },
                               ).pack
            mw.bind('<Alt-q>', { btn.invoke })
            tk.MainLoop()
        }.fork
    }
}

Honeycombs().display(title: 'Honeycombs')