136 lines
3.8 KiB
Ruby
136 lines
3.8 KiB
Ruby
Shoes.app(title: "Honeycombs", height: 700, width: 700) do
|
|
C = Math::cos(Math::PI/3)
|
|
S = Math::sin(Math::PI/3)
|
|
Radius = 60.0
|
|
letters = [
|
|
%w[L A R N D 1 2],
|
|
%w[G U I Y T 3 4],
|
|
%w[P C F E B 5 6],
|
|
%w[V S O M K 7 8],
|
|
%w[Q X J Z H 9 0],
|
|
]
|
|
|
|
def highlight(hexagon)
|
|
hexagon.style(fill: magenta)
|
|
end
|
|
|
|
def unhighlight(hexagon)
|
|
hexagon.style(fill: yellow)
|
|
end
|
|
|
|
def choose(hexagon)
|
|
hexagon.choose
|
|
highlight hexagon
|
|
chosen = @hexagons.find_all {|h| h.chosen?}.map {|h| h.letter}
|
|
if chosen.size == @hexagons.size
|
|
@chosen.text = 'Every hexagon has been chosen.'
|
|
else
|
|
@chosen.text = "Chosen: #{chosen.sort.join(',')}\n" +
|
|
"Last Chosen: #{hexagon.letter}"
|
|
end
|
|
end
|
|
|
|
width = 20 + (Radius*(7*letters[0].size - 3)/4.0).ceil
|
|
height = 60 + (Radius*(1 + 2*S*letters.size)).ceil
|
|
@hexagons = []
|
|
letter_to_hex = {}
|
|
|
|
# create the GUI
|
|
stack(height: height, width: width) do
|
|
@chosen = para("Chosen:\nLast chosen:")
|
|
|
|
# draw the hexagrams
|
|
letters.each_index do |row|
|
|
letters[0].each_index do |column|
|
|
x = 60 + column * Radius * 0.75 + (1-S) * Radius
|
|
y = 80 + row * S * Radius + (column.odd? ? S * Radius * 0.5 : 0)
|
|
h = shape(x-Radius, y-S*Radius) do
|
|
strokewidth 3
|
|
move_to(x-C*Radius, y-S*Radius)
|
|
line_to(x+C*Radius, y-S*Radius)
|
|
line_to(x+Radius, y)
|
|
line_to(x+C*Radius, y+S*Radius)
|
|
line_to(x-C*Radius, y+S*Radius)
|
|
line_to(x-Radius, y)
|
|
line_to(x-C*Radius, y-S*Radius)
|
|
end
|
|
|
|
# add some attributes and methods to the shape
|
|
class << h
|
|
attr_accessor :x, :y, :state, :letter
|
|
def chosen?
|
|
not @state.nil?
|
|
end
|
|
def choose
|
|
@state = :chosen
|
|
end
|
|
def contains?(px, py)
|
|
if @x-Radius < px and px <= @x-C*Radius
|
|
ratio = (px - @x + Radius)/(Radius*(1-C))
|
|
@y - ratio*S*Radius < py and py <= @y + ratio*S*Radius
|
|
elsif @x-C*Radius < px and px <= @x+C*Radius
|
|
@y - S*Radius < py and py < @y + S*Radius
|
|
elsif @x+C*Radius < px and px <= @x+Radius
|
|
ratio = (@x + Radius - px)/(Radius*(1-C))
|
|
@y - ratio*S*Radius < py and py <= @y + ratio*S*Radius
|
|
else
|
|
false
|
|
end
|
|
end
|
|
def inspect
|
|
%q(<%s,"%s",%s,%d@%d>) % [self.class, letter, chosen?, x, y]
|
|
end
|
|
end
|
|
|
|
h.x = x + x - Radius
|
|
h.y = y + y - S*Radius
|
|
h.letter = letters[row][column]
|
|
unhighlight h
|
|
|
|
@hexagons << h
|
|
letter_to_hex[h.letter.downcase] = h
|
|
letter_to_hex[h.letter.upcase] = h
|
|
|
|
# add the letter to the hexagon
|
|
para(h.letter).style(size:56, stroke:red) \
|
|
.move(h.x - C*Radius, h.y - S*Radius)
|
|
end
|
|
end
|
|
|
|
# highlight the hexagon under the mouse
|
|
hex_over = nil
|
|
motion do |x, y|
|
|
hex = @hexagons.find {|h| h.contains?(x,y)}
|
|
unless hex.nil? or hex.chosen?
|
|
highlight hex
|
|
end
|
|
unless hex_over == hex or hex_over.nil? or hex_over.chosen?
|
|
unhighlight hex_over
|
|
end
|
|
hex_over = hex
|
|
end
|
|
|
|
# handle mouse clicks
|
|
click do |button, x, y|
|
|
info("button #{button} clicked at (#{x}, #{y})")
|
|
hexagon = @hexagons.find {|h| h.contains?(x,y)}
|
|
if hexagon
|
|
info("clicked hexagon #{hexagon}")
|
|
choose hexagon
|
|
end
|
|
end
|
|
|
|
# handle keystrokes
|
|
keypress do |key|
|
|
if key == "\x11" # control-Q
|
|
exit
|
|
elsif key == "?"
|
|
info @hexagons.collect {|h| h.inspect}.join("\n")
|
|
elsif letter_to_hex.has_key?(key)
|
|
info("pressed key #{key} -> #{letter_to_hex[key]}")
|
|
choose letter_to_hex[key]
|
|
end
|
|
end
|
|
end
|
|
end
|